LeetCode 77 组合

给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]

示例 2:

输入:n = 1, k = 1
输出:[[1]]

提示:

  • 1 <= n <= 20
  • 1 <= k <= n

解题:

func combine(n int, k int) [][]int {
	var r [][]int
	var t []int
	b := make([]bool, n)
	var backtrack func(m int)
	backtrack = func(m int) {
		if len(t) == k {
			tmp := make([]int, k)
			copy(tmp, t)
			r = append(r, tmp)
			return
		}
		for j := m; j < n; j++ {
			if b[j] || (m > 0 && j < t[len(t)-1]) {
				continue
			}
			t = append(t, j+1)
			b[j] = true
			backtrack(m + 1)
			t = t[:len(t)-1]
			b[j] = false
		}
	}
	backtrack(0)
	return r
}

官方解答:

1.递归实现组合型枚举

func combine(n int, k int) (ans [][]int) {
	var temp []int
	var dfs func(int)
	dfs = func(cur int) {
		// 剪枝:temp 长度加上区间 [cur, n] 的长度小于 k,不可能构造出长度为 k 的 temp
		if len(temp)+(n-cur+1) < k {
			return
		}
		// 记录合法的答案
		if len(temp) == k {
			comb := make([]int, k)
			copy(comb, temp)
			ans = append(ans, comb)
			return
		}
		// 考虑选择当前位置
		temp = append(temp, cur)
		dfs(cur + 1)
		temp = temp[:len(temp)-1]
		// 考虑不选择当前位置
		dfs(cur + 1)
	}
	dfs(1)
	return
}

2.非递归(字典序法)实现组合型枚举

func combine(n int, k int) (ans [][]int) {
	// 初始化
	// 将 temp 中 [0, k - 1] 每个位置 i 设置为 i + 1,即 [0, k - 1] 存 [1, k]
	// 末尾加一位 n + 1 作为哨兵
	var temp []int
	for i := 1; i <= k; i++ {
		temp = append(temp, i)
	}
	temp = append(temp, n+1)

	for j := 0; j < k; {
		comb := make([]int, k)
		copy(comb, temp[:k])
		ans = append(ans, comb)
		// 寻找第一个 temp[j] + 1 != temp[j + 1] 的位置 t
		// 我们需要把 [0, t - 1] 区间内的每个位置重置成 [1, t]
		for j = 0; j < k && temp[j]+1 == temp[j+1]; j++ {
			temp[j] = j + 1
		}
		// j 是第一个 temp[j] + 1 != temp[j + 1] 的位置
		temp[j]++
	}
	return
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注