LeetCode 55 - Jump Game


Related: LeetCode 45 - Jump Game II
Jump Game
Given an array of non-negative integers, you are initially positioned at the first index of the array.Each element in the array represents your maximum jump length at that position.
Determine if you are able to reach the last index.
For example:
A = [2,3,1,1,4], return true.
A = [3,2,1,0,4], return false.
https://xuezhashuati.blogspot.com/2017/05/55-jump-game.html
We maintains the max distance that we can jump (a greedy algorithm).
If at any position, we find we can jump to here, we set the max distance to be the max of previous max distance and the distance we can jump from the current position.

If we find we can jump to the end, return true.

After trying all positions, we know we have not reach the end, so we return false;
X. Greedy
The time complexity is O(n).

https://leetcode.com/articles/jump-game/
Once we have our code in the bottom-up state, we can make one final, important observation. From a given position, when we try to see if we can jump to a GOOD position, we only ever use one - the first one (see the break statement). In other words, the left-most one. If we keep track of this left-most GOODposition as a separate variable, we can avoid searching for it in the array. Not only that, but we can stop using the array altogether.
Iterating right-to-left, for each position we check if there is a potential jump that reaches a GOOD index (currPosition + nums[currPosition] >= leftmostGoodIndex). If we can reach a GOOD index, then our position is itself GOOD. Also, this new GOOD position will be the new leftmost GOOD index. Iteration continues until the beginning of the array. If first position is a GOOD index then we can reach the last index from the first position.
To illustrate this scenario, we will use the diagram below, for input array nums = [9, 4, 2, 1, 0, 2, 0]. We write G for GOODB for BAD and U for UNKNOWN. Let's assume we have iterated all the way to position 0 and we need to decide if index 0 is GOOD. Since index 1 was determined to be GOOD, it is enough to jump there and then be sure we can eventually reach index 6. It does not matter that nums[0] is big enough to jump all the way to the last index. All we need is one way.

Index0123456
nums9421020
memoUGBBBGG
  public boolean canJump(int[] nums) {
    int lastPos = nums.length - 1;
    for (int i = nums.length - 1; i >= 0; i--) {
      if (i + nums[i] >= lastPos) {
        lastPos = i;
      }
    }
    return lastPos == 0;

  }
https://www.cnblogs.com/struggleli/p/6934287.html
    public boolean canJump(int[] A) {
        // think it as merging n intervals
        if (A == null || A.length == 0) {
            return false;
        }
        int farthest = A[0];
        for (int i = 1; i < A.length; i++) {
            if (i <= farthest && A[i] + i >= farthest) {
                farthest = A[i] + i;
            }
        }
        return farthest >= A.length - 1;
    }

    public boolean canJump(int[] nums) {
        int maxReach = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i <= maxReach) {
                maxReach = Math.max(maxReach, i + nums[i]);
            }
            if (maxReach >= nums.length - 1) {
                return true;
            }
        }
        return false;
    }
X. http://bangbingsyb.blogspot.com/2014/11/leetcode-jump-game-i-ii.html
注意题目中A[i]表示的是在位置i,“最大”的跳跃距离,而并不是指在位置i只能跳A[i]的距离。所以当跳到位置i后,能达到的最大的距离至少是i+A[i]。用greedy来解,记录一个当前能达到的最远距离maxIndex:

1. 能跳到位置i的条件:i<=maxIndex。
2. 一旦跳到i,则maxIndex = max(maxIndex, i+A[i])。
3. 能跳到最后一个位置n-1的条件是:maxIndex >= n-1
    bool canJump(int A[], int n) {
        int maxIndex = 0;
        for(int i=0; i<n; i++) {
            if(i>maxIndex || maxIndex>=(n-1)) break;
            maxIndex = max(maxIndex, i+A[i]);
        } 
        return maxIndex>=(n-1) ? true : false;
    }
public boolean canJump(int[] A) { int max = 0; for(int i=0;i<A.length;i++){ if(i>max) {return false;} max = Math.max(A[i]+i,max); } return true; }
From begin to top, the time complexity will be O(n), space will be in O(1)
    bool canJump(int A[], int n) {
        if (0 == n)
            return false;
        
        int cur_max = A[0];
        int i = 0;
        
        while (i <= cur_max) {
            cur_max = max(cur_max, i + A[i]);
            
            if(cur_max >= n - 1)
                return true;
                
            ++i;
        }
        
        return false;
    }
Using Greedy Algorithm
bool canJump(int A[], int n) {
if (0 == n)
            return false;
        int cur_max = A[0];
        int i = 0;
        while (i <= cur_max) {
            cur_max = max(cur_max, i + A[i]);
            
            if(cur_max >= n - 1)
                return true;
                
            ++i;
        }
        return false;
    }
bool canJump(int A[], int n) {       
        if (1 == n)
            return true;
        int i = 0;
        while (i < n)
        {
            int currMax = A[i] + i;
            
            if (0 == A[i])
                return false;
            if (currMax >= n - 1)
                return true;
                
            int tmpMax = 0;
            for (int j = i + 1; j <= currMax; ++j)
            {
                if (A[j] + j > tmpMax)
                {
                    tmpMax = A[j] + j;
                    i = j;
                }
            }
        }
        
        return (i >= n - 1);
    }
X. Approach 2: Dynamic Programming Top-down

enum Index {
  GOOD, BAD, UNKNOWN
}

