【Leetcode】回溯-递归系列
【Leetcode-17】
一、题目:电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
二、代码:
def letterCombinations(self, digits: str) -> List[str]: res_all = [] if len(digits) == 0: return res_all def back_up(pre, arr): if len(arr) == 0: res_all.append(pre) return # 不加入 # back_up(pre, arr[1:]) # 加入 letters = list(look_up[arr[0]]) for i in range(len(letters)): letters[0], letters[i] = letters[i], letters[0] back_up(pre+letters[0], arr[1:]) letters[i], letters[0] = letters[0], letters[i] look_up = { "2": "abc", "3": "def", "4": "ghi", "5": "jkl", "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz" } back_up('', digits) return res_all
【Leetcode-22】
一、题目:括号生成
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
二、代码
def generateParenthesis(self, n: int) -> List[str]: res = [] def back_up(pre, left, right): if left == 0 and right == 0: res.append(pre) if left > 0: back_up(pre+'(', left-1, right) if left < right: # 左放的多,可放右 back_up(pre+')', left, right-1) back_up('', n, n) return res
【Leetcode-46】
一、题目:全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
二、代码:
def permute(self, nums: List[int]) -> List[List[int]]: res = [] if len(nums) == 0: return res def back(pre, arr): if len(arr) == 0: res.append(pre[:]) for i in range(len(arr)): arr[i], arr[0] = arr[0], arr[i] pre.append(arr[0]) back(pre, arr[1:]) pre.pop() arr[0], arr[i] = arr[i], arr[0] back([], nums) return res
【Leetcode-39】
一、题目:组合总数
给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
二、代码:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: n = len(candidates) res = [] if n == 0: return res def back(pre, arr, t): if len(arr) == 0 or t < 0: # 放完了 if len(arr) == 0 and t == 0: res.append(pre[:]) return # 不放 back(pre, arr[1:], t) # 放 if t-arr[0] >= 0: pre.append(arr[0]) back(pre, arr, t-arr[0]) pre.pop() back([], candidates, target) return res
【Leetcode-51】
一、题目:N皇后
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
要求皇后不能在同一行、同一列、对角。
二、代码:
def solveNQueens(self, n: int) -> List[List[str]]: """ 每一行往下放,放的时候检查冲突,如果冲突则不放,冲突记录为已经放的列,已经放的对角线(i-j和i+j分别表示两条对角线) """ res = [] def back_up(i, pre_res, pre_cols, pre_diags1, pre_diags2): # 输入为当前要放的行,前面行放完后的结果,前面行已经放的列,前面行已经放的对角线(行列差值表示对角线) if i == n: # 已经放完了 res.append(pre_res[:]) return # 往i行放,若已经冲突则直接返回 for j in range(n): if j in pre_cols or i - j in pre_diags1 or i+j in pre_diags2: # 该列/对角已经放过 continue # 该行放在第j列,其他列为'.' res_item = ['.'] * n res_item[j] = 'Q' res_item = "".join(res_item) pre_res.append(res_item) pre_cols.add(j) pre_diags1.add(i-j) pre_diags2.add(i+j) back_up(i+1, pre_res, pre_cols, pre_diags1, pre_diags2) # 尝试放其他列 pre_res.pop() pre_cols.remove(j) pre_diags1.remove(i-j) pre_diags2.remove(i+j) back_up(0, [], set(), set(), set()) return res
【Leetcode-78】
一、题目:子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
二、代码:
def subsets(self, nums: List[int]) -> List[List[int]]: res = [] n = len(nums) if n == 0: return [[]] def back(pre, arr): if len(arr) == 0: res.append(pre[:]) return # 放 pre.append(arr[0]) back(pre, arr[1:]) pre.pop() # 不放 back(pre, arr[1:]) back([], nums) return res
【Leetcode-77】
一、题目:组合
给定两个整数 n 和 k,返回 1 ... n 中所有可能的 k 个数的组合。
二、代码:
def combine(self, n: int, k: int) -> List[List[int]]: res = [] ''' # 下面是求排列组合,考虑了顺序,思路是每个坑位必须放元素,每次尝试放不同元素,直到填满坑位 def back_up(pre, arr, left): # 已经放的,剩下的元素, 剩下几个坑位 if left == 0: res.append(pre[:]) return # 放元素 for i in range(len(arr)): arr[0], arr[i] = arr[i], arr[0] pre.append(arr[0]) back_up(pre, arr[1:], left-1) pre.pop(-1) arr[i], arr[0] = arr[0], arr[i] ''' # 下面是求组合,不考虑顺序,思路是对元素1-n挨个放,每个元素都有放和不放两种选择,直到坑位满或者元素不够 def back_up(pre, arr, left): # 已经放的,剩下的元素, 剩下几个坑位 if left == 0: res.append(pre[:]) return if len(arr) < left: # 剩下的元素太少,坑位太多哦 return # 放当前元素,每个元素有放和不放两种 # 放 pre.append(arr[0]) back_up(pre, arr[1:], left-1) pre.pop(-1) # 不放 back_up(pre, arr[1:], left) if k > n: return res arr = [t+1 for t in range(n)] back_up([], arr, k) return res
【Leetcode-79】
一、题目:单词搜索
给定一个二维网格和一个单词,找出该单词是否存在于网格中。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
二、代码:
def exist(self, board: List[List[str]], word: str) -> bool: neibors = [[-1, 0], [1, 0], [0, -1], [0, 1]] m, n = len(board), len(board[0]) flag = [[True]*n for _ in range(m)] def dfs(i, j, k): if board[i][j] != word[k]: return False if k == len(word) - 1: return True flag[i][j] = False matched = False for pos in neibors: x, y = pos new_i, new_j = x + i, j + y if 0 <= new_i < m and 0 <= new_j < n and flag[new_i][new_j]: if dfs(new_i, new_j, k+1): matched = True break flag[i][j] = True return matched for i in range(m): for j in range(n): if dfs(i, j, 0): return True return False
【Leetcode-93】
一、题目:复原IP地址
给定一个只包含数字的字符串,用以表示一个 IP 地址,返回所有可能从 s 获得的 有效 IP 地址 。你可以按任何顺序返回答案。
有效 IP 地址 正好由四个整数(每个整数位于 0 到 255 之间组成,且不能含有前导 0),整数之间用 '.' 分隔。
例如:"0.1.2.201" 和 "192.168.1.1" 是 有效 IP 地址,但是 "0.011.255.245"、"192.168.1.312" 和 "192.168@1.1" 是 无效 IP 地址。
二、代码:
def restoreIpAddresses(self, s: str) -> List[str]: """ 回溯 """ total_cnt = 4 max_len = 3 # 某一段最长为3 res = [] def back(pre, cnt, s): # 前面已经放好的结果,本次放第几段,剩下元素 if cnt > total_cnt: # 段数够了 if len(s) == 0: # 元素也放完了 res.append('.'.join(pre)) return # 剪枝,剩下的元素太多或太少 if len(s) < total_cnt-cnt+1 or len(s) / max_len > total_cnt-cnt+1: return # 放该段元素,若前缀为0则只能放0 if s[0] == '0': pre.append('0') back(pre, cnt+1, s[1:]) pre.pop(-1) else: # 逐渐截出来尝试放 for this_len in range(1, max_len+1): if len(s) < this_len: # 剩下的都没这么长 continue item = s[:this_len] if int(item) <= 255: pre.append(item) back(pre, cnt+1, s[this_len:]) pre.pop(-1) back([], 1, s) return res
浙公网安备 33010602011771号