12.双指针
双指针技巧与相关题目
设置两个指针的技巧,其实这种说法很宽泛,似乎 没什么可总结的 1)有时候所谓的双指针技巧,就单纯是代码过程用双指针的形式表达出来而已。没有单调性(贪心)方面的考虑 2)有时候的双指针技巧包含单调性(贪心)方面的考虑,牵扯到可能性的取舍。对分析能力的要求会变高。其实是先有的思考和优化,然后代码变成了 双指针的形式。 3)所以,双指针这个“皮”不重要,分析题目单调性(贪心)方面的特征,这个能力才重要。
常见的双指针类型: 1)同向双指针 2)快慢双指针 3)从两头往中间的双指针 4)其他
已解答
困难
给定 n
个非负整数表示每个宽度为 1
的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
输入: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; }
已解答
中等
给定数组 people
。people[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; }
已解答
中等
提示
给定一个长度为 n
的整数数组 height
。有 n
条垂线,第 i
条线的两个端点是 (i, 0)
和 (i, height[i])
。
找出其中的两条线,使得它们与 x
轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
输入:[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 ; }
中等
冬季已经来临。 你的任务是设计一个有固定加热半径的供暖器向所有房屋供暖。
在加热器的加热半径范围内的每个房屋都可以获得供暖。
现在,给出位于一条水平线上的房屋 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; }
已解答
困难
提示
给你一个未排序的整数数组 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 ; }