整数划分,并输出所有的结果

前天遇到一个整数划分的问题,要求输出所有的划分结果.例如若输入的数字是6,那么应该输出

6

5+1

4+2

4+1+1

3+3

3+2+1

3+1+1+1

2+2+2

2+2+1+1

2+1+1+1+1

1+1+1+1+1+1

看了这个问题之后我第一反应是递归...递归的把大的数分解成小的数,然后每次分解输出一次结

有了大致的思路就开始仔细分析这些数字,为了更容易的找出规律,不妨把上面的输出结果稍

改变一下位置,改成下面的样子

6

5+1

4+2, 4+1+1

3+3, 3+2+1, 3+1+1+1

2+2+2, 2+2+1+1, 2+1+1+1+1

1+1+1+1+1+1

现在我们把从上而下看叫做层次6是第层,5+1是第五层......1+1+1+1+1+1是第1层.那么层

次与层次之间的关系是相差1.现在再从左边向右边看,右边的式子总是从左边的式子分解得到的.

诸如4+2 把2分成1+1得到4+1+1.

另外假设我们以+号作为分隔符左边的操作数记为L右边的操作数记为R那么总有L >= R.现在

再来观察一下6, 5+1, 4+2, 3+3这几个式子把6看成6+0那么从6+0 -> 3+3的变化我们可以

用L = L - R + R来表示

6 = 6 - 0 + 0 = 6 + 0

6 = 6 - 1 + 1 = 5 + 1

6 = 6 - 2 + 2 = 4 + 2

6 = 6 - 3 + 3 = 3 + 3

 

而这样的L = L - R + R关系不仅仅在不同的层次当中有,而且在每一层的前后关系中也有.有了

这样的关系实际上要写出,自上而下不断将大的数分解成小的数的递归方程就不难了.但是这里要

说的是另外一种思路.从集合的角度来考虑

 

从1+1+1+1+1+1到2+1+1+1+1实际上就相当于我从左边那一堆{1,1,1,1,1,1}的集合中拿

两个1出来相加然后再把结果放回集合当中得到{2,1,1,1,1}.若这个时候我继续拿集合里面的两个

1相加再放回去就可以得到{2,2,1,1},同理再做同样的处理的话我们会得到{2,2,2} 

 

而对于第三层,我们可以先从{1,1,1,1,1,1}里面拿三个1,相加之后放回去得到{3,1,1,1},对于

{3,1,1,1}来说,剩下的三个1可以有两种不同的拿的策略

第一种是一次性拿三个1得到{3,3}

第二种是拿两个1得到{3,2,1}

这些正好是3+3, 3+2+1, 3+1+1+1

 

 

而从集合里面拿1这样的操作,利用堆栈就可以很容易的实现,我拿几个就弹出几个,然后把结果

压回栈中.但是这样的话并不是很直观,实际上使用两个栈来操作的话效果会更好.现在假设有两

个栈S1和S2.将S1栈全部压入1,S2栈为空.S1栈元素的个数就是我们输入要分解的整数,就像题

目输入的是6,那么S1栈里面就是6个1. 现在我们要做的事情就是从S1栈里面弹出N个1然后相加

把结果压入S2栈中,一直到S1栈空的时候,就将S2栈中的元素作为结果输出.

 

从前面的分析,我们可以把递归分成两个方面的,一个方面是深度的递归,就是不同层次之间的转变

的递归,另外一方面的递归是广度的递归,把同一层中的大数再分小,直至不能再分.举例子来说就是

6 -> 5+1 -> 4+2 -> 3+3这里是深度递归

3+3 -> 3+2+1 -> 3+1+1+1 这里是广度递归

 

运用到我们从S1栈弹出的元素来说,那么第一次弹几个元素就代表着深度,而第二次弹出的元素个

数只能是<=第一次弹出的元素的个数.第三次弹出的又要<=第二次弹出的 一直到S1栈空为止.

举例子来说

假设我们输入的是6,即我们要把6拿来分解.S1就应该有6个1 S2开始的时候是空.

1.第一次弹6个1,把6压入S2,这个时候S1空 ->输出6

2.第一次弹5个1,把5压入S2,这时候S1还剩下一个1,S2有一个5. 下一次弹出栈时候我只能弹出

一个1,压入S2,现在S1空 S2内为{1,5} 输出5+1

3.第一次弹4个1,S2{4},这里因为S1剩下的元素个数>1所以会出现不同的弹出的策略(广度递归

分解)

①第二次弹出两个1,S1空 S2{2,4} 输出 4 + 2

②第二次弹出一个1,第三次弹出一个1, S1空 S2{1,1,4}输出4+1+1

4.第一次弹出三个1, S1{1,1,1} S2{3} 因为S1剩下的元素个数大于1产生不同的弹出策略

①第二次弹出个1,S1空 S2{3,3} 输出3+3

②第二次弹出个1,S1{1} S2{2,3} ,继续弹出一个1 S1空 S2{1,2,3} 输出 3+2+1

③第二次弹出个1,S1{1,1} S2{1,3},弹出一个1 S1{1} S2{1,1,3}, 弹出一个1 S1空

S2{1,1,1,3}

......如此一直到

第一次弹出一个1 S1{1,1,1,1,1,1} S2{1},弹出一个1 S1{1,1,1,1} S2{1,1} 弹出一个

S1{1,1,1} S2{1,1,1} ......最后S1空 S2{1,1,1,1,1,1} 输出1+1+1+1+1+1

 

思路实际上还是很清晰的,在写代码的时候,实际上栈S1根本不需要存在....因为我们在弹出N

个元素的时候运算之后的结果是N,在压入S2栈,这个过程实际上我们根本不需要栈S1,我们只需

要一个变量来记录这个不存在的栈还有几个元素,就足够了,下面的代码段描述的就是这个事情

大家看到没有,我们的栈S1实际上并不参与我们的计算.

完整的代码如下

 

若有错误或者其他更好的想法,欢迎讨论

 

 

 

 

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值