当需要快速查询数据的记录时:
- 手动按某规则为数据建立索引,利用数组维护数据
- 若1中需要开大数组爆内存,利用官方库的Hash集合,可以将最好情况下的时间复杂度优化到O(1)避免T和M。
1. LC 2036 最大好子数组和
VP双周赛123T3。一开始卡住了。一直想在Hash表里存每种数字出现的索引,查询nums[i]±k的所有可能索引,前缀和相减得到子数组和维护最大值。最后不出意外的T了。既然要找之前的最小前缀和,为啥不在Hash表里直接维护每个数字对应的最小前缀和呢?改完A了。
import java.util.HashMap;class Solution {public long maximumSubarraySum(int[] nums, int k) {HashMap<Integer, Long> m = new HashMap<>();int n = nums.length;long[] prefix = new long[n+1];long ans = Long.MIN_VALUE;long sum = 0;for (int i = 0; i < n; i++) {sum += nums[i];prefix[i+1] = sum;Long nk = m.get(nums[i] - k);Long pk = m.get(nums[i] + k);if(nk!=null){ans = Math.max(ans,sum-nk);}if(pk!=null){ans = Math.max(ans,sum-pk);}Long pre = m.get(nums[i]);if(pre==null){m.put(nums[i],prefix[i]);}else{m.put(nums[i],Math.min(prefix[i],pre));}}return ans==Long.MIN_VALUE?0:ans;}
}
注意子数组是闭区间,前缀和数组里加个哨兵即可。然后这道题实际上不需要前缀和数组,滚动一个前缀和就可以了,闭区间滞后一个元素即可。
import java.util.HashMap;class Solution {public long maximumSubarraySum(int[] nums, int k) {HashMap<Integer, Long> m = new HashMap<>();int n = nums.length;long ans = Long.MIN_VALUE;long sum = 0;for (int num : nums) {Long nk = m.get(num - k);Long pk = m.get(num + k);if (nk != null) {ans = Math.max(ans, sum + num - nk);}if (pk != null) {ans = Math.max(ans, sum + num - pk);}Long pre = m.get(num);if (pre == null) {m.put(num, sum);} else {m.put(num, Math.min(sum, pre));}sum += num;}return ans==Long.MIN_VALUE?0:ans;}
}