LeetCode 343. 整数拆分 | Python

343. 整数拆分


题目来源:力扣(LeetCode)https://leetcode-cn.com/problems/integer-break

题目


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

示例 1:

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

示例 2:

输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。

解题思路


思路:推导

这里,我们用数学推导的方法,来尝试解决这个问题。先审题,题目中要我们将数字 n 进行拆分,然后求拆分后数字乘积最大值。这里需要注意:题目中说明 n 至少拆分为两个正整数。

由前面所述的题意,我们可知,目前的问题就是如何拆分,才能使得乘积最大?这里举个例子,若将 1 个数拆分为 2 个数求乘积(均为正整数),我们知道,拆分的两个数字越接近,那么乘积会越大。比较符合前面这段话的有:求矩形面积。我们知道,矩形当中,正方形面积最大。

那么,我们先按照这个思路往下思考(后续在推导)。前面举例说的拆分为 2 个数字,这道题当中说的是至少两个正整数,那么按照前面所得出的推论,将数字 n 进行拆分,可能会出现以下情况:

  • 数字 n 进行拆分时,不一定均分(因为题目要的拆分之后还是正整数)
  • 当上面的情况一定存在时,那么将数字 n 进行拆分时,拆分的数字应该为多少最合适。

上面的情况中,第一种比较好理解。第二种情况,这里举个例子,例如给定的数字 n 为 6,那么:

# ans 在这里表示乘积
n = 6 = 3 + 3
ans = 3 * 3 = 9

或者

n = 6 = 2 + 2 + 2
ans = 2 * 2 * 2 = 8

上面都是将数字 n 拆分为相同的正整数,只是拆分数量不同,但是两者的乘积会有差距。那么这里也就还有个问题,将给定的数字 n 进行拆分时,要拆分为哪个正整数,最终的乘积为最大。

由前面的分析,我们知道,现在的主要的问题有两个:

  1. 如何证明拆分的数字相等,乘积最大?
  2. 数字 n 拆分为哪个数字,最终的乘积最大?

先看第一个问题,这里直接引用 “算术-几何均值不等式”,公式如下:

x 1 + x 2 + . . . + x a a ≥ x 1 x 2 . . . x a a \frac{x_1+x_2+...+x_a}{a} \geq \sqrt[a]{x_1x_2...x_a} ax1+x2+...+xaax1x2...xa

上面的式子中,当且仅当 x 1 = x 2 = . . . = x a x_1=x_2=...=x_a x1=x2=...=xa 的时候,等号成立。

这里,我们得到:当确定拆分数量 a,那么拆分的数字相同时,乘积最大。

现在看第二个问题,根据前面的结论,设拆分数量为 a,拆分数字为 x,也即是 n=ax,那么乘积为 x a x^a xa。现在,则是要求得什么情况下 x a x^a xa 取得最大值?证明如下:

  • x a x^a xa 公式进行转换

x a = x n x = ( x 1 x ) n x^a = x^{\frac{n}{x}}=(x^{\frac{1}{x}})^{n} xa=xxn=(xx1)n

在这里,n 为常数且不小于 2,那么幂函数中,此时,底数越大,值越大。也就是要求得 x 1 x x^{\frac{1}{x}} xx1 的最大值。

  • 那么现在的问题就是要求得 f ( x ) = x 1 x f(x)=x^{\frac{1}{x}} f(x)=xx1 的最大值。先对两边取对数:

l n ( f ( x ) ) = 1 x l n x ln(f(x)) = \frac{1}{x}lnx ln(f(x))=x1lnx

  • 再对两边进行求导:

