目录
- 0 引言
- 1 有序数组列表
- 1.1 我的题解(双指针)
- 1.2 根据官方解题修改后
- 2 长度最小的子数组
- 2.1 我的题解
- 2.2 官方滑动窗口(双指针)题解
- 3 螺旋矩阵
- 3.1 我的题解
- 🙋♂️ 作者:海码007
- 📜 专栏:算法专栏
- 💥 标题:
- ❣️ 寄语:书到用时方恨少,事非经过不知难!
0 引言
1 有序数组列表
- 🎈 文档讲解:https://programmercarl.com/0977.%E6%9C%89%E5%BA%8F%E6%95%B0%E7%BB%84%E7%9A%84%E5%B9%B3%E6%96%B9.html
- 🎈 视频讲解: https://www.bilibili.com/video/BV1QB4y1D7ep
- 🎈 做题状态:没有抓住顺序排序的精髓,导致解题思路不明确。现在知道双指针不仅可以从一头遍历,也可以同时从两头遍历
1.1 我的题解(双指针)
这道题主要利用了数组顺序排序的特性,基于此可以得知数组平方后的最大数一定在数组的两端。所以只需要从两端开始比较找出最大的数,然后插入到新数组的最后一位即可得到排序好的新数组。
class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {// 平方后的数肯定大于等于0vector<int> result;int leftIndex, rightIndex;leftIndex = 0; rightIndex = nums.size() - 1;// 双指针法基于数组非递减顺序的特点,可知平方后的最大数在数组的两端// 所以从两头往中间遍历依次把最大数插入到新的数组中,即可得到答案。while (leftIndex <= rightIndex){// 当左侧数的绝对值更大时插入左侧的数据,leftIndex加一if (abs(nums[leftIndex]) >= abs(nums[rightIndex])){result.insert(result.begin(), abs(nums[leftIndex] * abs(nums[leftIndex])));leftIndex++;}// 当右侧数的绝对值更大时插入右侧的数据,rightIndex减一else{int temp = abs(nums[rightIndex] * abs(nums[rightIndex]));result.insert(result.begin(), temp);rightIndex--;}}return result;}
};
1.2 根据官方解题修改后
但是我这个题解还有很多不足的地方,例如新数组的插入操作,使用的是Insert,这个函数的时间复杂度是 n,因为是从头插入新的元素,所以每次都会导致其他元素全部向后移动一位。
通过官方题解,可以得知。直接将新数组元素个数确定,然后采用索引的方式从后往前给新数组赋值,这样可以节省很多的时间。
class Solution {
public:vector<int> sortedSquares2(vector<int>& nums) {// 平方后的数肯定大于等于0int leftIndex, rightIndex, insertIndex;leftIndex = 0; insertIndex = rightIndex = nums.size() - 1;vector<int> result(nums.size());while (leftIndex <= rightIndex){if (abs(nums[leftIndex]) >= abs(nums[rightIndex])){result[insertIndex] = abs(nums[leftIndex] * abs(nums[leftIndex]));leftIndex++;}else{result[insertIndex] = abs(nums[rightIndex] * abs(nums[rightIndex]));rightIndex--;}insertIndex--;}return result;}
};
2 长度最小的子数组
- 🎈 文档讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
- 🎈 视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
- 🎈 做题状态:不看视频和文档直接写出来了(因该还是学习了之前的双指针思想有所启发),但是代码还是有很多地方需要优化
2.1 我的题解
主要就是通过左右两个索引来对该范围内的数组进行相加统计。但是我的代码存在很多特殊条件的判断,不够精简。
class Solution {
public:int minSubArrayLen(int target, vector<int>& nums) {int result = nums.size() + 1, leftIndex = 0, rightIndex = 0;int sum = nums[0];// 当rightIndex大于数组长度时才结束遍历while (rightIndex < nums.size() && leftIndex < nums.size()){ // 当sum的合小于目标值,rightIndex加一if (sum < target){rightIndex++;if (rightIndex >= nums.size()){// 处理特殊情况if (result == nums.size() + 1){return 0;}return result;}sum = sum + nums[rightIndex];}// 当sum大于等于target时,将result和 (rightIndex-leftIndex)+1 作比较,取最小的值// 此时leftIndex要减一else{result = min(result, rightIndex - leftIndex + 1);// 如果result等于1时,直接返回if (result == 1) return result;// 先减去左边索引的值,然后在将坐标索引向右移动一位sum = sum - nums[leftIndex];leftIndex++;}}// 处理特殊情况if (result == nums.size() + 1){return 0;}return result;}
};
2.2 官方滑动窗口(双指针)题解
官方的滑动窗口和我写的有细微区别,但是对于 sum 的操作都是一样,当rightIndex向右移动是需要 sum加,让leftIndex向右移动时,需要sum减去值。
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;}
};
3 螺旋矩阵
- 🎈 文档讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
- 🎈 视频讲解:https://www.bilibili.com/video/BV1SL4y1N7mV/?vd_source=d499e7f3a8e68e2b173b1c6f068b2147
- 🎈 做题状态:主要是循环条件的确定需要慢慢调试
3.1 我的题解
- 思路:根据n来计算需要遍历的圈数,n为1时0圈,n为2时一圈,n为3时一圈。圈数为 n/2 然后取整。然后再根据四个赋值的方向制作四个循环。最后当n为奇数时,需要手动给中间的数赋值。
- 难点:每次循环时,条件的确定。时刻记住数组的最大的下标和数组元素个数相差1。
class Solution {
public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> result(n, vector<int>(n));int number = 1;int i = 0;// 遍历的圈数确定,圈数 = n/2然后取整 (n为1时0圈,n为2时一圈,n为3时一圈)for ( ; i < n/2; i++){// 每遍历完一圈后,行的区间要从首尾各减去一,列的区间也要从首尾各减去一int j = i;for (j = i; j < (n - i); j++){// 第一行result[i][j] = number;number++;}for (j = i+1; j < (n - i); j++){// 最后一列,n-1 对应最后一列result[j][n - 1 - i] = number;number++;}for (j = i+1; j < (n - i); j++){// 最后一行,从最后一列开始遍历,n-1是最后一列result[n - 1 - i][n - 1 - j] = number;number++;}// 第一列遍历,少一个元素,需要注意for (j = i+1; j < (n - i) - 1; j++){// 第一列,从最后一行向上result[n - 1 - j][i] = number;number++;}}// 当n为奇数时,需要手动给中心点赋值if (n%2 != 0){result[i][i] = number;}// 遍历完后返回结果return result;}
};