【力扣十道】回溯

好久没写,仍然是模版方法
思路简述:递归调用
看到 全排列,或者 枚举全部解,等类似的 搜索枚举类型题,基本就是 回溯 没跑了。

def backtrack(State,判断条件):
	if 满足什么条件就可以将State加入到res:
		res.append(S)
		return 
	if 怎么怎么:
		backtrack(State,条件变化)
res =[]
backtrack(初始状态)
return res

22. 括号生成

class Solution:
    def generateParenthesis(self, n: int) -> List[str]:
        def backtrack(S,left,right):
            if left + right == 2 * n:
                res.append(S)
                return 
            if left < n :
                backtrack(S + "(" , left+1 , right)
            if right < left:
                backtrack(S + ")" , left , right+1)
        res = []        
        backtrack("",0,0)
        return res

17. 电话号码的字母组合

class Solution:
    def letterCombinations(self, digits: str) -> List[str]:
        phone={
            "2":['a','b','c'],
            "3":['d','e','f'],
            "4":['g','h','i'],
            "5":['j','k','l'],
            "6":['m','n','o'],
            "7":['p','q','r','s'],
            "8":['t','u','v'],
            "9":['w','x','y','z']
        }
        if len(digits) == 0:
            return []
        def Backtrack(component,ss):
            if len(ss) == 0:
                res.append(component)
                return
            for i in phone[ss[0]]:
                Backtrack(component+i,ss[1:])
        res = []
        Backtrack("",digits)
        return res

77. 组合

class Solution:
    def combine(self, n: int, k: int) -> List[List[int]]:
        def backtrack(S,q,k):
            if k == 0 :
                res.append(S)
                return 
            for i in range(q,n+1):
                backtrack(S+[i],i+1,k-1)
        res = []
        backtrack([],1,k)
        return res

78. 子集

class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        def backtrack(s,ns):
            for i,j in enumerate(ns):
                backtrack(s+[j],ns[i+1:]) 
            if len(s) <= n:
                res.append(s)
                return
        res = []
        backtrack([],nums)
        return res

46. 全排列
知识点有一个是复制的话直接等号改变新的会覆盖旧的,用[:]切片的话不会更改旧的

