zoukankan      html  css  js  c++  java
  • 剪绳子

    转自:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/xiang-jie-bao-li-di-gui-ji-yi-hua-ji-zhu-dong-tai-/

    给你一根长度为 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

    题解思路:

    方法一:暴力递归

    我们往往会在头脑中形成一种很直观的暴力解法,就是列举出所有的情况,找到乘积最大的那个解。
    设 F(n) 为长度为 n 的绳子可以得到的最大乘积,对于每一个 F(n),可以得到如下分解:

    14.png

    从上图看出我们可以把求解 F(n)的问题分解成求解 F(n−1)的问题,以此类推,直到求解到 F(2) 时,1F(2)=1,递推回去,问题就得到了解决。这用到的就是分治的思想。

    分治思想的解决方法往往是递归,注意到我们每次将一段绳子剪成两段时,剩下的部分可以继续剪,也可以不剪, 因此我们得到了递归函数 F(n)=max(i×(n−i),i×F(n−i)),i=1,2,...,n−22F(n)=max(i×(n−i),i×F(n−i)),i=1,2,...,n−2。

    代码(超时)

    • python
    class Solution:
        def cuttingRope(self, n: int) -> int:
            if n == 2:
                return 1
            res = -1
            for i in range(1, n):
                res = max(res, max(i * self.cuttingRope(n - i),i * (n - i)))
            return res
    •  Java
    class Solution {
        
        public int cuttingRope(int n) {
            //暴力递归
            if(n==2)
                return 1;
            int res=-1;
            for(int i=1;i<n-1;i++){
                res=Math.max(res,Math.max(i*cuttingRope(n-i),i*(n-i)));
            }
            return res;
        }
    }

     

    方法二:记忆化技术(自顶向下)

    上述暴力解法会超时,但是很多进阶解法往往是暴力解法的优化。注意到上述代码中超时的原因主要是因为重复计算了 F(n),为了避免重复计算可以使用 记忆化(memoization) 技术(维基百科)。

    记忆化技术的代码中经常需要建立函数 memoize 辅助实现。我们使用数组 f 来保存长度为 i时的最大长度 f[i],最后返回 f[n]即可。

    代码

    • python
    class Solution:
        def cuttingRope(self, n: int) -> int:
            # 使用辅助函数
            def memoize(n):
                if n == 2: return 1
                if f[n] != 0: # 如果f[n]已经计算过,直接返回避免重复计算
                    return f[n]
                res = -1
                for i in range(1, n):
                    res = max(res, max(i * (n - i),i * memoize(n - i)))
                f[n] = res
                return res
    
            f = [0 for _ in range(n + 1)]
            return memoize(n)
    • java
    class Solution {
        private int dp[];
        public int cuttingRope(int n) {
            dp=new int[n+1];
            dp[2]=1;
            return helper(dp,n);
        }
        public int helper(int dp[],int n) {
            //记忆化递归
            if(n==2)
                return dp[2];
            if(dp[n]!=0)
                return dp[n];
            int res=-1;
            for(int i=1;i<n-1;i++){
                res=Math.max(res,Math.max(i*helper(dp,n-i),i*(n-i))); 
            }
            dp[n]=res;
            return res;
        }
    }

     

    方法三:动态规划(自底向上)

    同样地,我们也可以使用动态规划,从已知值 F(2)逐步迭代到目标值 F(n),它是一种自底向上的方法。

    算法

    建立一维动态数组 dp

    • 边界条件:dp[1] = dp[2] = 1,表示长度为 2 的绳子最大乘积为 1
    • 状态转移方程:dp[i] = max(dp[i], max((i - j) * j, j * dp[i - j])),可以这样理解:

    14.jpg

    代码

    • python
    class Solution:
        def cuttingRope(self, n: int) -> int:
            dp = [0 for _ in range(n + 1)]  # dp[0] dp[1]其实没用
            dp[2] = 1  # 初始化
            res = -1
            for i in range(3, n + 1):
                for j in range(i):
                    dp[i] = max(dp[i], max((i - j) * j, j * dp[i - j]))
            return dp[n]
    • java
    class Solution {
        private int dp[];
        public int cuttingRope(int n) {
            //自底向上
            dp=new int[n+1];
            dp[2]=1;
            for(int i=3;i<=n;i++){
                for(int j=0;j<i;j++)
                    dp[i]=Math.max(dp[i],Math.max(j*(i-j),j*dp[i-j]));
            }
            return dp[n];
        } 
    }
     

     

     


    链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof

  • 相关阅读:
    分布式事务
    K8s应用案例介绍——阿里云
    数据库索引的底层原理——b树
    Understanding the GitHub flow
    Code Review
    详解微服务架构
    yarn之package.json
    yarn.lock文件
    Git Api——git开发
    Unit Test —— xUnit.net
  • 原文地址:https://www.cnblogs.com/treasury/p/12618112.html
Copyright © 2011-2022 走看看