V2EX_JumpingFrog [source code]


public class V2EX_JumpingFrog {
static
/******************************************************************************/
class Solution {
    int solve (int[] staircase, int[] possible_steps) {
        int min_step = Integer.MAX_VALUE, N = staircase.length;
        for (int step : possible_steps)
            min_step = Math.min (min_step, step);
        if (min_step > N)
            return 0;
        int[] dp = new int[N];
        for (int i = -1 + min_step; i < N; i++) {
            int cur = Integer.MIN_VALUE;
            for (int step : possible_steps) {
                if (i - step >= -1)
                    cur = Math.max (cur, i - step >= 0 ? dp[i - step] : 0);
            }
            dp[i] = cur + staircase[i];
        }
        int res = Integer.MIN_VALUE;
        for (int i = N - 1; (N - 1) - i < min_step; i--)
            res = Math.max (res, dp[i]);
        return res;
    }
}
/******************************************************************************/

    public static void main(String[] args) {
        V2EX_JumpingFrog.Solution tester = new V2EX_JumpingFrog.Solution();
        int[][] inputs = {
            {11, 22, 44, 5, 12, 34, 55, 45, 23, 64}, {3,4,5}, {163},
            {11, 22, 44, 5, 12, 34, 55, 45, 23, 64}, {300}, {0},
        };
        for (int i = 0; i < inputs.length / 3; i++) {
            System.out.println (Printer.separator ());
            int[] staircase = inputs[3 * i], possible_steps = inputs[3 * i + 1];
            int ans = inputs[3 * i + 2][0], output = tester.solve (staircase, possible_steps);
            System.out.printf ("%s and %s\n%s, expected: %d\n", 
                Printer.array (staircase), Printer.array (possible_steps), Printer.wrap (output + "", output == ans ? 92 : 91), ans
            );
        }
    }
}

还能进一步优化: 第二个循环, 求min_step这个window里面的最小值, 这个可以用一个min_heap来维护; 一个固定size的窗口的min用一个minheap来维护, 之前是见过的;

大概实现了一下, 我用的方法跟当时看的awice的有点区别, 我这个是直接ad-hoc的做法, 用composition来完成; awice当时给的做法, 还有泛型, 是一个更加generic的做法;

这个是第一版的代码:

这个优化降低的是min_step级别的常数级别的factor; 如果min_step很大, 比如达到了O(N)级别, 那么这个优化还是很有效果的;

上面说的maxqueque做法代码:

class Solution {  
    int solve (int[] staircase, int[] possible_steps) {  
        int min_step = Integer.MAX_VALUE, N = staircase.length;  
        for (int step : possible_steps)  
            min_step = Math.min (min_step, step);  
        if (min_step > N)  
            return 0;  
        int[] dp = new int[N];  
        MaxQueue min_queue = new MaxQueue ();  
        for (int i = 0; i < min_step; i++)  
            min_queue.addLast (0);  
        for (int i = -1 + min_step; i < N; i++) {  
            int cur = Integer.MIN_VALUE;  
            for (int step : possible_steps) {  
                if (i - step >= -1)  
                    cur = Math.max (cur, i - step >= 0 ? dp[i - step] : 0);  
            }  
            cur += staircase[i];  
            cur = Math.max (cur, min_queue.windowMax ());  
            min_queue.removeFirst ();  
            min_queue.addLast (cur);  
            dp[i] = cur;  
        }  
        return dp[N - 1];  
    }  

    static class MaxQueue {  
        Deque<Integer> maxes;  
        Deque<Integer> window;  

        MaxQueue() {  
            maxes = new ArrayDeque<> ();  
            window = new ArrayDeque<> ();  
        }  

        void addLast (int x) {  
            window.addLast (x);  
            while (maxes.peekLast() != null && x > maxes.peekLast ())  
                maxes.removeLast ();  
            maxes.addLast (x);  
        }  

        int removeFirst () {  
            int x = window.removeFirst ();  
            if (x == maxes.peekFirst ())  
                maxes.removeFirst ();  
            return x;  
        }  

        int windowMax () {  
            return maxes.peekFirst ();  
        }  
    }  
}

但是!!!

这个做法实际上是错的; i循环里面的第二个min_step循环, 实际上根本不需要! 事实上, 不仅不需要, 而且不应该; 按照root level involvement的思路, 这题在每一个node的位置, 只要考虑ending at this的path就行了, 然后最后所有的算完了, 再走一个单独的min_step循环(从右到左)找到一个最大值就行了; 自己想想为什么不能每一个node都有这个min_step循环, 这个bug稍微有点subtle;


Problem Description

一个青蛙跳台阶
每个台阶上有个随机数, 比如:

staircase = [11, 22, 44, 5, 12, 34, 55, 45, 23, 64]
给定 n 个台阶和可能跳的步数,比如:

possible_steps = [3,4,5]
对跳到的台阶的数求和,比如:

step_sequence = [3,4] , sum = 44+55 = 99
step_sequence = [4,4,4] , sum = 5+45+(超出台阶算 0) = 50
问和最大的时候是多少? 比如:

best_step_sequence = [3,4,4] , best_sum = 44+55+64 = 163
Example:

Input:

staircase = [11, 22, 44, 5, 12, 34, 55, 45, 23, 64]
possible_steps = [3,4,5]
Output

163

results matching ""

    No results matching ""