leetcode 343

Leetcode 343

题目来自leetcode 343 integer break
leetcode 343
对于本题,尝试了两种方法,第一种方法比较直接,直接针对题目中的问题求解,但效率较低,第二种方法对问题进行了数学分析,效率较高:

一,直接求解

1、 算法分析

对于该题来讲,首先我们根据题目所述我们需要对一个整数进行加法的拆解,然后最大化这个乘积。由于没有确定要将原分成几部分,所以很难解决,但我们可以把它当作一个二分的问题,这样我们就可以用迭代的思想进行求解。

  • 我们从2开始来计算最大化的乘积M(2),假设对于整数n我们可以已经知道前面所有的已经确定的最大化乘积(M(i),i=1…n-1)。
  • 对于给定整数n 我们总能把他分成两部分a(a<n)和n-a,我们只需要遍历a=1…n 求解 argmaxaM(a)(M(na))argmax_a M(a)(M(n-a)) 即可找到最大化的二分割问题
  • 对于任意分割问题,我们总能对分割出的部分进行组合变成一个二分割问题。

2、注

  • 对于2,3来说他们只能分成1,1和1,2,但是如果对于任何大3的数字来说当数字已经被分成2,3就不需要急需细分,因为3&gt;12,3&gt;1*2, 2&gt;112&gt;1*1。所以说在这里我们进行迭代的时候应该记M(2)=2,M(3)=3,但是在最后展示的时候应该战是M(2)=1, M(3)=2.
  • 对于a的遍历,由于a和n-a是对称的所以我们只需要的对a=1...n/2a=1...\lceil n/2\rceil遍历即可

综上,我们可以写出代码(python)

class Solution:
    def integerBreak(self, n: int) -> int:
        if n<=3:
           return(max(0,n-1))
        else:
           M = [0 for i in range(n+1)]
           M[2]=2                                            #迭代前设置2,3的值
           M[3]=3
           for i in range(4,n+1):                      
               for j in range(1,(i//2)+1):                   #由于对称性只需要进行前一半的迭代
                   M[i] = max(M[i],M[i-j]*M[j])
           M[2]=1                                            #返回结果前修改2,3作为参数对应的最大乘积
           M[3]=2
           return M[n]

这种解法时间复杂度是o(n2)o(n^2)的,效率一般,

二、数学分析

问题分析

  • 对于2,3我们之前已经讨论过,只有一种分解模式,但是在更大数字分解时如果遇到2,3不做分解可以得到更大的结果。
  • 4=2+2=3+14=2+2=3+122&gt;312*2&gt;3*1,所以对于4来说,分成2和2是更合适的做法。
  • 6=3+3=2+2+26=3+3=2+2+2, 33&gt;2223*3&gt;2*2*2 该问题中3是一个比2高效的元素
  • 很显然的在进行分解时最优分解中一定不包含1,根据迭代的思想我们可以得知数字的最优分解中的元素应只包含2,3
  • 综上,我们应在分解时尽量多的分解出3,且分解中不包含1,单独列出2,3的情况,我们可以写出一个极简单的代码
class Solution(object):
    def integerBreak(self, n):
        if n<4:
            return n-1
        a=n//3
        b=n%3
        z=[0,1,3]
        return 3**(a-1)*(3+z[b])

该代码只使用了幂函数,所以最终的时间复杂度应该是o(log(n))o(log(n))的。