文章目录
- [LeetCode:39. 组合总和](#LeetCode:39. 组合总和)
- [LeetCode:40. 组合总和II](#LeetCode:40. 组合总和II)
- [LeetCode:131. 分割回文串](#LeetCode:131. 分割回文串)
LeetCode:39. 组合总和
https://leetcode.cn/problems/combination-sum/description/
思路
先将 candidates 排序。排序后,如果当前数字已经大于剩余目标值,那么它后面的数字只会更大,可以立即跳出循环。
解答
python
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
def backtrack(remaining, start, current):
if remaining == 0: # 如果剩余值为0,说明当前组合有效
result.append(list(current))
return
for i in range(start, len(candidates)):
num = candidates[i]
if num > remaining:
break
current.append(num)
backtrack(remaining - num, i, current)
current.pop()
candidates.sort() # 排序以便剪枝
result = []
backtrack(target, 0, [])
return result
LeetCode:40. 组合总和II
https://leetcode.cn/problems/combination-sum-ii/
思路
先将 candidates 排序。同一层递归中,如果当前数字和前一个数字相同,并且前一个数字在本层已经使用过(即 i > start),那么以当前数字开头的所有组合都会与以前一个数字开头的组合重复,因此跳过。注意这里 i > start 的条件保证了我们只跳过同一层中的重复,而不影响不同层(例如 [1,1,2] 中两个 1 可以同时出现在一个组合中,因为它们在递归的不同层)。
解答
python
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
results = []
n = len(candidates)
def backtrack(remain: int, start: int, path: List[int]) -> None:
if remain == 0:
results.append(path[:])
return
for i in range(start, n):
if candidates[i] > remain:
break
# 去重:同一层递归中,如果当前数字和前一个数字相同,跳过
if i > start and candidates[i] == candidates[i - 1]:
continue
path.append(candidates[i])
backtrack(remain - candidates[i], i + 1, path)
path.pop()
candidates.sort()
backtrack(target, 0, [])
return results
LeetCode:131. 分割回文串
https://leetcode.cn/problems/palindrome-partitioning/description/
思路
-
从字符串的起始位置
start开始遍历,尝试所有可能的分割点end。 -
对于每个分割点,检查子串
s[start:end+1]是否是回文。(1)如果是,则将该子串加入当前路径
path,然后递归处理剩余部分。(2)如果不是,则跳过该分割点,继续尝试下一个。
-
当
start到达字符串末尾时,说明找到了一个完整的分割方案,将当前路径加入结果。 -
回溯:在递归返回后,将最后加入的子串弹出,以便尝试其他分割方式。
解答
python
class Solution:
def partition(self, s: str) -> List[List[str]]:
n = len(s)
results = []
path = []
def backtrack(start: int):
if start == n:
results.append(path[:])
return
for end in range(start, n): # 枚举子串的结束位置
sub_s = s[start:end+1]
if sub_s == sub_s[::-1]: # 子串 s[start:end+1] 是回文
path.append(sub_s)
backtrack(end + 1)
path.pop()
backtrack(0)
return results