双指针法的理解

mac2024-05-29  39

LeetCode上的题目:

盛最多水的容器

 

给定 n 个非负整数 a1,a2,...,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0)。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

说明:你不能倾斜容器,且 n 的值至少为 2。

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

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

示例:

输入: [1,8,6,2,5,4,8,3,7] 输出: 49

 

暴力法:

public class Solution { public int maxArea(int[] height) { int maxarea = 0; for (int i = 0; i < height.length; i++) for (int j = i + 1; j < height.length; j++) maxarea = Math.max(maxarea, Math.min(height[i], height[j]) * (j - i)); return maxarea; } }

 

对暴力法的优化:

 

class Solution { public int maxArea(int[] height) { int max = 0; //目前获得的最大的面积 int area; //需要计算面积时,用来存储新计算的面积,用来和max比较 int lower; //代表较小边界的值 int highest = 0; int nums = height.length; int left = 0; //左边界的值 int right; //表示右边界的值 while (left < nums - 1) { //只有在height[left] > highest的情况下才有可能出现更大面积 if (height[left] > highest) { right = left + 1; do { //只有在height[right] > highest的情况下,才有可能出现更大的面积 if (height[right] > highest ) { if (height[right] < height[left]) { lower = height[right]; } else { lower = height[left]; } area = lower * (right - left); if (area > max) { max = area; } } right ++; } while (right < nums); highest = height[left]; } left ++; } return max; } }

 

优化的基本思路:

可以确定没有出现更大面积的可能时,可以直接跳过不做处理。

 

双指针法:

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

双指针法的思路:

两线段之间形成的区域总是会受到其中较短那条长度的限制。此外,两线段距离越远,得到的面积就越大。

我们在由线段长度构成的数组中使用两个指针,一个放在开始,一个置于末尾。 此外,我们会使用变量 maxarea来持续存储到目前为止所获得的最大面积。 在每一步中,我们会找出指针所指向的两条线段形成的区域,更新 maxarea,并将指向较短线段的指针向较长线段那端移动一步。

查看下面的例子将有助于你更好地理解该算法:

1 8 6 2 5 4 8 3 7

 

 

(leetcode上面是一个视频)

 

看到现在还是不理解双指针法为什么就是正确的,为什么就不会错过最优解?没有关系,我当时看完题解也没看明白。

现在,你只要知道双指针法是从两边向中间移动,每次移动一个指针,移动值较小的指针,向值较大的指针的方向移动。

每次计算一下面积,保存当前获得的最大面积。

现在,先不去想为什么对,先去写一遍代码,或者在纸上写写画画,熟悉双指针法的流程。

 

如果,你已经深刻理解了暴力法、暴力法的优化以及双指针法的流程,你就会明白,双指针法其实也是对暴力法的优化:

可以确定没有出现更大的面积的可能时,则跳过不作处理。

 

其实对暴力法的优化算法和双指针算法,都是基于暴力法的,都隐含着O(n^2)的遍历,都是在确定不可能出现更大的面积时,就跳过,不做处理。

 

还是不太懂?那你得再好好熟悉下上述三个算法的流程。

 

提醒一下:

每次移动对应值较小的指针,跳过的是所有,较小指针,和,较小指针到较大指针之间的指针,组成的面积。

因为可以确定这些面积里不会有更大的面积(在较小的指针头顶上画一条水平线,和较大的指针相交,很容易看出来,较小指针和中间指针组成的面积一定不会比较小指针和较大指针组成的面积大)。

也就是说双指针法也是考虑了所有情况的,只不过显式处理的比较少,多数都被直接跳过了(可以确定没有最大面积的)

 

 

 

 

 

 

 

 

 

最新回复(0)