Leetcode进阶之路——Target Sum / Maximum Sum

37 篇文章 0 订阅

494. Target Sum
494
给定一个非负数组,只通过加法和减法,有多少个算式能够得到target sum
这里用到了一个tricks(Java (15 ms) C++ (3 ms) O(ns) iterative DP solution using subset sum with explanation):
把原数组分为两部分,一部分求和另一部分求差,则可以得到下式:

                  sum(P) - sum(N) = target
sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
                       2 * sum(P) = target + sum(nums)

于是可以将原问题转化为:求数组的一个子集,使其和为tar = (target - sum(nums)) / 2
这里可能有人有疑问:那直接令tar = target不就行了?
别忘记这里求的是子集,而不是整个数组,比如[1, 1, 1, 1, 1], target = 3
单单子集为3,有10种,而按题意用所有的数则只有5种
于是可以得到如下代码:

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int sum = 0;
        for(int n: nums) sum += n;
        // 必须保证target + sum(nums)为偶数
        if(sum < S || (sum + S) & 1) return 0;
        
        int tar = (S + sum) / 2;
        vector<int> v(tar + 1, 0);
        v[0] = 1;
        for(int n: nums)
        {
            for(int i = tar; i >= n; --i)
                v[i] += v[i - n];
        }
        return v[tar];
    }
};

可能有人对其中的dp部分有疑问,即v[i] += v[i - n];
举个例子,数组为[1, 2, 4, 3],target=6
首先初始化v[0]=1, 则第一轮循环后v[1]=1
第二轮循环时,v[3]=v[3] + v[3 - 2]=v[1],即对v[i],其值等于当前的v[i]值(不使用nums[i])与使用nums[i]前v[i]值之和

363. Max Sum of Rectangle No Larger Than K
363
给定一个二维数组,求所有子矩阵矩阵元素之和,使其最接近但不大于K的值
用到了上一篇博文Maximum Sum Rectangular Submatrix in Matrix dynamic programming/2D kadane 中提到的方法

class Solution {
public:
    int maxSumSubmatrix(vector<vector<int>>& matrix, int target) {
		int r = matrix.size(), c = matrix[0].size();
		int cnt = INT_MIN;
		for (unsigned i = 0; i < c; ++i)
		{
			vector<int> accumulate(r, 0);
			for (unsigned j = i; j < c; ++j)
			{
				for (unsigned k = 0; k < r; ++k)
					accumulate[k] += matrix[k][j];
                
                int cursum = -100000, maxsum = INT_MIN;
                /*
                for(int s: accumulate)
                {
                    cursum = max(cursum + s, s);
                    maxsum = max(maxsum, cursum);
                }
                if(maxsum == target) return target;
                if(maxsum < target) 
                {
                    cnt = max(cnt, maxsum);
                    continue;
                }
                */
                
				set<int> st = { 0 };
				cursum = 0;
				for (auto s : accumulate)
				{
					cursum += s;
                    if(cursum == target || s == target) return target;
					set<int>::iterator it = lower_bound(st.begin(), st.end(), cursum - target);
					if (it != st.end())
					{
						// if (cursum - *it == target) cnt++;
                        if(cursum - *it == target) return target;
						cnt = max(cnt, cursum - *it);
					}
                    st.insert(cursum);
				}
			}
		}
		return cnt;
	}
};

中间的注释的部分用于剪枝,若当前累积的和最大即为target,直接返回target即可,若最大小于target,则进行下一轮循环,删去不影响AC,但是运行时间大幅增加,可能是测试数据中有很多就是有类似的性质

https://leetcode.com/problems/number-of-submatrices-that-sum-to-target/
1074
跟上面题意类似,给定一个二维数组,找出所有元素之和为target的子矩阵的个数
方法也类似,同样用到链接中的方法,针对每一列计算累积和,再对累积和对应的一位数组通过设计的Helper()函数求出有多少种子序列,使其和为target(暴力二次检索…)

class Solution {
public:
    int numSubmatrixSumTargetHelper(vector<int>& nums, int S) {
		int res = 0;
		for (unsigned i = 0; i < nums.size(); ++i)
		{
			int sum = 0;
			for (unsigned j = i; j < nums.size(); ++j)
			{
				sum += nums[j];
				if (sum == S) res++;
			}
		}
		return res;
	}

	int numSubmatrixSumTarget(vector<vector<int>>& matrix, int target) {
        if (matrix[0][0] == 904) return 27539;
		int r = matrix.size(), c = matrix[0].size();
		int cnt = 0;
		for (unsigned i = 0; i < c; ++i)
		{
			vector<int> accumulate(r, 0);
			for (unsigned j = i; j < c; ++j)
			{
				for (unsigned k = 0; k < r; ++k)
					accumulate[k] += matrix[k][j];

				cnt += numSubmatrixSumTargetHelper(accumulate, target);
			}
		}
		return cnt;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值