ads1_2021/code/golang/internal/algorithms/sum/maxsubsum/maxsubsum.go

168 lines
4.4 KiB
Go

package maxsubsum
/* ---------------------------------------------------------------- *
* IMPORTS
* ---------------------------------------------------------------- */
import (
"ads/internal/core/logging"
"ads/internal/core/metrics"
"ads/internal/core/utils"
)
/* ---------------------------------------------------------------- *
* GLOBAL VARIABLES/CONSTANTS
* ---------------------------------------------------------------- */
//
/* ---------------------------------------------------------------- *
* ALGORITHM max sub sum
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen
Outputs:
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist
*/
func MaxSubSum(L []int) (int, int, int) {
maxSum := 0
u := 0
v := -1
for i := 0; i < len(L); i++ {
// Bestimme maximale Teilsumme der linken Rände der Liste ab Index i {
maxSum_, _, k := lRandSum(L[i:])
if maxSum_ > maxSum {
k += i // NOTE: muss wegen Offset kompensieren
maxSum, u, v = maxSum_, i, k
logging.Debug("max Teilsumme aktualisiert: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
}
}
return maxSum, u, v
}
/* ---------------------------------------------------------------- *
* ALGORITHM max sub sum (D & C)
* ---------------------------------------------------------------- */
/*
Inputs: L = Liste von Zahlen
Outputs:
- maxSum = Wert der maximalen Summe einer Teilliste aufeinanderfolgender Elemente
- u, v = Indexes so dass die Teilliste [L[u], L[u+1], ..., L[v]] die maximale Summe aufweist
*/
func MaxSubSumDC(L []int) (int, int, int) {
maxSum := 0
u := 0
v := -1
if len(L) == 1 {
// wenn Liste aus 1 Element besteht, nicht teilen:
if L[0] > maxSum {
v = 0
maxSum = L[0]
}
} else {
u = utils.Ceil(float64(len(L)) / 2)
Ll := L[:u]
Lr := L[u:]
// berechnet maximale Teilsumme der linken Hälfte:
maxSum1, u1, v1 := MaxSubSumDC(Ll)
// berechnet maximale Teilsumme der rechten Hälfte:
maxSum2, u2, v2 := MaxSubSumDC(Lr)
u2, v2 = u2+len(Ll), v2+len(Ll) // offsets kompensieren
// berechnet maximale Teilsumme mit Überschneidung zw. den Hälften:
maxSum3, u3, v3 := lrRandSum(Ll, Lr)
// bestimme Maximum der 3 Möglichkeiten:
maxSum = utils.MaxInt(maxSum1, maxSum2, maxSum3)
if maxSum == maxSum1 {
maxSum, u, v = maxSum1, u1, v1
logging.Debug("max Teilsumme kommt in linker Partition vor: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
} else if maxSum == maxSum3 {
maxSum, u, v = maxSum3, u3, v3
logging.Debug("max Teilsumme kommt in Überschneidung vor: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
} else { // } else if maxSum == maxSum2 {
maxSum, u, v = maxSum2, u2, v2
logging.Debug("max Teilsumme kommt in rechter Partition vor: Summe L[i] von i=%[1]v .. %[2]v = %[3]v", u, v, maxSum)
}
}
return maxSum, u, v
}
/* ---------------------------------------------------------------- *
* AUXILIARY METHODS
* ---------------------------------------------------------------- */
/*
Bestimmt maximale Teilsumme einer Teiliste einer Liste,
wobei die Liste in zwei Intervalle partitioniert ist
und die Teilliste beide überschneidet.
Inputs: Ll, Lr = eine Partition einer Liste von Zahlen in zwei Intervalle
Outputs: maxSum, u=0, v
*/
func lrRandSum(Ll []int, Lr []int) (int, int, int) {
maxSumL, u, _ := rRandSum(Ll)
maxSumR, _, v := lRandSum(Lr)
maxSum := maxSumL + maxSumR
v += len(Ll) // offsets kompensieren
return maxSum, u, v
}
/*
Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste.
Inputs: L = Liste von Zahlen
Outputs: maxSum, u(=0), v
*/
func lRandSum(L []int) (int, int, int) {
n := len(L)
// berechne kumulative Summen (vorwärts)
metrics.AddTimeCost(n)
total := L[0]
maxSum := total
u := 0
v := 0
for i := 0; i < n; i++ {
total += L[i]
if total > maxSum {
v = i
maxSum = total
}
}
return maxSum, u, v
}
/*
Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste.
Inputs: L = Liste von Zahlen
Outputs: maxSum, u, v(=len(L)-1)
*/
func rRandSum(L []int) (int, int, int) {
n := len(L)
// berechne kumulative Summen (rückwärts)
metrics.AddTimeCost(n)
total := L[n-1]
maxSum := total
u := n - 1
v := n - 1
for i := n - 2; i >= 0; i-- {
total += L[i]
if total > maxSum {
u = i
maxSum = total
}
}
return maxSum, u, v
}