LeetCode-Self Crossing

LiBlog發表於2016-07-13

You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north, then x[1] metres to the west, x[2] metres to the south, x[3] metres to the east and so on. In other words, after each move your direction changes counter-clockwise.

Write a one-pass algorithm with O(1) extra space to determine, if your path crosses itself, or not.

Example 1:

Given x = [2, 1, 1, 2],
┌───┐
│   │
└───┼──>
    │

Return true (self crossing)

Example 2:

Given x = [1, 2, 3, 4],
┌──────┐
│      │
│
│
└────────────>

Return false (not self crossing)

Example 3:

Given x = [1, 1, 1, 1],
┌───┐
│   │
└───┼>

Return true (self crossing)

Analysis:
  There are two possible modes: 1. Area is expanding, and 2. Area is shrinking. We need to identify the current mode.

  For shrinking mode, let current index be i, then if x[i] < x[i-2], x[i] is safe.
  For expanding mode, it is more complicated. For index i, there are 3 possible situations:
    1. x[i] > x[i-2]: still expanding mode, safe
    2. x[i] < x[i-2] - x[i-4]: switch to shrink mode, but safe
    3. x[i] >= x[i-2] - x[i-4]: switch to shrink mode, but possibly not safe, we need further determine, see the code.

Solution:
 1 public class Solution {
 2     public boolean isSelfCrossingExpand(int[] x, int start){
 3         for (int i=start;i<x.length;i++){
 4             if (x[i] > x[i-2]){
 5                 continue;
 6             } else {
 7                 // becomes shrink mode
 8                 int bar = (i>=4) ? x[i-4] : 0;
 9                 if (x[i] <= x[i-2] && x[i] >= (x[i-2] - bar)){
10                     if ( i+1 == x.length){
11                         return false;
12                     }
13                     if (x[i+1] >= (x[i-1] - x[i-3])){
14                         return true;
15                     }
16                     return isSelfCrossingShrink(x,i+2);
17                 } else {
18                     return isSelfCrossingShrink(x,i+1);
19                 }
20             }        
21         }
22         return false;
23     }
24 
25     public boolean isSelfCrossingShrink(int[] x, int start){
26         for (int i=start; i<x.length;i++){
27             if (x[i] >= x[i-2])
28                 return true;
29         }
30         return false;
31     }
32     public boolean isSelfCrossing(int[] x) {
33         if (x.length<=3) return false;
34 
35         if (x[2] <= x[0]) return isSelfCrossingShrink(x,3);        
36         return isSelfCrossingExpand(x,3);
37         
38     }
39 }