public class Solution {
  public boolean canJump(int[] nums) {
    Index[] memo = new Index[nums.length];
    for (int i = 0; i < memo.length; i++) {
      memo[i] = Index.UNKNOWN;
    }
    memo[memo.length - 1] = Index.GOOD;

    for (int i = nums.length - 2; i >= 0; i--) {
      int furthestJump = Math.min(i + nums[i], nums.length - 1);
      for (int j = i + 1; j <= furthestJump; j++) {
        if (memo[j] == Index.GOOD) {
          memo[i] = Index.GOOD;
          break;
        }
      }
    }

    return memo[0] == Index.GOOD;
  }
}
bool canJump(int A[], int n) {
        bool ATag[n];
        for (int i = n - 1; i >= 0; --i)
        {
            ATag[i] = false;
            int maxReach = A[i] + i;
         
            if (maxReach >= n - 1)
            {
                ATag[i] = true;
                continue;
            }
         
            for (int j = maxReach; j > i; --j)
            {
                if (ATag[j])
                {
                    ATag[i] = true;
                    break;
                }
            }
        }
        return ATag[0];
    }
http://fisherlei.blogspot.com/2012/12/leetcode-jump-game.html
Just one round DP. No need an array to track the status. Refactor the code.
1:       bool canJump(int A[], int n) {  
2:            int maxCover = 0;  
3:            for(int start =0; start<= maxCover && start<n; start++)  
4:            {  
5:                 if(A[start]+start > maxCover)  
6:                      maxCover = A[start]+start;  
7:                 if(maxCover >= n-1) return true;  
8:            }  
9:            return false;  
10:       }  
http://yucoding.blogspot.com/2013/01/leetcode-question-28-jump-game.html
The simple but time-consuming way is O(n^2). Set every future step true according to the A[i]. 
    bool canJump(int A[], int n) {
        if (n==0) {return false;}
        if (n==1) {return true;}
         
        vector<bool>B(n-1,false);
        B[0]=true;
        for (int i=0;i<n;i++){
            if (B[i]==true){
                for (int j=1;j<=A[i];j++){
                    B[i+j]=true;
                }
            }
        }
        return B[n-1];
    }
http://n00tc0d3r.blogspot.com/2013/03/jump-game.html
 public boolean canJump(int[] A) {  
   if (A.length <= 1) return true;  
   boolean[] canReach = new boolean[A.length];  
   for (int i=A.length-2, dist=1; i>=0; --i, ++dist) {  
     if (A[i] >= dist) {  
       canReach[i] = true;  
     } else {  
       int j=1;  
       while (j<=A[i] && !canReach[i+j]) ++j;  
       if (j<=A[i]) canReach[i] = true;  
     }  
   }  
   return canReach[0];  
 }  
The downside of this algorithm is that it requires O(n^2) time since in worst case we need to check each element within the range. Also, it requires O(n) space.

Do we really need to check each of them? Actually, all we want to know whether the next can-reach-end element is within my range. So, during the iteration, we can store the position of the next can-reach-end element and then for each successor element, we only need to check whether that node is reachable.
 public boolean canJump(int[] A) {  
   int next = A.length - 1;  
   for (int i=A.length-2; i>=0; --i) {   
     if (A[i] >= (next - i)) {   
       next = i;   
     }  
   }   
   return (next == 0);  
 }  
This algorithm runs in time O(n) and uses O(1) space.
X. DFS + Cache
  • Time complexity : O(n^2). For every element in the array, say i, we are looking at the next nums[i]elements to its right aiming to find a GOOD index. nums[i] can be at most n, where n is the length of array nums.
  • Space complexity : O(2n) = O(n). First n originates from recursion. Second n comes from the usage of the memo table. 
enum Index {
  GOOD, BAD, UNKNOWN
}

public class Solution {
  Index[] memo;

  public boolean canJumpFromPosition(int position, int[] nums) {
    if (memo[position] != Index.UNKNOWN) {
      return memo[position] == Index.GOOD ? true : false;
    }

    int furthestJump = Math.min(position + nums[position], nums.length - 1);
    for (int nextPosition = position + 1; nextPosition <= furthestJump; nextPosition++) {
      if (canJumpFromPosition(nextPosition, nums)) {
        memo[position] = Index.GOOD;
        return true;
      }
    }

    memo[position] = Index.BAD;
    return false;
  }

  public boolean canJump(int[] nums) {
    memo = new Index[nums.length];
    for (int i = 0; i < memo.length; i++) {
      memo[i] = Index.UNKNOWN;
    }
    memo[memo.length - 1] = Index.GOOD;
    return canJumpFromPosition(0, nums);
  }

}

X. Brute Force
Time complexity : O(2^n). There are 2^n (upper bound) ways of jumping from the first position to the last, where n is the length of array nums. For a complete proof, please refer to Appendix A.
One quick optimization we can do for the code above is to check the nextPosition from right to left. The theoretical worst case performance is the same, but in practice, for silly examples, the code might run faster. Intuitively, this means we always try to make the biggest jump such that we reach the end as soon as possible
The change required is:

For instance, in the example below, if we start from index 0, jump as far as possible and reach 1, jump as far as possible and reach 6. By doing so, we determine that 0 is a GOOD index in 3 steps.


  public boolean canJumpFromPosition(int position, int[] nums) {
    if (position == nums.length - 1) {
      return true;
    }

    int furthestJump = Math.min(position + nums[position], nums.length - 1);
    for (int nextPosition = position + 1; nextPosition <= furthestJump; nextPosition++) {
      if (canJumpFromPosition(nextPosition, nums)) {
        return true;
      }
    }

    return false;
  }

  public boolean canJump(int[] nums) {
    return canJumpFromPosition(0, nums);

  }
Read full article from Jump Game

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts