以一道题目的优化过程来浅显的说一说首尾指针法
这是一道leetcode的题目
我之前的博客记录过
博客中我的做法就是比较常规的记录每个位置的左右最大值
1.第一种优化
只用一个数组记录每个位置右边最大值,不记录左边最大值,左边最大值用一个变量来记录即可,这样节省了空间,其他步骤相同
2.第二种优化,使用首尾指针
大体逻辑延续上面的做法,首尾两个位置是不可能有雨水装的。
首尾指针怎么做,逻辑如下:分别记录左右指针左右两边的当前最大值,然后每次解决左右最大值中的较小值并移动左或右指针。
为什么能这么做(正确性?)?
举例,比如当前左指针左边最大值比右指针右边最大值小,那么对于左指针,当前左边最大值已知并且是确定的因为指针从左到右移动,虽然中间仍有很多数没有遍历到,但不影响结果的正确性,因为右指针右边的最大值比左指针左边最大值大,所以中间的数的最大值必然大于等于右指针右边最大值,所以左指针当前位置是可以计算得出结果的(不管能不能装水),然后更新左指针左边最大值并移动左指针。右指针同理
代码:
public static int water4(int[] arr) {
if (arr == null || arr. length < 2) {
return 0;
}
int N = arr.length;
int L= 1;
int leftMax = arr[0];
int R=N-2;
int rightMax = arr[N -1];
int water =0;
while (L <= R) {
if (leftMax <= rightMax) {
water += Math. max(0, leftMax -arr[L]);
leftMax = Math.max(leftMax,arr[L++]);
} else {
water += Math. max(0, rightMax -arr[R]);
rightMax =Math. max(rightMax, arr[R--]);
}
return water
}
总结:
1.能用首尾指针技巧解决的问题,往往序列是存在规律的,但其实这种要求并不严格,不一定要有序!!
2.但是要求首尾指针根据制定的规则往中间移动的过程中确保移动过的数之后不再影响答案并不会错过答案
3.制定的规则与数据状况和问题本身有关(需要分析具体问题,一点点灵感)