算法:吹气球

问题

有n个气球,编号为0到n-1,每个气球都有一个分数,存在nums数组中。每次吹气球i可以得到的分数为 nums[left] * nums[i] * nums[right],left和right分别表示i气球相邻的两个气球。当i气球被吹爆后,其左右两气球即为相邻。要求吹爆所有气球,得到最多的分数。

样例

给出 [4, 1, 5, 10]
返回 270

nums = [4, 1, 5, 10] burst 1, 得分 4 * 1 * 5 = 20
nums = [4, 5, 10]    burst 5, 得分 4 * 5 * 10 = 200 
nums = [4, 10]       burst 4, 得分 1 * 4 * 10 = 40
nums = [10]          burst 10, 得分 1 * 10 * 1 = 10

总共的分数为 20 + 200 + 40 + 10 = 270

第一种思路

通过递归实现暴力枚举,但是不言而喻,这种做法时间复杂度很高(指数阶),虚拟机栈创建方法的开销也很高。

实现

public static int maxCoins(int[] nums) {
        // write your code here
        // 把数组转化成list
        List list = new LinkedList<>();
        for (Integer num : nums) {
            list.add(num);
        }
        return recursive(list);
    }

    public static int recursive(List list) {
        int ans = 0;
        for (int i=0;i sublist = new ArrayList<>();
            sublist.addAll(list);
            sublist.remove(i);
            //递归
            subAns += recursive(sublist);
            ans = Math.max(ans, subAns);

        }
        return ans;
    }

第二种思路

利用区间动态规划来求解,dp(i,j)表示吹爆所有在区间[i,j]的气球,所能得到的最大分数。那么如何进行状态转移?假设吹爆第k个气球,那么k-1和k+1个气球变得相邻,不方便转移。那么我们就先吹爆区间[i,k−1]和区间[k+1,j]的所有气球,最后再来吹爆第k个气球,那么这样就十分方便转移了。枚举k的位置,

dp(i,j)=max{dp(i,k−1)+score(k)+dp(k+1,j)|(i≤k≤j)},score(k)=a[l−1]∗a[k]∗a[r+1]

求解思路如图所示:


算法:吹气球_第1张图片
计算过程

计算过程依次由红-->橙-->黄-->绿


算法:吹气球_第2张图片
矩阵填充

实现

public static int maxCoinsDp(int[] nums) {
        // write your code here
        // 首尾添加两个值为1的元素,方便计算
        int[] nbrs = new int[nums.length + 2];
        nbrs[0] = 1;
        nbrs[nbrs.length - 1] = 1;
        for (int i=0;i

如果文章对你有帮助的话,不要忘了打赏小编哟


算法:吹气球_第3张图片
多谢支持

你可能感兴趣的:(算法:吹气球)