给定一个输入数组,我们可以找到一个单个子阵列,它通过跟踪到目前为止找到的总和和起始位置,在线性时间内总和为K(给定)。如果当前总和大于K,我们继续从起始位置移除元素,直到我们得到当前总和< = K.
我从geeksforgeeks找到了示例代码并更新了它以返回所有这些可能的集合。但假设输入数组仅由+ ve数组成。
bool subArraySum(int arr[], int n, int sum)
{
int curr_sum = 0, start = 0, i;
bool found = false;
for (i = 0; i <= n; i++)
{
while (curr_sum > sum && start < i)
{
curr_sum = curr_sum - arr[start];
start++;
}
if (curr_sum == sum)
{
cout<<"Sum found in b/w indices: "<<start<<" & "<<(i-1)<<"\n";
curr_sum -= arr[start];
start++;
found = true;
}
// Add this element to curr_sum
if (i < n) {
curr_sum = curr_sum + arr[i];
}
}
return found;
}
我的问题是,我们是否也为混合数字组合(正数和负数)提供了这样的解决方案?
答案 0 :(得分:23)
对于正数和负数都没有线性时间算法。
由于您需要总和为K
的所有子数组,因此任何算法的时间复杂度都不能优于生成的子数组集的大小。这个大小可能是二次的。例如,[K, -K, K, -K, K, -K, ...]
的任何子数组,以正'K'开始和结束都有所需的总和,并且有N 2 / 8这样的子数组。
如果O(N)额外空间可用,仍然可以在O(N)预期时间内得到结果。
计算数组中每个元素的前缀和,并将对(prefix_sum, index)
插入哈希映射,其中prefix_sum
是键,index
是与此键关联的值。在此哈希映射中搜索prefix_sum - K
以获取生成的子数组开始的一个或多个数组索引:
hash_map[0] = [-1]
prefix_sum = 0
for index in range(0 .. N-1):
prefix_sum += array[index]
start_list = hash_map[prefix_sum - K]
for each start_index in start_list:
print start_index+1, index
start_list2 = hash_map[prefix_sum]
start_list2.append(index)
答案 1 :(得分:6)
@Evgeny Kluev给出的解决方案用Java编写了一些解释。
public static void main(String[] args) {
int[] INPUT = {5, 6, 1, -2, -4, 3, 1, 5};
printSubarrays(INPUT, 5);
}
private static void printSubarrays(int[] input, int k) {
Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>();
List<Integer> initial = new ArrayList<Integer>();
initial.add(-1);
map.put(0, initial);
int preSum = 0;
// Loop across all elements of the array
for(int i=0; i< input.length; i++) {
preSum += input[i];
// If point where sum = (preSum - k) is present, it means that between that
// point and this, the sum has to equal k
if(map.containsKey(preSum - k)) { // Subarray found
List<Integer> startIndices = map.get(preSum - k);
for(int start : startIndices) {
System.out.println("Start: "+ (start+1)+ "\tEnd: "+ i);
}
}
List<Integer> newStart = new ArrayList<Integer>();
if(map.containsKey(preSum)) {
newStart = map.get(preSum);
}
newStart.add(i);
map.put(preSum, newStart);
}
}
答案 2 :(得分:1)
尝试使用此代码可以为您服务:
private static void printSubArrayOfRequiredSum(int[] array, int requiredSum) {
for (int i = 0; i < array.length; i++) {
String str = "[ ";
int sum = 0;
for (int j = i; j < array.length; j++) {
sum = sum + array[j];
str = str + array[j] + ", ";
if (sum == requiredSum) {
System.out.println(" sum : " + sum + " array : " + str
+ "]");
str = "[ ";
sum = 0;
}
}
}
}
使用以下方法:
int array[] = { 3, 5, 6, 9, 14, 8, 2, 12, 7, 7 };
printSubArrayOfRequiredSum(array, 14);
输出:
sum : 14 array : [ 3, 5, 6, ]
sum : 14 array : [ 14, ]
sum : 14 array : [ 2, 12, ]
sum : 14 array : [ 7, 7, ]
答案 3 :(得分:1)
二次时间:最坏情况下为O(n2)。
private static void findSubArray(int[] is, int N) {
System.out.println("Continuous sub array of " + Arrays.toString(is) + " whose sum is " + N + " is ");
List<Integer> arry = new ArrayList<>(is.length);
for (int i = 0; i < is.length; i++) {
int tempI = is[i];
arry.add(tempI);
for (int j = i + 1; j < is.length; j++) {
if (tempI + is[j] == N) {
arry.add(is[j]);
System.out.println(arry);
} else if (tempI + is[j] < N) {
arry.add(is[j]);
tempI = tempI + is[j];
} else {
arry.clear();
break;
}
}
}
}
public static void main(String[] args) {
findSubArray(new int[] { 42, 15, 12, 8, 6, 32 }, 26);
findSubArray(new int[] { 12, 5, 31, 13, 21, 8 }, 49);
findSubArray(new int[] { 15, 51, 7, 81, 5, 11, 25 }, 41);
}
答案 4 :(得分:0)
此问题与此处解决的组合问题非常相似:http://introcs.cs.princeton.edu/java/23recursion/Combinations.java.html
这是我的解决方案:
public static void main(String[] args) {
int [] input = {-10, 0, 5, 10, 15, 20, 30};
int expectedSum = 20;
combination(new SumObj(new int[0]), new SumObj(input), expectedSum);
}
private static void combination(SumObj prefixSumObj, SumObj remainingSumObj, int expectedSum){
if(prefixSumObj.getSum() == expectedSum){
System.out.println(Arrays.toString(prefixSumObj.getElements()));
}
for(int i=0; i< remainingSumObj.getElements().length ; i++){
// prepare new prefix
int [] newPrefixSumInput = new int[prefixSumObj.getElements().length + 1];
System.arraycopy(prefixSumObj.getElements(), 0, newPrefixSumInput, 0, prefixSumObj.getElements().length);
newPrefixSumInput[prefixSumObj.getElements().length] = remainingSumObj.getElements()[i];
SumObj newPrefixSumObj = new SumObj(newPrefixSumInput);
// prepare new remaining
int [] newRemainingSumInput = new int[remainingSumObj.getElements().length - i - 1];
System.arraycopy(remainingSumObj.getElements(), i+1, newRemainingSumInput, 0, remainingSumObj.getElements().length - i - 1);
SumObj newRemainingSumObj = new SumObj(newRemainingSumInput);
combination(newPrefixSumObj, newRemainingSumObj, expectedSum);
}
}
private static class SumObj {
private int[] elements;
private int sum;
public SumObj(int[] elements) {
this.elements = elements;
this.sum = computeSum();
}
public int[] getElements() {
return elements;
}
public int getSum() {
return sum;
}
private int computeSum(){
int tempSum = 0;
for(int i=0; i< elements.length; i++){
tempSum += elements[i];
}
return tempSum;
}
}
答案 5 :(得分:0)
由@Evgeny Kluev在c ++编码的解决方案
#include<bits/stdc++.h>
using namespace std;
int c=0;
// Function to print subarray with sum as given sum
void subArraySum(int arr[], int n, int k)
{
map<int,vector<int>>m1;
m1[0].push_back(-1);
int curr_sum=0;
for(int i=0;i<n;i++){
curr_sum=curr_sum+arr[i];
if(m1.find(curr_sum-k)!=m1.end()){
vector<int>a=m1[curr_sum-k];
c+=m1[curr_sum-k].size();
for(int j=0;j<a.size();j++){ // printing all indexes with sum=k
cout<<a[j]+1<<" "<<i<<endl;
}
}
m1[curr_sum].push_back(i);
}
}
int main()
{
int arr[] = {10,2,0,10,0,10};
int n = sizeof(arr)/sizeof(arr[0]);
int sum = 10;
subArraySum(arr, n, sum);
cout<<c<<endl; //count of subarrays with given sum
return 0;
}
答案 6 :(得分:0)
我发现以下情况使用的是O(n)的时间复杂度。
function maxSumArr(arr) {
var s = [];
s.length = arr.length;
for (var i in arr){
s[i] = (s[i-1] + arr[i]) > arr[i] ? s[i-1] + arr[i] : arr[i];
}
s = s.reduce((T,c) => (T > c ? T : c))
return s; // gives array of all possible max sub arrays at each index.
}
答案 7 :(得分:0)
具有O(n)空间和时间复杂度的Python代码
import { Request, Response, NextFunction } from 'express';
import multer from 'multer';
const multerMiddleware = (dest: string) => (req: Request, res: Response, next: NextFunction) => {
const upload = multer({
storage: multer.diskStorage({
destination: dest,
filename: (req, file, cb) => {
const { videoId } = req.body;
const filename = `${videoId}-${file.originalname}`;
cb(null, filename);
}
})
});
upload.single('file')(req, res, next);
}
export default multerMiddleware;
答案 8 :(得分:-1)
我在几次采访中也遇到了这个问题,并提出了以下最佳方法:
class MazSubArraySum {
public static void main(String[] args) {
int[] a = { -2, -3, 4, -1, -2, 1, 5, -3 };
System.out.println("Maximum contiguous sum is " + maxSubArraySum(a));
}
static int maxSubArraySum(int a[]) {
int size = a.length;
int currentindex = 0, end = 0, begin = 0;
int max_so_far = Integer.MIN_VALUE, max_ending_here = 0;
for (int i = 0; i < size; i++) {
max_ending_here = max_ending_here + a[i];
if (max_so_far < max_ending_here) {
max_so_far = max_ending_here;
begin = currentindex;
end = i;
}
if (max_ending_here < 0) {
max_ending_here = 0;
currentindex++;
}
}
System.out.println("begin and end: " + begin + "&" + end);
return max_so_far;
}
}
以下是输出:
begin and end: 2&6
Maximum contiguous sum is 7
以上解决方案是时间和空间复杂度的最佳解决方案,即O(n)。