代码随想录算法训练营 Day2
- 知识点:
- 双指针
- 滑动窗口
- 模拟:二分法中区间的概念(着重判断边界条件)
977.有序数组的平方
- 思路:
根据平方的特性,大的数都在左右两边,中间的数最小
→ 以第一个非负数为界,具有局部单调性
→ 用双指针,开一个数组存答案
→ i:从前往后,j:从后往前
!!!:所有可以用双指针的题目想不清楚过程,都可以先用暴力写一遍
- AcWing模板:
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作 √
- 答案:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int i = 0, j = nums.size() - 1;
int size = nums.size() - 1;
vector<int> ans(nums.size());
while (i <= j) {
int x = nums[i]*nums[i];
int y = nums[j]*nums[j];
if (x > y) {
ans[size--] = x;
i++;
}
else {
ans[size--] = y;
j--;
}
}
return ans;
}
};
- 为什么是 i≤j ?
若数组长度为偶数,则取不到i==j的那个元素
没啥用的优化(位运算):
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int i = 0, j = nums.size() - 1;
int size = nums.size() - 1;
vector<int> ans(nums.size());
while (i <= j) {
if (abs(nums[i]) > abs(nums[j])) {
ans[size--] = nums[i] * nums[i];
i++;
}
else {
ans[size--] = nums[j] * nums[j];
j--;
}
}
return ans;
}
private:
int abs(int x) {
// 实现参考csapp data lab
int mask = x >> (sizeof(int) * CHAR_BIT - 1);
return (x + mask) ^ mask;
}
};
209.长度最小的子数组
- 思路:动态调整起始位置来找大于等于target的区间,本质上还是双指针
- 答案:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum = 0, sub_len = 0;
int ans = INT32_MAX;
for (int l = 0, r = 0; r < nums.size(); r++) {
sum+=nums[r];
while (sum >= target) {
sub_len = r - l + 1;
ans = ans < sub_len ? ans : sub_len;
sum-=nums[l++];
}
}
return ans == INT32_MAX ? 0 : ans;
}
};
[TODO]相关题目:
59.螺旋矩阵II
- 思路:想清楚螺旋拆分为几个阶段,有哪些变量很重要
- 左闭右开:只处理第一个点,不处理最后一个点
- 答案:
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
// 注意四角元素,左闭右开
// 一共转几圈? n/2
// 初始位置如何定义
vector<vector<int>> res(n, vector<int>(n, 0));
int startx = 0, starty = 0;
int loop = n / 2;
int offset = 1;
int i, j, count = 1;
while (loop--) {
i = startx;
j = starty;
// 1.上左到右
for (j = starty; j < n - offset; j++)
res[startx][j] = count++;
// 2.右上到下
for (i = startx; i < n - offset; i++)
res[i][j] = count++;
// 3.下右到左
for (; j > starty; j--)
res[i][j] = count++;
// 4.左下到上
for (; i > startx; i--)
res[i][starty] = count++;
// 下一圈初始
startx++;
starty++;
offset++;
}
// 处理奇数的情况
if (n % 2) {
int mid = n/2;
res[mid][mid] = n * n;
}
return res;
}
};
[TODO]相关题目:
54.螺旋矩阵(opens new window)
剑指Offer 29.顺时针打印矩阵