Leetcode 753. Cracking the Safe 双端队列实现 给出证明思路

题意

  • 我们希望构造一个最短的字符串,这个字符串每位可以是0k-1的字符,并且这个字符串的所有n长子串可以包含所有的 nk n k 种情况(即包含所有用k个字符构建的n长串)

思路

  • 不难想象,如果构造的这个串每一个n长子串恰好就是一个unique的情况,那么一定就是最短的串,长度为 nk+n1 n k + n − 1
  • 先假设我们一定可以构造出这样的串。然后可以换一个角度来看这个问题,设每一种独特的子串是一个节点,如果一个节点的n-1长后缀恰好另一个节点n-1长的前缀,那么我们就给这两个节点连一条边,因为这两个子串是可以在我们构造的串中直接相连的。这样我就构造了一个有向图,不难证明这个图是一个强连通图,即任意两点之间都是有通路的。那么我们假设的前提,就对应了这个图一定存在一条汉密尔顿通路。而这个图本身不大,我们就完全可以用bfs或者dfs去解这个题了。
  • 但是这个假设是否成立却是需要证明的,我参考了Discussion中的方法(Discussion中的原文),这里我给出一个我个人觉得可能更好理解一些的证明。

证明

实现

class Solution {
public:
    int pow(int x, int n){
        int ret = 1;
        for (int i = 0; i < n; i++){
            ret *= x;
        }
        return ret;
    }
    string crackSafe(int n, int k) {
        deque<string> q;
        unordered_set<string> mapp;
        q.push_back(string(""));
        for (int i = 0; i < n; i++){
            *q.begin() += '0';
        }
        mapp.insert(q.back());
        int len = pow(k, n) ;
        while (q.size() < len){
            string now = q.back().substr(1, n - 1);
            bool flag = true;
            for (char i = '0'; i < k + '0'; i++){
                now += i;
                if (mapp.find(now) == mapp.end()){
                    flag = false;
                    mapp.insert(now);
                    q.push_back(now);
                    break;
                }
                now.pop_back();
            }
            if (flag){
                now = q.front();
                q.pop_front();
                q.push_back(now);
            }
        }
        string ret;
        for (auto& it : q){
            ret += it[0];
        }
        ret.pop_back();
        ret += q.back();
        return ret;
    }
};

你可能感兴趣的:(ACM-字符串,ACM_图论)