977. 有序数组的平方 - 力扣(LeetCode)
以下思路为经典反例
思路:因为刚做过27. 移除元素 - 力扣(LeetCode),所以第一时间就想到了用快慢指针做这道题,思路很简单,同样也是两个指针,快指针负责遍历,慢指针负责收集,不过这次要求返回一个vector
,所以我们要新建一个cnt
大小的vector
并且赋值为-1(因为前面的数据经过平方以后不可能小于0,这边为了与下面的a[slow++]
配合,其实这不是不要的,只是比较简单明了),后面快指针遇到和慢指针一样的就忽略,和慢指针不一样的就让慢指针收集,这样就保证慢指针中收集到的都是不重复的数字
我的AC代码
(虽然AC了,但貌似会错意了,阴差阳错,题目不要求数字不重复)
// 时间复杂度O(n + nlog n) 空间复杂度O(n) class Solution { public: vector<int> sortedSquares(vector<int>& nums) { int cnt = nums.size(); for(int i = 0; i < cnt; ++i) { nums[i] = nums[i] * nums[i]; } sort(nums.begin(), nums.begin() + cnt); vector<int>a(cnt,-1); int slow = 0; int fast = 0; for(fast = 0; fast < cnt; ++fast) { if(nums[fast] == a[slow]) { ++fast; } else { a[slow++]=nums[fast]; } } return a; } };
我的AC代码2
以下为正确思路,看了标准答案以后写的
class Solution { public: vector<int> sortedSquares(vector<int>& nums) { int cnt = nums.size(); for(int i = 0; i < cnt; ++i) { nums[i] = nums[i] * nums[i]; } vector<int>a(cnt,-1); int l = 0; int r = cnt-1; while(l <= r) { if(nums[l] <= nums[r]) { a[--cnt] = nums[r]; --r; } else { a[--cnt] = nums[l]; ++l; } } return a; } };
标准答案
class Solution { public: vector<int> sortedSquares(vector<int>& A) { int k = A.size() - 1; vector<int> result(A.size(), 0); for (int i = 0, j = A.size() - 1; i <= j;) { // 注意这里要i <= j,因为最后要处理两个元素 if (A[i] * A[i] < A[j] * A[j]) { result[k--] = A[j] * A[j]; j--; } else { result[k--] = A[i] * A[i]; i++; } } return result; } };
209. 长度最小的子数组 - 力扣(LeetCode)
思路:因为以前做过,所以第一时间想到了滑动窗口,即一个指针负责右端,一个指针负责左端,当总和小于target
的时候,右端不停向右移动,直到总和大于target
,然后此时再让左端指针不停向右移动(不要忘了减数据),力图找出最小的连续子数组长度,第一次没AC是因为忘记无解的时候返回0了,很尴尬
我的AC代码
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int sum = 0; int slow = 0; int fast = 0; int cnt = nums.size(); int ans = 1e5 + 10; for(fast = 0;fast < cnt; ++fast) { sum += nums[fast]; while(sum >= target) { ans = min(ans, fast - slow + 1); sum -= nums[slow]; slow++; } } if(ans == 1e5 + 10) { ans = 0; } return ans; } };
标准答案
// 滑动窗口法 // 时间复杂度:O(n) // 空间复杂度:O(1) class Solution { public: int minSubArrayLen(int s, vector<int>& nums) { int result = INT32_MAX; int sum = 0; // 滑动窗口数值之和 int i = 0; // 滑动窗口起始位置 int subLength = 0; // 滑动窗口的长度 for (int j = 0; j < nums.size(); j++) { sum += nums[j]; // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件 while (sum >= s) { subLength = (j - i + 1); // 取子序列的长度 result = result < subLength ? result : subLength; sum -= nums[i++]; // 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置) } } // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列 return result == INT32_MAX ? 0 : result; } };
59. 螺旋矩阵 II - 力扣(LeetCode)
思路:这题目第一眼很懵逼,但是思路还是简单的,只要坚持左闭右开的原则,顺时针画一遍就行了,主要是边界处比较难处理,想得挺久的
此处借用一下carl哥的图,这样更易于理解
我的AC代码
//时间复杂度O(n2),空间复杂度O(n2) 感觉也算遍历二维矩阵了吧 class Solution { public: vector<vector<int>> generateMatrix(int n) { vector<vector<int>> ans(n,vector<int>(n,1)); int end = n*n; int r = 0; int c = 0; int q = 1; if(1 == n) { return ans; } for(int i = 0; i <= end; ) { while(c <= (n - q - 1)) { ++i; ans[r][c] = i; ++c; if(end == i) { return ans; } } while(r <= (n - q - 1)) { ++i; ans[r][c] = i; ++r; if(end == i) { return ans; } } while(c >= q) { ++i; ans[r][c] = i; --c; if(end == i) { return ans; } } while(r >= q) { ++i; ans[r][c] = i; --r; if(end == i) { return ans; } } ++r; ++c; ++q; if((end - 1) == i){ ans[r][c] = end; return ans; } } return ans; } };
附一个vector初始化二维数组的办法
// 初始化一个 二维的matrix, 行M,列N,且值为0 vector<vector<int>> matrix(M,vector<int>(N)); // 等价于下面的 vector<vector<int> > matrix(M); for(int i=0;i<M;i++) { matrix[i].resize(N); } // 等价于下面的 vector< vector<int> > matrix; matrix.resize(M);// M行 for(int i=0;i<matrix.size();i++){ matrix[i].resize(N);// 每一行都是N列 } // 初始化一个 二维的matrix, 行M,列N,且值自定义为data; vector<vector<int>> matrix(M,vector<int>(N,data));
我和carl哥代码的最大区别就是我的终止条件不是转几圈,而是数字全部赋完,这也导致一个问题,就是n为奇数时最后一个数字可能无法赋值,循环就永远都无法结束,得加入特判
标准答案
class Solution { public: vector<vector<int>> generateMatrix(int n) { vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组 int startx = 0, starty = 0; // 定义每循环一个圈的起始位置 int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理 int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2) int count = 1; // 用来给矩阵中每一个空格赋值 int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位 int i,j; while (loop --) { i = startx; j = starty; // 下面开始的四个for就是模拟转了一圈 // 模拟填充上行从左到右(左闭右开) for (j = starty; j < n - offset; j++) { res[startx][j] = count++; } // 模拟填充右列从上到下(左闭右开) for (i = startx; i < n - offset; i++) { res[i][j] = count++; } // 模拟填充下行从右到左(左闭右开) for (; j > starty; j--) { res[i][j] = count++; } // 模拟填充左列从下到上(左闭右开) for (; i > startx; i--) { res[i][j] = count++; } // 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1) startx++; starty++; // offset 控制每一圈里每一条边遍历的长度 offset += 1; } // 如果n为奇数的话,需要单独给矩阵最中间的位置赋值 if (n % 2) { res[mid][mid] = count; } return res; } };
Comments NOTHING