Algorithm 最大子阵和模M

Algorithm 最大子阵和模M,algorithm,binary-search,modulo,kadanes-algorithm,Algorithm,Binary Search,Modulo,Kadanes Algorithm,我们中的大多数人都熟悉这个问题。我遇到了这个问题的一个变体,它要求程序员以某个数M为模输出所有子数组和的最大值 解决这个变量的简单方法是找到所有可能的子数组和(N^2的数量级,其中N是数组的大小)。当然,这还不够好。问题是——我们如何才能做得更好 示例:让我们考虑以下数组: 6 6 11 15 12 1 设M=13。在这种情况下,子阵列6 6(或12或6 11 15或11 15 12)将产生最大和(=12) 让A作为我们的输入数组,使用基于零的索引。我们可以在不改变结果的情况下减少模M 首先,让

我们中的大多数人都熟悉这个问题。我遇到了这个问题的一个变体,它要求程序员以某个数M为模输出所有子数组和的最大值

解决这个变量的简单方法是找到所有可能的子数组和(N^2的数量级,其中N是数组的大小)。当然,这还不够好。问题是——我们如何才能做得更好

示例:让我们考虑以下数组:

6 6 11 15 12 1

设M=13。在这种情况下,子阵列6 6(或12或6 11 15或11 15 12)将产生最大和(=12)

让A作为我们的输入数组,使用基于零的索引。我们可以在不改变结果的情况下减少模M

首先,让我们通过计算表示a的前缀和的数组p(模M),将问题简化为一个稍微简单的问题:

现在,让我们按降序处理解决方案子阵列的可能左边界。这意味着我们将首先确定从索引n-1开始的最优解,然后是从索引n-2开始的最优解,等等

在我们的示例中,如果选择i=3作为左边界,则可能的子数组和由后缀p[3..n-1]加上常数a=a[i]-p[i]表示:

全局最大值也将出现在一个点上。由于我们可以从右向左插入后缀值,因此我们现在将问题归结为以下几点:

给定一组值S和整数x和M,求S+x模M的最大值

这个很简单:只需使用一个平衡的二叉搜索树来管理S的元素。给定一个查询x,我们希望在S中找到小于M-x的最大值(即在添加x时不会发生溢出的情况)。如果没有这样的值,就使用S的最大值。这两个值都可以在O(log | S |)时间内完成

此解决方案的总运行时间:O(n日志n)

这里有一些C++代码来计算最大和。还需要一些较小的自适应来返回最佳子阵列的边界:

