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)  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)  O(n3), reduced from   O ( n 4 ) \ O(n^4)  O(n4) 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)  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;
        
    }
};

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值