Lintcode 404. Subarray Sum II

题目

Given an integer array, find a subarray where the sum of numbers is in a given interval. Your code should return the number of possible answers. (The element in the array should be positive)

Example Given [1,2,3,4] and interval = [1,3], return 4. The possible answers are:

[0, 0] [0, 1] [1, 1] [2, 2]

思路

这道题如果用平常的prefixSum + HashMap/TreeMap去解会发现复杂度非常高,和暴力解并没有区别。这里我们要做的其实是range query。如果用TreeMap(BST)去做这个事,复杂度比较高,因为Map不能存key相同的元素,所以Map只能存成sum->frequency。我们需要遍历Map来得到区间内每一个key的count,worst case会是O(n)。

但是如果我们是在sorted array里面做range query,我们可以存的下每一个duplicate,这样我们可以通过index直接得出range内元素的个数。

这样这道题就转化为number of elements within a range in a sorted array with duplicates。我们要做的就是找到first element >= start的index,以及first element >= end + 1的index,做减法就可以了。注意为乐得到sorted array数组,我们需要先去compute一个prefixSum数组并对其排序。这里我们只需要count不需要index,所以排序并不会使我们丢失信息。

复杂度

time O(nlogn) because of sorting, space O(1)

代码

  public class Solution {
    /**
     * @param A an integer array
     * @param start an integer
     * @param end an integer
     * @return the number of possible answer
     */
    public int subarraySumII(int[] A, int start, int end) {
        // Write your code here
        // check edge
        if (A == null || A.length == 0 || start > end) {
            return 0;
        }
        // preprocess
        for (int i = 1; i < A.length; i++) {
            A[i] += A[i-1];
        }
        Arrays.sort(A);

        // main
        int count = 0;
        for (int i = 0; i < A.length; i++) {
            int cur = A[i];
            if (cur >= start && cur <= end) {
                count++;
            }

            int left = cur - end;
            int right = cur - start;
            count += (binarySearch(A, right + 1) - binarySearch(A, left));
        }
        return count;
    }
    //find first occurance of the target
    public int binarySearch(int[] A, int target) {
        if (A[A.length - 1] < target) {
            return A.length;
        }
        int start = 0;
        int end = A.length - 1;
        int mid;
        while (start + 1 < end) {
            mid = (start + end)/2;
            if (A[mid] == target) {
                end = mid;
            } else if (A[mid] > target) {
                end = mid;
            } else {
                start = mid;
            }
        }

        //budao
        if (A[start] >= target) {
            return start;
        }
        return end;
    }
}

results matching ""

    No results matching ""