当前位置: 首页 > news >正文

算法专题一:双指针

1.移动零

题目链接:283. 移动零 - 力扣(LeetCode)

我们可以定义一个dest,一个cur,dest表示数组中不为零的数的最后一位,cur用来遍历数组

class Solution {
    public void moveZeroes(int[] nums) {

        for(int cur=0,dest=-1;cur<nums.length;cur++){
            if(nums[cur]!=0){
                dest++;
                int tem=nums[dest];
                nums[dest]=nums[cur];
                nums[cur]=tem;
            }
        }
    }
}

 

2.复写零

题目链接:1089. 复写零 - 力扣(LeetCode)

按正序的方式,判断cur是否为0,如果不是cur++,dest++,如果为0,dest+=2,并且dest经过的两位都赋值为0,会导致后面的数被覆盖,所以我们需要换一种方法。

我们可以先找到最后一个复写的数

先判断cur位置的值,来决定dest走一步还是两步,然后根据dest的位置来判断是否为最后一位,不是dest最后一位,则cur++,如果dest为最后一位,那么cur现在的位置则是最后一个复写的数。

但是我们发现这样我们写的代码还是有问题

举一个例子

此时dest指向的位置已经发生了越界

所以我们需要再加上一个判断当cur(n-1)的位置为0,则cur--,dest-=2

最后我们只需要逆序进行复写就可以了

代码如下:

class Solution {
    public void duplicateZeros(int[] arr) {
        int cur=0;
        int dest=-1;
        int n=arr.length;
        while(cur<n){

            if(arr[cur]!=0){
                dest+=1;
            }else{
                dest+=2;
            }
            if(dest >= n - 1){
                break;
            }
            cur++;
        }
        if(dest==n){
            arr[n-1]=0;
            dest-=2;
            cur--;
        }
        while(cur>=0){
            if(arr[cur]!=0){
                arr[dest--]=arr[cur--];
            }else{
                arr[dest--]=0;
                arr[dest--]=0;
                cur--;
            }
        }
    }
}

 

3.快乐数 

题目链接:202. 快乐数 - 力扣(LeetCode)

 

所以我们的算法原理:可以定义一个快指针,一个慢指针,快指针每次走两步,慢指针每次走一步,直至两个指针相遇,如果相遇时的数为1,则是快乐数,如果不是1,就不是快乐数。 

代码如下:

class Solution {

    public int sum(int n){
        int sum=0;
        while(n!=0){
        int t=n%10;
        sum+=t*t;
        n/=10;
        }
        return sum;
    }
    public boolean isHappy(int n) {
        int slow=n;
        int fast=sum(n);
        while(slow!=fast){
            slow=sum(slow);
            fast=sum(sum(fast));
        }
        return slow==1;
    }
}

4.盛最多水的容器 

题目链接:11. 盛最多水的容器 - 力扣(LeetCode)

大家看到这个题目一定会想到这道题的暴力解法,套两层for循环,进行暴力枚举,但是这种解法会超时。O(n2)

我们就要需要找到其中的规律

比如这种情况:

我们从中取出一小部分进行讲解

体积无非就是长  *  宽
我们通过左右的比较,发现6比3大,我们可以将3的位置往前移动一位。

这样移动的思想就是,我们如果将6往前移动一位,无非就是三种情况

  1. 宽度减小,高度不变
  2. 宽度减小,高度也减小
  3. 宽度减小,高度不变

无论我们怎么样移动体积都会减小,所以我们每次将两边较小的进行移动。

代码如下:

class Solution {
    public int maxArea(int[] height) {
        int left=0;
        int right=height.length-1;
        int result=0;
        while(left < right){
            int v=Math.min(height[left],height[right]) * (right-left);
            result=Math.max(v,result);
            if(height[left]<height[right]){
                left++;
            }else{
                right--;
            }
            
        }
        return result;
        
    }
}

5.有效三角形的个数 

题目链接:611. 有效三角形的个数 - 力扣(LeetCode)

规律

class Solution {
    public int triangleNumber(int[] nums) {
        Arrays.sort(nums);
        int n=nums.length;
        int total=0;
        for(int i=n-1;i>=2;i--){
            int left=0;
            int right=i-1;
            while(left<right){
            if(nums[left] + nums[right]<=nums[i]){
                left++;
            }else{
                total+=right-left;
                right--;
            }
            }
        }
        return total; 
    }
}

 

6.和为s的两个数字 

题目链接:LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)

class Solution {
    public int[] twoSum(int[] price, int target) {
        int n=price.length;
         int left=0;
        int right=n-1;
        while(left<right){
           
            if(price[left]+price[right]<target){
                left++;
            }else if(price[left]+price[right]>target){
                right--;
            }else{
                return new int[]{price[left],price[right]};
            }
        }
        return new int[]{0};
    }
}

7.三数之和

题目链接:15. 三数之和 - 力扣(LeetCode) 

小优化:

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

8.四数之和

题目链接: 18. 四数之和 - 力扣(LeetCode)

这个题目跟上一个题目基本一致,唯一的差别就是需要外面在套一层循环,整体思路和思想都是一样的。

注意:要把aim定义为long类型,否则会出现整数溢出的问题

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ret=new ArrayList<>();
        Arrays.sort(nums);
        int n=nums.length;
        for(int i=0;i<n;){
            for(int j=i+1;j<n;){
                int left=j+1;
                int right=n-1;
                long aim=(long)target-nums[i]-nums[j];
                while(left<right){
                    int sum=nums[left]+nums[right];
                    if(sum>aim){
                        right--;
                    }else if(sum<aim){
                        left++;
                    }else{
                        ret.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        left++;
                        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;
    }
}

希望能对大家有所帮助!!! 

相关文章:

  • 基于eNSP的IPV4和IPV6企业网络规划
  • Mac电脑python 有没有ros接口 查看lidar的数据
  • Vue配置和安装教程(2025最新)
  • 小米路由器SSH下安装DDNS-GO
  • Qt 控件概述 QPushButton 与 QRadioButton
  • JDBC技术基础
  • DeepSeek 助力 Vue3 开发:打造丝滑的表格(Table)之添加列宽调整功能,示例Table14_09自定义单元格的固定表头表格
  • 数据结构------线性表(顺序表)
  • CAD球体密堆积3D插件V2.0
  • 【C++】STL全面简介与string类的使用(万字解析)
  • 大盗阿福-选和不选思路:状态数组st写法-->新写法DFS-->记忆化-->递推
  • 初一信息科技教程专用抓包软件1.4.2版本
  • 【经验分享】SpringBoot集成WebSocket开发02 之 实现一个基本示例并Spring Bean注入的方式来组织代码
  • 在浏览器中配置vue请求后端的接口地址
  • 剖析sentinel的限流和熔断
  • 虚幻基础:移动组件
  • x012-MSP430F249智能步进电动百叶窗_proteus_光敏电阻_步进电机_仿真
  • 在芯片器件制造中,一氧化氮气体什么会提升栅氧膜层的质量。
  • Ubuntu 优化 Vim 指南
  • 【GPT入门】第17课 RAG向量检索分类、原理与优化
  • 做拼货商城网站/企业网络营销推广方案策划
  • 深圳教育科技网站建设/附近的计算机培训班