关于数组的技巧有:双指针(快慢指针(时差、位差))
例题1:合并两个有序数组
代码:逆向双指针,可以不用重开数组,如果是正向的,需要重开一个数组腾空间。
class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int p1 = m-1, p2 = n-1, p = m+n-1;while(p1 >= 0 && p2 >=0){if(nums1[p1] > nums2[p2]){nums1[p--] = nums1[p1--];}else{nums1[p--] = nums2[p2--];}}while(p1 >= 0){nums1[p--] = nums1[p1--];}while(p2 >= 0){nums1[p--] = nums2[p2--];}}
};
还有一个方法是把nums2数组搬进去,然后sort,但是太简单了,并且时空复杂度比这个高。
例题2:有序数组的平方
代码:
思路1:平方后sort
class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {int n = nums.size();for(int i = 0; i< n; i++){nums[i] = nums[i] * nums[i];}sort(nums.begin(), nums.end());return nums;}
};
注意:for (int num : nums)得到的是拷贝,所以不能够修改原数组
思路2:双指针,找到正负分界线
class Solution {
public:vector<int> sortedSquares(vector<int>& nums) {int pos = 0;int n = nums.size();vector<int> ans;if(n == 0){return ans;}while( pos < n && nums[pos] < 0){pos++;}int left = pos-1, right = pos;while(left >= 0 && right < n){if(-nums[left] < nums[right]){ans.push_back(nums[left] * nums[left]);left--;}else{ans.push_back(nums[right] * nums[right]);right++;}}while(left >= 0){ans.push_back(nums[left] * nums[left]);left--;}while(right < n){ans.push_back(nums[right] * nums[right]);right++;}return ans;}
};
注意点:边界情况是>还是>=, pos<n && nums[pos] <0的顺序(不然会引用非法指针)
例题3:反转字符串中的单词
分析:从末尾开始,两个指针,一快一慢,夹紧一个单词的边界,把它拎出来放到ans字符串里面。最后通过resize裁剪去末尾的空格即可。
因为两边界可能有空格或者没有,但是到最后如果没有边界,需要出while循环单独判断,所有把S两边加上’ ‘把问题简化,这种化归的思想很有用处。
代码:
class Solution {
public:string reverseWords(string s) {//算法1:快慢指针string ans; s = ' ' + s + ' ';int fast = s.size() -1, slow = s.size()-1;int wordLength;while(fast >= 0){if(s[fast] == ' '){fast--;}else{slow = fast;//进入单词了,遍历完再出来while(s[fast] != ' '){fast--;}//刚好出单词 "string string 1string2 "wordLength = slow - fast;ans += s.substr(fast+1, wordLength) + ' ';slow = fast;}}ans.resize(ans.size() -1);return ans;}
};
总结:
i)对迭代器的增减不会改变数组的长度。
ii)截取字符串用 s.substr( begin, length); 选取区间是[begin, begin + length), 拼接字符串简单的+就可以。
iii)string中的erase:
按位置删除:s.erase(int ),直接从第int个位置删除,并且截断字符串(后面的不看了)
按位置和长度删除多个字符: s.erase(n, len), 从 n开始删除 len个,不截断,保留后面的。
例题4:二维网格迁移
代码:
思路1:开一个新数组,然后转移过去,需要用 cnt 来计算新数组对应原数组的位置,cnt/n为行, cnt%n 为列。
class Solution {
public:vector<vector<int>> shiftGrid(vector<vector<int>>& grid, int k) {int m = grid.size(), n = grid[0].size();int mul = m*n;k %= mul;vector<vector<int>> copy(m, vector<int>(n));int cnt = (mul - k)%mul;for(int i = 0; i < m; i++){for(int j = 0; j< n; j++){copy[i][j] = grid[cnt/n][cnt%n];cnt = (cnt+1)%mul;}}return copy;}
};
总结
一般代码出了匪夷所思的问题,都是边界问题没有处理好。