LeetCode 977 有序数组的平方
题目链接:977
解1:暴力
思路:先求每个值的平方,再对数组进行排序
分析:时间复杂度为O(n+nlogn),即O(nlogn)
代码:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for (int i=0; i<nums.size(); ++i) {
nums[i] = nums[i] * nums[i];
}
std::sort(nums.begin(), nums.end());
return nums;
}
};
解2:双指针法
思路:由于原数组为非递减顺序,因此若将数组根据正负分为两段,则平方后,前段递减,后段递增,因此最大值一定为最左值或最右值。选出最大值填入新数组的末尾,剩下的子数组的最大值仍为子数组的最左值或最右值,因此可不断迭代。
分析:时间复杂度为O(n)
代码:
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res(nums.size(), 0);
// left, right指向原数组两侧
// k指向新数组的待写入位置
int left = 0;
int right = nums.size() - 1;
int k = right;
while (left <= right) {
int left_square = nums[left] * nums[left] ;
int right_square = nums[right] * nums[right];
// 由于当前范围内的最大值只能由left或right指向,因此只需考虑这两者即可
if (left_square >= right_square) {
res[k--] = left_square;
++left;
} else {
res[k--] = right_square;
--right;
}
}
return res;
}
};
LeetCode 209 长度最小的子数组
题目链接:209
滑动窗口法
思路:通过滑动窗口寻找满足sum大于target的子串。当sum小于target时,移动右边界直至找到满足要求的子串;当sum大于等于target时,尝试移动左边界以缩小子串长度,寻找右边界固定时符合要求的最小子串长度。
分析:时间复杂度O(n)
代码1:此为自己写的版本,在while循环中,每次只移动左边界或右边界一个单位
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// fast, slow定义滑动窗口的边界
int fast = 0;
int slow = 0;
int res = INT32_MAX;
int sum = nums[slow];
bool fast_flag;
while (fast < nums.size()){
// 为防止fast越界,在前次迭代++fast之后先不加nums[fast]
// 在判断fast在范围内后,再将其加入sum
if (fast_flag) sum += nums[fast];
if (sum >= target) {
// 若和大于target,则左边界右滑,尝试更短的子串
int num = fast - slow + 1;
if (num < res) res = num;
sum -= nums[slow++];
fast_flag = false;
} else {
// 若和小于target,则右边界右滑,尝试更长的子串
++ fast;
fast_flag = true;
}
}
if (res < INT32_MAX) {
return res;
}
return 0;
}
};
代码2:此为参考题解后写的版本,for循环右边界,对于每个固定的右边界,移动左边界,寻找最小的符合要求的子串长度
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
// fast, slow定义滑动窗口的边界
int fast = 0;
int slow = 0;
int res = INT32_MAX;
int sum = 0;
for (fast; fast < nums.size(); ++fast) {
sum += nums[fast];
// 固定fast,若sum大于target,则尝试右滑slow
// 缩短子串长度
while (sum >= target) {
int num = fast - slow + 1;
if (num < res) res = num;
sum -= nums[slow++];
}
}
return res==INT32_MAX ? 0 : res;
}
};
LeetCode 59 螺旋矩阵II
题目链接:59
思路:将目标矩阵分层,从外到内一圈为一层,对于每一层,按上行-右列-下行-左列的顺序填数,机按螺旋顺序填数
代码1:此为自己写的版本,每条边的边界条件不一致,逻辑上较为不清晰,但不需要针对奇数维矩阵单独填入中间数
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
int num = 0;
vector<vector<int>> mat(n, vector<int>(n));
// 每个level可理解为1圈
// 若n为奇数,则中间的值单独成圈
for (int level=0; level < (n+1)/2; ++level) {
//填充上行
for (int i=level; i<=(n-level-1); ++i)
mat[level][i] = ++num;
//填充右列
for (int i=level+1; i<=(n-level-1); ++i)
mat[i][n-1-level] = ++num;
//填充下行
for (int i=n-level-2; i>=level; --i)
mat[n-1-level][i] = ++num;
//填充左列
for (int i=n-2-level; i>=level+1; --i)
mat[i][level] = ++num;
}
return mat;
}
};
代码2:此为参考代码随想录后写的版本,四条边的遍历规则都为左闭右开,但需要针对奇数维矩阵单独填入中间数
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> mat(n, vector<int>(n, 0));
int level = n / 2;
int start_x = 0;
int start_y = 0;
int num = 0;
while (level > 0 ) {
int i = start_y;
int j = start_x;
for (j; j < n-1-start_x; ++j)
mat[i][j] = ++num;
for (i; i < n-1-start_y; ++i)
mat[i][j] = ++num;
for (j; j > start_x; --j)
mat[i][j] = ++num;
for (i; i > start_y; --i)
mat[i][j] = ++num;
++start_x;
++start_y;
--level;
}
if (n % 2 != 0) {
int mid = n/2;
mat[mid][mid] = ++num;
}
return mat;
}
};
代码3:此为参考LeetCode高赞题解版本。设置上下左右四条边界,按上右下左顺序填充,每填充完一条边界的值,则移动边界。代码逻辑清晰,且无需针对奇数矩阵做额外处理。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> mat(n, vector<int>(n, 0));
int num = 1;
// 上下左右边界
int top = 0;
int bottom = n-1;
int left = 0;
int right = n-1;
while (num <= n*n) {
for (int i=left; i<=right; ++i)
mat[top][i] = num++;
++top;
for (int i=top; i<=bottom; ++i)
mat[i][right] = num++;
--right;
for (int i=right; i>=left; --i)
mat[bottom][i] = num++;
--bottom;
for (int i=bottom; i>=top; --i)
mat[i][left] = num++;
++left;
}
return mat;
}
};