Leetcode算法——46、全排列

給定一個無重複整數數組,返回所有可能的排列。

示例:

Input: [1,2,3]
Output:
[
  [1,2,3],
  [1,3,2],
  [2,1,3],
  [2,3,1],
  [3,1,2],
  [3,2,1]
]

思路

1、字典序法

使用字典序法不斷尋找當前排序的下一個排序,直至返回到了起始序列。

2、深度優先搜索

使用遞歸法,維護一個結果數組、以及每個元素對應的剩餘元素集合。每次依次從剩餘的元素集合中取出一個,並且分別追加到每一個已取序列的最後,直至剩餘元素集合爲空。

3、廣度優先搜索

維護一個狀態列表,裏面的元素是所有狀態詞典,詞典中有兩個key,記錄已經搜索到的和尚未搜索到的。

每次循環,對於所有狀態詞典,對每個尚未搜索到的數字,都拼接到已經搜索到的數組的末尾,然後形成一個新的狀態列表。

這樣,每次循環,所有狀態詞典中的已搜索到的序列長度+1,尚未搜索到的集合長度-1。

因此,只需要循環 len(nums) 次,所有狀態都表示搜索完畢了。

4、分治法

設nums的長度爲n,則前n項的全排列 = 第n個數字依次插入到前n-1項的全排列的兩兩之間的縫隙中(包括首尾兩端)。

因此可以使用遞歸。

python實現

import copy
def permute(nums):
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    字典序法。
    """
    def nextPermutation(nums):
        """
        :type nums: List[int]
        尋找下一個字典序排列
        """
        l = len(nums)
        result = copy.deepcopy(nums)
        # 從右向左查詢第一個小於右鄰的元素
        for i in range(l-2, -1, -1):
            if result[i+1] > result[i]:
                break
        else: # 沒有找到,說明爲降序排列
            result[:] = result[::-1]
            return result
        # 從右向左查詢第一個大於nums[i]的元素
        for j in range(l-1, -1, -1):
            if result[j] > result[i]:
                break
        # 交換i和j
        result[i], result[j] = result[j], result[i]            
        # i後面的序列進行反轉
        result[i+1:l] = result[-1:i:-1]
        return result
    
    if not nums:
        return []
    result = [nums]
    cur = nums
    while(True):
        cur = nextPermutation(cur)
        if cur == nums: # 回到了第一個
            break
        result.append(cur)
    return result

def permute2(nums):
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    深度優先搜索。
    """
    def get_rest(result_list, pre_list, rest_set):
        '''
        遞歸,對rest_set進行全排列,並分別與pre_list拼接,最終加入到result_list中
        '''
        if not rest_set:
            result_list.extend(pre_list)
        for i in rest_set:
            get_rest(result_list, [x+[i] for x in pre_list], rest_set-{i})
            
    result_list = []
    get_rest(result_list, [[]], set(nums))
    return result_list

def permute3(nums):
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    廣度優先搜索。
    """
    state_list = [{'pre':[],'rest':set(nums)}]
    for _ in range(len(nums)): # 循環len(nums)次
        new_state_list = []
        for dic in state_list:
            for num in dic['rest']:
                new_state_list.append({'pre':dic['pre']+[num],'rest':dic['rest']-{num}})
        state_list = new_state_list
    return [x['pre'] for x in state_list]

def permute4(nums):
    """
    :type nums: List[int]
    :rtype: List[List[int]]
    分治法。
    """
    def get_permutes(n):
        '''
        得到nums前n項的全排列。
        '''
        # 遞歸結束條件
        if n == 1:
            return [[nums[0]]]
        
        # 得到前n-1項的全排列
        pre_list = get_permutes(n-1)
        # 將第 n 個元素,依次插入到 pre_list 中的元素縫隙中
        result_list = []
        for permute in pre_list:
            for i in range(len(permute)+1):
                result_list.append(permute[:i] + [nums[n-1]] + permute[i:])
        return result_list
    return get_permutes(len(nums))

if '__main__' == __name__:
    nums = [1,2,3]
    print(permute4(nums))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章