专题:permutation相关的题

这一部分针对于permutations相关的题,核心问题在于每多一个数,需要将其插入之前的所有结果中

  1. # 31. Next Permutation, 找出下一个排序,可重复
  2. # 46. Permutations,列出所有可能的排列,无重复
  3. # 47. Permutations II,有重复的情况下得到所有排列
  4. # 77. Combinations,给定(n, k),从1-n中选k个数的方式
  5. # 78. Subsets, 给定数组,问其所有子集,无重复元素
  6. # 90. Subsets II,有重复元素
  7. # 773. Sliding Puzzle,打乱的顺序,通过变换回到123450的顺序,用visited记录走过的值,每次用level更新,其实这一题关系不大
  8. # 267. Palindrome Permutation II, 给定s,如果能排序为回文串,列出所有回文串,可以用backtracking,由内到外添加
  9. # 60. Permutation Sequence,给定1-n,求第k个排列,从头到尾一个个更新

# 31. Next Permutation, 找出下一个排序,可重复

  1. .从后往前找,找到一个元素a,比紧靠在它之后的元素要小(不是小于等于)。
  2. 然后再一次从后往前找,找到第一个比元素a大(不是大于等于)的元素,叫元素b。
  3. 将元素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)

猜你喜欢

转载自www.cnblogs.com/dl3182/p/11955936.html