[题解][LeetCode][Combinations]

题目:

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

For example,
If n = 4 and k = 2, a solution is:

[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

题解:

递归回溯

递归回溯的一一列举每种情况即可。

注意:

1. 递归的时候,可以选择print一些参数出来,方便调试。

2. 注意遍历的深度,以及在每一个位置,应该遍历到哪个数字为止


Code:

class Solution:
	# @return a list of lists of integers
	def __init__(self):
		self.a = []
		self.ans = []

	def make(self, x, p, n, k):

		print (x,p,n,k)
		if p == k:
			self.ans.append(list(self.a))
			print(self.a)
		else:
			for i in range(x+1, n-k+p+2):
				self.a.append(i)
				self.make(self, i, p+1, n, k)
				self.a.pop()

	def combine(self, n, k):

		if n == k:
			self.ans = [list(range(1,n+1))]
		else:
			self.a = []
			self.ans = []
			for i in range(1,n-k+2):
				self.a.append(i)
				self.make(self, i, 1, n, k)
				self.a.pop()
		return self.ans


但是,这个代码太丑了!...并且,会超时...

递归需要系统堆栈,消耗的空间大,而且消耗的时间也多。

大部分的递归都能改成循环或者递推!



题解2:

生成第一个list,即 [1,2,3...k]

然后直接在这个list上面操作:

每次都是在最后一位(即第k位)上+1,若第k位超过了n,那么从k-1位由后往前依次检查每位,是否比n-k+i大(i是第几位)(即当前这位是否已经到达了这位可以取的数字的上限)

例如,n=6, k = 4

现在是[2,3,5,6],最后一位+1,超过了n=6,那么从k-1位开始向前检查,k-1位是5,已经取到了这位的上限(不能取6),然后检查k-2位,3,还可以+1.


那么,找到还未到达上限的位置之后,将这个位置上的数字+1,后面的数字依次+1

即,下一个是[2,4,5,6]


当检查,检查到第一位,发现也已经到达上限,那么break,结束。


Code2:

class Solution:
	def combine(self, n, k):
		a = list(range(1,k+1))
		ans = []
		ans.append(list(a))
		while sum(a) < n*k:
			a[k-1] += 1
			i = k-1
			if a[i] > n:
				i -= 1
				while i>=0 and a[i]>n-k+i:
					i -= 1
				if i == -1:
					break
				a[i] += 1
				i += 1
				while i < k:
					a[i] = a[i-1]+1
					i+=1
			ans.append(list(a))
		return ans


注意:

每次我们都是将产生的list加入answer list,然后再在这个list上修改,那么当我们将当前list加入answer list的时候,我们需要使用深拷贝而不是浅拷贝。

如果我们直接使用ans.append(a)的话,即为浅拷贝,当我们修改a中元素的时候,ans中的元素也会对应被修改。所以,我们要使用ans.append(list)


Python的浅拷贝和深拷贝:

1.浅拷贝:使用copy.copy,它复制了对象,但对于对象中的元素,依然使用引用。 

2.深拷贝:使用copy.deepcopy,不仅复制了对象,同时也复制了对象中的元素。

3.复制列表Llist(L)

4.复制字典ddict(d)

5.复制集合s set(s)



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值