https://oj.leetcode.com/problems/jump-game/

http://blog.csdn.net/linhuanmars/article/details/21354751

public class Solution {
    public boolean canJump(int[] A) {
        
        // Solution A:
        // return canJump_GreadyRange(A);
        
        // Solution C:
        // return canJump_Checking0s(A);
        
        // Solution D:
        // return canJump_BruteForce(A);
        
        // Solution B:
        // return canJump_DP(A);
        
        // Solution E:
        return canJump_BestDP(A);
    }
    
    /////////////////////////
    // Solution A: GreadyRange
    //
    private boolean canJump_GreadyRange(int[] A) {
        
        if (A == null || A.length == 0)
            return false; // Invalid input
            
        int len = A.length;
        int start = 0;
        int end = 0;
        int maxcango = 0;
        
        // Only check to A[len - 2] position.
        // When end to A[len - 1], return true;
        while (end < A.length - 1)
        {
            for (int i = start ; i <= end ; i ++)
            {
                int go = i + A[i];
                if (go >= len - 1)
                    return true;    // reached.
                    
                maxcango = Math.max(maxcango, go);
            }

            if (maxcango <= end)
                return false;   // Cannot go further

            start = end + 1;
            end = maxcango;
        }
        return true;
    }
    
    /////////////////////////
    // Solution E: BestDP
    //
    // See http://blog.csdn.net/linhuanmars/article/details/21354751
    private boolean canJump_BestDP(int[] A)
    {
        if(A==null || A.length==0)
            return false;
    
        int global = 0;
        int local = 0;
        for (int i = 0 ; i < A.length - 1 ; i ++)
        {
            local = A[i] + i;   // 从当前i出发最远
            global = Math.max(global, local);
            if (global <= i)
                return false;   // Cannot go further
        }
        return true;
    }
    
    /////////////////////////
    // Solution B: DP
    //
    // Jump to i.
    // There is 2 ways:
    // Jump from i -1
    // Or Jump before i - 1.
    private boolean canJump_DP(int[] A)
    {
        if (A == null || A.length == 0)
            return false; // Invalid input
            
        if (A.length == 1)
            return true;    // No need to jump.

        int lastJump = -1;
        for (int i = 0 ; i < A.length - 1 ; i ++)
        {
            int curJump;
            if (i == 0)
                curJump = A[0];
            else
                curJump = Math.max(lastJump, A[i - 1]) -1;
                
            if (curJump + A[i] <= 0) // Cannot jump again !!
                return false;

            lastJump = curJump;
        }
        return true;
    }
    
    /////////////////////////
    // Solution C: Checking0s
    //
    private boolean canJump_Checking0s(int[] A)
    {
        if (A == null || A.length == 0)
            return false; // Invalid input
            
        if (A.length == 1)
            return true;    // No need to jump.
    
        // Find 0 BEFORE ENDPOINT.
        // for each 0, find if exists any point can fly over it.
        for (int i = 0 ; i < A.length - 1 ; i ++)
        {
            if (A[i] == 0)
            {
                boolean canFly = false;
                for (int j = i - 1 ; !canFly && j >= 0 ; j --)
                {
                    if (canFlyOver(A, j, i))
                    {
                        canFly = true;
                    }
                }
                if (!canFly)
                    return false;
            }
        }
        return true;
    }
    
    private boolean canFlyOver(int[] A, int i, int p)
    {
        return A[i] > p - i;
    }
    
    /////////////////////////
    // Solution D: Brute force
    //
    private boolean canJump_BruteForce(int[] A)
    {
        return canJump_BruteForce_help(A, A.length - 1);
    }

    private boolean canJump_BruteForce_help(int[] A, int end)
    {
        if (end == 0)
            return true;
        
        boolean r = false;
        for (int i = 0 ; i < end - 1 ; i ++)
        {
            if (canReach(A, i, end))
            {
                r = canJump_BruteForce_help(A, i);
                if (r)
                    return true;
            }
        }
        return false;
    }
    
    // If can reach from i to j
    private boolean canReach(int[] A, int i, int j)
    {
        return A[i] >= j - i + 1;
    }
}