【问题标题】:Smallest Binary String not Contained in Another String不包含在另一个字符串中的最小二进制字符串
【发布时间】:2022-01-09 11:46:48
【问题描述】:

问题描述比较简单,举个例子

input: 10100011
output: 110

我尝试过使用 BFS,但我认为这不是一个足够有效的解决方案(可能是某种位图 + 滑动窗口的解决方案?)

string IntToString(int a)
{
    ostringstream temp;
    temp << a;
    return temp.str();
}

bool is_subsequence(string& s, string& sub) {
    if(sub.length() > s.length()) return false;
    int pos = 0;
    for(char c : sub)
    {
        pos = s.find(c, pos);
        if(pos == string::npos) return false;
        ++pos;
    }
    return true;
}

string shortestNotSubsequence(string& s) {
    Queue q(16777216);
    q.push(0);
    q.push(1);
    while(!q.empty())
    {
        string str;
        int num = q.front; q.pop();
        str = IntToString(num);
        if(!is_subsequence(s, str)) return str;
        string z = str + '0';
        string o = str + '1';
        q.push(stoi(str+'0'));
        q.push(stoi(str+'1'));
    }
    return "";
}

int main() {
    string N;
    cin >> N;
    cout << shortestNotSubsequence(N) << endl;
    return 0;
}

【问题讨论】:

    标签: c++ string algorithm


    【解决方案1】:

    您可以在 O(N) 时间内轻松完成此操作。

    令 W = ceiling(log2(N+1)),其中 N 是输入字符串 S 的长度。

    有 2W 个可能的长度为 W 的字符串。S 必须有少于 N 个作为子字符串,并且少于 2W,因此至少有一个字符串长度为 W 的不能出现在 S 中。

    W 也小于size_t 中的位数,并且只需要 O(N) 空间来存储长度为 W 的所有可能字符串的掩码。将这样的掩码初始化为 0,然后迭代S 使用size_t 中的最低 W 位作为您遇到的子字符串的滑动窗口。将遇到的每个子字符串的掩码位设置为 1。

    完成后,扫描掩码以找到第一个 0,这将是缺少的长度为 W 的字符串。

    但也可能存在较短的缺失字符串,因此将掩码位成对合并,为长度为 W-1 的字符串制作掩码,然后还为 S 中的最后 W-1 位设置掩码位,因为这些可能不包含在任何 W 长度的字符串中。然后扫描掩码是否为 0,看看是否能找到较短的缺失字符串。

    只要您继续寻找较短的字符串,就继续合并较小字符串的掩码,直到达到长度 1。由于每个此类操作都将掩码大小除以 2,因此这不会影响总的 O(N) 时间整个算法。

    这是一个 C++ 实现

    #include <string>
    #include <vector>
    #include <algorithm>
    
    std::string shortestMissingBinaryString(const std::string instr) {
        const size_t len = instr.size();
        if (len < 2) {
            if (!len || instr[0] != '0') {
                return std::string("0");
            }
            return std::string("1");
        }
        // Find a string size guaranteed to be missing
        size_t W_mask = 0x3;
        unsigned W = 2;
        while(W_mask < len) {
            W_mask |= W_mask<<1;
            W+=1;
        }
    
        // Make a mask of all the W-length substrings that are present
        std::vector<bool> mask(W_mask+1, false);
        size_t lastSubstr=0;
        for (size_t i=0; i<len; ++i) {
            lastSubstr = (lastSubstr<<1) & W_mask;
            if (instr[i] != '0') {
                lastSubstr |= 1;
            }
            if (i+1 >= W) {
                mask[lastSubstr] = true;
            }
        }
    
        //Find missing substring of length W
        size_t found = std::find(mask.begin(), mask.end(), false) - mask.begin();
    
        // try to find a shorter missing substring
        while(W > 1) {
            unsigned testW = W - 1;
            W_mask >>= 1;
            // calculate masks for length testW 
            for (size_t i=0; i<=W_mask; i++) {
                mask[i] = mask[i*2] || mask[i*2+1];
            }
            mask.resize(W_mask+1);
            // don't forget the missing substring at the end
            mask[lastSubstr & W_mask] = true;
    
            size_t newFound = std::find(mask.begin(), mask.end(), false) - mask.begin();
            if (newFound > W_mask) {
                // no shorter string
                break;
            }
            W = testW;
            found = newFound;
        }
    
        // build the output string
        std::string ret;
        for (size_t bit = ((size_t)1) << (W-1); bit; bit>>=1) {
            ret.push_back((found & bit) ? '1': '0');
        }
        return ret;
    }
    

    【讨论】:

    • 您好,谢谢您的回答。我对 size_t 的含义有些困惑。
    • 在 C++ 中,size_t 是一种无符号整数类型,其大小足以容纳字符串或向量的大小。 en.cppreference.com/w/cpp/types/size_t
    • 为了澄清一点实现:所以递归过程从 window = len(input) 的大小开始,我们创建一个数组,其中每个条目对应于 len(严格来说?)是的所有序列n.所以就像 n = 3 的 000、001 等。我们通过计算相应位置(在所有二进制序列中)来标记所有存在的此类序列,同时我们将窗口移动到输入并相应地将 0 翻转为 1。扫描将向我们展示该长度的最小缺失序列。在实践中我们如何合并以找到更小的序列?我不确定我是否完成了这一步。
    • 从窗口大小 log(len(input)) 开始,而不是 len(input),否则是的。合并序列很容易:如果你有010 或者你有011 那么你有01。您只需将掩码中的位或位成对组合在一起。
    • 请允许我重新措辞。我看到 01 是按位的,或者删除了第一个或最后一个数字。我了解操作,但我不了解理由。所有 w-1 个子序列的集合不是所有 w 个子序列都去掉了第一个数字+所有 w 个子序列去掉了最后一个数字吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-31
    • 2013-10-12
    • 2012-11-21
    • 2017-12-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多