977. 有序数组的平方
题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
解答链接:代码随想录
思路:
这道题的思路是计算每个位置,然后把之前的快速排序。这种属于暴力解法,其实还不如先算好,之后再快速排序,时间复杂度为O(n+nlogn)。
解答:
应该注意到数组本身是有序的,呈现海鸥状,只是中间点不知道。因此,题目可以被分为两个部分,一个从一边开始,一个从另一边开始,不断比较往中心靠拢。因此,设置头尾双指针。
感悟:
双指针本质上是将为题进行了拆分,因此也可以有三指针、四指针等等。在上一道题目(27.移除元素)中,一个指针用来记录位置,一个指针用来指向元素。这道题中,一个指针用来阅读右翼,一个指针用来阅读左翼。而在(704.二分查找)中,就有了迭代的双指针。每一次迭代,双指针用来确定中心位置。
代码:
vector<int> sortedSquares(vector<int>& nums) {
int k = nums.size() - 1;
int last = nums.size() - 1;
int first = 0;
vector<int> result(nums.size(),0);
while(first <= last){
if(nums[first] * nums[first] < nums[last] * nums[last]){
result[k--] = nums[last] * nums[last];
last--;
}else if(nums[first] * nums[first] >= nums[last] * nums[last]){
result[k--] = nums[first] * nums[first];
first++;
}
}
return result;
}
209. 长度最小的子数组
思路:
想到了滑动窗口的方法,但对于具体的细节没有想清楚。
解答:
滑动窗口有点类似于动态规划,重点是判断如何做优化这个步骤。在这道题目里,当目前的窗口和没有达到目标的时候,需要包含下一个数字。当目前的窗口达到目标的时候,需要记录长度,并尝试缩小这个区间。
感悟:
1. 动态优化
最开始考虑这个问题的时候,担心缩小区间这个步骤可能会丢掉潜在的核心元素,陷入局部最优解。但是这道题有一个核心的假设,就是区间连续。因此区间的增减只能依靠区间边缘的伸缩。给定右侧边缘不动,最优解就是左边边缘右移的极限。然后再上调右侧边缘,再次寻找。注意这个时候,不用让左边缘从最左边开始遍历,因为上一个最优左边缘在这一轮中对应的数组长度一定大于既有的优化目标。所以从上一个最优左边缘开始右遍历至极限即可。
总结一下,这道题就是在不同的右侧边缘求解最优化问题,动态改变右侧边缘,得到最优的结果。而在优化过程中,上一次的最优结果可以复用至下一次优化。
2. 从大到小遍历的方法:
先设置成INT32_MAX,之后向下寻找。如果找不到,就是result == INT32_MAX ? 0 : result_len
代码:
int minSubArrayLen(int target, vector<int>& nums) {
int result_len = INT32_MAX;
int sub_len = 0;
int result_sum = 0;
int start = 0;
int size = nums.size();
for(int end=0; end<size; end++){
result_sum += nums[end];
while(result_sum >= target){
sub_len = (end - start + 1); // 取子序列的长度
result_len = result_len < sub_len ? result_len : sub_len;
result_sum -= nums[start++];
}
}
return result_len == INT32_MAX ? 0 : result_len;
}
错题:
1. 在result_sum++的位置,nums[end]写成nums[start],导致结果总是4,对变量定义不清晰。
2. 在for循环里面,end<size写成<=了,导致溢出。for循环马虎。
59. 螺旋矩阵2
思路:
每一圈都是一个独立的函数,输入为起始位置、每条边的打印长度。循环每一圈,每一圈都更新起始位置、打印长度即可,调用函数。
起始位置从0开始的,每轮+1;打印长度(假设每条边左闭右开)从n-1开始的,每轮-2。打印轮数是n/2,注意如果n为奇数,则中心不能被打印,所以还要判断一下最后补上。
感悟:
这道题不难,关键是定义好函数,对起始位置、打印长度有深刻的理解。不然容易混乱。在写的时候,最难的就是每条边如何用这两个参数定义。明白每条边都是start:start+draw_len,这道题就好做了。
代码:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int loop = n/2; // 画圈的次数
int fill_num = 1; // 填充的数字
int draw_len = n-1;
int start_pos = 0;
while(loop--){
for(int i = start_pos; i<start_pos+draw_len; i++){
res[start_pos][i] = fill_num++;
}
for(int i = start_pos; i<start_pos+draw_len; i++){
res[i][start_pos + draw_len] = fill_num++;
}
for(int i = start_pos + draw_len; i>start_pos; i--){
res[start_pos + draw_len][i] = fill_num++;
}
for(int i = start_pos + draw_len; i>start_pos; i--){
res[i][start_pos] = fill_num++;
}
start_pos++;
draw_len-=2;
}
if(n%2!=0){
int center_pos = n/2;
res[center_pos][center_pos] = fill_num;
}
return res;
}