代码随想录算法训练营第29天|回溯算法part02|216. 组合总和 III、17. 电话号码的字母组合
216. 组合总和 III
自己做
思路:
相比77. 组合,多了一个相加之和必须为n的条件,在不考虑剪支的条件下,在77. 组合的基础上代码的确定终止条件部分加上求和条件并修改集合范围,即可做出本题
代码:
python
class Solution(object):
def __init__(self):
self.path = []
self.result = []
def combinationSum3(self, k, n):
"""
:type k: int
:type n: int
:rtype: List[List[int]]
"""
#
self.backtracking(n, k, 1)
return self.result
def backtracking(self, n, k, startIndex): # 1. 确定参数和返回值
# 2. 确定终止条件
if len(self.path) == k and sum(self.path) == n:
#print(self.path)
self.result.append(list(self.path))
return
# 3. 确定单层递归逻辑
for index in range(startIndex, 10):
self.path.append(index)
self.backtracking(n, k, index+1)
self.path.pop()
return
代码随想录
思路:
本题k相当于树的深度,9(因为整个集合就是9个数)就是树的宽度。
例如 k = 2,n = 4的话,就是在集合[1,2,3,4,5,6,7,8,9]中求 k(个数) = 2, n(和) = 4的组合。
选取过程如图:
重点是剪支操作
- 已选元素总和如果已经大于n(图中数值为4)了,那么往后遍历就没有意义了,直接剪掉
- 如果集合中剩余的元素的数量不够构成大小为k的子集,就没有必要继续寻找下去
代码:
python
class Solution(object):
def __init__(self):
self.path = []
self.result = []
def combinationSum3(self, k, n):
"""
:type k: int
:type n: int
:rtype: List[List[int]]
"""
#
self.backtracking(k, n, 0, 1)
return self.result
def backtracking(self, k, n, curSum, startIndex): # 1. 确定参数和返回值
# 2. 确定终止条件
if len(self.path) == k:
if curSum == n:
self.result.append(list(self.path))
return
else:
return
# 3. 确定单层递归逻辑
for index in range(startIndex, 9-(k-len(self.path))+2): # 剪支1
curSum += index
self.path.append(index)
if curSum > n: # 剪支2
curSum -= index
self.path.pop()
return
self.backtracking(k, n, curSum, index+1)
curSum -= index
self.path.pop()
return
17.电话号码的字母组合
自己做
思路:
- 数字对应了字母集合:将数字字符串转换成对应的字符串列表
- 列表中的每个字符串取一个元素进行组合
代码:
python
class Solution(object):
def __init__(self):
self.path = ''
self.result = []
def letterCombinations(self, digits):
"""
:type digits: str
:rtype: List[str]
"""
if len(digits) == 0:
return []
letters_list = self.number2letters(digits)
self.backtracking(len(digits), letters_list, 0)
return self.result
def backtracking(self, k, letters_list, startIndex): # 1. 确定参数和返回值
# 2. 确定终止条件
if len(self.path) == k:
self.result.append(''.join(self.path))
return
# 3. 确定单层递归逻辑
for letter in letters_list[startIndex]: # 循环字符串列表的每个字符
# a,b,c
self.path += letter # 加入到路径中
self.backtracking(k, letters_list, startIndex+1) # 列表索引+1,去下一个字符串中取元素
self.path = self.path[:-1] # 回溯
return
# 将数字字符串转换成对应的字符串列表
def number2letters(self, digits):
letter_list = []
for number in digits:
number = int(number)
if number in range(2, 7):
letters = []
for index in range(3):
letters.append(chr(ord('a')+3*(number-2) + index))
letter_list.append(''.join(letters))
if number == 7:
letter_list.append('pqrs')
if number == 8:
letter_list.append('tuv')
if number == 9:
letter_list.append('wxyz')
return letter_list
代码随想录
思路:
理解本题后,要解决如下三个问题:
- 数字和字母如何映射
- 两个字母就两个for循环,三个字符我就三个for循环,以此类推,然后发现代码根本写不出来
- 输入1 * #按键等等异常情况
数字和字母如何映射:可以使用map或者定义一个二维数组
回溯法来解决n个for循环的问题:
如图抽象为树形结构所示:
回溯三部曲:
- 确定回溯函数参数
参数:
1. digites
2. index: 这个index是记录遍历第几个数字了,就是用来遍历digits的(题目中给出数字字符串),同时index也表示树的深度。
- 确定终止条件
index == len(digits) 就终止
- 确定单层遍历逻辑
首先要取index指向的数字,并找到对应的字符集(手机键盘的字符集)。
然后for循环来处理这个字符集,代码如下:
```
int digit = digits[index] - '0'; // 将index指向的数字转为int
string letters = letterMap[digit]; // 取数字对应的字符集
for (int i = 0; i < letters.size(); i++) {
s.push_back(letters[i]); // 处理
backtracking(digits, index + 1); // 递归,注意index+1,一下层要处理下一个数字了
s.pop_back(); // 回溯
}
```
注意
因为本题每一个数字代表的是不同集合,也就是求不同集合之间的组合,而77. 组合 (opens new window)和216.组合总和III (opens new window)都是求的同一个集合中的组合!
代码:
python
class Solution:
def __init__(self):
self.letterMap = [
"", # 0
"", # 1
"abc", # 2
"def", # 3
"ghi", # 4
"jkl", # 5
"mno", # 6
"pqrs", # 7
"tuv", # 8
"wxyz" # 9
]
self.result = []
self.s = ""
def backtracking(self, digits, index):
if index == len(digits):
self.result.append(self.s)
return
digit = int(digits[index]) # 将索引处的数字转换为整数
letters = self.letterMap[digit] # 获取对应的字符集
for i in range(len(letters)):
self.s += letters[i] # 处理字符
self.backtracking(digits, index + 1) # 递归调用,注意索引加1,处理下一个数字
self.s = self.s[:-1] # 回溯,删除最后添加的字符
def letterCombinations(self, digits):
if len(digits) == 0:
return self.result
self.backtracking(digits, 0)
return self.result