剑指offer 14——剪绳子

栏目: IT技术 · 发布时间: 4年前

内容简介:这道题的一般解法是动态规划,优化时可以尝试找规律。给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为示例 1:

这道题的一般解法是动态规划,优化时可以尝试找规律。

原题

给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m] 。请问  k[0]*k[1]*...*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

示例 1:

输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

提示:

  • 2 <= n <= 58

原题url:https://leetcode-cn.com/problems/jian-sheng-zi-lcof

解题

动态规划 DP

我们想想,本题要求是计算 n 被分成 m 份后,相乘最大的结果,这比较明显可以看出是需要求一定要求下的最优解,那么如果能求出局部最优解的话,也能求出方便求出最终最优解。讲白了,就是一个个试,但需要保证需要将所有情况都计算过,且不要重复计算。

那这就要利用动态规划的思想了,从初始情况开始,一步步递推。假设绳子长度为 x ,其最大乘积为 f(x),则有:

f(2) = 1; (1 * 1)
f(3) = 2; (1 * 2)
f(4) = 4; (2 * 2)
f(5) = 6; (3 * 2)
f(6) = 9; (3 * 3)
f(7) = 12; (3 * 2 * 2 = 3 * f(4))
f(8) = 18; (3 * 3 * 2 = f(6) * 2 = 3 * f(5))

自己先试着写出初始的情况,然后从中找出规律:

  1. 长度1、2、3,并没有继续分隔的必要,其作为整体,直接参与计算应该就是最大的数字了。

  2. 长度4,分隔成2、2是比较合理的。

  3. 当长度越长,被分隔成的数量越多时,其实可以想象成将其中多段合并成1段,最后都是可以当做分隔成2段来计算的。

因此,根据上面总结出来的规律,我们应该是需要从小开始计算,并将中间结果保留,因此可以用一个数组进行存储。

我们来看看代码:

class Solution {
    public int cuttingRope(int n) {
        if (n == 2) {
            return 1;
        }
        // 记录计算结果,第2位代表长度为2的绳子,其最大乘积
        int[] result = new int[n + 1];
        result[1] = 1;
        result[2] = 1;
        for (int i = 3; i <= n; i++) {
            // 默认初始值就是剪成两段:1 和 i-1,所以最大乘积是 i-1
            result[i] = i - 1;
            for (int j = 1; j <= i / 2; j++) {
                int x = Math.max(result[i - j], i - j);
                int y = Math.max(result[j], j);
                result[i] = Math.max(x * y, result[i]);
            }
        }
        return result[n];
    }
}

提交OK。

数学推导的极致优化

这个解法,我也是看了别人的解析才知道的,通过代码提交发现结论确实是正确的,但其中的推导过程我也没有看懂,看看原文:

剑指offer 14——剪绳子 剑指offer 14——剪绳子

接下来我们看看代码:

class Solution {
    public int cuttingRope(int n) {
        if (n == 2) {
            return 1;
        }
        if (n == 3) {
            return 2;
        }
        // 可以被3分成几段
        int count = n / 3;
        // 剩余的数字
        int remain = n % 3;
        // 如果没有剩余的
        if (remain == 0) {
            // 直接计算当前的值
            return (int) Math.pow(3, count);
        }
        // 如果剩1,则和原本的一个3,重新拆分成2和2,因为2 * 2 > 3 * 1
        if (remain == 1) {
            return (int) Math.pow(3, count - 1) * 2 * 2;
        }
        // 如果剩2,则正常乘
        return (int) Math.pow(3, count) * 2;
    }
}

提交OK。

总结

以上就是这道题目我的解答过程了,不知道大家是否理解了。这道题的一般解法是动态规划,优化时可以尝试找规律,数学推导出其中当然是最快的,但这需要一定的功底。

有兴趣的话可以访问我的博客或者关注我的公众号,说不定会有意外的惊喜。

https://death00.github.io/

公众号:健程之道

剑指offer 14——剪绳子

点击此处留言


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Nine Algorithms That Changed the Future

Nine Algorithms That Changed the Future

John MacCormick / Princeton University Press / 2011-12-27 / GBP 19.95

Every day, we use our computers to perform remarkable feats. A simple web search picks out a handful of relevant needles from the world's biggest haystack: the billions of pages on the World Wide Web.......一起来看看 《Nine Algorithms That Changed the Future》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具