递归算法(求n的加法组合,将一个整数拆分成多个整数相加的形式, O(N)时间,O(N)空间)

原创 2016年08月30日 16:56:20


网上的多种解法比较复杂,本文用递归方法,22行代码搞定。时间和空间复杂度已经降到最低!

第三版:加入创作思路。

这个函数的主要功能就是输出所有组合。既然是输出所有的组合,那就意味着内部有一个遍历所有组合的过程。既然是遍历,而且是O(N)时间,那就说明这个遍历是按照某种输出次序,从“第一个组合”遍历到“最后一个组合”。

如何给组合定义次序呢?举例说明

例1:

3=1+1+1

3=1+2

3=3

上面的例子就说明了次序,即,按照组合中出现数字的从小到大顺序。

定义了次序,剩下的就是如何让程序按照这个程序一个一个的遍历。遍历的过程不会那么完美的一个不重复,当然也会重复,这就涉及到过滤。过滤那些重复的元素,举例说明

例2:

3=1+1+1

3=1+2

3=2+1

3=3

可以看出这个例2中的3=2+1被过滤掉了,并没有输出,这也是必须的,为什么呢?因为3=2+1和之前出现的3=1+2本质上就是一种组合,还要交换一下数字的位置就可以了。而加法自然有交换率。所以就不必输出了。从这里还可以看出来过滤的依据,那就是让一个组合中的所有数字也保持从小到大出现,这样就不会出现3=2+1了,因为2比1大,之前肯定出现过了。这样一来就解决了输出的唯一性

至此,就剩下如递归的进行了。递归的思路是这样的,例如拆分3:

既然

 3=1+后续组合

那么递归也就自然的变成了对“后续组合”进行继续拆分,只要“后续组合“的所有排列找到了,后续组合的每个排列前面加上1这个前缀自然就解决了1作为前缀的所有情况,这样一来就会遍历到

3=1+1+1

3=1+2

由于组合次序的定义可以知道,1作为前缀的情况被遍历完之后,自然就变成了遍历2开头的数字

2开头的数字还需要遍历吗?基于如下事实

n=m1+m2+...+mk, m1<m2<...<mk

第一个数字m1不会超过n/2,因为m1后面的数字要比m1大。所以可以看出,遍历的时候第一个数字最多尝试到n/2.

但是m1最大取n/2是合理的,比如

11=5+6

也就是说拆分的时候总是有拆分成两个数的和的形式,其中n=m1+m2,m1<m2,这样一来m1取n/2就是合适的。

那么下面就是递归程序的实现了。

f(int n,list l,int start)

参数说明:

n:这里n表示要对n进行拆分

l:这里表示子拆分的时候前缀的那些子递增序列,当n被初次拆分的时候,list当然是空的,只有子拆分才会有非空的前缀

start:表示在遍历的时候当前组合的第一个数字,这个数字用来去除重复,参考输出的唯一性

java实现:

public class Sum1ToN {

    private void print(List<Integer> list) {
        for (Integer k : list) {
            System.out.print(k + "+");
        }
    }

    private void f(int n, List<Integer> list, int start) {
        if (n == 1) {
            print(list);
            System.out.println(1);
        } else {
            for (int i = start; i <=n / 2; i++) {
                list.add(i);
                f(n - i, list, i);
                list.remove(list.size() -1);
            }
            print(list);
            System.out.println(n);

        }
    }

    public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        new Sum1ToN().f(9,list, 1);
    }

}


 输出:f(9,null,1)

参考:http://blog.csdn.net/calmreason/article/details/8024342

版权声明:欢迎转载,请注明出处:http://blog.csdn.net/bluetjs

相关文章推荐

组合的两种递归算法

组合就是从n个物品中任意选择m个组成一组,下面两种递归算法都可以求出不同的组合,如果待选物品当中有重复的,比如说下面代码中an = new char[]{'1','2','3','4','5'} 变成...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

递归算法之全组合排列

输入: 给定数据数N,然后输入n个数字,找出所有的排列数。 输出: 输出所有的排列数。 样例输入: 3 1 2 3 样例输出: 123 132 213 231 312 321...

用递归实现排列组合(java代码)

全排列递归算法思想:假设求abcdefg的全排列,先将第一个字母确定为a,然后求bcdefg的全排列就行了,然后将a与b交换位置,重复上述过程,直到a和g交换。 全组合递归算法思想:假设求abcde...

整数拆分问题的四种解法

经典整数拆分的问题的算法设计与实现,分别给出递归版本、动态规划版本、五边形数定理版本、母函数版本四种算法设计与实现...

acm题目及我的程序(3)——正整数n的加法组合

在网上看到的acm题目,来源忘记了,现在贴出自己的算法。 要求:一个正整数n可以写为几个正整数的和,如:4=44=3+14=2+24=2+1+14=1+1+1+1输入一个正整数,找出符合这种要求的所有...

java将一个正整数分解质因数(每天一道算法题)

将一个正整数分解质因数。例如:输入60;打印出2*3*5*2 算法实现构思: 用Scanner实现输入一个正整数n 用一个for循环遍历一个从 k=2开始查找到k...

[算法]将一个正整数拆分成若干个正整数的和,输出所有的结果不重复

推荐先看我的一篇介绍Set去重的博文地址是 http://blog.csdn.net/bug_moving 看了这个之后,再来看下面的程序基本就能看懂了题目我也不太记得,因为是朋友给我口述的,然后...

利用递归实现1到100以内的求和

一、什么叫做递归?

将一个数m分解为n个不同的数之和(积)

简单递归求解.#include "iostream" #include "vector" #include "algorithm" using namespace std; #define N 4 v...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:递归算法(求n的加法组合,将一个整数拆分成多个整数相加的形式, O(N)时间,O(N)空间)
举报原因:
原因补充:

(最多只允许输入30个字)