今日任务
977. 有序数组的平方
方法一:二分找临界+双指针
(本题昨天有个数据是4,1,4,导致我无法直接用双指针来做,后面发现这个数据是莫名其妙多出来的)
主要思想: 从离0最近的两个数开始分别往左右方向遍历比较,将绝对值比较小的先放进res数组
time: O ( l o g n + n ) = O ( l o g n ) O(logn + n) = O(logn) O(logn+n)=O(logn)
记住一定要边写代码边检查,不然最后debug很耗时间!
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
sort(nums.begin(), nums.end());
int mid, left = 0, right = nums.size() - 1, target = 0, len = nums.size();
// 找的左边界
while (left < right) {
mid = (left + right) >> 1;
if (nums[mid] >= target) right = mid;
else left = mid + 1;
}
int pleft, pright;
if (nums[left] == 0) pleft = left - 1, pright = left;
else if (nums[left] < 0) pleft = left, pright = left + 1;
else pleft = left - 1, pright = left;
// cout << left << ' ' << right << endl;
// cout << nums[pleft] << ' ' << nums[pright];
// 人傻了,二分的条件写成 right < left了,num[mid]写成num[left]了
vector<int> res;
while (pleft >= 0 && pright <= len - 1) {
if (abs(nums[pleft]) <= abs(nums[pright])) res.push_back(pow(nums[pleft--], 2));
else res.push_back(pow(nums[pright++], 2));
}
while (pleft >= 0) res.push_back(pow(nums[pleft--], 2));
while (pright <= len - 1) res.push_back(pow(nums[pright++], 2));
return res;
}
};
方法二:先算平方然后直接排序
暴力解法,主要复习下排序
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for (int i = 0; i < nums.size(); ++i) {
nums[i] = nums[i] * nums[i];
}
sort(nums.begin(), nums.end());
return nums;
}
};
方法三:先平方,然后使用双指针从两侧开始比较逆序对
class Solution {
public:
// vector<int> sortedSquares(vector<int>& nums) {
// for (int i = 0; i < nums.size(); ++i) {
// nums[i] = nums[i] * nums[i];
// }
// // 完成后如果之前有负数,那么此时顺序是先递减后递增
// // 如果没有负数,那么是非严格递增
// // 两种情况都有较大数在外头
// // 所以用双指针从两头开始比较(逆序对)
// vector<int> res;
// int left = 0, right = nums.size() - 1;
// while (left <= right) {
// if (nums[left] >= nums[right]) {
// res.push_back(nums[left++]);
// } else {
// res.push_back(nums[right--]);
// }
// }
// reverse(res.begin(), res.end());
// return res;
// }
// 简化版
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res(nums.size());
cout << res[0] << endl;
int left = 0, right = nums.size() - 1, k = nums.size() - 1;
while (left <= right) {
if (nums[left] * nums[left] >= nums[right] * nums[right]) {
res[k--] = nums[left] * nums[left];
left++;
}
else {
res[k--] = nums[right] * nums[right];
right--;
}
}
return res;
}
};
209. 长度最小的子数组
滑动窗口
O
(
n
)
O(n)
O(n)
主要思路
- 当窗口内和小于target时,不停右移窗口的指针,直到其和大于窗口值
- 当窗口不为空且内和大于target时,先更新最小值 m i n L e n = m i n ( m i n L e n , d q . s i z e ( ) ) minLen = min(minLen, dq.size()) minLen=min(minLen,dq.size()) ,再移动窗口左边的指针,重复这一步循环
- 重复前两个循环直到右指针超出数组边界
class Solution {
public:
// O(n), 使用deque,类似于双指针
int minSubArrayLen(int target, vector<int>& nums) {
deque<int> dq;
int minLen = INT_MAX, sum = 0, i = 0;
while (i < nums.size()) {
// 先移动右边界
while (sum < target && i < nums.size()) {
dq.push_back(nums[i++]);
sum += dq.back();
}
// 再移动左边界
while ((dq.size()) && (sum >= target)) {
minLen = minLen < dq.size() ? minLen : dq.size();
sum -= dq.front();
dq.pop_front();
}
cout << dq.size() << ' ' << i << endl;
}
return minLen == INT_MAX ? 0 : minLen;
}
};
59. 螺旋矩阵 II
模拟即可
O
(
n
2
)
O(n^2)
O(n2)
分上下左右四个边界进行模拟即可
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> Matrix(n, vector<int>(n));
int num = 1, endNum = n * n, leftBound = 0, rightBound = n - 1, topBound = 0, bottomBound = n - 1;
while (num <= endNum) {
for (int i = leftBound; i <= rightBound; ++i) Matrix[topBound][i] = num++;
topBound++;
for (int i = topBound; i <= bottomBound; ++i) Matrix[i][rightBound] = num++;
rightBound--;
for (int i = rightBound; i >= leftBound; --i) Matrix[bottomBound][i] = num++;
bottomBound--;
for (int i = bottomBound; i >= topBound; --i) Matrix[i][leftBound] = num++;
leftBound++;
}
return Matrix;
}
};