算法--双指针二

算法原理

双指针

常见的双指针有两种形式,一种是对撞指针,一种是左右指针

对撞指针:一般用于顺序结构中,也称左右指针,对撞指针一般从两端向中间移动,终止条件一般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环)

快慢指针:又叫龟兔赛跑算法,基本思想就是使用两个移动速度不同的指针在数组或链表等结构上移动(我们在数据结构学习链表解决链表有环问题的时候用到了这种算法)

题目解析

5.有效三角形的个数

https://leetcode.cn/problems/valid-triangle-number/

题目解析

给定一个包含非负整数的数组nums,返回其中可以组成三角形三条边的三元组个数

三角形两边之和大于第三边,两步之差小于第三边

如果a<=b<=c--->只要a+b>c就可以构成三角形

算法原理

解法一:暴力枚举

先固定一个数,然后再找两个数,三层for循环

时间复杂度较高

解法二:利用单调性,使用双指针算法

根据题目解析中"如果a<=b<=c--->只要a+b>c就可以构成三角形",并且题目中对返回的数字顺序并未要求,那么我们可以先对数组排序

数组此时已经按照从小到大的顺序排列,我们可以从后固定一个c,然后一个left,一个right指针进行移动

如果a+b>c 那么这个c对应着right-left种组合,中间的一定可以构成三角形 然后right--

如果a+b<=c,那么left左移

代码实现

复制代码
  public int triangleNumber(int[] nums) {
        Arrays.sort(nums);
        int n=nums.length;
        int ret=0;
        for(int c=n-1;c>=0;c--){
            int left=0,right=c-1;
            while(left<right){
                if(nums[left]+nums[right]>nums[c]){
                    ret+=right-left;
                    right--;
                }else{
                    left++;
                }
            }
        }
        return ret;
    }

6.和为s的两个数

https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/description/

题目解析

输入一个递增的数组和一个数字s,在数组中查找两个数,使得他们的和正好为s,如果有多对,则随意输出一对即可

算法原理

解法一:暴力枚举 时间复杂度过高

for(int i=0;i<nums.length;i++)

for(int j=i+1;i<nums.length;j++)

check(nums[i]+nums[j],s]

解法二:利用单调性,使用双指针

代码实现

复制代码
public int[] twoSum(int[] price, int t) {
        int left=0,right=price.length-1,sum=0;
        while(left<right){
            sum=price[left]+price[right];
            if(sum==t){
                return new int[] {price[left],price[right]};
            }else if(sum>t){
                right--;
            }else{
                left++;
            }
        }
        return new int[]{};
}

7.三数之和

https://leetcode.cn/problems/3sum/description/

题目解析

给一个整数数组nums,判断是否存在【nums【i】,nums【j】,nums【k】】,满足i!=k,j!=k,i!=j,同时三数相加为0,返回所有和为0且不重复的三元组(注意:输出的顺序和三元组的顺序并不重要)

算法原理

解法一:排序(因为题目说输出的顺序和三元组的顺序并不重要)+暴力枚举+set去重

解法二:排序+双指针

1.排序 2.固定一个数a(并且这个数要小于0,否则在已经有序的情况下不可能找到符合要求的两个数)

3.在该数后的区间。利用双指针算法,找到和为-a

ps:1.去重 找到一种结果之后,left和right必须要跳过重复的元素 使用完一次双指针算法后,i也要跳过重复的元素

2.不漏:找到一种结果后,不要停,缩小区间,继续寻找

代码实现

复制代码
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
      List<List<Integer>> ret=new ArrayList<>();
      Arrays.sort(nums);
      for(int i=0;i<nums.length-2;i++){
        if(nums[i]>0) break;
        int t=-nums[i];
        if(i>0&&nums[i]==nums[i-1]) continue;
        int left=i+1,right=nums.length-1;
        while(left<right){
            int sum=nums[left]+nums[right];
            if(sum==t){
                ret.add(new ArrayList<Integer>(Arrays.asList(nums[i],nums[left],nums[right])));
                while(left<right&&nums[left]==nums[++left]);
                while(left<right&&nums[right]==nums[--right]);
            }else if(sum>t){
                 while(left<right&&nums[right]==nums[--right]);
            }else{
              while(left<right&&nums[left]==nums[++left]);
            }
        }
       
      }
       return ret;
    }
}

8.四数之和

https://leetcode.cn/problems/4sum/description/

题目解析

给n个整数组成的数组nums和一个目标值t,返回满足全部条件并且不重复的四元组 0<=a,b,c,d<n

a b c d 互不相同

nums[a]+nums[b]+nums[c]+nums[d]==t

算法原理

解法一:排序+暴力枚举+set去重

解法二:排序+双指针

1.依次固定一个数a

2.在a后的区间内,利用"三数之和",使三数之和=t-a

细节:1.不重 跳过重复元素

2.不漏 找到一种结果后,不要停,缩小区间,继续寻找

代码实现

复制代码
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        Arrays.sort(nums);
        int n=nums.length;
        List<List<Integer>> ret=new ArrayList<>();
        for(int i=0;i<n;){
            for(int j=i+1;j<n;){
                int left=j+1,right=n-1;
                long t=(long)target-nums[i]-nums[j];
                while(left<right){
                    int sum=nums[left]+nums[right];
                    if(sum>t){
                        right--;
                    }else if(sum<t){
                        left++;
                        
                    }else{
                        ret.add(Arrays.asList(nums[i],nums[j],nums[left++],nums[right--]));
                    while(left<right&&nums[left]==nums[left-1]){
                        left++;
                    }
                    while(left<right&&nums[right]==nums[right+1]){
                        right--;
                    }
                    }
                }
                j++;
                while(j<n&&nums[j]==nums[j-1]){
                    j++;
                }
            }
            i++;
            while(i<n&&nums[i]==nums[i-1]){
                i++;
            }
        }
        return ret;
    }
}
相关推荐
做科研的周师兄3 小时前
【机器学习入门】8.2 主成分分析:一文吃透主成分分析(PCA)—— 从原理到核心逻辑
人工智能·算法·决策树·机器学习·流程图
LeeZhao@3 小时前
【具身智能】具身机器人VLA算法入门及实战(四):具身智能VLA技术行业进展
人工智能·算法·机器人
lingchen19063 小时前
矩阵的除法
人工智能·算法·矩阵
liu****3 小时前
笔试强训(六)
数据结构·c++·算法
前端小刘哥4 小时前
超越“接收端”:解析视频推拉流EasyDSS在RTMP推流生态中的核心价值与中流砥柱作用
算法
前端小刘哥4 小时前
新版视频直播点播平台EasyDSS用视频破局,获客转化双提升
算法
海琴烟Sunshine4 小时前
leetcode 168. Excel 表列名称 python
python·算法·leetcode
京东零售技术5 小时前
探索无限可能:生成式推荐的演进、前沿与挑战
算法
lingchen19065 小时前
多项式的积分
算法