代码随想录算法训练营Day23
力扣131.分割回文串【medium】
力扣.20组合——剪枝优化【medium】
力扣216.组数总和Ⅲ【medium】
一、力扣131.分割回文串【medium】
题目链接:力扣131.分割回文串
视频链接:代码随想录、灵茶山艾府
1、思路
- 回文串是向前和向后读都相同的字符串——用一个
-1
倒排就可以判断 - 从答案角度出发:枚举回文字串/逗号结束的位置
- 递归函数参数:
i
表示当前处理到字符串的起始位置 - 终止条件:切割线切到了字符串最后面,说明找到了一种切割方法,
i=n
- 单层搜索的逻辑:遍历所有可能的结束位置
j
,分割子串s[i.j+1];判断是否回文,是在添加到路径,递归考虑剩余的字串怎么切割,最后pop - 注意这边并不需要找到一个path就添加到ans中,而是要都切割完才可以。
- 时间复杂度: O ( n ∗ 2 n ) O(n*2^n) O(n∗2n),其中 n 为 s 的长度。答案的长度至多为逗号子集的个数,即 O ( 2 n ) O(2 ^n) O(2n),因此会递归 O ( 2 n ) O(2 ^n) O(2n)次,再算上判断回文和加入答案时需要 O ( n ) O(n) O(n) 的时间,所以时间复杂度为 O ( n ∗ 2 n ) O(n*2^n) O(n∗2n)。
2、代码
class Solution:
def partition(self, s: str) -> List[List[str]]:
n = len(s)
ans = []
path = []
def dfs(i): # i 表示回文子串结束的位置 / 表示当前处理到字符串的起始位置
# 如果起始位置已经到达字符串末尾,说明当前分割完成
if i == n:
ans.append(path.copy())
return
# 遍历所有可能的结束位置j,分割子串s[i..j]
for j in range(i, n):
t = s[i:j+1]
if t == t[::-1]:
path.append(t)
dfs(j+1) # 递归处理剩余子串s[j.+1.n-1]
path.pop() # 回溯,移除当前子串,尝试其他分割方式
dfs(0)
return ans
3、代码问题
- 太难了,理解的还不到位
二、力扣77.组合——剪枝优化【medium】
题目链接:力扣77.组合——剪枝优化
视频链接:代码随想录
1、思路
- 如果还可以选的数
i
的个数比还需要选的数d = k - len(path)
来的小,那就不用继续往下迭代,直接结束 - 时间复杂度: O ( k ∗ C n k ) O(k*C_n^k) O(k∗Cnk)
2、代码
- 答案视角
class Solution:
def combine(self,n:int,k:int) -> List[List[int]]:
ans = []
path = []
def dfs(i):
d = k - len(path)
if i < d :
return
if len(path) == k:
ans.append(path.copy())
return
for j in range(i, 0, -1):
path.append(j)
dfs(j-1)
path.pop()
dfs(n)
return ans
- 输出视角
class Solution:
def combine(Self,n:int,k:int) -> List[List[int]]:
ans = []
path = []
def dfs(i):
d = k - len(path)
if d == 0:
ans.append(path.copy())
return
# 不选 i ;如果i比d来的小就必须选了
if i > d:
dfs(i-1)
path.append(i)
dfs(i-1)
path.pop()
dfs(n)
return ans
3、代码问题
if i < d : return
可以删掉,在for
循环那里的终止区间改成d-1
三、力扣216.组数总和Ⅲ【medium】
题目链接:力扣216.组数总和Ⅲ【medium】
left =x300
视频链接:代码随想录
1、思路
- 和组合那题类似,这边多一个目标:
k
数之和为n
,我们可以给dfs
多设置一个参数target
,表示我们剩余的目标之和 - 剪枝:如果
t<0
,说明已经超过目标n,终止.如果t
大到剩下的d
个数加起来都不够t > (i * 2 - d + 1) * d // 2
,终止 - 时间复杂度: O ( k ∗ C 9 k ) O(k*C_9^k) O(k∗C9k)
2、代码
class Solution:
def combinationSum3(self, k: int, n: int) -> List[List[int]]:
ans = []
path = []
def dfs(i,t):
d = k - len(path)
if t < 0 or t > (i * 2 - d + 1) * d // 2:
return
if len(path) == k:
ans.append(path.copy())
return
for j in range(i, d-1, -1):
path.append(j)
dfs(j-1, t-j)
path.pop()
dfs(9,n)
return ans
3、代码问题
- 这边不用再额外判断t是否等于0,因为if的那两个判断的就是t大于零或者t小于零的情况