題目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)