class Solution:
    def permute(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        def backtrack(S,ns):
            for i,j in enumerate(ns):
                
                cp = ns[:]
                cp.remove(j)
                print(S,j,cp)
                backtrack(S+[j],cp)
            if len(S) == n:
                res.append(S)
                return

        res = []
        backtrack([],nums)
        return res

47. 全排列 II
!开始剪纸,剪纸就是continue,发现递归想从代码里面理解是很容易绕进去的,但是从逻辑解释还是可以通的,这边加一个check,和sort
剪纸条件是没有重复出现+该元素跟上一个元素相同且上一个元素未使用
每一个backtrack是一条枝,节点访问完之后就要把访问标记恢复成0,为了下次回溯

class Solution:
    def permuteUnique(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        check = [0 for i in range(n)]
        nums.sort()
        def backtrack(S,k):
            if k == 0:
                res.append(S)
                return
            for i,j in enumerate(nums):
                
                if i > 0 and nums[i] == nums [i-1] and check[i-1] == 0:
                    continue
                if check[i] == 1:
                    continue
                check[i] = 1
                backtrack(S+[j],k-1)
                check[i] = 0
        res = []
        backtrack([],n)
        return res

39. 组合总和
这个题解的时候慢了些,要理解第一次调用是[]连接candidates,而不是从第一个candidates开始画
数组添加元素可以直接用+[],而不使用append

class Solution:
    def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
        def backtrack(S,k,candidates):
            if k == target:
                res.append(S)
                return 
            if k > target:
                return 
            for i,j in enumerate(candidates):
                backtrack(S+[j], k+j,candidates[i:])
        res = [] 
        S = []
        backtrack(S,0,candidates)
        return res

解释
40. 组合总和 II
两种写法
1.相对位置

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        n = len(candidates)
        candidates.sort()
        def backtrack(S,k,can,p):
            if k == target:
                res.append(S)
                return 
            if k > target:
                return
            for i,j in enumerate(can):
                if i > 0 and can[i] == can[i-1] :
                    continue
                backtrack(S+[j],k+j,can[i+1:],p+1)
        res = []
        backtrack([],0,candidates,0)
        return res

2.绝对位置

class Solution:
    def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
        n = len(candidates)
        candidates.sort()
        def backtrack(S,k,begin):
            if k == target:
                res.append(S)
                return 
            if k > target:
                return 
            for i in range(begin,n):
                if i > begin and candidates[i] == candidates[i-1] :
                    continue
                backtrack(S+[candidates[i]],k+candidates[i],i+1)

        res = []
        backtrack([],0,0)
        return res

在这里插入图片描述
90. 子集 II

class Solution:
    def subsetsWithDup(self, nums: List[int]) -> List[List[int]]:
        nums.sort()
        def backtrack(S,ns):
            res.append(S)
            for i,j in enumerate(ns):
                if i > 0 and ns[i] == ns [i-1]:
                    continue
                backtrack(S+[j],ns[i+1:])
        res = []
        backtrack([],nums)
        return res

401. 二进制手表
用回溯还是费点脑子的,candidate就很妙,把它改成组合总和了,非常棒这个题解思路,也学到了一下%格式控制

class Solution:
    def readBinaryWatch(self, turnedOn: int) -> List[str]:
        hours = [8,4,2,1,0,0,0,0,0,0]
        minus = [0,0,0,0,32,16,8,4,2,1]
        def backtrack(k,index,hour,minu):
            if k == 0 :
                if hour < 12 and minu < 60:
                    res.append('%d:%02d' % (hour, minu))
                    return 
                return 
            for i in range(index,10):
                backtrack(k-1,i+1,hour+hours[i],minu+minus[i])
        res = []
        backtrack(turnedOn,0,0,0)
        return res

93. 复原 IP 地址

class Solution:
    def restoreIpAddresses(self, s: str) -> List[str]:
        ans = []
        def backtrack(S,s):
            if len(S)== 4:
                if not s:
                    ans.append(".".join(S))
                return 
            for i in range(1,len(s)+1):
                if 0< int (s[:i]) <= 255 and s[0] != '0' or s[:i] == '0':
                    backtrack(S+[s[:i]],s[i:])
                else:
                    return
        backtrack([],s)
        return ans
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
力扣是一个在线编程平台,提供了大量的算法题目,可以帮助程序员提高算法能力。回溯算法是一种搜索算法,它通过不断地尝试所有可能的解来求解问题。在回溯算法中,我们首先定义一个解空间,然后从解空间中搜索所有可能的解,直到找到符合要求的解为止。回溯算法通常用于求解组合问题、排列问题、子集问题等。 在 Java 中实现回溯算法,通常需要定义一个递归函数来搜索解空间。在递归函数中,我们首先判断当前状态是否符合要求,如果符合要求,则将当前状态加入到解集中;否则,我们继续搜索下一个状态。在搜索下一个状态时,我们需要对当前状态进行一些修改,然后递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。 以下是回溯算法的一般步骤: 1. 定义解空间:确定问题的解空间,并定义一个数据结构来表示解空间中的每个状态。 2. 确定约束条件:确定哪些状态是合法的,并定义一个函数来判断当前状态是否符合要求。 3. 确定搜索策略:确定搜索解空间的顺序,并定义一个函数来生成下一个状态。 4. 搜索解空间:使用递归函数搜索解空间,如果当前状态符合要求,则将其加入到解集中;否则,继续搜索下一个状态。 5. 回溯:当搜索完所有可能的状态后,回溯到上一个状态,继续搜索其他可能的状态。 以下是一个力扣题目的回溯算法 Java 实现示例: ``` class Solution { List<List<Integer>> res = new ArrayList<>(); List<Integer> path = new ArrayList<>(); public List<List<Integer>> subsets(int[] nums) { dfs(nums, 0); return res; } private void dfs(int[] nums, int start) { res.add(new ArrayList<>(path)); for (int i = start; i < nums.length; i++) { path.add(nums[i]); dfs(nums, i + 1); path.remove(path.size() - 1); } } } ``` 该算法用于求解给定数组的所有子集。在递归函数中,我们首先将当前状态加入到解集中,然后从当前位置开始搜索下一个状态。在搜索下一个状态时,我们将当前元素加入到路径中,并递归调用自身来搜索下一个状态。当搜索完所有可能的状态后,我们需要回溯到上一个状态,继续搜索其他可能的状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值