查找最大索引 j 的有效算法,使得从索引 i 到 j 的总和小于 k

Posted

技术标签:

【中文标题】查找最大索引 j 的有效算法,使得从索引 i 到 j 的总和小于 k【英文标题】:Efficient algorithm for finding largest index j such that sum from index i to j is less than k 【发布时间】:2021-02-17 15:51:54 【问题描述】:

我得到一个大小为 n 的正整数数组。对于数组的每个索引 i,我想找到最大的索引 j,使得从索引 i 到 j 的数组元素之和小于或等于某个整数 K。我只能想到蛮力 O (n^2) 方式。我想知道是否有更有效的方法?

【问题讨论】:

我想到了对范围 i 到 n-1 的二进制搜索,假设数组已排序。我相信这会给你 nlog(n)。 啊,是的,正如@Andrew Vershinin 所指出的,我们需要找到前缀总和,然后进行二分搜索得到 O(nlgn)。 @gateway2745 请查看正确答案 很好!..从技术上讲,以前的答案并不正确,所以也许可以更改第一行? 【参考方案1】:

之前的答案不正确,但我会留下它,因为它已被接受并有评论。 有一个O(n)时间,O(1)空间滑动窗口(或,“两个指针”)的方法。下面的代码是Java:

public static int[] rightBoundSums(int[] arr, long K) 
    final int N = arr.length;

    int[] ans = new int[N]; // the result

    int r = 0; // the right index of the window
    long sum = 0; // current sum
    for (int l = 0; l < N; l++) 
        // invariant: r is the first such index that 
        // sum(l, r - 1) > K, or N, if the end of the array was reached
        while (r < N && sum <= K) 
            sum += arr[r++];
        

        if (arr[l] > K) 
            ans[l] = -1; // if the i-th element itself is larger, than K, there is no such j
         else 
            ans[l] = (r == N) ? N - 1 : r - 2;
        

        sum -= arr[l];
    

    return ans;


计算前缀和pref[0] = 0, pref[i] = pref[i - 1] + arr[i - 1]。总和将单调递增,因为 arr 的值为正数,因此您可以对每个 i 的前缀总和 pref[i + 1] ... pref[N] 使用二分搜索值 arr[i] + k(请注意前缀总和是 1 索引的事实) .由此产生的复杂性将是O(N logN) 时间和O(N) 空间。

【讨论】:

赞成这个答案。此外,如果需要数组来允许更新,则可以使用 Fenwick 树(扩展了前缀求和的想法)link; link

以上是关于查找最大索引 j 的有效算法,使得从索引 i 到 j 的总和小于 k的主要内容,如果未能解决你的问题,请参考以下文章

算法题:最大连续子数组选择

算法练习之存在重复元素

查找算法(I) 顺序查找 二分查找 索引查找

查找是不是存在任何 i 使得 array[i] 等于 i 的算法

查找数组中最大数字的索引

快速排序的C语言实现