#!/usr/bin/env python3 # -*- coding: utf-8 -*- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # IMPORTS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ from local.maths import *; from local.typing import *; from code.core.log import *; from code.algorithms.methods import *; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # GLOBAL VARIABLES/CONSTANTS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # CHECKS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def preChecks(L: List[int], **_): assert len(L) > 0, 'Liste darf nicht leer sein.'; return; def postChecks(L: List[int], **_): # TODO return; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # ALGORITHM max sub sum # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @algorithmInfos(name='MaxSubSum (Maximale Teilsumme mit D & C)', outputnames=('maxSum', 'index_from', 'index_to'), checks=True, metrics=True, preChecks=preChecks, postChecks=postChecks) def MaxSubSumDC(L: List[float]) -> Tuple[float, int, int]: ''' 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 ''' 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 = math.ceil(len(L)/2); Ll = L[:u]; Lr = L[u:]; ## berechnet maximale Teilsumme der linken Hälfte: maxSum1, u1, v1 = MaxSubSumDC(L=Ll); ## berechnet maximale Teilsumme der rechten Hälfte: maxSum2, u2, v2 = MaxSubSumDC(L=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=Ll, Lr=Lr); ## bestimme Maximum der 3 Möglichkeiten: maxSum = max(maxSum1, maxSum2, maxSum3); if maxSum == maxSum1: maxSum, u, v = maxSum1, u1, v1; logDebug('max Teilsumme kommt in linker Partition vor: Summe L[i] von i={i} bis {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); elif maxSum == maxSum3: maxSum, u, v = maxSum3, u3, v3; logDebug('max Teilsumme kommt in Überschneidung vor: Summe L[i] von i={i} bis {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); else: # elif maxSum == maxSum2: maxSum, u, v = maxSum2, u2, v2; logDebug('max Teilsumme kommt in rechter Partition vor: Summe L[i] von i={i} bis {j} = {value}'.format(L = L, i = u, j = v, value = maxSum)); return maxSum, u, v; # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # AUXILIARY METHODS # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ def lrRandSum(Ll: List[float], Lr: List[float]) -> Tuple[float, int, int]: ''' 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 ''' maxSumL, u, _ = rRandSum(L=Ll); maxSumR, _, v = lRandSum(L=Lr); maxSum = maxSumL + maxSumR; v += len(Ll) # offsets kompensieren return maxSum, u, v; def lRandSum(L: List[float]) -> Tuple[float, int, int]: ''' Bestimmt maximale Teilsumme aller nicht leeren linken Segmente einer Liste. Inputs: L = Liste von Zahlen Outputs: maxSum, u(=0), v ''' n = len(L); ## berechne kumulative Summen (vorwärts) AddToCounter(n); total = L[0]; M = [total]; for i in range(1, n): total += L[i]; M.append(total); ## berechne maximum AddToCounter(n); maxSum = M[0]; u = 0; v = 0; for i in range(1, n): if M[i] > maxSum: v = i; maxSum = M[i]; return maxSum, 0, v; def rRandSum(L: List[float]) -> Tuple[float, int, int]: ''' Bestimmt maximale Teilsumme aller nicht leeren rechten Segmente einer Liste. Inputs: L = Liste von Zahlen Outputs: maxSum, u, v(=len(L)-1) ''' n = len(L); ## berechne kumulative Summen (rückwärts) AddToCounter(n); total = L[n-1]; M = [total]; for i in range(0, n-1)[::-1]: total += L[i]; M.insert(0, total); ## berechne maximum AddToCounter(n); maxSum = M[n-1]; u = n-1; v = n-1; for i in range(0, n-1)[::-1]: if M[i] > maxSum: u = i; maxSum = M[i]; return maxSum, u, v;