Leetcode - Burst Balloons

Leetcode - Burst Balloons_第1张图片
Screenshot from 2016-02-22 22:51:47.png

My code:

public class Solution {
    public int maxCoins(int[] nums) {
        if (nums == null || nums.length == 0)
            return 0;
        int n = nums.length;
        int[] help = new int[n + 2];
        for (int i = 1; i < n + 1; i++)
            help[i] = nums[i - 1];
        help[0] = 1;
        help[n + 1] = 1;
        
        int[][] dp = new int[n + 2][n + 2];
        for (int i = 0; i < n + 2; i++)
            dp[i][i] = help[i];
        
        for (int len = 2; len <= n + 1; len++) {
            for (int i = 0; i <= n + 1 - len; i++) {
                int j = i + len;
                for (int k = i + 1; k < j; k++) {
                    dp[i][j] = Math.max(dp[i][j], help[i] * help[k] * help[j] + dp[i][k] + dp[k][j]);
                }
            }
        }
        
        return dp[0][n + 1];
    }
}

这道题目看了答案后还是做了很久。
今天状态也很差。
具体看这篇文章把:
http://algobox.org/burst-balloons/
具体就是一种思路的转变。
假设[i...j]中以k,作为分割点。先破k。
那么 [i, k] and [k, j] 并不是互相独立的。因为他们之间还可以交际。
但是,如果假设,k是最后一个破裂的,那么, [i, k] and [k, j] 就是互相独立的了。

真的就是一个假设的转变,and everything changes.
记住这种reverse想法在DP中的应用。

Anyway, Good luck, Richardo!

首先说下,这道题目做了接近5个小时,最后给出的答案仍然超时,主要在于,思考的起点,还是不对的。

下面是正确的解法:
My code:

import java.util.HashMap;

public class Solution {
    public int maxCoins(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        int[] bb = new int[nums.length + 2];
        for (int i = 1; i < bb.length - 1; i++) {
            bb[i] = nums[i - 1];
        }
        bb[0] = 1;
        bb[bb.length - 1] = 1;
        int n = bb.length;
        int[][] cache = new int[n][n];
        return helper(bb, cache, 0, n - 1);
    }
    
    private int helper(int[] bb, int[][] cache, int left, int right) {
        if (left + 1 >= right) {
            return 0;
        }
        else if (cache[left][right] != 0) {
            return cache[left][right];
        }
        
        int ret = 0;
        for (int i = left + 1; i < right; i++) {
            ret = Math.max(ret, bb[left] * bb[i] * bb[right] + helper(bb, cache, left, i) + helper(bb, cache, i, right));
        }
        cache[left][right] = ret;
        return ret;
    }
}

reference:
https://discuss.leetcode.com/topic/30746/share-some-analysis-and-explanations

感觉想说的,上面的网页说的很清楚了。

他是 divide conquer + dp
最为重要的是,他把左右完全独立开来了。
这道题目太恶心,我不想多说什么,只是在问,有什么意义?
我的时间?

下面说下我的解法:
My code:

import java.util.HashMap;

public class Solution {
    HashMap cache = new HashMap();
    int total = 0;
    int hit = 0;
    public int maxCoins(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        boolean[] isVisited = new boolean[nums.length];
        return helper(nums, isVisited);
    }
    
    private int helper(int[] nums, boolean[] isVisited) {
     String hashcode = getHashcode(isVisited, nums);
     if (cache.containsKey(hashcode)) {
      return cache.get(hashcode);
     }
        int max = 0;
        for (int i = 0; i < nums.length; i++) {
            if (isVisited[i]) {
                continue;
            }
            else {
             isVisited[i] = true;
                int coins = getCoin(isVisited, i, nums);
                int ret = helper(nums, isVisited) + coins;
                max = Math.max(max, ret);
                isVisited[i] = false;
            }
        }
        cache.put(hashcode, max);
        return max;
    }
    
    private String getHashcode(boolean[] isVisited, int[] nums) {
        StringBuilder hashcode = new StringBuilder();
        for (int i = 0; i < isVisited.length; i++) {
            if (!isVisited[i]) {
             hashcode = hashcode.append("_" + nums[i]);
            }
        }
        return hashcode.toString();
    }
    
    private int getCoin(boolean[] isVisited, int index, int[] nums) {
        int left = index - 1;
        int right = index + 1;
        while (left >= 0) {
            if (!isVisited[left]) {
                break;
            }
            else {
                left--;
            }
        }
        while (right < isVisited.length) {
            if (!isVisited[right]) {
                break;
            }
            else {
                right++;
            }
        }
        
        int p1 = (left == -1 ? 1 : nums[left]);
        int p2 = (right == isVisited.length ? 1 : nums[right]);
        
        return p1 * nums[index] * p2;
    }
    
    public static void main(String[] args) {
     Solution test = new Solution();
     int[] nums = new int[]{8, 2, 6, 8, 9, 8, 1, 4, 1, 5, 3, 0, 7, 7, 0, 4, 2};
     int ret = test.maxCoins(nums);
     System.out.println(ret);
     System.out.println("hit rate: " + test.hit / (test.total * 1.0));
    }
}

是从上往下,但是对于某些已经计算过的情况,我会用cache。
比如
0 1 2 3 4
F F F F F

假设扎破了0
0 1 2 3 4
11 32 43 8 9
T F F F F
然后一直dfs,算出来他的最大值 m
然后我设计了一个hashcode 函数,计算 TFFFF的hashcode
即: _32_43_8_9
那么下次,我再碰到 _32_43_8_9 组合时,就直接拿结果就行了。

但这个解法仍然很恐怖的超时,应该速度快于 n! 但是 慢于 2^n

至于 上面的那个更好的解法,我不清楚他的算法复杂度是多少,但是真的很快!

题目,还是要坚持刷的!
简历上的那些软件,项目,也要全部准备好!
路,还很遥远。
你, 在哪里?

Anyway, Good luck, Richardo! -- 08/19/2016

你可能感兴趣的:(Leetcode - Burst Balloons)