目录
一、LeetCode977.有序数组的平方
首先,根据题目的意思,数组是递增序列,并且里面是含有负数的,要求我们将所有数字进行平方后,再次排列成一个有序数组。
解法1:
暴力解法:在原数组遍历数组中的所有元素,并对其平方,赋值进去,然后进行排序即可;
class Solution { public: void MergeSort(int left, int right, vector<int>& nums, vector<int>& tmp) { if(left >= right) return; int mid = (left + right) / 2; MergeSort(left, mid, nums, tmp); MergeSort(mid + 1, right, nums, tmp); int i = left, j = mid + 1; for(int k = left; k <= right; k++) { tmp[k] = nums[k]; } for(int k = left; k <= right; k++) { if(i == mid + 1) { nums[k] = tmp[j++]; } else if(j == right + 1 || tmp[i] < tmp[j]) { nums[k] = tmp[i++]; } else { nums[k] = tmp[j++]; } } } vector<int> sortedSquares(vector<int>& nums) { vector<int> tmp(nums.size()); for(int i = 0; i < nums.size(); i++) { nums[i] = nums[i] * nums[i]; } //sort(nums.begin(),nums.end());//你可以使用C++的sort算法 MergeSort(0, nums.size() - 1, nums, tmp);//也可以自己写一个排序算法,我这里写的是归并排序 return nums; } };
解法2:
双指针法:我们从给出的数组中可以看出,数组被划分为了两个区间,左区间全部是负数,右区间全部是正数,并且数组是递增的,这样一来:对于数组的两端来说,平方之后都是最大值,从外向内一次减小,我们只需要将左右两端的值平方之后进行比较,取出最大的值,开辟一个新的数组,插入到数组的最后一个位置,然后从尾部迭代向前插入,就能得到有序数组的平方。
class Solution { public: vector<int> sortedSquares(vector<int>& nums) { int n = nums.size(); vector<int> res(n); int left = 0; int right = n - 1; int k = n - 1; while(left <= right) { //最左边的平方值和最右边的平方值进行比较,谁大就把谁插入到res数组的最后面 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; } };
二、LeetCode209.长度最小的子数组
解法1:
暴力解法:使用两层for循环,外循环主要用来遍历每个数组元素,内循环则是对每个元素进行向后累加,计算出长度最小的子数组,由于外循环会遍历每一个元素,所以内循环可以处理每个元素所对应的子数组长度,不断更新这个子数组长度,直到找到最小的。但是这道题,暴力解法会超时。但也是一种思路。
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int n = nums.size(); if(n == 0) return 0; int minlength = INT_MAX;//INT_MAX整形的最大值,用来记录子数组长度 for(int i = 0; i < n; i++) { int sum = 0;//每个元素计算完子数组长度后,都需要将这个sum置0,为了下一个元素重新计算 for(int j = i; j < n; j++) { sum += nums[j]; if(sum >= target) { minlength = min(minlength, j - i + 1); break; } } } return minlength == INT_MAX ? 0 : minlength; } };
解法2:
滑动窗口:所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。大致效果如下:
class Solution { public: int minSubArrayLen(int target, vector<int>& nums) { int begin = 0; //滑动窗口的起始位置 int minlength = INT_MAX;//记录最小的子序列 int result = 0;//记录每一次子序列的长度 int sum = 0; //滑动窗口中数的和 for(int end = 0; end < nums.size(); end++)//end作为滑动窗口的终止位置 { sum += nums[end]; // 注意这里使用while,每次更新 i(起始位置),并不断比较子序列是否符合条件 while(sum >= target) { result = end - begin + 1;//计算子序列 minlength = min(minlength, result);//更新最小的子序列长度 sum -= nums[begin++];//不断变更滑动窗口的起始位置,为了算出当前子序列中最小的子序列 } } // 如果minlength没有被赋值的话,就返回0,说明没有符合条件的子序列 return minlength == INT_MAX ? 0 : minlength; } };
三、LeetCode59.螺旋矩阵II
题解:
模拟顺时针画矩阵的过程:
- 填充上行——从左到右
- 填充右列——从上到下
- 填充下行——从右到左
- 填充左列——从下到上
由外向内一圈一圈这么画下去。
可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海;
这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。
那么我按照左闭右开的原则,来画一圈,大家看一下:
可以发现当n为奇数的时候,最后还剩下一个没有赋值,我们可以在最后做一下特殊处理。
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n));
int left = 0;
int right = n - 1;
int top = 0;
int bottom = n - 1;
int num = 1; //用来累加赋值
int mid = n / 2;//如果n是奇数,就可以用mid处理最后一个值
while(left < right && top < bottom)
{
//左->右
for(int i = left; i < right; i++)
{
res[top][i] = num++;
}
//上->下
for(int i = top; i < bottom; i++)
{
res[i][right] = num++;
}
//右->左
for(int i = right; i > left; i--)
{
res[bottom][i] = num++;
}
//下->上
for(int i = bottom; i > top; i--)
{
res[i][left] = num++;
}
//一圈结束后,将四个坐标更新到下一个圈
left++;
right--;
top++;
bottom--;
}
if(n % 2 == 1)//如果n是奇数,则循环结束后最中间的一个元素没有赋值,需要特殊处理
{
res[mid][mid] = num;
}
return res;
}
};