算法之双指针

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;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

orcharddd_real

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值