Leetcode 560 和为K的子数组 前缀和哈希(箭头,反码补码)
JAVA 暴力:
public final int subarraySum(int[] nums, int k) { int res = 0; for (int i = 0; i < nums.length; i++) { int currK = k; for (int j = i; j < nums.length; j++) { currK -= nums[j]; if (currK == 0) res++; } } return res; }
JAVA 前缀和哈希,时间复杂度由 O(N2) 优化为 O(N) :
/** * @Author Niuxy * @Date 2020/11/19 8:35 下午 * @Description 以 i 开头的子数组中和为 k 的子数组个数 * 也就是 pre[i]-k = pre[j] 的个数 */ public final int subarraySum(int[] nums, int k) { Map<Integer, Integer> preMap = new HashMap<Integer, Integer>(); preMap.put(0,1); int res = 0, pre = 0; for (int i = 0; i < nums.length; i++) { pre += nums[i]; res += preMap.getOrDefault(pre-k, 0); preMap.put(pre, preMap.getOrDefault(pre, 0) + 1); } return res; }
JS 前缀和哈希:
/** * @param {number[]} nums * @param {number} k * @return {number} */ var subarraySum = function (nums, k) { Map.prototype.getOrDefault = (key, defaultV) => { if (!this.get(key)) return defaultV; return this.get(key); } let preMap = new Map(); let res = 0, pre = 0; for (let i = 0; i < nums.length; i++) { pre += nums[i]; res += preMap.getOrDefault(pre - k, 0); preMap.set(pre, preMap.getOrDefault(pre) + 1); } return res; };
需要注意 JS 中,箭头函数与 function 声明函数中,this 的指向是不同的。箭头函数中 this 指向定义函数时的作用域,而 function 声明函数中 this 指向会根据调用时作用域的不同而改变。所以在编辑原型时切不可使用箭头函数(为了保险,包含 this 的函数都不要使用箭头函数声明)。
另外在做缓存时,如果使用 long 存储两个 int ,需要注意负数的情况。JAVA 中负数是用补码进行保存的,至于补码为何为反码加一,可以这么理解:
互为补码的两个数,在模内运算时 加a 等于 减b 。 0+a=0-b --> 补码 b =0-a --> 而在运算 0-a 时,会为 0 进位,因此 b=~a+1 (二进制中相减,进位后除最后一位外均取反);
当你看清人们的真相,于是你知道了,你可以忍受孤独