将一个自然数拆分为若干不重复自然数之和(OO实现)

原题出处:[url]http://www.iteye.com/topic/927532[/url]
使用OO的方式实现会占用更多的内存,在递归调用的时候需要保存每次参数,对性能大打折扣,加大JVM参数到256M后,使用1000测试都会宕掉,然而这里演示的是一种解题思路。

初步结构分析:

/**
* 将一个自然数拆分为若干不重复自然数之和。
* 以10为例:
* 1+9 --对原数据(10)的初次拆分(拆为m+n)应该很容易
* |_2+7 --对9拆分为x+y,x应该大于1,这样就避免了因子重复
* |_3+4 --对7拆分为i+j,i应该大于2,以此规律持续下去
* |_3+6 --此处依然对9拆分
* |_4+5
* 2+8
* |_3+5
* 3+7 --7,在此处无法拆分,否则导致重复
* 4+6
*/

java代码如下:

import java.util.ArrayList;
import java.util.List;

public class SplitNumber {
public static void main(String[] args) {
SplitNumber.split(30);
System.out.println("=>DONE...");
}
public static void split(int number){
if(number<3){
System.out.println(number+"=>can not split...");
return;
}
List<Splitor> outer=new ArrayList<Splitor>();
int half=(number+1) >> 1; //+1 计算奇数与偶数的一半
Splitor s=null;
for(int i=1;i<half;i++){ //for-loop:初次拆分为m+n
s=new Splitor();
s.smaller=i; //
s.bigger=number-i;
outer.add(s);
s.splitCenter(s); //是对m+n中的n进行深度拆分
} // end for
for(Splitor t:outer){ //上面拆分完毕后输出
showRetHelper(t.splitors,t);
}
}
/**
* 这个递归很恶心:它要把保存每次传入的参数
* @param sps 按照顺序保存传入的参数
*/
private static void showRetHelper(List<Splitor> splitors,Splitor... sps){
int len=sps.length;
for(int i=0;i<len;i++){ //每次递归前都要先输出各个因子
if(len==1){ //只有一个就输出 smaller+bigger
System.out.print(sps[0]+" ");
break;
}
if(i==len-1){ //最后一个同样输出 smaller+bigger
System.out.print(sps[i]+" ");
}else {
System.out.print(sps[i].smaller+"+"); //不是最后一个就输出小的那个数
}
}
System.out.println(""); //换行
for(Splitor s:splitors){
showRetHelper(s.splitors,copyArray(sps,s)); //保存每次的参数,递归
}
}
private static Splitor[] copyArray(Splitor[] src, Splitor s){ //不多说
if(src==null || src.length==0){
return new Splitor[]{s};
}else{
int srcLength=src.length;
Splitor[] dest=new Splitor[srcLength+1];
System.arraycopy(src, 0, dest, 0, srcLength);
dest[srcLength]=s;
return dest;
}
}

//内部类:对数据的包装
private static class Splitor{
private int smaller;
private int bigger;
private List<Splitor> splitors=new ArrayList<Splitor>(); //作用:构造树

private void add(Splitor s){
this.splitors.add(s);
}
public void splitCenter(Splitor s){
int half=(s.bigger+1) >>1; //+1 计算奇数与偶数的一半,用于for里的小于
int small=s.smaller+1; //+1 防止重复
if(small>=half) return;
Splitor s2=null;
for(int i=small;i<half;i++){
s2=new Splitor();
s2.smaller=i;
s2.bigger=s.bigger-i;
s.add(s2); //s指向s.bigger被拆分的结果集
splitCenter(s2); //recursively 持续拆分
}
}
@Override
public String toString(){
return smaller+"+"+bigger;
}
}
}

对[b]30[/b]测试结果如下:

1+29
1+2+27
1+2+3+24
1+2+3+4+20
1+2+3+4+5+15
1+2+3+4+5+6+9
1+2+3+4+5+7+8
1+2+3+4+6+14
1+2+3+4+7+13
1+2+3+4+8+12
1+2+3+4+9+11
1+2+3+5+19
1+2+3+5+6+13
1+2+3+5+7+12
1+2+3+5+8+11
1+2+3+5+9+10
1+2+3+6+18
1+2+3+6+7+11
1+2+3+6+8+10
1+2+3+7+17
1+2+3+7+8+9
1+2+3+8+16
1+2+3+9+15
1+2+3+10+14
1+2+3+11+13
1+2+4+23
1+2+4+5+18
1+2+4+5+6+12
1+2+4+5+7+11
1+2+4+5+8+10
1+2+4+6+17
1+2+4+6+7+10
1+2+4+6+8+9
1+2+4+7+16
1+2+4+8+15
1+2+4+9+14
1+2+4+10+13
1+2+4+11+12
1+2+5+22
1+2+5+6+16
1+2+5+6+7+9
1+2+5+7+15
1+2+5+8+14
1+2+5+9+13
1+2+5+10+12
1+2+6+21
1+2+6+7+14
1+2+6+8+13
1+2+6+9+12
1+2+6+10+11
1+2+7+20
1+2+7+8+12
1+2+7+9+11
1+2+8+19
1+2+8+9+10
1+2+9+18
1+2+10+17
1+2+11+16
1+2+12+15
1+2+13+14
1+3+26
1+3+4+22
1+3+4+5+17
1+3+4+5+6+11
1+3+4+5+7+10
1+3+4+5+8+9
1+3+4+6+16
1+3+4+6+7+9
1+3+4+7+15
1+3+4+8+14
1+3+4+9+13
1+3+4+10+12
1+3+5+21
1+3+5+6+15
1+3+5+6+7+8
1+3+5+7+14
1+3+5+8+13
1+3+5+9+12
1+3+5+10+11
1+3+6+20
1+3+6+7+13
1+3+6+8+12
1+3+6+9+11
1+3+7+19
1+3+7+8+11
1+3+7+9+10
1+3+8+18
1+3+9+17
1+3+10+16
1+3+11+15
1+3+12+14
1+4+25
1+4+5+20
1+4+5+6+14
1+4+5+7+13
1+4+5+8+12
1+4+5+9+11
1+4+6+19
1+4+6+7+12
1+4+6+8+11
1+4+6+9+10
1+4+7+18
1+4+7+8+10
1+4+8+17
1+4+9+16
1+4+10+15
1+4+11+14
1+4+12+13
1+5+24
1+5+6+18
1+5+6+7+11
1+5+6+8+10
1+5+7+17
1+5+7+8+9
1+5+8+16
1+5+9+15
1+5+10+14
1+5+11+13
1+6+23
1+6+7+16
1+6+8+15
1+6+9+14
1+6+10+13
1+6+11+12
1+7+22
1+7+8+14
1+7+9+13
1+7+10+12
1+8+21
1+8+9+12
1+8+10+11
1+9+20
1+10+19
1+11+18
1+12+17
1+13+16
1+14+15
2+28
2+3+25
2+3+4+21
2+3+4+5+16
2+3+4+5+6+10
2+3+4+5+7+9
2+3+4+6+15
2+3+4+6+7+8
2+3+4+7+14
2+3+4+8+13
2+3+4+9+12
2+3+4+10+11
2+3+5+20
2+3+5+6+14
2+3+5+7+13
2+3+5+8+12
2+3+5+9+11
2+3+6+19
2+3+6+7+12
2+3+6+8+11
2+3+6+9+10
2+3+7+18
2+3+7+8+10
2+3+8+17
2+3+9+16
2+3+10+15
2+3+11+14
2+3+12+13
2+4+24
2+4+5+19
2+4+5+6+13
2+4+5+7+12
2+4+5+8+11
2+4+5+9+10
2+4+6+18
2+4+6+7+11
2+4+6+8+10
2+4+7+17
2+4+7+8+9
2+4+8+16
2+4+9+15
2+4+10+14
2+4+11+13
2+5+23
2+5+6+17
2+5+6+7+10
2+5+6+8+9
2+5+7+16
2+5+8+15
2+5+9+14
2+5+10+13
2+5+11+12
2+6+22
2+6+7+15
2+6+8+14
2+6+9+13
2+6+10+12
2+7+21
2+7+8+13
2+7+9+12
2+7+10+11
2+8+20
2+8+9+11
2+9+19
2+10+18
2+11+17
2+12+16
2+13+15
3+27
3+4+23
3+4+5+18
3+4+5+6+12
3+4+5+7+11
3+4+5+8+10
3+4+6+17
3+4+6+7+10
3+4+6+8+9
3+4+7+16
3+4+8+15
3+4+9+14
3+4+10+13
3+4+11+12
3+5+22
3+5+6+16
3+5+6+7+9
3+5+7+15
3+5+8+14
3+5+9+13
3+5+10+12
3+6+21
3+6+7+14
3+6+8+13
3+6+9+12
3+6+10+11
3+7+20
3+7+8+12
3+7+9+11
3+8+19
3+8+9+10
3+9+18
3+10+17
3+11+16
3+12+15
3+13+14
4+26
4+5+21
4+5+6+15
4+5+6+7+8
4+5+7+14
4+5+8+13
4+5+9+12
4+5+10+11
4+6+20
4+6+7+13
4+6+8+12
4+6+9+11
4+7+19
4+7+8+11
4+7+9+10
4+8+18
4+9+17
4+10+16
4+11+15
4+12+14
5+25
5+6+19
5+6+7+12
5+6+8+11
5+6+9+10
5+7+18
5+7+8+10
5+8+17
5+9+16
5+10+15
5+11+14
5+12+13
6+24
6+7+17
6+7+8+9
6+8+16
6+9+15
6+10+14
6+11+13
7+23
7+8+15
7+9+14
7+10+13
7+11+12
8+22
8+9+13
8+10+12
9+21
9+10+11
10+20
11+19
12+18
13+17
14+16
=>DONE...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值