今天我们来学习一下数组中的双指针思想及其应用
我们为什么要学呢,因为在对数组的增删操作中,时常需要移动大量的元素,开销很大,所以就要用到双指针思想。接下来看一道题
LeetCode27.一个数组num和一个值val,要求移除所有值为val的元素,空间复杂度为O(1),元素的位置可以改变。
思路一:快慢指针
定义slow和fast两个指针,初始都在num[0]的位置,num[fast] != val时,两个指针一起移动,待找到val后,slow不懂,fast接着后移,当num[fast] != val时,开始移除元素。具体代码实现如下。
public static int removeElement(int[] num,int val){
int slow = 0;
for (int fast =0;fast < num.length;fast++){
if (num[fast] != val){
num[slow] = num[fast];
slow++;
}
}
return slow;
}
思路二:对撞双指针
数组两边各一个指针,当left == val且right != val的时候,将两个值交换,最后left的左边就是val全部删除后的数组
public static int removeElement(int[] num,int val){
int right = num.length-1;
int left = 0;
for (left=0;left <= right;){
if (num[left] == val && num[right] != val){
int tmp = num[left];
num[left] = num[right];
num[right] = tmp;
}
if (num[left] != val) left++;
if (num[right] == val) right--;
}
return left;
}
接下来再看一道题
给一个数组,例如num={0,0,1,1,1,2,2,3,3,4},要求删除重复的元素,但是保留一个。
思路:还是快慢指针,以num[fast] != num[slow]为关键条件。具体代码实现如下
public static int removeElement(int[] num){
int slow = 1;
for (int fast =0;fast < num.length;fast++){
if (num[fast] != num[slow-1]){
num[slow] = num[fast];
slow++;
}
}
return slow;
}
——————————————————————————————————————————————————————————————————————————————————————
元素奇偶移动问题
给定一个数组,将其中偶元素移到前面,奇元素移到后面,两部分的内部顺序不要求。
思路:对撞型双指针
简单来说,左值为奇数且右值为偶数,则交换,否则两个指针继续前进
public static int[] isSorted(int[] num){
int left =0;
int right = num.length-1;
while (left < right){
if ((num[left])%2 == 1 && (num[right])%2 ==0){
int tmp = num[left];
num[left] = num[right];
num[right] = tmp;
}
if ((num[left])%2 == 0) left++;
if ((num[left])%2 == 1) right--;
}
return num;
}
——————————————————————————————————————————————————————————————————————————————————————
数组轮转问题
一个数组,向右轮转k个位置(k <0),例如num{1,2,3,4,5},k=1,则结果为num{5,1,2,3,4}
思路:先将整个数组反转一下,再按照k将其分成两个部分,再分别反转。代码如下
public void rotate(int[] num,int k){
k %= num.length;
reverse(num,0,num.length-1);
reverse(num,0,k-1);
reverse(num,k,num.length-1);
}
public void reverse(int[] num,int start,int end){
while (start < end){
int tmp = num[end];
num[end] = num[start];
num[start] = tmp;
start++;
end--;
}
}
——————————————————————————————————————————————————————————————————————————————————————
数组的区间问题
LeetCode228.给一个数组num{0,1,2,4,5,7},我们可以将其分为三个区间1->2,4->5,7.可见,区间可以有一个或多个元素。
那么我们可以怎么实现呢
思路:使用快慢指针,在fast到达最后一个元素,或者遇到不+1递增的情况时,及时分组。
具体代码如下
public static List<String> summaryRanges(int[] num){
List<String> res = new ArrayList<>();
int slow =0;
for (int fast =0;fast < num.length;fast++){
if (fast+1 ==num.length || num[fast] +1 != num[fast + 1]){
StringBuilder sb = new StringBuilder();
sb.append(num[slow]);
if (slow != fast){
sb.append("->").append(num[fast]);
}
res.add(sb.toString());
slow = fast+1;
}
}
return res;
}