#包括
使用名称空间std;
int max_mod_sum(常数向量&A,int M){
向量P(A.size());
对于(int i=0;i0?P[i-1]:0))%M;
设置S;
int res=0;
对于(int i=A.size()-1;i>=0;--i){
S.插入(P[i]);
int a=(a[i]-P[i]+M)%M;
自动it=S.下限(M-a);
如果(it!=开始)
res=最大(res,*prev(it)+a);
res=最大(res,(*prev(end))+a)%M;
}
返回res;
}
int main(){
//随机测试救援
对于(int i=0;i<1000;++i){
int M=rand()%1000+1,n=rand()%1000+1;
向量A(n);
对于(int i=0;i
我们可以按如下方式进行:

维护一个数组
sum
,该数组在索引
ith
处包含从0到
ith
的模和

对于每个索引
ith
,我们需要找到在该索引处结束的最大子和:

对于每个子阵列(开始+1,i),我们知道该子阵列的模和为

inta=(和[i]-和[start]+M)%M

因此,只有当
sum[start]
大于
sum[i]
并尽可能接近
sum[i]
时,我们才能实现大于
sum[i]
的子和

如果使用二叉搜索树,这可以很容易地完成

伪代码:

int[]和;
和[0]=A[0];
树木;
tree.add(和[0]);
int结果=总和[0];
对于(int i=1;i

时间复杂度:O(n logn)

使用O(n*log(n))的整个java实现

导入java.io.BufferedReader;
导入java.io.InputStreamReader;
导入java.util.TreeSet;
导入java.util.stream.stream;
公共类最大化{
公共静态void main(字符串[]args)引发异常{
BufferedReader in=新的BufferedReader(新的InputStreamReader(System.in));
Long times=Long.valueOf(in.readLine());
while(次-->0){
long[]pair=Stream.of(in.readLine().split(“”).mapToLong(long::parseLong).toArray();
长模=对[1];
long[]numbers=Stream.of(in.readLine().split(“”).mapToLong(long::parseLong.toArray();
printMaxMod(数字,mod);
}
}
私有静态void printMaxMod(长[]个数字,长mod){
Long maxSoFar=(数字[numbers.length-1]+数字[numbers.length-2])%mod;
maxSoFar=(maxSoFar>(数字[0]%mod))?maxSoFar:数字[0]%mod;
数字[0]%=mod;
用于(长i=1L;icurrentNumber?maxSoFar:currentNumber;
数字[i.intValue()]=(当前数字+数字[i.intValue()-1])%mod;
maxSoFar=maxSoFar>numbers[i.intValue()]?maxSoFar:numbers[i.intValue()];
}
if(mod.equals(maxSoFar+1)| | numbers.length==2){
系统输出打印LN(maxSoFar);
返回;
}
long previousNumber=数字[0];
树集=新树集();
set.add(以前的编号);
用于(长i=2L;iA = 6 6 11 2 12 1
P = 6 12 10 12 11 12
a = A[3] - P[3] = 2 - 12 = 3 (mod 13)
P + a = * * * 2 1 2
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.TreeSet;
import java.util.stream.Stream;

public class MaximizeSumMod {

    public static void main(String[] args) throws Exception{

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        Long times = Long.valueOf(in.readLine());

        while(times --> 0){
            long[] pair = Stream.of(in.readLine().split(" ")).mapToLong(Long::parseLong).toArray();
            long mod = pair[1];            
            long[] numbers = Stream.of(in.readLine().split(" ")).mapToLong(Long::parseLong).toArray();
            printMaxMod(numbers,mod);
        }
    }

    private static void printMaxMod(long[] numbers, Long mod) {

        Long maxSoFar = (numbers[numbers.length-1] + numbers[numbers.length-2])%mod;
        maxSoFar = (maxSoFar > (numbers[0]%mod)) ? maxSoFar : numbers[0]%mod;
        numbers[0] %=mod;
        for (Long i = 1L; i < numbers.length; i++) {
            long currentNumber = numbers[i.intValue()]%mod;            
            maxSoFar = maxSoFar > currentNumber ? maxSoFar : currentNumber;
            numbers[i.intValue()] = (currentNumber + numbers[i.intValue()-1])%mod;
            maxSoFar = maxSoFar > numbers[i.intValue()] ? maxSoFar : numbers[i.intValue()];
        }

        if(mod.equals(maxSoFar+1) || numbers.length == 2){
            System.out.println(maxSoFar);
            return;
        }

        long previousNumber = numbers[0];
        TreeSet<Long> set = new TreeSet<>();
        set.add(previousNumber);

        for (Long i = 2L; i < numbers.length; i++) {
            Long currentNumber = numbers[i.intValue()];
            Long ceiling = set.ceiling(currentNumber);
            if(ceiling == null){
                set.add(numbers[i.intValue()-1]);            
                continue;
            }

            if(ceiling.equals(currentNumber)){
                set.remove(ceiling);
                Long greaterCeiling = set.ceiling(currentNumber);
                if(greaterCeiling == null){
                    set.add(ceiling);
                    set.add(numbers[i.intValue()-1]);            
                    continue;
                }
                set.add(ceiling);                    
                ceiling = greaterCeiling;
            }
            Long newMax = (currentNumber - ceiling + mod);
            maxSoFar = maxSoFar > newMax ? maxSoFar :newMax;
            set.add(numbers[i.intValue()-1]);            
        }

        System.out.println(maxSoFar);

    }

}
#python3
#source: https://github.com/harishvc/challenges/blob/master/dp-largest-sum-sublist-modulo.py  
#Time complexity: O(n)
#Space complexity: O(n)
def maxContiguousSum(a,K):
    sum_so_far =0
    max_sum = 0
    count = {} #keep track of occurrence
    for i in range(0,len(a)):
            sum_so_far += a[i]
            sum_so_far = sum_so_far%K
            if sum_so_far > 0:
                    max_sum = max(max_sum,sum_so_far)
                    if sum_so_far in count.keys():
                            count[sum_so_far] += 1
                    else:
                            count[sum_so_far] = 1
            else:
                    assert sum_so_far < 0 , "Logic error"
                    #IMPORTANT: reset sum_so_far
                    sum_so_far = 0
    return max_sum,count[max_sum]

  a = [6, 6, 11, 15, 12, 1]
  K = 13
  max_sum,count = maxContiguousSum(a,K)
  print("input >>> %s max sum=%d #occurrence=%d" % (a,max_sum,count))
public static long maxModulo(long[] a, final long k) {
    long[] s = new long[a.length];
    TreeSet<Long> tree = new TreeSet<>();

    s[0] = a[0] % k;
    tree.add(s[0]);
    long result = s[0];

    for (int i = 1; i < a.length; i++) {

        s[i] = (s[i - 1] + a[i]) % k;

        // find least element in the tree strictly greater than s[i]
        Long v = tree.higher(s[i]);

        if (v == null) {
            // can't find v, then compare v and s[i]
            result = Math.max(s[i], result);
        } else {
            result = Math.max((s[i] - v + k) % k, result);
        }
        tree.add(s[i]);
    }
    return result;
 }
def maximumSum(coll, m):
    n = len(coll)
    maxSum, prefixSum = 0, 0
    sortedPrefixes = []

    for endIndex in range(n):
        prefixSum = (prefixSum + coll[endIndex]) % m
        maxSum = max(maxSum, prefixSum)

        startIndex = bisect.bisect_right(sortedPrefixes, prefixSum)
        if startIndex < len(sortedPrefixes): 
            maxSum = max(maxSum, prefixSum - sortedPrefixes[startIndex] + m)

        bisect.insort(sortedPrefixes, prefixSum)

    return maxSum
public int[] kadanesAlgorithm (int[] array) {
        int start_old = 0;
        int start = 0;
        int end = 0;
        int found_max = 0;

        int max = array[0];

        for(int i = 0; i<array.length; i++) {
            max = Math.max(array[i], max + array[i]);
            found_max = Math.max(found_max, max);
            if(max < 0)
                start = i+1;
            else if(max == found_max) {
                start_old=start;
                end = i;
                }
        }

        return Arrays.copyOfRange(array, start_old, end+1);
    }
proxy[n] = (a[1] + ... a[n]) % M
maxSubarraySum[i, j] = (proxy[j] - proxy[j]) % M
def maximumSum(a, m):
    prefix_sum = [a[0] % m]
    prefix_sum_sorted = [a[0] % m]
    current_max = prefix_sum_sorted[0]
    for elem in a[1:]:
        prefix_sum_next = (prefix_sum[-1] + elem) % m
        prefix_sum.append(prefix_sum_next)
        idx_closest_bigger = bisect.bisect_right(prefix_sum_sorted, prefix_sum_next)
        if idx_closest_bigger >= len(prefix_sum_sorted):
            current_max = max(current_max, prefix_sum_next)
            bisect.insort_right(prefix_sum_sorted, prefix_sum_next)
            continue
        if prefix_sum_sorted[idx_closest_bigger] > prefix_sum_next:
            current_max = max(current_max, (prefix_sum_next - prefix_sum_sorted[idx_closest_bigger]) % m)
            bisect.insort_right(prefix_sum_sorted, prefix_sum_next)
    return current_max
val seen = sortedSetOf(0L)
var prev = 0L

return max(a.map { x ->
    val z = (prev + x) % m
    prev = z
    seen.add(z)
    seen.higher(z)?.let{ y ->
        (z - y + m) % m
    } ?: z
})
def maximumSum(a, m):
    prefixSums = [(0, -1)]
    for idx, el in enumerate(a):
        prefixSums.append(((prefixSums[-1][0] + el) % m, idx))
    
    prefixSums = sorted(prefixSums)
    maxSeen = prefixSums[-1][0]
    
    for (a, a_idx), (b, b_idx) in zip(prefixSums[:-1], prefixSums[1:]):
        if a_idx > b_idx and b > a:
            maxSeen = max((a-b) % m, maxSeen)
            
    return maxSeen
x ... z
k ... i
x ... y ... z
k ... j ... i
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.TreeSet;
public static void main(String[] args) throws IOException {
    BufferedReader read = new BufferedReader(new InputStreamReader(System.in)) ;
    String[] str = read.readLine().trim().split(" ") ;
    int n = Integer.parseInt(str[0]) ;
    long m = Long.parseLong(str[1]) ;
    str = read.readLine().trim().split(" ") ;
    long[] arr = new long[n] ;
    for(int i=0; i<n; i++) {
        arr[i] = Long.parseLong(str[i]) ;
    }

    long maxCount = 0L ;
    TreeSet<Long> tree = new TreeSet<>() ;
    tree.add(0L) ;
    long prefix = 0L ;
    for(int i=0; i<n; i++) {
        prefix = (prefix + arr[i]) % m ;
        maxCount = Math.max(prefix, maxCount) ;

        Long temp = tree.higher(prefix) ;
        System.out.println(temp);
        if(temp != null) {
            maxCount = Math.max((prefix-temp+m)%m, maxCount) ;
        } 
        
        //System.out.println(maxCount);
        tree.add(prefix) ;
    }

    System.out.println(maxCount);
}
public static long maximumSum2(long[] arr, long n, long m)
{
    long x = 0;
    long prefix = 0;
    long maxim = 0;
    TreeSet<Long> S = new TreeSet<Long>();
    S.add((long)0);

    // Traversing the array.
    for (int i = 0; i < n; i++)
    {

    // Finding prefix sum.
    prefix = (prefix + arr[i]) % m;

    // Finding maximum of prefix sum.
    maxim = Math.max(maxim, prefix);

    // Finding iterator poing to the first
    // element that is not less than value
    // "prefix + 1", i.e., greater than or
    // equal to this value.
    long it = S.higher(prefix)!=null?S.higher(prefix):0;
    // boolean isFound = false;
    // for (long j : S)
    // {
    //     if (j >= prefix + 1)
    //     if(isFound == false) {
    //         it = j;
    //         isFound = true;
    //     }
    //     else {
    //         if(j < it) {
    //             it = j;
    //         }
    //     }
    // }
    if (it != 0)
    {
        maxim = Math.max(maxim, prefix - it + m);
    }

    // adding prefix in the set.
    S.add(prefix);
    }
    return maxim;
}