LeetCode 312: Brust Balloon 解题与思考

来源:互联网 发布:java http下载文件 编辑:程序博客网 时间:2024/06/05 12:44

LeetCode 312: Brust Balloon 解题与思考

[原题链接]

题目描述

题目会输入一个长度为n的数列an(n从0开始算),你需要从中按照一定顺序取出所有的数字;每次取出一个数字ak时,你将得到该数字与其左右相邻数字的乘积的分数ak1akak+1
几点注意:

  • 最左边的数的左边,以及最右边的数的右边视为1(a1=an=1)
  • 取出之后这个数会从原数列消除,这个数的左右两个数将会变得相邻

题目要求求出对于给出的任意序列所能得到的得分最大值。

思路:

我最开始直观地感觉是这是一道动态规划的题目,因为假设我们取出某个数,这个问题就变成为:求剩下的数列中所能取得的最大值,是原问题的一个类似子问题

我们也可以得到一个关系式:

=max(+)

但是很快就遇到了如下问题:

  • 取出一个数的得分和其左右两个数相关,而这两个数原则上可以是剩下的左边和右边的任意某个数(当然也能是1)
  • 这个数被取走后,数列会被分成两半,而这两半独自的最大分数,与将这两个数列看做一个新数列所能取得的最大分数,并不存在关系:因为取走某个数之后,相邻关系会改变,左边的数可能会与右边的任意数相邻,反之亦然;之前求得的最大值毫无意义

但是动态规划的这个方向应该还是没问题的
所以接下来的工作重心,就在于

  • 如何确定取走某个数之后所能得到的确切分数
  • 如何建立原数列最大分数与新数列分数的关系

突破口在于,当数列中只有一个数,或者被取到只剩一个数(a[k])时,我们(理所当然地)知道最后我们能拿到这个数所得到的分数,为

1ak1

或者说:
a1akan

而且取走这个数左边的数所能得到的最大分数,与取走这个数右边的数所能取得的最大分数相互无关,因为a[k]是最后取走的,此时左边的数列永远不会与右边的数相邻。
而此时,我们看左边的数列,其最左边的数的左边是1,最右边的数的右边是a[k];而对于最右边的数列,其最左边的数的左边是a[k],最右边的数的右边是1。倘若a[k] == 1,不难发现其和最初的数列类似,可以视作一个子问题处理。

算法

假设ansp,q 代表数列中从第p项开始,包括该项在内的接下来q项的所构成新数列,所能取得的最大分数
ak是该数列中最后取走的数,那么

ansp,q=max(ap1apap+q+ansp,kp+ansk+1,p+qk1)

其中

1、pk<p+q
2、ap1为数列最左边的数左边的数,ap+q为数列最右边的数右边的数,这两个数在操作这个数列的时候不会被取走,也不会有变化
3、 ansp,kpap1ak之间的数列所能取得的最大分数,ansk+1,p+qk1ak+1ap+q之间的数列所能取得的最大分数
4、ansp,0=0
5、ansp,1=ap1apap+1
6、ans0,n为所求解

代码

#include <iostream>#include <stdlib.h>#include <vector>#include <stdio.h>using namespace std;class Solution {    //取最大值函数    int max(int a, int b) {        return (a > b) ? a : b;    }public:    int maxCoins(vector<int>& nums) {        int i, j, k;        int length = nums.size();        //新建数组并初始化为0        int *ans = (int*)(malloc(sizeof(int) * (length + 1) * (length + 1)));        memset((void*)ans, 0, sizeof(int) * (length + 1) * (length + 1));        //动态规划,三层循环        for ( i = 1; i < length + 1; i++ ) {            for ( j = 0; j < length - i + 1; j++ ) {                for ( k = j; k < j + i; k++ ) {                    ans[j * length + i] = max(nums.at(k) * ((j <= 0) ? 1 : nums.at(j - 1)) * ((j + i >= length)?1:nums.at(j + i)) + ans[j * length + k - j] + ans[(k + 1) * length + j + i - k - 1], ans[j * length + i]);                }            }        }        //好习惯,申请的空间要释放        int result = ans[length];        free(ans);        //返回结果        return result;    }};

思考

很有趣的一道题目,关键点在于从每次取走一个数,变成取走的是最后一个数,这一思维上的转变——而后者是能够轻松动态规划的

原创粉丝点击