656 Coin Path

https://leetcode.com/problems/coin-path/description/
首先这道题看上去可以用Dijkstra做。 最小路径嘛,又带了权重,那Dijstra最合适,不过他要求的是path不是 path的长度,所以还得记一个从哪里来的。我最初是思路是从前往后找,然后找完之后从尾向前重建路径。 但是我写完之后发现解决不了lexicographical order的问题。有一个test case“ [0,0,0,0,0,0], 3 ” 解决不了。 果断看答案,发现是用dp而且是从后向前倒推再从前向后重建路径,跟我的作法正好反过来。
这一点比较坑(如何解决lexicographical order),我第二遍做时还是花了不少时间。
下面解释一下我看来的答案。
1。 最外层的顺序从最后一个点开始倒推。每个点的DP状态记录这个点到终点的最少花费。如果从这个点到不了终点,就是-1;
2。对于每个点求他dp值的时候又是从左向右推。这样可以保证lexicographical order。如果后面出现的值和当前一样,那还是留之前的,因为之前的lexicographical order比较小。
这两个trick都是平淡无奇但结合在一起就能完美解决这道题。
后来发现这个挺绕的思路可以直接从recursion + mem推导出来。
如果从recursion的思路就比较直接了。 所以一定要一题会多解,这样这条路遇到问题我们可以从袖子里掏出另外一个trick来。
用Dijkstra方法就不是很方便做。当然我在leetcode论坛上也看到有人用Dijkstra做,不过那个代码实在是太难看了。
下面是DP代码,新手可以略过直接看recursion的。

public List<Integer> cheapestJump(int[] A, int B) {
        int N = A.length; //省得老写A.length好麻烦 
        List<Integer> ans = new LinkedList<>();
        int[] dp = new int[N]; 
        //dp state: the min cost from the end;
        Arrays.fill(dp, -1);
        dp[N - 1] = A[N - 1]; // 初始化
        Map<Integer, Integer> leftRightMap = new HashMap<>();
        // 这个map从左边的点指向他右边的点,
        //由于这里是倒着找的, parentChild有点confusing, 
        //所以用leftRight而不是parentChild, 
        for (int i = N - 2; i >= 0; i--){ //从右向左 
            if (A[i] == -1) continue;
            for (int b = 1; b <= B && b + i < N; b++) { //从左向右
                if (A[b + i] == -1 ||dp[i + b] == -1) continue;
                if (dp[i] == -1 || dp[b + i] + A[i] < dp[i]) {
                    dp[i] = dp[b + i] + A[i];
                    // 现在记一下从i点去哪个点总cost小,
                    leftRightMap.put(i, i + b); 
                }
            }
        }

        if (dp[0] == -1) return ans;
        Integer cur = 0;
        while (cur != null) {
            ans.add(cur + 1);
            cur = leftRightMap.get(cur);
            
        }
        return ans;

用Recursion + memorization的办法解相比就直观多了。
我建议如果面试中如果被问到这道题,先propose recursion + Memorization吧, 这样保证lexicographical order没有问题。下面是代码, 没有DP好看,但好懂呀

  public List<Integer> cheapestJump(int[] A, int B) {
        List<Integer> ans = new LinkedList<>();
        int N = A.length;
        if (A[N - 1] == -1) return ans;
        Map<Integer, Integer> leftRightMap = new HashMap<>();
        Map<Integer, Integer> costMap = new HashMap<>();
        if (cheapestJump(A, B, 0, leftRightMap, costMap, N) == -1) {
            return ans;
        }
        // reconstruct Map;
        Integer cur = 0;
        while (cur != null) {
            ans.add(cur + 1); //indexed from 1
            cur = leftRightMap.get(cur);
        }
        return ans;
    }
    private int cheapestJump(int[] A, int B, int index, 
                             Map<Integer, Integer> leftRightMap,
                             Map<Integer, Integer> costMap, int N) {
        if (index >= N ) return -1;
        if (costMap.containsKey(index)) return costMap.get(index);
        if (index == N - 1 && A[index] != -1) {
            costMap.put(index, A[index]);
            return costMap.get(index);
        }
        if (A[index] == -1) {
            costMap.put(index, -1);
            return costMap.get(index);
        }
        int localMin = -1, right = -1;
        for (int step = 1; step <= B; step++) {
            int cost = cheapestJump(A, B, step + index, leftRightMap, costMap, N);
            if (cost != -1) {
                if (localMin == -1 || cost < localMin){
                    localMin = cost;
                    right = step + index;
                }
            }
        }
        costMap.put(index, localMin != -1 ? localMin + A[index] : -1);
        leftRightMap.put(index, right);
        return costMap.get(index);
    }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 动态规划(Dynamic Programming) 本文包括: 动态规划定义 状态转移方程 动态规划算法步骤 最长...
    廖少少阅读 3,336评论 0 18
  • LeetCode 刷题随手记 - 第一部分 前 256 题(非会员),仅算法题,的吐槽 https://leetc...
    蕾娜漢默阅读 17,934评论 2 36
  • 不久前跟室友聊天,突然聊到“无聊”这个词,然后大家就进入了各种的吐槽状态中…… 大家吐槽的中心无外乎都围...
    伊伊烑阅读 438评论 0 1
  • 眼泪流了一遍又一遍,心痛了一遍又一遍,原来用心的爱着一个人是这般感受。亲爱的小孩不要哭了。你多么希望你还是曾经的那...
    这样一个女孩阅读 145评论 0 0
  • 身体舒服,心情也随着好起来。每年的寒暑假我都要找个适合我的地方去调理身体,因为上班期间没闲空调理身体,不舒...
    秋雨素娟阅读 718评论 5 4