Java双指针专题——1.移动0 2.复写0 3.快乐数4.盛最多水的容器5.有效三角形的个数 6.和为s的两个数字7.三数之和8.四数之和

目录

1.移动0

2.复写0

3.快乐数

4.盛最多水的容器

5.有效三角形的个数 

6.和为s的两个数字

7.三数之和

8.四数之和


 

1.移动0

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

 

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:

输入: nums = [0]
输出: [0]

fa53648477594d3bbfa0212ca2449ba5.png

d2ca1c23b180437eaa51592d75578a64.jpg

 

class Solution {
    public void moveZeroes(int[] array) {
         int index0=-1;
        for (int i = 0; i < array.length; i++) {
            if(array[i]!=0){
                if(index0!=-1){//(还没初始化)如果第一个0还没出现,那就不管现在出现的非0的数字
                //如果出现了那就交换这个数字和第一个出现0的位置                                             
                    int temp=array[i];
                    array[i]=array[index0];
                    array[index0]=temp;
                    index0++;
                }
            }
            else{//遍历到0,初始化第一个0出现的下标
                if(index0==-1){
                    index0=i;
                }
            }
        }
    }
}
//目标就是让0全部放在末尾

2.复写0

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

 

示例 1:

输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]
示例 2:

输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]

根据双指针的异地操作将他优化成原地操作。

变成原地的过程会发现,覆盖问题,根据“删除数组中值为val的元素”。 

f4181d15e4a444f0bbe17084148a0904.png

class Solution {
    public void duplicateZeros(int[] arr) {
        int cur=0,dest=-1,n=arr.length;
        //1.找到最后一个需要腹泻的数字
        while(cur<n){
            if(arr[cur]==0) dest+=2;
            else dest+=1;
            if(dest>=n-1)  break;
            cur++;

        }
        //2.处理边界情况
        if(dest==n){
            arr[n-1]=0;
            cur--;
            dest-=2;
        }
        //3.从后向前完成复写
        while(cur>=0){
            if(arr[cur]!=0) {
                arr[dest--]=arr[cur--];
            }else{
                arr[dest--]=0;
                arr[dest--]=0;
                cur--;
            }
        }

    }
}

3.快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

 

示例 1:

输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

  d0982f3fcc174fd68dd7b3b89fda25fd.png

451633cacf1d425fb9888455b7289794.png

class Solution {
    public int bitSum(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,fast=bitSum(n);
        while(slow!=fast){
            slow=bitSum(slow);
            fast=bitSum(bitSum(fast));
        }
        return slow==1;
    }
}

4.盛最多水的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

 

示例 1:d66b1935e9c94d7ea124939d8b9c6f39.png

 

输入:[1,8,6,2,5,4,8,3,7]
输出:49 
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

e83269a600e847ec9cff27ccf7982054.png

class Solution {
    public int maxArea(int[] height) {
        int left=0,right=height.length-1,ret=0;
        while(left<right){
            int v=Math.min(height[left],height[right])*(right-left);
            ret=Math.max(ret,v);
            //左右两个值中相对小的移动;
            if(height[left]<height[right]) left++;
            else right--;
        }
        return ret;
    }
}

 

5.有效三角形的个数 

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

 

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

e71f0c6b38d54484af143fbc94964467.png

暴力解

class Solution {
    public int triangleNumber(int[] nums) {
        Arrays.sort(nums);
        if(nums.length<3){
            return 0;
        }
        int count=0;
        for(int i=0;i<nums.length;i++){
            for(int j=i+1;j<nums.length;j++){
                for(int k=j+1;k<nums.length;k++){
                    if(nums[j]+nums[i]>nums[k]){
                         count++;
                    }
                            
                 }
                
            }
        }
        return count;
    }
}

 9dd8e2a2119543589f85f37998f7f509.png

class Solution {
    public int triangleNumber(int[] nums) {
        //利用单调性的双指针
        //1.排序
        Arrays.sort(nums);
        //2.利用双指针;
        int ret=0,n=nums.length;
        for(int i=n-1;i>=2;i--){//固定最大的数
        //利用left,right指针统计符合要求的三元组的个数
             int left=0,right=i-1;
            while(left<right){
                if(nums[left]+nums[right]>nums[i]){
                    ret+=right-left;
                    right--;
                }else{
                    left++;
                }
            }

        }
        return ret;
    }
}

 

6.和为s的两个数字

d79e8b594cfc463798a8c14777db26ef.png

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int i = 0, j = nums.length - 1;
        while(i < j) {
            int s = nums[i] + nums[j];
            if(s < target) i++;
            else if(s > target) j--;
            else return new int[] { nums[i], nums[j] };
        }
        return new int[0];
    }
}

7.三数之和

d9b6801d940d4c3d9abd7d67aeac6b41.png

 17dbba3622f44ce3a6b6f81d441ed8e4.png

63d0637be41d40aeb9b63f55f3d7c866.png

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {

        List<List<Integer>> ret=new ArrayList<>();
        Arrays.sort(nums);
        int n=nums.length;
        for(int i=0;i<n;){
            if(nums[i]>0) break;//小优化
            int left=i+1,right=n-1,target=-nums[i];
            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&&nums[i]==nums[i-1]) i++;
        }
        return ret;
    }
}

8.四数之和

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。

 

示例 1:

输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

 

排序+双指针 

5550b6e489324bfc85abad38f35fc855.png 

 

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<nums.length;){
            for(int j=i+1;j<nums.length;){
               int left=j+1,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(new ArrayList<Integer>(Arrays.asList(nums[i],nums[j],nums[left++],nums[right--])));
                        ret.add(Arrays.asList(nums[i],nums[j],nums[left++],nums[right--]));
                        //这两种我看都是可以的
                        //去重1
                        while(left<right&&nums[left]==nums[left-1]) left++;
                        while(left<right&&nums[right]==nums[right+1]) right--;

                    }

                }//去重2
                j++;
                while(j<n&&nums[j]==nums[j-1]) j++;
            }
            //去重3
            i++;
            while(i<n&&nums[i]==nums[i-1]) i++;
        }
        return ret;
    }
}

 

 

 

 

 

 

  • 7
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

sqyaa.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值