23-12-05 双指针 12-07dfs、差分数组、双指针

15. 三数之和——双指针+遍历

自己写的思路总体正确,但是去重时出现了一些问题

分为几步:

先判断数组是否为空或者个数是否小于3,如果是,直接返回;

排序数组;

排序后遍历:

        先判断开头是否>0,如果大于0,则一定无法满足三者相加为0,跳出循坏;

        再判断该开头是否与前一个数相同,若相同,则跳过此次遍历,去重;

        设左右指针,l=i+1,r=n-1,进行以下判断:

                *若nums[i]+nums[l]+nums[r]=0,将该组合添加到list,然后判断l的右边是否与l相等,若相等,则跳过,r的左边亦是,让l、r都跳到不相等的下一个数

                *若nums[i]+nums[l]+nums[r]<0,l++

                *若nums[i]+nums[l]+nums[r]>0,r--

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> list=new ArrayList<List<Integer>>();

        if(nums==null||nums.length<3){
            return list;
        }

        Arrays.sort(nums);
        for(int i=0;i<nums.length-1;i++){
            if(nums[i]>0){
                break;
            }
            //去重
            if(i!=0&&nums[i]==nums[i-1]){
                continue;
            }
            int l=i+1,r=nums.length-1;
            int ans=-nums[i];
            while(l<r){
                if(nums[l]+nums[r]==ans){
                    List<Integer> list_add=new ArrayList<>();
                    list_add.add(nums[i]);
                    list_add.add(nums[l]);
                    list_add.add(nums[r]);
                    list.add(list_add);
                    //去重
                    while(l<r&&nums[l]==nums[l+1]){
                        l++;
                    }
                    while(l<r&&nums[r]==nums[r-1]){
                        r--;
                    }
                    //保证不漏
                    l++;
                    r--;
                }else if(nums[l]+nums[r]<ans){
                    l++;
                }else{
                    r--;
                }
            }
        }
        return list;
    }
}

2477. 到达首都的最少油耗

class Solution {
    private long ans;
    public long minimumFuelCost(int[][] roads, int seats) {
        //思路为计算每一条路的贡献值,然后向上取整,再把贡献值相加
        int n=roads.length+1;
        List<Integer>[] g=new ArrayList[n];
        Arrays.setAll(g,e->new ArrayList<>());
        for(int[] e:roads){
            int x=e[0],y=e[1];
            g[x].add(y);
            g[y].add(x);
        }
        dfs(0,-1,g,seats);
        return ans;

    }

    private int dfs(int x,int fa,List<Integer>[] g,int seats){
        int size=1;
        for(int y:g[x]){
            if(y!=fa){
                size+=dfs(y,x,g,seats);
            }
        }
        if(x>0){
            ans+=(size-1)/seats+1;
        }
        return size;
    }
}

1094. 拼车——差分数组

count[k]=count[k-1]+diff[k]

diff数组维护如下:

        根据trips:

        *k<from,不管

        *k=from,diff[k]要加上当前上车乘客数

        *from<k<to,不管

        *k=to,diff[k]要减去下车乘客数

        *k>to,不管

class Solution {
    public boolean carPooling(int[][] trips, int capacity) {
        int toMax=0;
        for(int[] trip:trips){
            toMax=Math.max(toMax,trip[2]);
        }

        int[] diff=new int[toMax+1];
        for(int[] trip:trips){
            diff[trip[1]]+=trip[0];
            diff[trip[2]]-=trip[0];
        }
        int count=0;
        for(int i=0;i<=toMax;i++){
            count+=diff[i];
            if(count>capacity){
                return false;
            }
        }
        return true;
    }
}

42. 接雨水

自己的方法,使用了双指针,但是代码不优美,效率也不高,但话锋一转,虽然效率不高,但是自己做出困难题还是有成就感的

class Solution {
    public int trap(int[] height) {
        //若没有遇到大于等于它的数,选取小于等于它的数中最大的,构成容器,容器高度为较小值
        //遇到大于它的数,构成容器,容器高度为较小值
        //容器的体积为,较小值*长度-中间每一个的高度
        int l=0;
        while(height[l]==0&&l<height.length-1){
            l++;
        }
        if(l>=height.length){
            return 0;
        }
        //从有柱子的地方开始
        int r=l+1;
        int ans=0;
        while(r<height.length){
            int maxright=0;
            int maxnum=0;
            int h=0;
            for(int i=r;i<height.length;i++){
                if(height[i]>=height[l]){
                    r=i;
                    h=height[l];
                    break;
                }
                if(height[i]>=maxright){
                    maxright=height[i];
                    maxnum=i;
                }
                if(i==height.length-1){
                    r=maxnum;
                    h=maxright;
                }

            }
            ans+=volume(l,r,h,height);
            l=r;
            r++;
        }
        return ans;
    }

    private int volume(int l,int r,int h,int[] height){
        int v=h*(r-l-1);
        for(int i=l+1;i<r;i++){
            v-=height[i];
        }
        return v;
    }
}

题解:

暂且不看动态规划(很好理解)和单调栈,只关注双指针

明显更简洁,思维更合理

class Solution {
    public int trap(int[] height) {
        //假设两柱子分别为 i,j。那么就有 iLeftMax,iRightMax,jLeftMx,jRightMax 这个变量。由于 j>i ,故 jLeftMax>=iLeftMax,iRigthMax>=jRightMax.
        //那么,如果 iLeftMax>jRightMax,则必有 jLeftMax >= jRightMax,所有我们能接 j 点的水。
        //如果 jRightMax>iLeftMax,则必有 iRightMax >= iLeftMax,所以我们能接 i 点的水。
        int ans = 0;
        int left = 0, right = height.length - 1;
        int leftMax = 0, rightMax = 0;
        while (left < right) {
            leftMax = Math.max(leftMax, height[left]);
            rightMax = Math.max(rightMax, height[right]);
            //height[left] < height[right],left接水
            //height[left]==height[right],right接水
            if (height[left] < height[right]) {
                ans += leftMax - height[left];
                ++left;
            } else {
                ans += rightMax - height[right];
                --right;
            }
        }
        return ans;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值