LeetCode之77. Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

Example:

Input: n = 4, k = 2
Output:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

是一种穷举遍历的思想;

自己的代码:(递归 DFS)

Runtime: 39 ms, faster than 37.50% of Java online submissions for Combinations.

Memory Usage: 43.8 MB, less than 26.50% of Java online submissions for Combinations.

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;


class Solution {
	
	  public static List<List<Integer>> combine(int n, int k) {
	  
		  List<List<Integer>> results = new ArrayList<>();
		  List<Integer> tempList = new ArrayList<>();	
		  
		  helper(results,tempList,1,n,k);
		  
		  return results;
	  }
	  
	  public static void helper(List<List<Integer>> results ,List<Integer> tempList,int start,int n, int k) {
		  
		  if(k == 0) {
			  List<Integer> list = new ArrayList<>();
			  for(Integer i : tempList) {
				  list.add(i);
			  }
			  results.add(list);
			  
			  return;
		  }
		  
		  for(int i=start;i<=n;i++) {
			  tempList.add(i);// not add(start)

			  helper(results,tempList,i+1,n,k-1); // 参数三:是i+1,不是start+1

			  tempList.remove(new Integer(i));
		  }
	  }
	 

	public static void main(String[] args) {
		int n = 4;
		int k = 2;
		
		List<List<Integer>> list = combine(n,k);
		
		System.out.println(list);
		
	}
}

              递归思想:(分解成子问题)

   0)因为不确定k的大小,所以想到用递归

              1)helper(start,n,k)的功能就是获得从start到n的数,组成的长度为k的所有可能结果

              2)那么helper(start+1,n,k-1)的功能就是获得从start+1到n的数,组成的长度为k-1的所有可能结果

 

自己的代码2

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

public class WelcomeApp {

	private static int count = 0;
	private static StringBuilder sb = new StringBuilder();
	private static List<String> lists = new ArrayList<>();

	// 获得n选k的全部组合
	public static void getK(int n, int k, int index,int start) {

		if(index > 3) {
			lists.add(sb.toString());
			count++;
			return;
		}

		for(int i=start;i<=n-k+1;i++) {
			String temp = i+" ";
			sb.append(temp);

			getK(n, k-1, index+1,i+1); // 注意第2 3 4个参数的设置;

			sb.delete(sb.length()-temp.length(), sb.length()); // 这句回溯一定不能少
		}

	}

	public static void main(String[] args) {

		int n=12;// 1,2,3,4,5
		int k=3;//取出3个数

		getK(n, k, 1,1);

		for(String str : lists) { 
			System.out.println(str);
		}

		System.out.println("count = "+count);

	}

}

小结:

a)应用DFS进行穷举遍历时,回溯的步骤是一定不能少的

 

别人的代码:

方法一:递归 + 回溯(和我的思路一模一样)

class Solution {
    public static List<List<Integer>> combine(int n, int k) {
		List<List<Integer>> combs = new ArrayList<List<Integer>>();
		combine(combs, new ArrayList<Integer>(), 1, n, k);
		return combs;
	}
	public static void combine(List<List<Integer>> combs, List<Integer> comb, int start, int n, int k) {
		if(k==0) {
			combs.add(new ArrayList<Integer>(comb)); // 直接通过构造函数,复制一个list
			return;
		}
		for(int i=start;i<=n;i++) {
			comb.add(i);
			combine(combs, comb, i+1, n, k-1);
			comb.remove(comb.size()-1);  // 使用的是remove(index)这个方法
		}
	}
}

              1)时间复杂度:The time complexity is "n times n choose k".

                  "n choose k" equals (n!/((n-k)! * k!)). In full notation is O(n * (n!/((n-k)! * k!))).

                   We will have "n choose k" combinations and in each call we will do O(n) work to copy the array to the answer.

 

和方法一相同的思路的Python解法:

class Solution(object):
    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        res = []
        def gen(i, tmp):
            if len(tmp) == k:
                res.append(list(tmp))
                return
            if i > n:
                return
            for j in range(i, n+1):
                tmp.append(j)
                gen(j+1, tmp)
                tmp.pop()
        gen(1, [])
        return res
class Solution(object):
    def combine(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: List[List[int]]
        """
        results = []
        result = []
        def DFS(results, result, start, n, k):
            if(k==len(result)):
                results.append(copy.deepcopy(result))	# python append()与深拷贝、浅拷贝应该注意,此处有一个大坑
                return  
            for i in range(start,n+1,1):
                result.append(i)
                DFS(results, result, i+1, n, k)
                result.pop()
        
        DFS(results, result, 1, n, k)
        return results
"""
[Python]_DFS_beats 97.24%

The key is to stop earlier (i.e. prune the search space) if the number of numbers could be selected (n-i) is less than the number of numbers we need to select (k).
      当剩余的可以被选择的数的个数n-i,小于我们所需要选择的数的个数k,那么就提前终止,不用递归函数再进行下去
"""

class Solution:
    def combine(self, n: 'int', k: 'int') -> 'List[List[int]]':
        res = []
        cur = []
        self.combine_helper(n, k, 0, cur, res)
        return res
    def combine_helper(self, n, k, idx, cur, res):
        if k == 0:
            res.append(cur[:])
        else:
            for i in range(idx, n):
                if k > (n-i):
                    break
                val = i + 1
                cur.append(val)
                self.combine_helper(n, k-1, i+1, cur, res)
                cur.pop()

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值