题目描述给定一个整数数组如果你爱上了一朵在一颗星星的花,那么你看所有的星星都像开着花一样。那是多么美好啊,天空中盛开着无数朵花,无数朵你所爱的花。
nums
,返回区间和在
[lower, upper]
之间的个数,包含
lower
和
upper
。
区间和
S(i, j)
表示在
nums
中,位置从
i
到
j
的元素之和,包含
i
和
j (i ≤ j)
。
说明:
最直观的算法复杂度是 O(n2)
,请在此基础上优化你的算法。
输入: nums = [-2,5,-1], lower = -2, upper = 2,
输出: 3
解释: 3个区间分别是: [0,0], [2,2], [0,2],它们表示的和分别为: -2, -1, 2。
题解
官方题解,颇有深度,很难理解,被打击的心塞塞的,小白只能用简单暴力法来躺躺水,能AC也算是leetcode大发善心了?。这道题分享的题解参考价值不太大,旨在个人打卡,不过考点真的值得去回味,前缀和+哈希也是用的多的,很奇特,另外还可以采用归并的思路进行求解。
方法1:暴力法
两次遍历,找出符合条件的所有和。
代码(Java):
1class Solution {
2 public int countRangeSum(int[] nums, int lower, int upper) {
3 int ans = 0;
4 for (int i = 0; i 5 long sum = 0;
6 for(int j = i; j 7 sum += nums[j];
8 if(sum >= lower && sum <= upper){
9 ans++;
10 }
11 }
12 }
13 return ans;
14 }
15}
方法2:前缀和+哈希
参考 560. 和为K的子数组,采用前缀和+哈希方法,对范围内的数据进行遍历求解,类似暴力求解,运行时间还没有暴力求解快。
代码(Java):
1class Solution {
2 public int countRangeSum(int[] nums, int lower, int upper) {
3 int ans = 0;
4 int n = nums.length;
5 if(n == 0){
6 return ans;
7 }
8 long []preSum = new long[n+1];
9 preSum[0] = 0;
10 for(int i = 1; i 11 preSum[i] = preSum[i-1] + nums[i-1];
12 }
13
14 for(int k = lower; k <= upper; ++k){
15 Map map = new HashMap<>();16 map.put(0l, 1l);17 for(int i = 1; i 18 if(map.containsKey(preSum[i] - k)){19 ans += map.get(preSum[i] - k);20 }21 map.put(preSum[i], map.getOrDefault(preSum[i], 0l) + 1);22 }23 }24 return ans;25 }26}
方法3、前缀和+归并
1、计算数组的前缀和,只需要前缀和数组中preSum[j] - preSum[i-1]在lower和upper范围内那么数组中的[i,j]的和,就符合条件。
2、采用归并排序的思想,对前缀和进行判断;
1class Solution {
2 public int countRangeSum(int[] nums, int lower, int upper) {
3 int ans = 0;
4 if(nums.length == 0){
5 return ans;
6 }
7 long []preSum = new long[nums.length + 1];
8 preSum[0] = 0;
9 for(int i = 1; i 10 preSum[i] = preSum[i - 1] + nums[i - 1];
11 }
12 return mergeCount(preSum, lower, upper, 0, preSum.length - 1);
13 }
14
15 private int mergeCount(long []sum, int lower, int upper, int left, int right){
16 if(left == right){
17 return 0;
18 } else {
19 int mid = (left + right) >> 1;
20 int a1 = mergeCount(sum, lower, upper, left, mid);
21 int a2 = mergeCount(sum, lower, upper, mid + 1, right);
22 int res = a1 + a2;
23
24 // 计算区间对的个数
25 int i = left;
26 int l = mid + 1;
27 int r = mid + 1;
28 while(i <= mid){
29 while(l <= right && sum[l]- sum[i] 30 l++;
31 }
32 while(r <= right && sum[r] - sum[i] <= upper){
33 r++;
34 }
35 res += r - l;
36 i++;
37 }
38
39 // 合并两个排序数组
40 long[] sorted = new long[right - left + 1];
41 int p = left;
42 int q = mid + 1;
43 int pos = 0;
44 while(p <= mid && q <= right){
45 if(sum[p] <= sum[q]){
46 sorted[pos++] = sum[p++];
47 }else{
48 sorted[pos++] = sum[q++];
49 }
50 }
51 while(p <= mid){
52 sorted[pos++] = sum[p++];
53 }
54 while(q <= right){
55 sorted[pos++] = sum[q++];
56 }
57
58 for (int j = 0, k = left; j 59 sum[k] = sorted[j];
60 }
61 return res;
62 }
63 }
64}
每一件事情,最难的不是开始,而是坚持!
(LeetCode历史刷题回顾)
5. 最长回文子串
8.字符串转整数
13. 罗马数字转整数
14. 最长公共前缀
33. 搜索旋转排序数组
46. 全排列
57.插入区间
58. 最后一个单词的长度
70.爬楼梯
74. 搜索二维矩阵
92. 反转链表 II
124. 二叉树中的最大路径和
127.单词接龙
160. 相交链表
234. 回文链表
236. 二叉树的最近公共祖先
300. 最长上升子序列
328. 奇偶链表
349.两个数组的交集
415. 字符串相加
876. 链表的中间结点
941. 有效的山脉数组
1356.根据数字二进制下 1 的数目排序
© THE END