Subarray Sum I/II/III

138. Subarray Sum

Tag:

Hash Table, Subarray.

Main Idea:

Subarray Problem.

In this problem, we will apply presum[i], which represents the sum of range[0, i].

The main idea of this problem is that if the sum of the range[l, r] is zero, then, the presum[l-1] is equal to presum[r+1]. In this sense, all we need to do is to hash the presume[i] with its index. If a key can be found in the hash table, then we get the result.

Tips/Notes:

  1. When we process the presum[i], presum[0] should be 0. And then presum[i] is the sum of range[0,i-1].

Time/Space Cost:

Time Cost:   O ( n ) \ O(n)

Code:

class Solution {
public:
    /**
     * @param nums: A list of integers
     * @return: A list of integers includes the index of the first number and the index of the last number
     */
    vector<int> subarraySum(vector<int> &nums) {
        // write your code here
        if(nums.empty())
            return nums;
            
        vector<int> res;
        int sum = 0;
        
        unordered_map<int,int> hash;
        hash[0] = 0;
        
        for(int i = 0; i < nums.size(); i++){
            sum += i;
            if(hash.find(sum) != hash.end()){
                res.push_back(hash[sum] + 1);
                res.push_back(i);
                
            } 
            else 
            {
                hash[sum] = i;
            }
        }
        return res;
    }
};

Follow-up Problem: 405. Submatrix Sum

Main Idea:

It’s common to transform the vector into matrix in the follow-up question.

Before dig into the problem, let top-left point as (x1, y1), bottom-right point as (x2, y2).

In sub-matrix problem, main idea is the same, but this time, the presum would be: presum[i][j] = presum[0][j] + … + presum[i][j]. It means we calculate the sum column by column. Why doing so? It helps us to enumerate the sub-matrix by sub-matrix’s column(x1 and x2). Then, we can use third for loop to enumerate the row(y1/y2).

The specific steps would be:

  1. process the presum, which is presum[i][j] = presum[0][j] + … + presum[i][j].
  2. find the sub-matrix by presum

Tips/Notes:

  1. In third for-loop, which enumerates the k. It’s tmp += sum[j][k]; but tmp += sum[j][k] - sum[i-1][k];. Because if i is the first line, it will go wrong.
  2. Don’t make mistake when you retrieve the previous j position.
  3. Don’t forget tot discuss the case that start line is the first line.

Time/Space Cost:

Time Cost:   O ( n 3 ) \ O(n^3) , reduced from   O ( n 4 ) \ O(n^4) by preprocessing sum.

Code:

class Solution {
public:
    /*
     * @param matrix: an integer matrix
     * @return: the coordinate of the left-up and right-down number
     */
    vector<vector<int>> submatrixSum(vector<vector<int>> &matrix) {
        // write your code here
        
        // 1. check the input
        int n = matrix.size();
        if( n == 0){
            return matrix;
        }
        int m = matrix[0].size();
        vector<vector<int>> res, sum;
        sum = matrix;
        
        // 2. calculate the presum
        // sum[i][j] = sum[0][j] + ... sum[i][j]
        for(int j = 0; j < m; j++){
            for(int i = 1; i < n; i++){
                sum[i][j] += sum[i-1][j];
            }
        }
        
        
        // 3. iterate the presum
        // 3.1 from 0 .. n, i is x1
        // 3.2 from i .. n, j is x2
        // 3.3 from 0 .. m, k is the third point of matrix
        
        for(int i = 0; i < n; i++){
            for(int j = i; j < n; j++){
                unordered_map<int, int> hash;
                int tmp = 0;
                for(int k = 0; k < m; k++){
                    tmp += sum[j][k];
                    // if start line is not the first line, then, it needs to minius the previous line
                    if(i){
                        tmp -= sum[i-1][k];
                    }
                    
                    if(tmp == 0){
                        res.push_back({i, 0});
                        res.push_back({j, k});
                        return res;
                    }
                    
                    if(hash.find(tmp) == hash.end()){
                        hash[tmp] = k;
                    }
                    // if there exist the sum already
                    else
                    {
                        res.push_back({i, hash[tmp] + 1});
                        res.push_back({j, k});
                        return res;
                    }
                }
            }
        }
        
        return res;
    }
};

Follow-up Problem2: 404. Subarray Sum II

Main Idea:

Besides the presum, our goal is to find out the number of ranges. Thus, in this problem, applying partition idea can improve the time efficiency. But how?

We are going to use three pointer: left_l, left_r, right. Let’s enumerate the right from 1 to n-1. Then, we need to find out the position of left_l and left_r. The position of three pointer should be:

" … left_l … left_r … right … ";

According to the problem, the sum’s range is [start, end]. Then, the we need to enumerate the situation that: right - left_r <= end && right - left_l < start.

Tips/Notes:

  1. notice situation: right - left_r <= end && right - left_l < start.

Time/Space Cost:

Time Cost:   O ( n ) \ O(n) , there is only one for-loop for right. As for left_l and left_r, it keeps increasing which will not burden the cost.

Code:

class Solution {
public:
    /**
     * @param A: An integer array
     * @param start: An integer
     * @param end: An integer
     * @return: the number of possible answer
     */
    int subarraySumII(vector<int> &A, int start, int end) {
        // write your code here
		// 1. initilize the solution
        if(A.empty())
            return 0;
        int len = A.size();
        vector<int> sum(len+1);
        sum[0] = 0;
        
        // 2. process the presum
        for(int i = 0; i <= len; i++){
            sum[i] = sum[i-1] + A[i-1];
        }
        
        // 3. solve the problem by applying partition
        int res = 0, left_l, left_r;
        left_r = left_l = 0;
        for(int right = 1; right <= len; right++){
            while(left_l < right && sum[right] - sum[left_l] > end ){
                left_l++;
            }
            while(left_r < right && sum[right] - sum[left_r] >= start){
                left_r++;
            }
            res += left_r - left_l;
        }
        
        return res;
        
    }
};

发布了28 篇原创文章 · 获赞 1 · 访问量 441

猜你喜欢

转载自blog.csdn.net/Zahb44856/article/details/103982317