1 f ( x ) ⋅ f ′ ( x ) = ( 1 x ) ′ l n x + 1 x x ⋅ ( x ) ′ f ′ ( x ) = [ ( 1 x ) ′ l n x + 1 x x ⋅ ( x ) ′ ] ⋅ f ( x ) f ′ ( x ) = [ − 1 x 2 l n x + 1 x 2 ] ⋅ x 1 x f ′ ( x ) = 1 − l n x x 2 ⋅ x 1 x \begin{aligned} \frac{1}{f(x)}·f^{\prime}(x)&=(\frac{1}{x})^{\prime}lnx + \frac{\frac{1}{x}}{x}·(x)^{\prime} \\ f^{\prime}(x)&=\left[(\frac{1}{x})^{\prime}lnx + \frac{\frac{1}{x}}{x}·(x)^{\prime}\right]·f(x)\\ f^{\prime}(x)&=\left[-\frac{1}{x^2}lnx+\frac{1}{x^2}\right]·x^{\frac{1}{x}}\\ f^{\prime}(x)&=\frac{1-lnx}{x^2}·x^{\frac{1}{x}} \end{aligned} f(x)1f(x)f(x)f(x)f(x)=(x1)lnx+xx1(x)=[(x1)lnx+xx1(x)]f(x)=[x21lnx+x21]xx1=x21lnxxx1

  • f ′ ( x ) = 0 f^{\prime}(x)=0 f(x)=0,也就是 1 − l n x = 0 1-lnx=0 1lnx=0,那么此时,可得临界点为: x = e x=e x=e。现在此时 x x x 是否是极值:

f ′ = { 值 大 于 0 , x ∈ [ − ∞ , e ) 值 小 于 0 , x ∈ ( e , + ∞ ] f^{\prime}= \begin{cases} 值大于 0,x\in[-\infty, e) \\ 值小于 0,x\in(e, +\infty] \end{cases} f={0x[,e)0x(e,+]

由此可以判断 x = e x=e x=e 时,取得极大值。我们知道自然常数 e e e 约等于 2.7。题目要求拆分的是正整数,那么我们将 2 和 3 分别代入函数 f ( x ) f(x) f(x) 当中,得:

f ( 2 ) = 2 1 2 ≈ 1.41 f ( 3 ) = 3 1 3 ≈ 1.44 \begin{aligned} f(2)=2^{\frac{1}{2}}\approx 1.41 \\ f(3)=3^{\frac{1}{3}}\approx 1.44 \end{aligned} f(2)=2211.41f(3)=3311.44

我们可以看到当 x 取 3 的时候,乘积达到最大。

现在上面提出的两个问题已经得以证明。但还有一个需要注意的,前面提到的情况中,提及拆分的时候可能出现不均分的情况。

现在确定拆分的数字为 3 的情况下,乘积可取最大值。那么此时拆分的时候,可能出现的余数会有 0,1,2。现在就这个情况下,逐个分析(下面的情况是针对 n > 3 的情况),令 n = ax + b,x 确定取 3,值可最大,也就是 n = 3a + b,那么会出现的情况如下:

  • b = 0,表示均分,此时直接返回 3^a;
  • b = 1,这里需要注意。这里需要重新合并拆分,当剩下 1 时,3 x 1 < 2 x 2,所以将其中一个 3 与余数 1,重新结合拆分为 2 和 2,那么最终返回 3^(a-1) x 2 x 2;
  • b = 2,返回 3^a x 2。

这里在说下 n <= 3 的情况,不拆分的结果更优。当时题目要求必须拆分至少两个整数,那么此时拆出一个数值 1,那么最终返回 n - 1。

具体的代码实现如下。

代码实现


class Solution:
    def integerBreak(self, n: int) -> int:
        # 先处理 n 小于或等于 3 的情况
        if n <= 3:
            return n-1
        
        # 先拆分,确定数量以及余数
        a = n // 3
        b = n % 3

        # 这里调用 math.pow() 方法,该方法调用底层 c 库的 pow 函数,效率更高
        import math
        # 均分直接返回 3^a
        if b == 0:
            return int(math.pow(3, a))
        elif b == 1:
            return int(math.pow(3, a-1) * 4)
        # 剩下就是余 2 的情况
        return int(math.pow(3, a) * 2)

实现结果


实现结果

欢迎关注


公众号 【书所集录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值