这一部分针对于permutations相关的题,核心问题在于每多一个数,需要将其插入之前的所有结果中
- # 31. Next Permutation, 找出下一个排序,可重复
- # 46. Permutations,列出所有可能的排列,无重复
- # 47. Permutations II,有重复的情况下得到所有排列
- # 77. Combinations,给定(n, k),从1-n中选k个数的方式
- # 78. Subsets, 给定数组,问其所有子集,无重复元素
- # 90. Subsets II,有重复元素
- # 773. Sliding Puzzle,打乱的顺序,通过变换回到123450的顺序,用visited记录走过的值,每次用level更新,其实这一题关系不大
- # 267. Palindrome Permutation II, 给定s,如果能排序为回文串,列出所有回文串,可以用backtracking,由内到外添加
- # 60. Permutation Sequence,给定1-n,求第k个排列,从头到尾一个个更新
# 31. Next Permutation, 找出下一个排序,可重复
- .从后往前找,找到一个元素a,比紧靠在它之后的元素要小(不是小于等于)。
- 然后再一次从后往前找,找到第一个比元素a大(不是大于等于)的元素,叫元素b。
- 将元素a和元素b调换位置,然后将原来的元素a(现在的元素b)之后的那个元素到数组结尾的元素全部倒转一次。
def nextPermutation(nums): """ :type nums: List[int] :rtype: None Do not return anything, modify nums in-place instead. """ def reverse(nums,i,j): while i<j: nums[i],nums[j]=nums[j],nums[i] i,j=i+1,j-1 return nums left = len(nums)-2 while left>=0 and nums[left]>=nums[left+1]: left-=1 if left<0: return reverse(nums,0,len(nums)-1) right = len(nums)-1 while right>left and nums[right]<=nums[left]: right -=1 nums[left],nums[right]=nums[right],nums[left] nums = reverse(nums,left+1,len(nums)-1) return nums nextPermutation([1,2,3])
# 46. Permutations,列出所有可能的排列,无重复
# 对最后一个元素做插入遍历
def permute(nums): """ :type nums: List[int] :rtype: List[List[int]] """ if len(nums)==0: return [[]] if len(nums)==1: return [nums] else: temp = permute(nums[:-1]) return [i[:j]+[nums[-1]]+i[j:] for i in temp for j in range(len(i)+1)] print(permute([1,2]))
# 47. Permutations II,有重复的情况下得到所有排列
- avoid inserting a number AFTER any of its duplicates.
- 也可以先排序,然后一次次nextPermute
# Suppose duplicate happens when inserting n into the ith location, the result is [l2[:i], n, l2[i:]], and it duplicates with the item [l1[:j], n, l1[j:]]
# Suppose i < j, then we have l1[i] ==n, however, we will break when l1[i]==n, and thus n will not be inserted after l1[:j] -> contradiction,
# Suppose i > j, then we have l2[j] == n, however we will break when l2[j] == n, and thus n will not be inserted after l2[:i] -> contradiction.
# Suppose i==j, then we have l1==l2, which contradicts the assumption that ans is a list of unique permutations.
# Thus the argument hold.
def permuteUnique(nums): ans = [[]] for n in nums: new_ans = [] for l in ans: for i in range(len(l)+1): new_ans.append(l[:i]+[n]+l[i:]) if i<len(l) and l[i]==n: break #handles duplication ans = new_ans return ans permuteUnique([1,1,3])
# 77. Combinations,给定(n, k),从1-n中选k个数的方式
def combine(n, k): """ :type n: int :type k: int :rtype: List[List[int]] """ dp = [[[] for _ in range(k+1)] for _ in range(n+1)] for i in range(1,n+1): dp[i][1]=[[j] for j in range(1,i+1)] for i in range(1,k+1): dp[i][i]=[[j for j in range(1,i+1)]] for j in range(1,k): for i in range(j+1,n): temp =[ele+[i+1] for ele in dp[i][j]] dp[i+1][j+1] = dp[i][j+1]+temp return dp[-1][-1] # combine(5,3) def combine(n, k):#Recursive if k <=0: return [[]] return [pre + [i] for i in range(k, n+1) for pre in combine(i-1, k-1)] def combine(n, k):#Iterative combs = [[]] for _ in range(k): combs = [[i] + c for c in combs for i in range(1, c[0] if c else n+1)] # 这个循环中range(1,c[0])如果没有区间,前面没有执行 return combs combine(5,3)
# 78. Subsets, 给定数组,问其所有子集,无重复元素
def subsets(nums): """ :type nums: List[int] :rtype: List[List[int]] """ res = [[]] for n in nums: temp = [] for lst in res: temp.append(lst+[n]) res+=temp return res
# 90. Subsets II,有重复元素
def subsetsWithDup(nums): """ :type nums: List[int] :rtype: List[List[int]] """ nums.sort() res = [[]] for i in range(len(nums)): if i==0 or nums[i]!=nums[i-1]: curcount = 1 else: curcount+=1 temp = [] # every turn, there must be new elements for lst in res: if curcount==1 or (len(lst)>=(curcount-1) and lst[-(curcount-1)]==nums[i]): temp.append(lst+[nums[i]]) res += temp return res subsetsWithDup([1,1,2])
# 773. Sliding Puzzle,打乱的顺序,通过变换回到123450的顺序,用visited记录走过的值,每次用level更新
def slidingPuzzle(board): """ :type board: List[List[int]] :rtype: int """ directions = {0:[1,3],1:[0,2,4],2:[1,5],3:[0,4],4:[1,3,5],5:[2,4]} board = "".join([str(i) for i in board[0]+board[1]]) empty = board.index('0') visited = {board:empty} level = {board:empty} step = 0 while True: if '123450' in level: return step if len(level)==0: return -1 step+=1 newlevel = dict() for i in level: pos = level[i]#pos of 0 for newpos in directions[pos]:#new pos to be replaced if newpos<pos: j = i[:newpos]+'0'+i[newpos+1:pos]+i[newpos]+i[pos+1:] else: j = i[:pos]+i[newpos]+i[pos+1:newpos]+'0'+i[newpos+1:] if j not in visited: newlevel[j] = newpos visited[j] = newpos level = newlevel slidingPuzzle(board = [[4,1,2],[5,0,3]])
# 267. Palindrome Permutation II,给定s,如果能排序为回文串,列出所有回文串,可以用backtracking,由内到外添加
import collections def generatePalindromes(s): """ :type s: str :rtype: List[str] """ ans = [] n = len(s) counter = collections.Counter(s) def helper(tmp): if len(tmp) == n: ans.append(tmp) return for k, v in counter.items(): if v > 0: counter[k] -= 2#对k处理了 helper(k + tmp + k) counter[k] += 2#回头处理下一个 odd = [key for key, value in counter.items() if value % 2 != 0] if len(odd) > 1: return [] if len(odd) == 1: counter[odd[0]] -= 1 helper(odd[0]) else: helper('') return ans generatePalindromes('aabb')
# 60. Permutation Sequence,给定1-n,求第k个排列,从头到尾一个个更新
def getPermutation(n, k): """ :type n: int :type k: int :rtype: str """ factorials = [1] prod = 1 for i in range(1,10): prod = prod*i factorials.append(prod) res = [] candidates = [i for i in range(1,n+1)] k = k-1 for i in range(n): candidate = candidates[k//factorials[n-1-i]] res.append(str(candidate)) candidates.remove(candidate) k = k%factorials[n-1-i] return "".join(res) getPermutation(5,10)