力扣-560-和为K的子数组

和为K的子数组…
首先子数组和子串一样,都是连续的
又是dp的感觉…好像又用不到dp
虽然不是dp的思路,但是感觉写出来跟dp很像

int subarraySum(vector<int>& nums, int k) {
	int count = 0,temp;

	for (int i = 0; i < nums.size(); i++) {
		temp = 0;
		for (int j = i; j < nums.size(); j++) {
			temp +=nums[j];
			if (temp == k) count++;
		}
	}
	return count;
}

原本觉得这是很简单的题,结果官方果然拿一篇1凑10000来恶心人

但是这题也不像二维dp或者一维dp,画出来感觉更像是一个上三角/下三角

设dp[i]表示以i结尾的数组中,和为K的子数组数量…

前缀和 + 哈希

考虑优化上面的时间复杂度,两步:

  1. 原本是二维累加,使用前缀和可以转化为一维,代价是空间(如果用数组,这里还是二维算法,还引入了空间,没有意义)
    public int subarraySum(int[] nums, int k) {
        // 生成一个前缀序列
        int[] pre = new int[nums.length];
        pre[0] = nums[0];
        for (int i = 1; i < nums.length; i++) {
            pre[i] = pre[i - 1] + nums[i];
        }
        int count = 0;
        for (int i = pre.length - 1; i >= 0; i--) {
            if (pre[i] == k) {
                count++;
            }
            for (int j = i - 1; j >= 0; j--) {
                if (pre[i] - pre[j] == k) {
                    count++;
                }
            }
        }
        return count;
    }
  1. 更进一步pre[j] - k = pre[i-1],关键是 pre[i-1] 的数量(数组 -> 哈希)
    public int subarraySum(int[] nums, int k) {
        int pre = 0;
        int count = 0;
        Map<Integer, Integer> map = new HashMap<>();
        for (int num : nums) {
            pre += num;
            if (pre == k) {
                count++;
            }
            count += map.getOrDefault(pre - k, 0);
            map.put(pre, map.getOrDefault(pre, 0) + 1);
        }
        return count;
    }

关键问题:count += map.getOrDefault(pre - k, 0);为什么过程中累加的这一步不会漏?
意思是:后面还有可能出现这个前缀和的位置
因为关键是:i 必须小于 j,后面出现的就是大于 j 的位置了,本就不该算入了

posted @ 2022-11-09 15:03  YaosGHC  阅读(46)  评论(0)    收藏  举报