【问题标题】:Permutation on a strange string一个奇怪的字符串上的排列
【发布时间】:2015-12-08 16:58:31
【问题描述】:

有一个奇怪的 10 个字符的字符串,即 '0' 或 '1'。我有 n 个过滤器字符串,每个字符串都有 10 个字符 ether '0' 或 '1'。过滤器字符串中第 i 个位置的 '1' 意味着如果我将此过滤器应用于奇怪字符串的第 i 个字符,则奇怪字符串的第 i 个字符将被反转:如果它变成 '1'是'0',反之亦然,而过滤器字符串中第i个位置的'0'不会对奇怪的字符串做任何事情。我可以应用任意数量的过滤器。我可以选择任意数量的过滤器,并且可以应用于奇怪的字符串。现在我想找出我可以应用多少个不同的过滤器子集来转换这个奇怪的字符串,以便奇怪的字符串只包含 1?我无法将问题概括为任意数量的字符串。任何人都可以帮忙。
让我们有一些测试用例

输入奇怪的字符串:
1111111111
过滤字符串总数
2
输入过滤字符串 :
0000000000
0000000000
输出为:4
说明:奇怪的字符串已经包含所有字符 1,我有两个不同的身份过滤器。我可以应用过滤器的空子集、仅应用第一个过滤器、仅应用第二个过滤器,或两者都应用。
输入奇怪的字符串:
0101010101
过滤字符串总数
3
输入过滤字符串
1010101010
1010000000
0000101010
输出为:2
说明
:我可以应用第一个过滤器(并将所有 0 反转)或以任意顺序应用第二个和第三个过滤器。

【问题讨论】:

  • 有可能没有一个过滤器能让你进入全 1 的状态,是吗?
  • 请参阅commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/… 获取方法getLevenshteinDistance。这将告诉您奇怪的字符串和 1111111111 之间有多少位不同。如果您有 n 个输入字符串,您可能需要通过由幂集组成的过滤器的 2^n 次应用。例如,假设您有 3 个过滤器字符串 a、b 和 c。您必须应用 2^3 个过滤器:null、a、b、c、ab、ac、bc、abc。吃两片阿司匹林,稍后再给我打电话。
  • 您的具体问题是什么?你不知道如何编码排列?或者你需要证明应用过滤器的操作不依赖于过滤器的应用顺序,这样你只需要过滤器集合的排列?
  • 想想当你对原始字符串应用过滤器时会发生什么。现在你有一个新的字符串和 1 个更少的过滤器需要担心。使用递归来减少问题,直到您可以轻松处理它。
  • 这个问题与this ongoing contest problem有显着的相似之处,N限制为100000

标签: c++ math combinations permutation


【解决方案1】:

蛮力算法:

std::uint16_t apply_filters(std::uint16_t init,
                            const std::vector<std::uint16_t>& filters,
                            const std::vector<bool>& mask)
{
    auto res = init;
    for (std::size_t i = 0; i != filters.size(); ++i) {
        if (mask[i]) {
            res ^= filters[i];
        }
    }
    return res;
}

bool increase(std::vector<bool>& bs)
{
    for (std::size_t i = 0; i != bs.size(); ++i) {
        bs[i] = !bs[i];
        if (bs[i] == true) {
            return true;
        }
    }
    return false; // overflow
}


std::size_t count_filters_combination(std::uint16_t init,
                                      const std::vector<std::uint16_t>& filters)
{
    std::vector<bool> bs(filters.size());

    std::size_t count = 0;
    const std::uint16_t expected = 0b1111111111;
    do
    {
        if (expected == apply_filters(init, filters, bs)) {
            ++count;
        }
    } while (increase(bs));
    return count;
}

Live Demo

【讨论】:

  • 伙计,这家伙已经为你完成了作业。打开一个调试器并跟踪它。
  • 非常感谢您的帮助。你能给我一些有效的方法,这样我就可以在不超过时间限制的情况下处理 10^5 个字符串。
【解决方案2】:

我用 python 编写了我的解决方案。应该很容易理解。我会留给你把它翻译成 C++。

def filterCombinations(original, filters):
    combinations = 1 if original == 0b1111111111 else 0
    for i in xrange(len(filters)):
        newvalue = original ^ filters[i]
        newfilters = filters[i+1:]
        combinations += filterCombinations(newvalue, newfilters)
    return combinations

使用 3 个过滤器,第一级递归如下所示:

filterCombinations(S, [F1, F2, F3])
--> X +
    filterCombinations(S^F1, [F2, F3]) +
    filterCombinations(S^F2, [F3]) +
    filterCombinations(S^F3, [])

如果S == 11111111110 否则X 为1。

【讨论】:

  • 我怎样才能让它更快?
  • 您可以通过缓存结果来加快速度。在进行任何递归之前进行查找。缓存可能会变得非常大,所以我不确定它的可行性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
  • 2021-12-13
  • 2021-11-27
相关资源
最近更新 更多