找到总和大于K的子阵列的最小长度

时间:2013-06-29 10:09:03

标签: c++ algorithm

如何找到符合其总和大于给定K的子阵列?

我想到的是将指针保持在序列的开始和结束处,并逐步减去较小的指针以缩短序列。但似乎它无效。为什么呢?

这是我的命名:

#include <iostream>

using namespace std;

int main() {
    while (!cin.eof()) {
        int caseCount;
        cin >> caseCount;
        int N, S;
        for (int i = 0; i < caseCount; i++) {
            cin >> N >> S;
            int * seq = new int[N];
            int maxSum = 0;
            for (int j = 0; j < N; j ++) {
                cin >> seq[j];
                maxSum += seq[j];
            }
            if (maxSum < S) {
                cout << 0 << endl;
                continue;
            }
            int left, right;
            left = 0;
            right = N-1;
            while(left < right) {
                if(seq[left] < seq[right]) {
                    if (maxSum - seq[left] < S) {
                        cout << right-left+1 << endl;
                        break;
                    } else {
                        maxSum -= seq[left];
                        left++;
                    }
                } else {
                    if (maxSum - seq[right] < S) {
                        cout << right-left+1 << endl;
                        break;
                    } else {
                        maxSum -= seq[right];
                        right--;
                    }
                }
            }
            if (left >= right) {
                cout << 1 << endl;
            }
        }
    }
    return 0;
}

示例输入:

2 // amount of sequences to input
10 15 // sequence 1 length and K
5 1 3 5 10 7 4 9 2 8 // sequence 1 data
5 11 // sequence 2 length and K
1 2 3 4 5 // sequence 2 data

示例输出:

2
3

4 个答案:

答案 0 :(得分:1)

这是Python中的一个想法(因为它主要是一个算法问题),假设你的输入是自然数(感谢@ChrisOkasaki)。它在list上运行,但应该很容易根据您的目的进行调整。 startend都包含在内。它返回子数组的第一个和最后一个索引。

def find_minimal_length_subarr(arr, min_sum):
    found = False
    start = end = cur_start = cur_end = 0
    cur_sum = arr[cur_start]
    while cur_end < len(arr):
        if cur_start < cur_end:
            cur_sum += arr[cur_end]
        while cur_sum-arr[cur_start] >= min_sum:
            cur_sum -= arr[cur_start]
            cur_start += 1
        if cur_sum >= min_sum and (not found or cur_end-cur_start < end-start):
            start, end = cur_start, cur_end
            found = True
        cur_end += 1
    if found:
        return start, end

print find_minimal_length_subarr([11, 2, 3, 4, 9, 5, 6, 7, 8], 21) # (6, 8)

它从头开始,在未到达min_sum时向右扩展。到达时,它仍会从左侧缩短,但仍然会到达min_sum。然后它继续扩大。只有找到更好(更短)的候选人,才会更换更早的候选人。时间复杂度为O(n),空间复杂度为O(1)。

答案 1 :(得分:1)

这是基于Thijs算法的C ++中的工作示例,它似乎是您问题的理想算法(如果我们正确理解它。可以轻松更改第一个子序列或与谓词匹配的所有子序列)

#include <vector>
#include <utility>
#include <iostream>

using namespace std;
template<typename It>
pair<It, It> subseq_with_sum_greater(It begin, It end, typename It::value_type barrier)
{
    typename It::value_type current_sum = 0;
    pair<It, It> res = make_pair(begin, end);
    for(It current = begin; current < end; ++current)
    {
        current_sum += *current;
        while(current_sum > barrier and current_sum - *begin > barrier)
            current_sum -= *begin++;
        if(current_sum > barrier and distance(begin, current) < distance(res.first, res.second))
            res = make_pair(begin, current);
    }
    return res;
}

int main()
{
    vector<int> v = {5, 1, 3, 5, 10, 7, 4, 9, 2, 8};
    auto subseq = subseq_with_sum_greater(v.begin(), v.end(), 15);
    cout << distance(v.begin(), subseq.first) << ", " << distance(v.begin(), subseq.second);
}

输出为4, 5,即子序列的索引。请注意,使用std::distance仅使用RandomAccess迭代器(如std :: vector上的那些)的O(1)复杂度,如果要在此类模板上使用此类模板,则可能需要添加size_t current_distance, minimal_distance个变量其他容器。此外,当没有找到任何子序列时,该算法返回begin, end对,这使得很难知道这是答案还是没有子序列匹配。根据您的情况,您可能希望获得更精确的输出。

答案 2 :(得分:0)

您的算法不正确。你基本上只检查序列的中间部分,这没有任何意义。相反,你应该从数组开头的两个索引开始,只要子范围的总和小于K就向右递增。当它变得更大时,开始向左递增,直到它再次变小。现在你有一个最短的后续候选人 - 保存它。重复直到右边不会越过数组的末尾,如果新的候选者更短,则更新你的候选人。

答案 3 :(得分:0)

这也适用于否定内容:

def s(arr, K):
   candidate = None
   for l,r in [(x,x+1) for x in range(len(arr))]:
     while sum(arr[l:r]) < K and r <= len(arr): r = r + 1
     if K <= sum(arr[l:r]):
       if candidate is None or r-l < candidate[1]-candidate[0]:
         candidate = (l,r)
   return candidate # ending index will be exclusive

在C ++中:

typedef struct {
    bool found; int l; int r; 
} range;

int sum(int arr[], int arr_n, int l, int r) {
    int sum = 0;
    for (int i=l; i<r && i<arr_n; i++)
        sum+=arr[i];
    return sum;
}

range s(int arr[], int K, int arr_n) {
    bool found = false; int c_l; int c_r;
    for (int l=0; l<arr_n; l++) {
        int r = l+1;
        while (sum(arr, arr_n, l, r) < K && r <= arr_n) r++;
        if (K <= sum(arr, arr_n, l, r))
            if (!found || r-l < c_r-c_l) {
                c_l = l; c_r = r; found = true;
            }
    }
    return (range){found, c_l, c_r};
}