给定一组正整数,相邻的整数之间将会进行浮点除法操作。例如, [2,3,4] -> 2 / 3 / 4 。
但是,你可以在任意位置添加任意数目的括号,来改变算数的优先级。你需要找出怎么添加括号,才能得到最大的结果,并且返回相应的字符串格式的表达式。你的表达式不应该含有冗余的括号。
示例:
输入: [1000,100,10,2]
输出: "1000/(100/10/2)"
解释:
1000/(100/10/2) = 1000/((100/10)/2) = 200
但是,以下加粗的括号 "1000/((100/10)/2)" 是冗余的,
因为他们并不影响操作的优先级,所以你需要返回 "1000/(100/10/2)"。
其他用例:
1000/(100/10)/2 = 50
1000/(100/(10/2)) = 50
1000/100/10/2 = 0.5
1000/100/(10/2) = 2
说明:
输入数组的长度在 [1, 10] 之间。
数组中每个元素的大小都在 [2, 1000] 之间。
每个测试用例只有一个最优除法解。
我的题解:
func optimalDivision(nums []int) string {
var str string
if len(nums) == 1{
return strconv.Itoa(nums[0])
}else if len(nums) == 2{
return strconv.Itoa(nums[0]) + "/" + strconv.Itoa(nums[1])
}
for i, v := range nums{
if i == 0{
str += strconv.Itoa(v)
}else if i == 1{
str += "/(" + strconv.Itoa(v)
}else if i == len(nums) - 1{
str += "/" + strconv.Itoa(v) + ")"
}else{
str += "/" + strconv.Itoa(v)
}
}
return str
}
官方题解:
方法一:动态规划
动态规划(Dynamic Programming)是一种分阶段求解决策问题的数学思想,它通过把原问题分解为简单的子问题来解决复杂问题.动态规划在很多领域都有着广泛的应用,例如管理学,经济学,数学,生物学.
动态规划适用于解决带有
最优子结构
和子问题重叠
性质的问题.
最优子结构
: 即是局部最优解能够决定全局最优解(也可以认为是问题可以被分解为子问题来解决),如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构
性质.
子问题重叠
: 即是当使用递归进行自顶向下的求解时,每次产生的子问题不总是新的问题,而是已经被重复计算过的问题.动态规划利用了这种性质,使用一个集合将已经计算过的结果放入其中,当再次遇见重复的问题时,只需要从集合中取出对应的结果.
type node struct {
minVal, maxVal float64//最小值,最大值
minStr, maxStr string//最小值对应的括号字符串,最大值对应的括号字符串
}
func optimalDivision(nums []int) string {
//1.记录区间[i,j]的属性的二维切片dp的初始化
n := len(nums)
dp := make([][]node, n)//二维切片初始化
for i := range dp {
dp[i] = make([]node, n)//一维切片初始化
for j := range dp[i] {
dp[i][j].minVal = 1e4//从i到j范围内的最小值初始化为所能达到的最大值
}
}
for i, num := range nums {//初始化(区间范围内只有一个元素时)
dp[i][i].minVal = float64(num)
dp[i][i].maxVal = float64(num)
dp[i][i].minStr = strconv.Itoa(num)
dp[i][i].maxStr = strconv.Itoa(num)
}
for i := 1; i < n; i++ {//gap间距,从1-n-1即[0,1]=>[0,n-1]
for j := 0; j+i < n; j++ {//区间起点j为0,区间终点为j+i
for k := j; k < j+i; k++ {//k用来切分区间[i,j] => [i,k] + [k+1,j],k从区间起点j开始
//最大值
if dp[j][j+i].maxVal < dp[j][k].maxVal/dp[k+1][j+i].minVal {
dp[j][j+i].maxVal = dp[j][k].maxVal / dp[k+1][j+i].minVal//最大值更新
if k+1 == j+i {
dp[j][j+i].maxStr = dp[j][k].maxStr + "/" + dp[k+1][j+i].minStr//区间右侧只有一个元素时
} else {
dp[j][j+i].maxStr = dp[j][k].maxStr + "/(" + dp[k+1][j+i].minStr + ")"//区间右侧有多个元素时
}
}
//最小值
if dp[j][j+i].minVal > dp[j][k].minVal/dp[k+1][j+i].maxVal {
dp[j][j+i].minVal = dp[j][k].minVal / dp[k+1][j+i].maxVal
if k+1 == j+i {
dp[j][j+i].minStr = dp[j][k].minStr + "/" + dp[k+1][j+i].maxStr
} else {
dp[j][j+i].minStr = dp[j][k].minStr + "/(" + dp[k+1][j+i].maxStr + ")"
}
}
}
}
}
return dp[0][n-1].maxStr
}
func optimalDivision(nums []int) string {
n := len(nums)
if n == 1 {
return strconv.Itoa(nums[0])
}
if n == 2 {
return fmt.Sprintf("%d/%d", nums[0], nums[1])
}
ans := &strings.Builder{}
ans.WriteString(fmt.Sprintf("%d/(%d", nums[0], nums[1]))
for _, num := range nums[2:] {
ans.WriteByte('/')
ans.WriteString(strconv.Itoa(num))
}
ans.WriteByte(')')
return ans.String()
}