今天的题目均属于代码随想录-数组章节
1. leetcode 977. 有序数组的平方
问题简述
给定一个非递减顺序的数组(数组中可能有负数),返回这一数组元素的平方构成的新数组,要求也按照非递减顺序排序。
思路描述
- 本题可以用左右双指针求解。由于绝对值越大的数,平方值越大,因此数组中平方最大的数一定是原数组的左右端点之一,每处理完一个数,左指针或右指针移动一个单位,直到原数组中的所有数都被处理完。
- 用这种方式填充结果数组时,按照绝对值从大到小填充。
算法实现
算法的C++语言实现如下:
时间复杂度
O
(
n
)
O(n)
O(n),空间复杂度
O
(
1
)
O(1)
O(1)。
vector<int> sortedSquares(vector<int>& nums) {
vector<int> ans(nums.size(), 0);
int left = 0;
int right = nums.size() - 1;
int index = nums.size() - 1;
while(left <= right){
if(nums[left] * nums[left] >= nums[right] * nums[right]){
ans[index--] = nums[left] * nums[left];
left++;
}
else{
ans[index--] = nums[right] * nums[right];
right--;
}
}
return ans;
}
核心要点
- while循环终止的条件
本题循环终止条件还是比较容易给出的,因为本题中的数组每个元素都需要处理一遍,因此left == right
时,循环不能结束。
2. leetcode 209.长度最小的子数组
问题简述
给定正整数数组和一个target,返回数组中和大于等于target的,长度最小的连续子数组的长度。
思路描述
- 本题很容易想到时间复杂度 O ( n 2 ) O(n^2) O(n2)的解法,即记录以数组的每个元素为子数组开端的,和大于target的最小子数组,并用一个变量实时记录这些子数组中的最短长度。但是在本题中,这样的解法会超出时间限制。
- 本题复杂度最低(
O
(
n
)
O(n)
O(n))的解法需要用到滑动窗口这一方法,其实滑动窗口也并不神秘,在暴力解法中,for循环遍历的是数组的起始元素,而在滑动窗口中,for循环遍历的是数组的最后一个元素。
滑动窗口的神奇之处就在于,数组的起始元素不需要每次都从第一个元素开始遍历。因为滑动窗口记录了一个数组终点对应的最小值后,如果只向后扩充窗口却没有超过target,那么这次扩充其实是没必要记录的,只有滑动窗口前端出现收缩的时候,才有记录的价值。子数组的起始不需要每次回溯到开头的原因也可以理解为数组向后扩张后的子数组起始的位置其实就是一个满足大于target条件,且和上一次记录的长度相比“子数组相对最短”的位置,此位置之前的位置一定满足大于target条件,因此不需要考虑了。
更详细的思路如图所示:
算法实现
算法的C++语言实现如下:
时间复杂度
O
(
n
)
O(n)
O(n),空间复杂度
O
(
1
)
O(1)
O(1)。
int minSubArrayLen(int target, vector<int>& nums) {
int min_len = INT_MAX;
int sum = 0;
int left = 0;
for(int right = 0; right < nums.size(); right++){
sum += nums[right];
while(sum >= target){
min_len = min(min_len, right - left + 1);
sum -= nums[left++];
}
}
if(min_len == INT_MAX){
return 0;
}
return min_len;
}
核心要点
- 本算法的核心要点就是理解滑动窗口的思路,在思路描述中已经给出了自己的一些理解。