【算法】【回溯篇】第4节:全排列问题

本期任务:介绍算法中关于回溯思想的几个经典问题

【算法】【回溯篇】第1节:八皇后问题

【算法】【回溯篇】第2节:解数独问题

【算法】【回溯篇】第3节:正则表达式问题

【算法】【回溯篇】第4节:全排列问题

【算法】【回溯篇】第5节:组合问题

【算法】【回溯篇】第6节:子集问题

【算法】【回溯篇】第7节:0-1背包问题


一、问题描述

问题来源:LeetCode 46. 全排列

给定一个 没有重复 数字的序列,返回其所有可能的全排列。


   示例:

    输入: [1,2,3]
    输出:
    [
      [1,2,3],
      [1,3,2],
      [2,1,3],
      [2,3,1],
      [3,1,2],
      [3,2,1]
    ]

二、算法思路

  • 使用回溯思想,暴力穷举,每一个位置都可能有1-3共3种可能,所有可能的摆放方式共有 3 3 3^3 ,穷举过程遵循深度优先搜索规则。
  • 剪枝策略:维护一个existed数组,用于记录每个数字的出现与否,再次出现则跳过。
  • 结算情形:所有数字都已遍历

三、Python代码实现

class AllPermutation():
    def __init__(self, array):
        self.arr = array
        self.size = len(self.arr)
        self.res = [-1] * self.size  # 记录当前排列
        self.ans = []

        self.visited = [0] * self.size  # 记录每个数字的被访问情况

    def all_permutation(self, index=0):
        """回溯的主逻辑"""
        if index == self.size:  # 找到一个排列
            self.ans.append(list(self.res))
            return

        for i, v in enumerate(self.arr):  # 每一个给位置都有三种可能
            if not self.visited[i]:  # 当前位置未被访问过
                self.res[index] = v
                self.visited[i] = 1
                self.all_permutation(index + 1)
                self.visited[i] = 0  # 由于回溯过程对三个二维数组进行了修改,故回溯完成需要对称复原。


def main():
    ap = AllPermutation([1, 2, 3])
    ap.all_permutation()
    print(ap.ans)


if __name__ == '__main__':
    main()

运行结果

[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

四、问题变形

问题来源:LeetCode 47. 全排列II

  1. 题目描述
给定一个可包含重复数字的序列,返回所有不重复的全排列。
	
	示例:
	
	输入: [1,1,2]
	输出:
	[
	  [1,1,2],
	  [1,2,1],
	  [2,1,1]
	]

  1. 解决方案:
    基于上文代码,仅需修改一行即可(即在计算的时候,判断当前排列是否已经出现过。):
        # if index == self.size:  # 找到一个排列(旧)
        if index == self.size and self.res not in self.ans:  # 找到一个排列(新)
            self.ans.append(list(self.res))
            return
原创文章 36 获赞 32 访问量 2743

猜你喜欢

转载自blog.csdn.net/weixin_43868754/article/details/105680230
今日推荐