39. 组合总和
1. 组合没有数量要求
2. 元素可无限重复选取
class Solution(object):
def backtracking(self,cadinates,target,sum_,startindex,path,result):
# recursion stop condition
if sum_ > target:
# we can't find any answer set
return
if sum_ == target:
# collect the answer set
result.append(path[:])
return
# each level recursion logic
for i in range(startindex,len(cadinates)):
# add number to our array
sum_ += cadinates[i]
path.append(cadinates[i])
# recursion
self.backtracking(cadinates,target,sum_,i,path,result)
# backtracking
sum_ -= cadinates[i]
path.pop()
def combinationSum(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
# sort the cadinates array
candidates.sort()
result = [] # collect our answer set
self.backtracking(candidates,target,0,0,[],result)
return result
40.组合总和II
0. nums集合要排序,要把相同的元素相邻再一起
1. 需要去重,不能出现重复的组合
2. 树层去重,树枝去重
1. 需要一个变量告诉我们,那个元素我们使用过
1. 如果该元素使用过赋值为1,如果没用过就是0
3. 树层去重
1. 前面取过的元素,后面就不能再取了
4. 使用used去重的逻辑:遍历到当前节点时,是否还在同一个树枝上,如果不是,则去掉。
class Solution(object):
def backtracking(self,canidates,target,total,startindex,path,result,used):
# recursion end condition
if total > target:
# we can't find any answer set
return
if total == target:
result.append(path[:])
return
# each level recursion logic
for i in range(startindex,len(canidates)):
# 对于相同的数字,只选择第一个未被使用的数字,跳过其他相同数字
if i > startindex and canidates[i] == canidates[i-1] and used[i-1] == 0:
# this mean's we still used same node before, we used just continue to next one
continue
# add element into our array
total += canidates[i]
path.append(canidates[i])
# update our used boolean value
used[i] = True
# recursion
self.backtracking(canidates,target,total,i+1,path,result,used)
# backtracking
path.pop()
total -= canidates[i]
used[i] = False
def combinationSum2(self, candidates, target):
"""
:type candidates: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = []
candidates.sort()
used = [False] * len(candidates)
self.backtracking(candidates,target,0,0,[],result,used)
return result
131.分割回文串
0. 回文串: 是指一个字符串从左往右读和从右往左读是一样的
1. 如果选择了a那就在后面剩余的字母选择
选择了b的话选择b后面的字母,以此类推
2. 分割:
1. 选完第一个字母之后就在后面分割
2. 选择分割的那个区间形成了一个子串
3. startindex就是切割线
1. 一开始切割的a
2. 下一层startindex就是从i+1开始,也就是切割了第二个
4. [startindex,i] 这个区间就是我们切割的子串
1. i是一直++的,startindex一开始是固定的值,startindex是一个切割线
i就向后移动,每向后移动一位,就代表一个子串,再向后移动就代表一个子串
class Solution(object):
def isPalindrome(self,s,start,end):
"""
check if the string is palindrome
return True, if it's palindrome
return False, if it's not palindrome
"""
# define two pointer
left = start
right = end
while left <= right:
if s[left] != s[right]:
# since string start and end are same, it is palindrome
return False
# move pointer
left += 1
right -= 1
return True
def backtracking(self,s,startindex,path,result):
# recursion end condition
if startindex >= len(s):
# collect the answer
result.append(path[:])
return
# recrusion logic
for i in range(startindex,len(s)):
# check if it's palindrome
if(self.isPalindrome(s,startindex,i)):
# it is palindrome
path.append(s[startindex:i+1])
# recursion
self.backtracking(s,i+1,path,result)
# backtracking
path.pop()
else:
# it's not palindrome, continue do not go to recursion
continue
def partition(self, s):
"""
:type s: str
:rtype: List[List[str]]
"""
result = []
self.backtracking(s,0,[],result)
return result