Likou-continuous sub-array sum (detailed official solution three)

Title description

Given an array containing non-negative numbers and a target integer k, write a function to determine whether the array contains continuous sub-arrays, the size of which is at least 2, and the sum is a multiple of k, that is, the sum is n*k, where n It is also an integer.

Example 1:

Input: [23,2,4,6,7], k = 6
Output: True
Explanation: [2,4] is a sub-array of size 2, and the sum is 6.
Example 2:

Input: [23,2,6,4,7], k = 6
Output: True
Explanation: [23,2,6,4,7] is a sub-array of size 5, and the sum is 42.

Official solution: ( solution link )

Method 3: Use the HashMap [Accepted]
algorithm

In this method, we use HashMap to store the cumulative sum up to the iith element, but we divide this prefix sum by kk to take the remainder. The reasons are as follows:

We traverse the given array and record the sum%ksum up to the current position. Once we find the new sum%ksum value (that is, there is no such value in the HashMap), we insert a record (sum%k, i)(sum) into the HashMap.

Now, suppose the value of sum%ksum at the iith position is remrem. If the sum of any sub-array with ii as the left end point is a multiple of kk, for example, the position is jj, then the jjth element in the HashMap holds the value (rem + n k)%k(rem+n∗k) %k, where nn is some integer greater than 0. We will find that (rem + n k)%k = rem(rem+n∗k)%k=rem, which is the same as the value of the iith element saved in the HashMap.

Based on this observation, we conclude that whenever the value of sum%ksum has been put into the HashMap, it means that there are two indexes ii and jj, and the sum of the elements between them is an integer multiple of kk. Therefore, as long as there is the same sum%ksum%k in the HashMap, we can directly return \teat{True}.

public class Solution {
    
    
    public boolean checkSubarraySum(int[] nums, int k) {
    
    
        int sum = 0;
        HashMap < Integer, Integer > map = new HashMap < > ();
        map.put(0, -1);
        for (int i = 0; i < nums.length; i++) {
    
    
            sum += nums[i];
            if (k != 0)
                sum = sum % k;
            if (map.containsKey(sum)) {
    
    
                if (i - map.get(sum) > 1)
                    return true;
            } else
                map.put(sum, i);
        }
        return false;
    }
}
Interpretation:

Among the three official solutions, this solution is the algorithm with the lowest time complexity. Of course, when you encounter this type of question, you must consider using prefixes and maps.
The author's idea is also very simple. We have made a little improvement on the basis of the prefix sum. We traverse the array and store the prefix and remainder in the map each time (if the title requires the starting position and end of the sub-array For the position, the key stored in our map is followed by the traversal coordinate i). Why do you want to do this, let's first look at an example.

  • arr = {3,4,3,4,5} k = 11;
  • Define p[i] to represent the sum of i items before arr and find the remainder
  • p[1] = 3; /*3
  • p[2] = 7; /*3,4
  • p[3] = 10; /*3,4,3
  • p[4] = 3; /*3,4,3,4

At this point, we find that p already contains the remainder 3, so that we can know that the sum of the sub-arrays in the array is n times k, because when the remainder of the number a is equal to the number b, the remainder of the number d is still Get c, which means that the number a must be added with a number that is divisible by b, that is, this number is n times k. The same reason also shows that the sum of subarrays is n times k, so Get the solution to the problem.

Guess you like

Origin blog.csdn.net/baldicoot_/article/details/109827421