LeetCode 破解保险箱(全排列)

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89813746

描述:

有一个需要密码才能打开的保险箱。密码是 n 位数, 密码的每一位是 k 位序列 0, 1, …, k-1 中的一个 。

你可以随意输入密码,保险箱会自动记住最后 n 位输入,如果匹配,则能够打开保险箱。

举个例子,假设密码是 “345”,你可以输入 “012345” 来打开它,只是你输入了 6 个字符.

请返回一个能打开保险箱的最短字符串。

示例1:

输入: n = 1, k = 2
输出: "01"
说明: "10"也可以打开保险箱。

示例2:

输入: n = 2, k = 2
输出: "00110"
说明: "01100", "10011", "11001" 也能打开保险箱。

提示:

n 的范围是 [1, 4]。
k 的范围是 [1, 10]。
k^n 最大可能为 4096。

\color{blue}{思路分析:} 这道题的意思是我们将n位长的全排列密码进行“合并”,达到密码的长度最短。比如n == 2,k == 2时,密码只有“00”,“01”,“10”,“11”,我们将“00”与“10”合并可得“100”,再与“01”合并得“10001”,最后与“11”合并得“100011”。不难发现n位长的两个密码最多只能重叠n - 1位,通过n - 1次合并累计,这样得出的密码串肯定是最短的。

class Solution {
public:
    string crackSafe(int n, int k) {
        const int total = pow(k, n);//全排列总共有k的n次方个
        string res = string(n, '0');//初始化
        unordered_set<string> visited;//用于记录res中已经构造过了的
        visited.insert(res); 
        //由初始化一直进行构造,直到res包含全排列中所有的元素
        for (int i = 1; i < total; ++i) {
            //获取res当前最后n - 1个字符用于重复利用,构造下一个还没有构造过的排列
            string tempRes = res.substr(res.length() - n + 1, n - 1);
            //穷举添加的最后元素
            for (int j = k -1; j >= 0; --j) { 
                string key = tempRes + to_string(j); 
                if (visited.find(key) == visited.end()) {
                    //如果这个元素没有构造过
                    res += to_string(j);
                    visited.insert(key);//标记构造
                    break; 
                } 
            } 
        } 
        return res; 
    }
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89813746