leetcode523. Continuous Subarray Sum

題目要求

Given a list of non-negative numbers and a target integer k, write a function to check if the array has a continuous subarray of size at least 2 that sums up to a multiple of k, that is, sums up to n*k where n is also an integer.java

Example 1:數組

Input: [23, 2, 4, 6, 7], k=6
Output: True
Explanation: Because [2, 4] is a continuous subarray of size 2 and sums up to 6.優化

Example 2:code

Input: [23, 2, 6, 4, 7], k=6
Output: True
Explanation: Because [23, 2, 6, 4, 7] is an continuous subarray of size 5 and sums up to 42.遞歸

Note:ip

  1. The length of the array won't exceed 10,000.
  2. You may assume the sum of all the numbers is in the range of a signed 32-bit integer.

假設有一個非負整數數組,要求找到其中一個連續的子數組,該子數組中全部元素的和是k的整數倍。要求連續子數組的長度大於等於2.get

思路一:暴力循環

若是咱們能夠計算出全部長度大於等於2的連續子數組的元素和,就能夠判斷出是否存在知足題意的子數組。這裏能夠作一個簡單的優化,即用一個額外的數組用來存[0..i]的子數組的元素和,則sum[i..j]的子數組的元素和能夠經過sum[0..j+1]-sum[0..i-1]計算得出。代碼以下:it

public boolean checkSubarraySum(int[] nums, int k) {  
    if (nums == null || nums.length <= 1) {  
        return false;  
    }  
    int[] sum = new int[nums.length+1];  
    sum[0] = 0;  
    for (int i = 1 ; i<sum.length ; i++) {  
        sum[i] += sum[i-1] + nums[i-1];  
    }  
    for (int i = nums.length ; i>=2 ; i--) {  
        for (int j = 0 ; j+i<sum.length ; j++) {  
            int diff = sum[j+i] - sum[j];  
            if (diff == k || (k!=0 && diff % k == 0)) {  
                return true;  
            }  
        }  
    }  
    return false;  
}

思路二:記錄中間結果

基於思路一的基礎上能夠進一步優化,既然咱們要計算的是k的整數倍的子數組和,而咱們有的是能夠經過O(N)的時間複雜度計算出[0...i]子數組的元素和。那麼咱們能夠推算出,假如sum[0..j]%k = m,而sum[0..i]%k = m(i-j>=2),那麼能夠知道[i+1, j]這個子數組必定是k的整數倍。所以咱們只須要記錄已經遍歷過的從0下標開始的全部子數組的和以及對應的下標值,而且判斷是否存在如上述的關聯便可。io

public boolean checkSubarraySum2(int nums[], int k){  
  
    Map<Integer,Integer> map = new HashMap<>();  
    map.put(0,-1);  
    int sumSoFar = 0;  
    for(int i=0; i < nums.length; i++){  
        sumSoFar = sumSoFar + nums[i];  
        if(k != 0) sumSoFar = sumSoFar % k;  
        if(map.containsKey(sumSoFar)){  
            int start = map.get(sumSoFar);  
            if(i-start > 1) return true;  
        }else{  
            map.put(sumSoFar, i);  
        }  
    }  
    return false;  
}

思路三:分治法

分治法在這題的核心思想在於,將整個數組先一分爲二,分別判斷在左子數組和右子數組中是否存在知足條件的子數組,若是沒有,再判斷跨左右子數組的子數組是否存在知足條件的連續子數組。分治法和動態規劃都在於想通遞歸場景後,代碼就行雲流水了。ast

public boolean checkSubarraySum(int[] nums, int lo, int hi, int k){  
    if(lo==hi) return false;  
    int mid = lo+(hi-lo)/2;  
    if(checkSubarraySum(nums, lo, mid, k)) return true;  
    if(checkSubarraySum(nums, mid+1, hi, k)) return true;  
    int left = mid, right = mid+1;  
    int sum = nums[left];  
    while(left>=lo&&right<=hi){  
        sum += nums[right];  
        if((k>0&&sum%k==0)||(k==0&&sum==0)) return true;  
        --left;  
        ++right;  
        if(left>=lo){  
            sum += nums[left];  
            if((k>0&&sum%k==0)||(k==0&&sum==0))  return true;  
        }  
    }  
    return false;  
}  
public boolean checkSubarraySum(int[] nums, int k) {  
    k = Math.abs(k);  
    return checkSubarraySum(nums, 0, nums.length-1, k);  
}
相關文章
相關標籤/搜索