二、字符串(25)553. 最优除法

553. 最优除法

给定一组正整数,相邻的整数之间将会进行浮点除法操作。例如, [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()
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值