题目及测试
package pid312;
/*戳气球
有 n 个气球,编号为0 到 n-1,每个气球上都标有一个数字,这些数字存在数组 nums 中。
现在要求你戳破所有的气球。每当你戳破一个气球 i 时,你可以获得 nums[left] * nums[i] * nums[right] 个硬币。
这里的 left 和 right 代表和 i 相邻的两个气球的序号。注意当你戳破了气球 i 后,气球 left 和气球 right 就变成了相邻的气球。
求所能获得硬币的最大数量。
说明:
你可以假设 nums[-1] = nums[n] = 1,但注意它们不是真实存在的所以并不能被戳破。
0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
示例:
输入: [3,1,5,8]
输出: 167
解释: nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
coins = 3*1*5 + 3*5*8 + 1*3*8 + 1*8*1 = 167
}*/
public class main {
public static void main(String[] args) {
int[][] testTable = {
{3,1,5,8},{1,1,2,2,5,6,7,7},{1,2,3,5},{1,1,1,1}};
for (int[] ito : testTable) {
test(ito);
}
}
private static void test(int[] ito) {
Solution solution = new Solution();
int rtn;
long begin = System.currentTimeMillis();
for (int i = 0; i < ito.length; i++) {
System.out.print(ito[i]+" ");
}//开始时打印数组
rtn = solution.maxCoins(ito);//执行程序
long end = System.currentTimeMillis();
System.out.println("rtn=" + rtn);
/*for (int i = 0; i < rtn; i++) {
System.out.print(ito[i]+" ");
}//打印结果几数组
*/ System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
没想出来
解法1(别人的)
回溯法
刚看到这个题目,脑中可以很轻易的想象出解空间的结构:一个n层的数组,每层的元素相同,我们从第一层走到第n层,每层走动时不能使用之前走过的元素。然后按照规则计算获取的金币,我们尝试所有可以走的路径并记录下每条路径所能获得的金币和,最大值即题目的解。在层数不确定的情况下,使用递归比for循环的嵌套更加方便:
因为被戳破的气球等于不存在,我们在计算获得的金币时需要做一点小小的处理。因为气球上的数字是大于等于0的,我们将走过的气球标志为-1。在计算可以获得的金币数时,如果相邻的气球是-1,则略过取相邻的下一个气球即可。另外,出于两边的气球只有一个相邻气球,需要做一下特殊处理。我们将上述代码的“尝试所有可走路径”中的“to do something”完善起来:
按上面的思路,这就是一个很简单的搜索问题,但每走一层都会对下面的路径造成影响,所以我们需要通过回溯的手法,每尝试完一种可能性后,在尝试下一种路径前我们都要把之前路径戳破的气球恢复。回溯很简单,只需要加一行代码,即递归调用结束后将当前for循环中戳破的气球恢复。
上述解法超时导致提交不通过。细想下当前解法的时间复杂度就可以知道,不通过是有原因的。
每层有n中选择,第i层有n-i中选择,时间复杂度为n*(n-1)*(n-2)...*1即 !n。n的阶乘,指数级的时间复杂度,太可怕,我们应该想办法优化它。
我们都都知道,算法的时间复杂度分为多项式级时间复杂度与非多项式级时间复杂度,我们来重温一下时间复杂度的排名:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n)< O(!n)
其中 O(!n)与O(2^n)被称为非多项式级时间复杂度,增长速度大于且远远大于前面的多项式级时间复杂度。
当遇到时间复杂度为 !n 的算法时,首先考虑的是使用分治的方式将问题规模缩小。因为 !n 的增长率是恐怖的,缩小问题规模,时间复杂度的优化效果也将是立竿见影的。下面看一个很简单的例子,8的阶乘是远大于两个4的阶乘的和的:
8的阶乘是40320。我们如果将问题分解,比如对半分则我们将得到两个问题规模为4的子问题,时间复杂度为4的阶乘加4的阶乘等于48。
在将规模为8