开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情 这也是第36篇文章
删除有序数组中的重复项
题目
给你一个 升序排列 的数组
nums,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有
k个元素,那么nums的前k个元素应该保存最终结果。将最终结果插入
nums的前k个位置后返回k。不要使用额外的空间,你必须在 原地修改输入数组 并在使用 O(1) 额外空间的条件下完成。
思路
快慢指针。当没有遇到重复元素时,两个指针是同步的,但是遇到重复元素时,慢指针不前移,导致下次快指针指向的值赋给当前慢指针指向的位置,从而将重复的元素覆盖。 最后慢指针指向的位置就是有效数组长度了(因为慢指针从1开始遍历)
代码实现
class Solution {
public int removeDuplicates(int[] nums) {
int n=nums.length;
int j=1;
for(int i=1;i<n;i++){
if(nums[i]!=nums[i-1]){
nums[j]=nums[i];
j++;
}
}
return j;
}
}
类题——移除元素
题目
给你一个数组
nums**和一个值val,你需要 原地 移除所有数值等于val**的元素,并返回移除后数组的新长度。不要使用额外的数组空间,你必须仅使用
O(1)额外空间并 原地修改输入数组。元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
思路
和前面那题一样,快慢指针,只是if条件里面的变量换成了val;快慢指针初始指向的位置也不同(这次是从下标0开始)。
代码实现
class Solution {
public int removeElement(int[] nums, int val) {
int n=nums.length;
int j=0;
for(int i=0;i<n;i++){
if(nums[i]!=val){
nums[j]=nums[i];
j++;
}
}
return j;
}
}
合并两个有序数组
题目
给你两个按 非递减顺序 排列的整数数组
nums1**和nums2,另有两个整数m和n,分别表示nums1和nums2中的元素数目。请你 合并
nums2**到nums1中,使合并后的数组同样按 非递减顺序 排列。注意: 最终,合并后数组不应由函数返回,而是存储在数组
nums1中。为了应对这种情况,nums1的初始长度为m + n,其中前m个元素表示应合并的元素,后n个元素为0,应忽略。nums2的长度为n。
思路
写题解时我还特意去翻了一下自己曾经的提交记录,发现那时候竟然是直接将2的元素先填到1,然后再排序,并没有用双指针。于是用双指针又写了一遍,下面代码会附上两个版本的实现。 双指针的解法思想和前面两道题大同小异。
代码实现
暴力法,直接塞进去再排序
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
for(int i=m,j=0;j<n;i++,j++){
nums1[i]=nums2[j];
}
Arrays.sort(nums1);
}
}
双指针法。ij分别指向两个数组,从后往前修改,把相对更大的放入1中。
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int i=m-1,j=n-1;
int r=m+n-1;
int cur;
while(i>=0||j>=0){
if(i==-1) cur=nums2[j--];
else if(j==-1) cur=nums1[i--];
else if(nums1[i]>nums2[j]){
cur=nums1[i--];
}else cur=nums2[j--];
nums1[r--]=cur;
}
}
}
写在最后的碎碎念
今天依然是一天都在回顾6.s081的实验,但是关于实验依然没什么新鲜的东西写,于是继续更新刷题笔记了。上一篇((一))有点跳跃,估计我自己之后看起来也都一脸懵,所以这次特意挑了一个鲜明的主题——双指针!