Algorithm 最大子阵和模M
我们中的大多数人都熟悉这个问题。我遇到了这个问题的一个变体,它要求程序员以某个数M为模输出所有子数组和的最大值 解决这个变量的简单方法是找到所有可能的子数组和(N^2的数量级,其中N是数组的大小)。当然,这还不够好。问题是——我们如何才能做得更好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 首先,让
示例:让我们考虑以下数组:
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;
}