977. 有序数组的平方
题目描述:
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]
思路:按正常先把整个数组平方再整个数组排序是可以的,但是考虑到题目给出的条件非递减顺序(即递增顺序),就可以利用正数部分平方后已经是非递减顺序,从而直接对负数部分平方,然后跟正数部分作比较即可。因为负数部分也是排好序的,只是是递减顺序,所以可以变换一下归并排序的指针设置,应用归并排序的思路来解决。
归并排序思想:通过比较已排序的子数组的元素,并依次合并它们,以创建一个新的已排序数组。
javascript解法:
var sortedSquares = function(nums) {
let arr = [];
let ng = -1;
let len = nums.length;
// 找到正负分界位置 ng
for(let i = 0; i < len; i++){
if(nums[i] < 0) { // 这里用 <=0 也可以
ng = i;
}else {
break;
}
}
// 归并排序:分解,排序,合并(这里合并只涉及两个子数组)
// 合并终止条件:
// 正负分界前面的负数数组从分界开始走到i = 0
// 或者 正负分界后面的正数数组从0开始走到j = len - 1
let i = ng, j = ng + 1;
while(i >= 0 || j < len) {
if(i < 0) {
arr.push(nums[j] * nums[j]);
j++;
}else if(j == len) {
arr.push(nums[i] * nums[i]);
i--;
}else if(nums[i] * nums[i] < nums[j] * nums[j]) {
arr.push(nums[i]*nums[i]);
i--;
}else {
arr.push(nums[j]*nums[j]);
j++;
}
}
return arr;
};
209.长度最小的子数组
题目描述:
给你一个数组
nums
和一个值val
,你需要 原地 移除所有数值等于val
的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用O(1)
额外空间并 原地 修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。示例 1:
输入:nums = [3,2,2,3], val = 4
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
思路:如果用暴力的解法,只要把所有可能出现的连续子数组的情况都遍历一遍就可以,此时需要用到两个for循环;还可以考虑用滑动窗口的思想,滑动窗口的思想只需要一个for里面嵌套while即可。下面着重写滑动窗口的解法:
javascript解法:
出处: leetcode灵茶山艾府
var minSubArrayLen = function(target, nums) {
const n = nums.length;
let ans = n + 1;
let sum = 0; // 子数组元素和
let left = 0; // 子数组左端点
for (let right = 0; right < n; right++) { // 枚举子数组右端点
sum += nums[right];
while (sum >= target) { // 满足要求
ans = Math.min(ans, right - left + 1);
sum -= nums[left++]; // 左端点右移
}
}
return ans <= n ? ans : 0;
};
对于上面代码,有几个疑问值得思考一下:
-
为什么 ans 的初始值是 n + 1?
因为我们最后要判断
return ans <= n ? ans : 0
, 如果 ans 的初始值为 n ,刚好为数组长度,那么当遇到下面这种测试用例的时候就会出错:
因为在数组里面所有数都加上后还是比 target 小的时候,right - left + 1
的值为 n + 1
, 此时如果 ans 为 n,就会导致最后作三元判断的时候ans <= n
从而返回错误结果:n .
-
为什么while的条件为
sum >= target
时就可以把right - left + 1
作为一个结果?会不会出现最后 ans 对应的是sum>target
而不是sum == target
的情况?首先,如果
sum < target
的话,窗口有边界就会不断右移加数;当 sum 比 target 大的时候,窗口左边界就需要右移缩小区间直到sum再次比target小或者等于target,这时候不断把答案放在ans里面并没有影响,因为只要有等于target的情况出现就会更新ans;当sum直接就等于target的时候,我们就把答案放在ans里。但是这个时候还没有结束,窗口左边界还要继续向右滑动直到遍历完所有的情况。有没有发现,当sum > target 和 sum == target的时候,他们执行的操作其实是一样的:① 存储当前的ans, ② 窗口向右滑动。