leetcode_343_整数拆分

整数拆分

描述

中等

给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。

示例 1:

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

示例 2:

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

解题

1.动态规划

  • 当n为2时,只能分解成1+1,返回2
  • 当n为3时,能分解成1+1+1或1+2,返回2

dp[i]为将i拆分为至少2个正整数后,这些整数乘起来可以得到的乘积

假设1~i之间有一个数j将i分解成ji-j,那么dp[i]等于ji-j的乘积

然后1~i-j之间有没有数将其分解成两部分,使得*dp[i-j]*等于两个数之和,不确定

好像找到转移方程了

i-j不再继续拆分时,例如6拆成3+3
d p [ i ] = j ∗ ( i − j ) dp[i] =j*(i-j) dp[i]=j(ij)
i-j继续拆分时,例如6拆成3+2+1
d p [ i ] = j ∗ d p [ i − j ] dp[i]=j*dp[i-j] dp[i]=jdp[ij]
因此其中取较大的数
d p [ i ] = j ∗ m a x ( i − j , d p [ i − j ] ) dp[i] = j*max(i-j,dp[i-j]) dp[i]=jmax(ij,dp[ij])
然后在遍历j时找到最大的dp[i]

class Solution:
    def integerBreak(self, n: int) -> int:
        if n <= 3:
            return n - 1
        dp = [0 for i in range(n + 1)]
        for i in range(2, n + 1):
            for j in range(1, i):
                dp[i] = max(dp[i], j * max(i - j, dp[i - j]))

        return dp[n]

2.数学方法

n分成多个数之和
n = n 1 + n 2 + . . . + n a n = n_1+n_2+...+n_a n=n1+n2+...+na
然后求解乘积(记作res
r e s = m a x ( n 1 ∗ n 2 ∗ . . . ∗ n a ) res=max(n_1*n_2*...*n_a) res=max(n1n2...na)
根据算术几何平均不等式
n 1 + n 2 + . . . + n a a ≥ n 1 ∗ n 2 ∗ . . . ∗ n a a \frac{n_1+n_2+...+n_a}{a} \geq \sqrt[a]{n_1*n_2*...*n_a} an1+n2+...+naan1n2...na
当且仅当
n 1 = n 2 = . . . = n a 时 , 不 等 式 取 等 号 n_1=n_2=...=n_a时,不等式取等号 n1=n2=...=na
所以,当分解出来的数都相同时,其乘积最大

那么问题来了,需要分解成多少个相同的数

假设分成a个数,每个数为x,则
n = a x n = ax n=ax
那么最后的乘积为
r e s = x a = x n x = ( x 1 x ) n res=x^a=x^{\frac{n}{x}}={(x^{\frac{1}{x}})}^n res=xa=xxn=(xx1)n
可以转化为求y的最大值
y = x 1 x y=x^{\frac{1}{x}} y=xx1
取对数后求导
l n ( y ) = 1 x l n ( x ) ln(y) = \frac{1}{x}ln(x) ln(y)=x1ln(x)

1 y y ˙ = − 1 x 2 l n ( x ) + 1 x 2 = 1 − l n ( x ) x 2 \frac 1 y \dot y=-\frac 1 {x^2}ln(x)+\frac 1 {x^2}=\frac{1-ln(x)}{x^2} y1y˙=x21ln(x)+x21=x21ln(x)

y ˙ = 1 − l n ( x ) x 2 ∗ y = 1 − l n ( x ) x 2 x 1 x \dot{y}=\frac{1-ln(x)}{x^2}*y=\frac{1-ln(x)}{x^2}x^{\frac 1 x} y˙=x21ln(x)y=x21ln(x)xx1

令导数
y ˙ = 0 \dot{y}=0 y˙=0
得到
1 − l n ( x ) = 0 1-ln(x)=0 1ln(x)=0

x = e ≈ 2.7 x = e \approx 2.7 x=e2.7

又因为
y ˙ = 1 − l n ( x ) x 2 x 1 x = k ( 1 − l n ( x ) ) { > 0 , x < e = 0 , x = e < 0 , x > e \dot{y}=\frac{1-ln(x)}{x^2}x^{\frac 1 x}=k(1-ln(x))\begin{cases}> 0,&x< e\\=0,&x=e \\<0,& x>e \end{cases} y˙=x21ln(x)xx1=k(1ln(x))>0,=0,<0,x<ex=ex>e
其中k为正数

所以,当xe时存在最大值(极大值)

由于x需要为正整数,x可以取2或3
y ( 2 ) = 2 1 2 y(2) = 2^{\frac{1}{2}} y(2)=221

y ( 3 ) = 3 1 3 y(3)=3^{\frac 1 3} y(3)=331

同时取6次方
( y ( 2 ) ) 6 = ( 2 1 2 ) 6 = 2 3 = 8 {(y(2))}^6=(2^{\frac 1 2})^6=2^3=8 (y(2))6=(221)6=23=8

( y ( 3 ) ) 6 = ( 3 1 3 ) 6 = 3 2 = 9 {(y(3))}^6=(3^{\frac 1 3})^6=3^2=9 (y(3))6=(331)6=32=9

所以
y ( 3 ) > y ( 2 ) y(3)>y(2) y(3)>y(2)

所以,x3

所以,将正整数n尽可能分解为3多的情况

那么就有3种情况

  • 刚好将n分为3+3+…+3,即n是3的倍数
  • 将n分为3+3+…+3+1,即n是3的倍数+1
  • 将n分为3+3+…+3+2,即n是3的倍数+2

那么针对的就有3种计算方式

  • 全部乘起来
  • 第一部分将最后一个3和1,加起来成4,在分成2+2,积为4,第二部分将剩余的3乘起来,最后两部分相乘
  • 将所有的3乘起来再乘上最后的2
class Solution:
    def integerBreak(self, n: int) -> int:
        if n <= 3:
            return n - 1
        a, b = n // 3, n % 3
        if b == 0:
            return int(math.pow(3, a))
        elif b == 1:
            return int(math.pow(3, a - 1) * 4)
        elif b == 2:
            return int(math.pow(3, a) * 2)

参考:leetcode题解

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值