算法刷题【面试经典150题】
文章目录
- 数组/字符串
- 1.合并两个有序数组
- 2.删除有序数组中的重复项(双指针)
数组/字符串
1.合并两个有序数组
法1:先将数组2合并到数组1,然后直接sort一下即可
class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {// 法1for(int i = 0; i < n; i++){nums1[i+m] = nums2[i];}sort(nums1.begin(), nums1.end());}
};
法2:类似归并排序(使用双指针依次遍历两个数组)
class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int i = 0, j = 0, k = 0;int arr[m+n];while(i < m && j < n){if(nums1[i] < nums2[j]) arr[k++] = nums1[i++];else arr[k++] = nums2[j++];}while(i < m){arr[k++] = nums1[i++];}while(j < n){arr[k++] = nums2[j++];}for(int i = 0;i < m + n; i++){nums1[i] = arr[i];} }
};
法3:从后往前处理,可以优化空间复杂度
空间复杂度可以优化到o(1)
不会覆盖的原因主要是因为,本身nums1的个数是两个数组之和,如果nums1的数先填进去,那么它本身的位置就会空出来一个
nums1=[1,2,6,∗,∗,∗],nums2=[3,4,5]。这里 num1中的 6 是最大的,应当填入末尾。现在nums1=[1,2,∗,∗,∗,6],注意nums1[2] 这个位置现在空出了。然后把 nums2中的数字填入空位,得到 [1,2,3,4,5,6],没有任何错误覆盖。
class Solution {
public:void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {int idx = m + n - 1;int p1 = m - 1, p2 = n - 1;while(p1 >= 0 && p2 >= 0){if(nums1[p1] > nums2[p2]) nums1[idx--] = nums1[p1--];else nums1[idx--] = nums2[p2--];}while(p1 >= 0) nums1[idx--] = nums1[p1--];while(p2 >= 0) nums1[idx--] = nums2[p2--];}
};
2.删除有序数组中的重复项(双指针)
相等的元素在数组中的下标一定是连续的
/* 双指针
由于数组是有序的,那么重复的元素一定是相邻的
如果数组长度为0,数组不包含任何元素,返回0
如果数组长度大于0,至少包含一个元素,删除后也至少会有一个元素,因此从1开始删除重复元素即可
*/
class Solution {
public:int removeDuplicates(vector<int>& nums) {if(nums.size() <= 1) return nums.size();// l代表下一个不同元素要填入的下标位置,r表示遍历数组到达的下标位置int l = 1, r = 1;while(r < nums.size()){if(nums[r] != nums[r-1]){nums[l] = nums[r];l++;}// 无论是否重复,都要继续往后寻找r++;}return l;}
};