今天滑动窗口有点忘了,本来想用队列思想来完成,并使用list转int[] nums方法,但还是太复杂了没写成。
前言
依旧是老套路,一个是双指针法,一个是滑动窗口法,此文配上动画更好理解
一、977.有序数组的平方
给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
这题关键点其实是这个数组的形势是两边大中间小,所以要从两边比较采用双指针法,下面直接来个图看的更清晰一些:
这里我没有使用while(left <= right) 条件 而是使用for循环整个数组,因为左右一共遍历就是整个数组,这样可以顺便给结果数组填入数字
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0;
int right = nums.length - 1;
int[] result = new int[nums.length];
for (int i = nums.length - 1; i >= 0; i--) {
if (nums[left] * nums[left] >= nums[right] * nums[right]) {
result[i] = nums[left] * nums[left];
left++;
}else {
result[i] = nums[right] * nums[right];
right--;
}
}
return result;
}
}
这里提供一种常规双指针解法while(left <= right)
class Solution {
public int[] sortedSquares(int[] nums) {
int right = nums.length - 1;
int left = 0;
int[] result = new int[nums.length];
int index = result.length - 1;
while (left <= right) {
if (nums[left] * nums[left] > nums[right] * nums[right]) {
// 正数的相对位置是不变的, 需要调整的是负数平方后的相对位置
result[index--] = nums[left] * nums[left];
++left;
} else {
result[index--] = nums[right] * nums[right];
--right;
}
}
return result;
}
}
二、长度最小的子数组
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解
废话不多说直接上图直观看滑动窗口,其实类似快慢指针:
其实本题 最主要是右窗口正常遍历所有数组,左窗口在满足条件时在while循环里面进行处理,并且减少窗口。
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
result = Math.min(result, right - left + 1);
sum -= nums[left];
left++;
}
}
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int sum = 0;
int left = 0;
int result = Integer.MAX_VALUE;
for (int right = 0; right < nums.length; right++) {
sum += nums[right];
while (sum >= target) {
result = Math.min(result, right - left + 1);
sum -= nums[left];
left++;
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
小细节
对于第二题,一般选最大最小值时,我们一般会使用 Integer类中的最大最小值
//取最小值时选择最大初始值
int result = Integer.MAX_VALUE;
//取最大值时选择最小初始值
int result = Integer.MIN_VALUE;