算法:双指针

12.双指针

双指针技巧与相关题目

设置两个指针的技巧,其实这种说法很宽泛,似乎 没什么可总结的 1)有时候所谓的双指针技巧,就单纯是代码过程用双指针的形式表达出来而已。没有单调性(贪心)方面的考虑 2)有时候的双指针技巧包含单调性(贪心)方面的考虑,牵扯到可能性的取舍。对分析能力的要求会变高。其实是先有的思考和优化,然后代码变成了 双指针的形式。 3)所以,双指针这个“皮”不重要,分析题目单调性(贪心)方面的特征,这个能力才重要。

常见的双指针类型: 1)同向双指针 2)快慢双指针 3)从两头往中间的双指针 4)其他

42. 接雨水

已解答

困难

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

img

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)
//双指针简易版
public static int trap(int[] height){
    int l = 0;
    int r = height.length-1;
    int rmax = height[r];
    int lmax = height[l];
    r--;
    l++;
    int sum = 0;
    while (r>=l){
        if (rmax>lmax){
            // l移动
            sum += Math.max(0,lmax-height[l]);
            lmax = Math.max(lmax,height[l++]);
        }else{
            // r 移动
            sum += Math.max(0,rmax-height[r]);
            rmax = Math.max(lmax,height[r--]);
        }
    }
    return  sum;
}

881. 救生艇

已解答

中等

给定数组 peoplepeople[i]表示第 i 个人的体重 ,船的数量不限,每艘船可以承载的最大重量为 limit

每艘船最多可同时载两人,但条件是这些人的重量之和最多为 limit

返回 承载所有人所需的最小船数

示例 1:

输入:people = [1,2], limit = 3
输出:1
解释:1 艘船载 (1, 2)
public static int numRescueBoats(int[] people, int limit) {
    Arrays.sort(people);
    int ans = 0;
    int l = 0;
    int r = people.length-1;
    while(l<=r){
        int next = limit;
        int time = 0;
        while(time<2&&r>=l&&next>=people[r]){
            next = next - people[r--];
            time++;
        }
        while(time<2&&r>=l&&next>=people[l]){
            next = next - people[l++];
            time++;
        }
​
        ans++;
    }
    return ans;
}

11. 盛最多水的容器

已解答

中等

提示

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

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

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

说明:你不能倾斜容器。

示例 1:

img

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

easy

public int maxArea(int[] height) {
    int l = 0;
    int r = height.length-1;
    int ans = 0;
    while(l<r){
        if(height[l]>height[r]){
            ans = Math.max((r-l)*height[r],ans);
            r--;
        }else{
            ans = Math.max((r-l)*height[l],ans);
            l++;
        }
    }
    return ans ;
}

475. 供暖器

中等

冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。

在加热器的加热半径范围内的每个房屋都可以获得供暖。

现在,给出位于一条水平线上的房屋 houses 和供暖器 heaters 的位置,请你找出并返回可以覆盖所有房屋的最小加热半径。

注意:所有供暖器 heaters 都遵循你的半径标准,加热的半径也一样。

使用同向双指针解决

示例 1:

输入: houses = [1,2,3], heaters = [2]
输出: 1
解释: 仅在位置 2 上有一个供暖器。如果我们将加热半径设为 1,那么所有房屋就都能得到供暖。
public static int findRadius(int[] houses, int[] heaters) {
    Arrays.sort(houses);
    Arrays.sort(heaters);
​
    int l  = 0;
    int r = 0;
​
    int ans = 0;
    while(l<houses.length){
        int radium = Math.abs(heaters[r]-houses[l]);
        int nradium = radium;
        if (r+1<heaters.length){
            nradium = Math.abs(heaters[r+1]-houses[l]);
            while(nradium<=radium){
                radium = nradium;
                if(r<heaters.length-1){
                    r++;
                }
                if(r+1<heaters.length){
                    nradium = Math.abs(heaters[r+1]-houses[l]);
                }else {
                    break;
                }
            }
        }
        l++;
        ans = Math.max(ans,radium);
    }
    return ans;
}

41. 缺失的第一个正数

已解答

困难

提示

给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。

请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。

示例 1:

输入:nums = [1,2,0]
输出:3
解释:范围 [1,2] 中的数字都在数组中。

​
//代码分为两个区域,r之后的区域 和 l之前的区域 ,每一步去判断数据是否是脏数据,
//如果是脏数据就放到r位置,r--
//如果是正常数据就放到l位置,l++
//什么是脏数据呢?题目要求找出nums中没有出现的最小正数,负数为脏数据,l之前有的数据也是脏数据,大于r长度的数据也是脏数据,对我们找答案都没有帮助,实在不懂就去看双指针那一节课
public static int firstMissingPositive(int[] nums) {
    int l = 0;
    int r = nums.length-1;
    while(l<=r){
        if(nums[l] == l+1){
            l++;
        }else{
            if((l+1)<nums[l]&&nums[l]<=(r+1)&&nums[nums[l]-1]!=nums[l]){
                swap(nums,l,nums[l]-1);
            }else{
                swap(nums,l,r);
                r--;
            }
        }
    }
    return l+1;
}
​
public static void swap(int [] arr,int l,int r){
    int temp = arr[l];
    arr[l]  =  arr[r];
    arr[r]  = temp ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值