Leetcode - Combinations

Paste_Image.png

My code:

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

public class Solution {
    public List> combine(int n, int k) {
        ArrayList> result = new ArrayList>();
        if (n <= 0 || k <= 0 || k > n)
            return result;
        ArrayList sample = new ArrayList();

        combine(1, n, k, sample, result);
        
        return result;
    }
    
    private void combine(int begin, int end, int k, ArrayList sample, ArrayList> result) {
        if (k <= 0)
            result.add(new ArrayList(sample));
        else {
            for (int i = begin; i <= end; i++) {
                sample.add(i);
                combine(i + 1, end, k - 1, sample, result);
                sample.remove(sample.size() - 1);
            }
            
            
        }   
    }
    
    public static void main(String[] args) {
        Solution test = new Solution();
        System.out.println(test.combine(5,3));
        
        
    }
}

My test result:

Paste_Image.png

好久没有做题了。。。十天。等等说。

这道题目着实不错啊。思路到现在也是精神上理解了下。
其实就是。比如 5, 3

那么一开始,
1, 2, 3 进袋。
然后 有个删除成员的细节操作,所以又变为,
1, 2 继续for 循环
然后 i = 4. 于是。
1, 2, 4 进袋。
1, 2, 5. 进袋。
然后for循环结束。整个函数结束,跳转到上一个递归处。即。
1, 然后插入2.
于是,删除2,继续for循环。
插入3, 于是
1, 3, 继续递归。。
以此类推。
我之前的确一直有这样的迷惑。
ArrayList, Queue, Stack 这些可以存储数据的包类,该如何在递归思想中保证其唯一性。
比如。
ArrayList a;
recursion(5, a);
...

当此处继续对a进行操作时,a的内容已经发生了变化。可能多了一些元素,也可能少了一些元素。因为他是和递归中的那些ArrayList 引用指向的同一个内存块。所以是统一的。
所以这段代码有个细节。

if (k <= 0)
            result.add(new ArrayList(sample));

为什么要新new一个ArrayList对象呢?因为储存在result这个范围内的仍然是指针,指向sample的那个内存块。如果不新new一个然后把原内容拷贝进来,那么就是仍指向原内存。那么存储的所有的指针都是指向同一个内存块sample,然后打印出来的内容都是sample最后状态的内容。所以必须先new一个。

这个算法还是一如既往的细致,灵巧。赞!

好久没刷题了。一恍惚,十天过去了,本来这十天可以干很多事的。算了,暑假在家没有怎么休息过,之前的确过于认真了,就算放松这十天吧。
哎,马上就要走了,没想到,在英国期盼的这些事,
见到爸妈然后狂吃美食,毕业典礼和同学的狂欢,和丹妮碰面一起旅行,和童年的小伙伴一起聚聚。。。这些事,这些盼了半年的事,这些一想起来就激动不已的事,竟然就这么过去了。
其实很多都做得还不够好,玩的不够尽兴。尤其是毕业典礼。刚回校三天,刚适应同学的体温,学校就强制离校了。
和丹妮,时间实在是太短了,短的我想带她去各处玩却发现哪个地方时间都是那么的紧。你至少给我十天啊,老天。??
这个世界上有条路,叫做, California State Route 1. I hope I can drive you through this long road, my girl, away from anything, everything, just you, and me.
爸妈的话,我内心是无比爱他们的,但是总觉得说出来肉麻,然后说不出来。有时候还故意气气他们,但他们的确为了做了太多太多。
昨天老爸50岁生日,但是过得很简单,就我和我妈陪着他,我们三个人。
他对我提出了他的要求,
第一,留学在外,人身安全第一位,绝对要注意安全,维护身体健康。
第二,要做一个让爸妈说起来觉得骄傲的儿子。
我会,努力去做到的,为了你们,也为了我。
今天去和表哥还有他女朋友吃了一顿饭,挺好的,我对她也挺满意的。心里不知道为什么,挺高兴的,好久没这么高兴了。也许他是我内心中,认为的,很重要很重要的人吧。
但是表哥工作最近被辞了,然后还没找到工作,这个事也一直瞒着那个姑娘,毕竟表哥条件不是很好,人家姑娘已经很好了,如果知道他现在没了工作,对于,结婚,还是会犹豫一些吧。所以瞒着她,打算先找到工作再说。
从小到大,我总觉得,因为一些自己弱的原因而去隐瞒,而去骗人,给自己所带来的屈辱,远比把这种弱的原因暴露出来更加让人感到羞耻。我一直记得小时候考得不好,别人问我成绩,我妈想撒撒谎,要点面子,但我爸就坚决不同意,就是得说真的。
我真觉得,这是一个好习惯。
一个连自己弱点都无法正视的人,又谈何奋发去改变这些弱点呢?
哎,想说的还有好多,我还是很怀念英国的日子,真的太美好了。
有机会,我一定要把那些写成一篇文章,发在这里。QQ空间实在是不太好意思发文章了,否则别人会觉得我又情绪泛滥了。
奈何,我就是个情绪泛滥的人。这算不算,不敢正视自己的弱点。
哈哈,我觉得,根本不算。
对了,给那个美国朋友写去的邮件还没回,不正常。估计是给我里面一段描写我对资本主义理解的文章所激怒了吧。哈哈。希望不是。还想着感恩节去他家做客呢。
**
总结:递归,Array, 如何保证递归中ArrayList的统一性。
**

Anyway, Good luck, Richardo!

My code:

public class Solution {
    public List> combine(int n, int k) {
        ArrayList> ret = new ArrayList>();
        if (n <= 0 || k <= 0 || k > n) {
            return ret;
        }
        helper(1, k, n, ret, new ArrayList());
        return ret;
    }
    
    private void helper(int begin, int k, int n, List> ret, List group) {
        if (group.size() > k) {
            return;
        }
        else if (group.size() == k) {
            ret.add(new ArrayList(group));
            return;
        }
        else {
            if (begin > n) {
                return;
            }
            else {
                for (int i = begin; i <= n; i++) {
                    group.add(i);
                    helper(i + 1, k, n, ret, group);
                    group.remove(group.size() - 1);
                }
            }
        }
    }
}

差不多的做法。

Combination 还有一种更高效的解法:

public class Solution {
    public List> combine(int n, int k) {
        List> ret = new ArrayList>();
        if (k < 0 || k > n) {
            return ret;
        }
        else if (k == 0) {
            ret.add(new ArrayList());
            return ret;
        }
        else {
            ret = combine(n - 1, k - 1);
            for (List list : ret) {
                list.add(n);
            }
            
            ret.addAll(combine(n - 1, k));
            return ret;
        }
     }
}

复杂度应该都在 O(n!) 左右。
这个做法的思想就是。
对于一个数,他只有两种情况:
要么在 combination 中,
要么不在。

combine(n - 1, k - 1) 算出在的情况,然后统一加入 n
combine(n - 1, k) 算出不在的情况,直接插入ret

Anyway, Good luck, Richardo! -- 08/06/2016

你可能感兴趣的:(Leetcode - Combinations)