Series01 排列问题 Permutations

一、题型

第 46 题,第 47 题。第 60 题,第 526 题,第 996 题。

46:全排列

47:全排列+去重

60: 输出第k个序列

526:优美的排列

996:正方形数组

二、主要思想

1. 回溯、深度优先遍历

共同点:尽可能尝试所有可能性

回溯:回退

DFS:遍历

2. 与动态规划的区别

动态规划:关心最优解

回溯:关心每一种解的可能性

三、代码

1. 主要代码

(1)记住每一种解的全排列

vector<int> a; //记住序列
vector<int> book;//标记是否被访问:1已经被访问0未被访问--寻求合法状态使用

void Permutations(int k, vector<int> &nums,  vector<vector<int>> &all)
{
    if(a.size()==k)
    {
        all.push_back(a);
        return;
    }

    for(int i=0; i<k; i++)
    {
        //判断状态是否合法
        if(book[i]==0)
        {
            //扩展状态
            a.push_back(nums[i]);
            book[i] = 1;
            DFS(k, nums, all);
            //还原状态
            book[i] = 0;
            a.pop_back();
        }
    }

}

(2)不记录中间解的全排列--计算多少种

 //不用记录中间数组,减轻排列压力
void Permutations(int n, int start, vector<int> nums, vector<bool>& visit, int &total)
{
    if(start == n)
    {
        total++;
        return;
    }
    
    for(int i=0;i<n;i++)//从1~n选数字,一个一个数字扩张
    {
        if( (!visit[i])
        {
            visit[i] = true;
            DFS(n, start+1, nums, visit, total);
            visit[i] = false;
        }
    }
}

2. 解题思路

46:全排列

47:全排列+去重

​ 去重:先排序(相同的数字不进行挑选),在确定合法条件时进行剪枝

剪枝一:
if(i>0 && (nums[i]==nums[i-1]) && !book[i-1])//效率更高,重复元素的第一个
{
    continue;
}
剪枝二:
if(i>0 && (nums[i]==nums[i-1]) && book[i-1])//重复元素的最后一个
{
    continue;
}

60: 输出第k个序列--数学方法

526:优美的排列--类似47-判断合法条件变动

996:正方形数组--类似47-判断合法条件变动

posted @ 2022-08-22 21:48  circlelll  阅读(19)  评论(0)    收藏  举报