正整数拆分问题

        如标题所述,作者认为把一个正整数拆分成几个正整数的和很重要。你可能会疑惑,很重要吗?好像不很重要,因为似乎没啥实际的用处,无论是学习还是工作,没有遇到过这种需求,但其实它非常重要,如果你曾经遇到过一个问题,n个结点的树,它有多少种形态,这个问题数据结构与算法的书里有答案,但如果要你画出所有树的形态,你画得出来吗?或者说,你有思路吗?

        让我们思考一下,n个结点的树的情形。首先它有一个根结点,然后它有几棵子树,显然它的各个子树的结点数之和是n-1,如果问它的几棵子树各有多少个结点?这不就是把n-1拆分成几个正整数的和的问题吗?所以,如果你知道如何拆分一个正整数,你就能知道n个结点的树,每一种形态下,它的各个子树各有多少个结点,这些都知道了,写一个程序画出n个结点的树的所有形态就不难了。作者之所以认为它很重要,是因为,树在编程里是非常重要的数据结构,对它没有一个形象立体的认识,是不利于你去真正得学习掌握它。

       下面让我们来研究一下如何拆分一个正整数,举例来说,对3进行拆分,很容易给出所有拆分的情形,3=1+1+1,3=1+2,3=2+1,3=3,为了简化输出,我们把3=1+2和3=2+1看成同一种拆分,我们以3=1+2代表了,也就是设定拆分序列为正序。那么如何进行拆分呢?其实是很简单的,这里存在一个递归的规律,只要找到了这个规律,问题就迎刃而解。对n进行拆分,假设拆出来的第一个数是m,那么对n的拆分便分解为了拆出一个数m和对n-m的拆分的问题了,数m可取哪些值?按照假定拆分序列为正序,m只能由上一步拆分的值m’(如果m是第一步拆出来的值m由1开始取)开始取直到 n/2(下取整),如果不假定拆分序列为正序,m更简单由1取到n就可以了,这里给出一个拆分为正序序列的实现,下面是代码。

class Intization(object):
    def __call__(self, n):
        self.n = n
        self.res = []
        yield from self.intization(self.n, 1)

    def intization(self, n, frm):
        for i in range(frm, int(n / 2) + 1):
            self.res.append(i)
            yield from self.intization(n - i, i)
            self.res.pop()

        #n不能被拆分就走到这里,意味着n就是拆分序列最后一个数
        self.res.append(n)
        yield self.res
        self.res.pop()

_i = Intization()
for i in _i(5):
    print(i)

           上面的实现需要定义一个类,稍显繁琐,不需要定义类的版本如下:

def intization(n):
    res = []
    def takeapart(n, frm):
        for i in range(frm, int(n / 2) + 1):
            res.append(i)
            yield from takeapart(n - i, i)
            res.pop()

        res.append(n)
        yield res
        res.pop()
    yield from takeapart(n, 1)

for i in intization(5):
    print(i)

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__空无一人__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值