170 lines
4.5 KiB
Go
170 lines
4.5 KiB
Go
|
package maxsubsum
|
||
|
|
||
|
/* ---------------------------------------------------------------- *
|
||
|
* IMPORTS
|
||
|
* ---------------------------------------------------------------- */
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"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.LogDebug(fmt.Sprintf("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.LogDebug(fmt.Sprintf("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.LogDebug(fmt.Sprintf("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.LogDebug(fmt.Sprintf("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
|
||
|
}
|