题目html
Given a list of positive integers, the adjacent integers will perform the float division. For example, [2,3,4] -> 2 / 3 / 4.java
However, you can add any number of parenthesis at any position to change the priority of operations. You should find out how to add parenthesis to get the maximum result, and return the corresponding expression in string format. Your expression should NOT contain redundant parenthesis.express
Example:
数组
Input: [1000,100,10,2]Output: "1000/(100/10/2)"Explanation:1000/(100/10/2) = 1000/((100/10)/2) = 200
However, the bold parenthesis in "1000/((100/10)/2)" are redundant,
since they don't influence the operation priority. So you should return "1000/(100/10/2)".
Other cases:
1000/(100/10)/2 = 50
1000/(100/(10/2)) = 50
1000/100/10/2 = 0.5
1000/100/(10/2) = 2
Note:app
The length of the input array is [1, 10].ide
Elements in the given array will be in range [2, 1000].ui
There is only one optimal division for each test case.spa
解法orm
1. 暴力破解htm
用i从数组的start到end进行遍历,每一个i都能将数组分为两部分,left=(start, i),right=(i+1,end)
按照题目要求,须要求该数组(start,end)的最大值,因此若是能将left取到最大值,right取到最小值,则能left/right获得最大值
因此问题又细分到两个小数组(start, i)的最大值,(i+1,end)的最小值,用一样的方法递归将两个数组再细分红left跟right就能够求出,其中要求最大值就max(left)/min(right),求最小值就min(left)/max(right)
至于加括号,很显然,若是right数组超过一个数字就须要加上括号,反之则不用,left由于原本就优先运算,不用加括号
另外注意既然是除法,有可能产生小数,须要额外处理
public class Solution { public String optimalDivision(int[] nums) { T t = optimal(nums, 0, nums.length - 1, ""); return t.max_str; } class T { float max_val, min_val; String min_str, max_str; } public T optimal(int[] nums, int start, int end, String res) { T t = new T(); if (start == end) { t.max_val = nums[start]; t.min_val = nums[start]; t.min_str = "" + nums[start]; t.max_str = "" + nums[start]; return t; } t.min_val = Float.MAX_VALUE; t.max_val = Float.MIN_VALUE; t.min_str = t.max_str = ""; for (int i = start; i < end; i++) { T left = optimal(nums, start, i, ""); T right = optimal(nums, i + 1, end, ""); if (t.min_val > left.min_val / right.max_val) { t.min_val = left.min_val / right.max_val; t.min_str = left.min_str + "/" + (i + 1 != end ? "(" : "") + right.max_str + (i + 1 != end ? ")" : ""); } if (t.max_val < left.max_val / right.min_val) { t.max_val = left.max_val / right.min_val; t.max_str = left.max_str + "/" + (i + 1 != end ? "(" : "") + right.min_str + (i + 1 != end ? ")" : ""); } } return t; } }
这种解法时间复杂度是O(n!),空间复杂度是O(n2)
显然其中存在不少重复的运算,马上想到用空间换时间
2.空间换时间,用二维数组记录已经计算过的结果
这个二维数组memo[start][end]记录题中数组(start, end)的最大最小值
public class Solution { class T { float max_val, min_val; String min_str, max_str; } public String optimalDivision(int[] nums) { T[][] memo = new T[nums.length][nums.length]; T t = optimal(nums, 0, nums.length - 1, "", memo); return t.max_str; } public T optimal(int[] nums, int start, int end, String res, T[][] memo) { if (memo[start][end] != null) return memo[start][end]; T t = new T(); if (start == end) { t.max_val = nums[start]; t.min_val = nums[start]; t.min_str = "" + nums[start]; t.max_str = "" + nums[start]; memo[start][end] = t; return t; } t.min_val = Float.MAX_VALUE; t.max_val = Float.MIN_VALUE; t.min_str = t.max_str = ""; for (int i = start; i < end; i++) { T left = optimal(nums, start, i, "", memo); T right = optimal(nums, i + 1, end, "", memo); if (t.min_val > left.min_val / right.max_val) { t.min_val = left.min_val / right.max_val; t.min_str = left.min_str + "/" + (i + 1 != end ? "(" : "") + right.max_str + (i + 1 != end ? ")" : ""); } if (t.max_val < left.max_val / right.min_val) { t.max_val = left.max_val / right.min_val; t.max_str = left.max_str + "/" + (i + 1 != end ? "(" : "") + right.min_str + (i + 1 != end ? ")" : ""); } } memo[start][end] = t; return t; } }
但就算这样子时间复杂度仍是有O(n3),空间复杂度升到O(n3)
3.使用数学定理
仔细分析发现,用些数学的手段能够很轻松获得解答,不须要遍历整个数组
对于数组[a, b, c, d],若要加优先级使a/b/c/d最大,则b/c/d须要最小
其实加上括号能够改变优先级,去掉括号就至关于把括号里的/变成*,*变成/
因此除了第一个/无法改变,其余后面的/均可以经过加括号使其变为*
显然须要获得最大值,就须要最多的*,那么a/(b/c/d/...)=a*c*d*.../b显示是咱们要求的最大值
public class Solution { public String optimalDivision(int[] nums) { if (nums.length == 1) return nums[0] + ""; if (nums.length == 2) return nums[0] + "/" + nums[1]; StringBuilder res = new StringBuilder(nums[0] + "/(" + nums[1]); for (int i = 2; i < nums.length; i++) { res.append("/" + nums[i]); } res.append(")"); return res.toString(); } }
这样的时间复杂度是线性的O(n),空间复杂度也是O(n)