【LeetCode】2.数组系列
总目录:
0.理论基础
0.1.要点
数组是存放在连续内存空间上的相同类型数据的集合。
数组可以方便的通过下标索引的方式获取到下标下对应的数据。
在删除或者增添元素的时候,就难免要移动其他元素的地址,只能覆盖而不能删除。
多维数组的地址也是连续的。
1.二分查找
1.1.问题描述
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
链接:https://leetcode.cn/problems/binary-search
1.2.要点
二分查找就是二分查找范围,注意边界的索引处理
在计算中值索引时注意防止溢出,固定套路为mid=left+(right-left)/2;
1.3.代码实例
1 class Solution { 2 public: 3 int search(vector<int>& nums, int target) { 4 int start=0,end=nums.size()-1; 5 int mid=0; 6 while(start<=end){ 7 mid=start+((end-start)>>1);//防止溢出 8 if(nums[mid]==target){ 9 return mid; 10 } 11 if(nums[mid]>target){ 12 end=mid-1; 13 } 14 if(nums[mid]<target){ 15 start=mid+1; 16 } 17 } 18 19 return -1; 20 } 21 };
2.移除指定元素
2.1.问题描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
链接:https://leetcode.cn/problems/remove-element
2.2.要点
不要开辟额外空间,绝对是使用双指针。有快慢指针和对撞指针2种解法。
快慢指针,可以保证有效数据的顺序不变,但存在较多的内存copy。
对撞指针,有效数据的顺序将发生改变,但只存在尽量少的内存copy。
2.3.代码实例
快慢指针
1 class Solution { 2 public int removeElement(int[] nums, int val) { 3 int curIndex = 0; 4 int len = nums.length; 5 for (int i = 0; i < len; i++) { 6 // 如果等于就被删除, 后面的向前合并 7 if(nums[i] != val){ 8 nums[curIndex++] = nums[i]; 9 } 10 } 11 return curIndex; 12 } 13 }
对撞指针
1 class Solution { 2 public: 3 int removeElement(vector<int>& nums, int val) { 4 int left=0,right=nums.size()-1; 5 if(right<0){ 6 return 0; 7 } 8 9 //对撞之后不再迭代 10 while(left<=right){ 11 //先找到最后一个非目标数的值 12 if(nums[right]==val){ 13 right--; 14 continue; 15 } 16 17 //如果在前面遇到目标值,则将其交换到后面 18 if(nums[left]==val){ 19 swap(nums[left],nums[right]); 20 right--; 21 } 22 23 left++; 24 } 25 26 //right值既为最后一个不为val的索引 27 return right+1; 28 } 29 };
3.有序数组的平方
3.1.问题描述
非递减顺序:相邻元素不是相等就是递增。
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
3.2.要点
这是合并两个有序集合的变种
双指针,分别比较两个集合的顶部元素,放入新的集合中,是一种归并排序算法
3.3.代码实例
归并排序
1 class Solution { 2 public: 3 vector<int> sortedSquares(vector<int>& nums) { 4 int n = nums.size(); 5 int negative = -1; 6 for (int i = 0; i < n; ++i) { 7 if (nums[i] < 0) { 8 negative = i; 9 } else { 10 break; 11 } 12 } 13 14 vector<int> ans; 15 int i = negative, j = negative + 1; 16 while (i >= 0 || j < n) { 17 if (i < 0) { 18 ans.push_back(nums[j] * nums[j]); 19 ++j; 20 } 21 else if (j == n) { 22 ans.push_back(nums[i] * nums[i]); 23 --i; 24 } 25 else if (nums[i] * nums[i] < nums[j] * nums[j]) { 26 ans.push_back(nums[i] * nums[i]); 27 --i; 28 } 29 else { 30 ans.push_back(nums[j] * nums[j]); 31 ++j; 32 } 33 } 34 35 return ans; 36 } 37 };
4.长度最小的子数组
4.1.问题描述
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
链接:https://leetcode.cn/problems/minimum-size-subarray-sum
4.2.要点
都是正整数,要连续的最短,只需要返回长度
1.滑动窗口法,左缩右伸
4.3.代码实例
1.滑动窗口法
1 class Solution { 2 public: 3 int minSubArrayLen(int target, vector<int>& nums) { 4 int minLen=INT_MAX; 5 if(nums.size()<1){ 6 return 0; 7 } 8 9 queue<int> sumQ; 10 int curLen=0; 11 int curSum=0; 12 int curId=0; 13 14 while(curId<nums.size()){ 15 //加上当前到达的值 16 sumQ.push(nums[curId]); 17 curSum+=nums[curId]; 18 19 //满足条件时持续左缩寻找最短长度 20 while(curSum>=target){ 21 curLen=sumQ.size(); 22 curSum-=sumQ.front(); 23 sumQ.pop(); 24 25 minLen=min(minLen,curLen); 26 } 27 28 //不够时向右延伸1步 29 curId++; 30 } 31 32 return minLen==INT_MAX?0:minLen; 33 } 34 };
5.螺旋矩阵2
5.1.问题描述
给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。
链接:https://leetcode.cn/problems/spiral-matrix-ii/
5.2.要点
顺时针
1.模拟,边界收缩
5.3.代码实例
边界收缩法
1 class Solution { 2 public: 3 vector<vector<int>> generateMatrix(int n) { 4 vector<vector<int>> ret(n,vector<int>(n,0)); 5 6 int i=0; 7 int curVal=1; 8 int up=0,down=n-1,left=0,right=n-1; 9 while(up<=down&&left<=right){ 10 for(i=left;i<=right;i++){ 11 ret[up][i]=curVal; 12 curVal++; 13 } 14 up++; 15 16 for(i=up;i<=down;i++){ 17 ret[i][right]=curVal; 18 curVal++; 19 } 20 right--; 21 22 for(i=right;i>=left;i--){ 23 ret[down][i]=curVal; 24 curVal++; 25 } 26 down--; 27 28 for(i=down;i>=up;i--){ 29 ret[i][left]=curVal; 30 curVal++; 31 } 32 left++; 33 } 34 35 return ret; 36 } 37 };
6.总结
6.1.经典套路
二分法
双指针
滑动窗口,精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。
模拟行为,核心是模拟行为+控制边界。
6.2.Fabulaous Mind

xxx.问题
xxx.1.问题描述
111
xxx.2.要点
222
xxx.3.代码实例
333

浙公网安备 33010602011771号