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 }