1)双指针更多是作为标记,方便处理,如力扣最左前缀题目209题,引入双指针,执行效率更高,用for循环需要引入更多变量进行标记反而麻烦;
public static int changduzuixiaoshuzu(int target, int[] nums){
int start=0,end=0,sum=0,ans=Integer.MAX_VALUE;
while(end < nums.length){
sum+=nums[end];
while (sum >= target){
ans=Math.min(ans,end-start+1);
sum-=nums[start];
start++;
}
end++;
}
return ans==Integer.MAX_VALUE?0:ans;
}
之前自己写的是这样的,但运行超时,基本类似双指针思想,但在左端标记时,并没有找到合适的标记,每次都是从最左端开始;
public int minSubArrayLen(int target, int[] nums) {
int preSum=0,min=Integer.MAX_VALUE,temp=0;
for (int i = 0; i < nums.length; i++) {
preSum+=nums[i];
temp=preSum;
for (int j = 0; j <= i; j++) {
if(temp >= target){
min=Math.min(min,i-j+1);
temp =temp-nums[j];
}
}
}
return min==Integer.MAX_VALUE?0:min;
}
2)双指针有时候也和二分算法有点像,如力扣第11题盛水最多的容器,由于盛水的具有木桶效应,所以当哪边出现短木板时,就向中点移动哪边的坐标;代码如下
public static int shengshuizuiduo(int[] height){
int ans=0,l=0,r=height.length-1;
while (l<r){
int area = Math.min(height[l],height[r])*(r-l);
ans = Math.max(ans,area);
if(height[l] < height[r]){
l++;
}else {
r--;
}
}
return ans;
}
3)双指针通常用于解决数组中两数求和为目标值或三数求和为目标值问题,如力扣15,16题就是如此;这两题的解题框架大致一样,最外层的for循环遍历第一个数,for循环中的while循环遍历另外两个数,分别是第一个数的下一个以及从尾部倒数的数,即双指针,不同的是16题需要取绝对值;
力扣15题如下
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
int len = nums.length;
ArrayList list = new ArrayList<List<Integer>>();
for (int i = 0; i < len; i++) {
if(i>0 && nums[i]==nums[i-1])continue;
int target=-nums[i],l=i+1,r=len-1;
while (l < r){
int sum= nums[r] + nums[l];
if(target == sum){
list.add(Arrays.asList(nums[i],nums[r],nums[l]));
while (l<r && nums[l]==nums[++l]);
while (r>l && nums[r]==nums[--r]);
}else if(target < sum){
r--;
}else {
l++;
}
}
}
return list;
}
力扣16题如下
public static int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int len = nums.length;
int minSum=Integer.MAX_VALUE;
int ans=0;
for (int i = 0; i < len; i++) {
if(i>0 && nums[i]==nums[i-1])continue;;
int left=i+1,right = len-1;
while (left<right){
int sum=nums[i]+nums[left]+nums[right];
if(sum-target==0) {
return sum;
}
if(Math.abs(sum-target) < minSum){
minSum=Math.abs(sum-target);
ans=sum;
}
if(sum<target){
while (left<right && nums[left]==nums[++left]);
}else{
while (left<right && nums[right]==nums[--right]);
}
}
}
return ans;
}
4)双指针既可以用在首尾,也可以用在“快慢”,如力扣26,27题,这两题几乎一致,由于需要原地修改数组,所以可以基于双指针,一个指针往后遍历用于判断,一个指针用于存储满足判断条件的值;
力扣26题 删除有序数组中的重复项,数组升序就会使相等元素的索引是连续的,基于这一点可以直接基于nums[fast] != nums[fast-1]进行判断;如果数组无序则此判断方法就不对;
public static int removeDuplicates(int[] nums) {
int fast=1,slow=1;
while (fast<nums.length){
if(nums[fast] != nums[fast-1]){
nums[slow++]=nums[fast];
}
fast++;
}
return slow;
}
力扣27 移除数组中与目标值相等的元素
public static int removeElement(int[] nums, int val) {
int fast=0,slow=0;
while (fast < nums.length){
if(nums[fast] != val){
nums[slow++]=nums[fast];
}
fast++;
}
return slow;
}