Two Pointers

需要先排序。

  • 适用于
    • 找重复/intersection
    • 把O(n^2)的优化成O(n)
  • 如果中间存在重复的值需要循环跳过
  • while中的while要保持left<right,保持這個判斷
  • 如果要的unique的解(不能重复用)需要while跳过

对型撞指针

Two Sum类型

通过两个指针,变成O(n),可以证明有些多态不用扫描

if (A[i] + A[j] > sum) {
    j--;
    do sth;
} else if (A[i] + A[j] < sum) {
    i++;
    do sth;
} else {
    i++; or j--;
    do sth;
}

灌水类

  • 先找左右两端的柱子,确定了基本线
  • 然后往内找
    • 如果高度降低,那么灌水面积肯定减少,可以排除
    • 如果高度增大,则要进行判断
    • 取左右两端较短的不变,将另一边柱子往内部移动,那么总的面积肯定会小于基本面积。所以只可能移动较短的那一侧柱子。
    • 只会遍历数组一次O(n), 一般都是O(n),需要排序的话,用O(nlogn)
      if (A[i] > A[j]) 
      j--;
      else if (A[i] < A[j]) 
      i++;
      else 
      i++; or j--;
      

Container with most water

Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two lines, which together with x-axis forms a container, such that the container contains the most water. 只与左右两边的高度有关,与中间无关

class Solution {
    public int maxArea(int[] height) {
        if (height == null || height.length < 2) return 0;
        int area = 0; 
        int left = 0;
        int right = len - 1;
        while (left < right) {
            area = Math.max(Math.min(height[left], height[right]) * (right-left), area);

            if (height[left] < height[right])
                left++;
            else 
                right--;
        }

        return area;
    }
}

Trapping the water

  • 简单的思路是从左边扫一遍,记录下对于每个点最左边的最高值,和最右边的最高值,可以知道扫过的地方灌水的最大的高度即为leftmax和rightmax中较短的最高高度。然后根据这两个数组进行判断
  • 思路是从左右两端分别出发,并保存左右两端的最高高度。每次loop中,比较此时左右点的高度,处理高度较小的那部分,因为只有这一部分才能确定不被另一端所影响。然后就是比较这个点的高度和这一端的最高高度,看是需要更新还是可以加入结果
  • 另一个思路是用PQ
public int trap(int[] height) {
        if (height == null || height.length <= 2) return 0;

        int len = height.length;
        int ans = 0;
        for (int i = 0; i < len; i++) {
            int leftMax = 0, rightMax = 0; 
            //find left most 
            for (int j = 0; j <= i; j++) {
                leftMax = Math.max(leftMax, height[j]);
            }

            for (int j = i+1; j < len; j++)
                rightMax = Math.max(rightMax, height[j]);

            int h = Math.min(leftMax, rightMax);
            if (h > height[i])
                ans += h - height[i];

        }
        return ans;
    }

// use two pointers to make it O(n)
public int trapRainWater(int[] heights) {
        // write your code here
        int left = 0, right = heights.length - 1; 
        int res = 0;
        if(left >= right)
            return res;
        int leftheight = heights[left];
        int rightheight = heights[right];
        while(left < right) {
            if(leftheight < rightheight) {
                left ++;
                if(leftheight > heights[left]) {
                    res += (leftheight - heights[left]);
                } else {
                    leftheight = heights[left];
                }
            } else {
                right --;
                if(rightheight > heights[right]) {
                    res += (rightheight - heights[right]);
                } else {
                    rightheight = heights[right];
                }
            }
        }
        return res;
    }

results matching ""

    No results matching ""