LeetCode
滑动窗口算法
LeetCode第1176题:
你的好友是一位健身爱好者。前段日子,他给自己制定了一份健身计划。现在想请你帮他评估一下这份计划是否合理。
他会有一份计划消耗的卡路里表,其中 calories[i] 给出了你的这位好友在第 i 天需要消耗的卡路里总量。
为了更好地评估这份计划,对于卡路里表中的每一天,你都需要计算他 「这一天以及之后的连续几天」 (共 k 天)内消耗的总卡路里 T:
如果 T < lower,那么这份计划相对糟糕,并失去 1 分;
如果 T > upper,那么这份计划相对优秀,并获得 1 分;
否则,这份计划普普通通,分值不做变动。
请返回统计完所有 calories.length 天后得到的总分作为评估结果。
注意:总分可能是负数。
示例一
输入:calories = [1,2,3,4,5], k = 1, lower = 3, upper = 3
输出:0
解释:calories[0], calories[1] < lower 而 calories[3], calories[4] > upper, 总分 = 0.
示例二
输入:calories = [3,2], k = 2, lower = 0, upper = 1
输出:1
解释:calories[0] + calories[1] > upper, 总分 = 1.
示例三
输入:calories = [6,5,0,0], k = 2, lower = 1, upper = 5
输出:0
解释:calories[0] + calories[1] > upper, calories[2] + calories[3] < lower, 总分 = 0.
看完这个题目基本上明白题意了,看了一下题目的评论,才知道这是滑动窗口算法。再百度一下滑动窗口算法。发现有一篇文章讲的很清楚。
https://blog.youkuaiyun.com/sty945/article/details/79846516
其中提到对于这个算法有一个很经典的题:给定一个大小为n的整形数组,计算长度为k的子数组的最大值。例如:
{1,2,3,4,5,6}
//有这样一个数组,求长度为3的子数组之和最大为多少
//对于这个数组来说数组之和最大并且长度为3的子数组肯定就是{4,5,6}
//那么用代码实现的过程就是滑动窗口算法实现的过程
代码:
int maxSum(int arr[], int n, int k)
//arr为原数组{1,2,3,4,5,6},n为数组长度,k为子数组长度
{
if (n < k)//如果原数组为{1,2}长度n=2;求长度k=3的子数组没有意义。
{
cout << "Invaild";
return -1;
}
int max_sum = 0;
for (int i=0; i<k; i++)//先求第一个窗格的和
{
max_sum += arr[i];
}
int windows_sum = max_sum;//max_sum=6
for (int i=k; i<n; i++)//往下求后面的窗格
{
/*
i=k=3
windows_sum=windows_sum+arr[3]-arr[0]=6+4-1=9
{2,3,4}=9;
相当于向后移动求和
*/
windows_sum += arr[i] - arr[i - k];
max_sum = max(max_sum, windows_sum);
}
return max_sum;
}
那么对于上面健身的题也是一样的道理,只是多了几个比较再加一个分数。
代码:
class Solution {
public int dietPlanPerformance(int[] calories, int k, int lower, int upper) {
if(calories.length<k)//如果数组长度小于k没有意义
{
return 0;
}
int ans=0;
int sum=0;
for(int i=0;i<k;i++){//先求第一个窗格
sum+=calories[i];
}
if(sum<lower){ans--;}//做判断定分数
if(sum>upper){ans++;}
for(int i=k;i<calories.length;i++){//求后面的窗格
sum+=calories[i]-calories[i-k];
if(sum<lower){ans--;}//再来判断分数
if(sum>upper){ans++;}
}
return ans;//返回分数
}
}
LeetCode第26题:删除排序数组中重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
这道题现在想起来不难,但是第一次看见还是卡在那里,直接看官方的代码
代码:
public int removeDuplicates(int[] nums) {
if (nums.length == 0) return 0;
int i = 0;
for (int j = 1; j < nums.length; j++) {
if (nums[j] != nums[i]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
官方讲解
数组完成排序后,我们可以放置两个指针 i 和 j,其中 i 是慢指针,而 j 是快指针。只要 nums[i] = nums[j],我们就增加 j 以跳过重复项。
当我们遇到 nums[j]!=nums[i]时,跳过重复项的运行已经结束,因此我们必须把它(nums[j])的值复制到 nums[i+1]。
然后递增i,接着我们将再次重复相同的过程,直到 j 到达数组的末尾为止。