力扣 553. 最优除法

题目来源:https://leetcode-cn.com/problems/optimal-division/

大致题意:
给一个数组,相邻元素之间会进行除法操作,可以在元素之间加上括号改变除法运算的顺序,求出如何加括号可以使最后运算结果的值最大。并返回最后的除法组成的字符串

思路

可以通过动态规划来解题。

使用 dp[i][j] 表示索引 i 至 j 的元素能组成的除法的最大值和最小值,以及对应的字符串,那么

  • dp[i][j] 的最大值等于dp[i][k]的最大值除以dp[k + 1][j] 的最小值,其中 i <= k < j
  • dp[i][j] 的最小值等于dp[i][k]的最小值除以dp[k + 1][j] 的最大值,其中 i <= k < j
动态规划
  1. 初始时,给所有 dp[i][i] 的最值都设为索引 i 处的数组值本身
  2. 从长度 2 开始,至长度 n,逐渐求出整个数组对应的最大值

加括号时需要注意,除法默认的运算顺序是从左至右的,所以分子不需要加括号,只有分母需要加,且题目规定不能有冗余括号,所以仅当分母的元素个数大于 1 时才加括号

代码:

public class OptimalDivision {
    public String optimalDivision(int[] nums) {
        int n = nums.length;
        Node[][] dp = new Node[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                dp[i][j] = i == j ? new Node(nums[i]) : new Node();
            }
        }
        for (int i = 1; i < n; i++) {   // 本轮迭代区间的长度为 i+1
            for (int j = 0; j + i < n; j++) {   // 本轮迭代区间为 [j, j + i]
                for (int k = j; k < j + i; k++) {   // 本轮迭代区间的分子分母的界限索引 k
                    // 更新区间最大值
                    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;
    }

    // 定义内部类,用来存储对应区间的最值和字符串
    class Node {
        double maxVal, minVal;
        String maxStr, minStr;

        public Node() {
            maxVal = 0.0;
            minVal = 1000.0;
        }

        public Node(int num) {
            maxVal = num;
            minVal = num;
            maxStr = String.valueOf(num);
            minStr = String.valueOf(num);
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值