以字符串形式循环检测

时间:2015-03-14 10:21:49

标签: algorithm cycle bitstring

给定长度为N(< = 10 ^ 5)的二进制字符串,我想找到字符串循环的长度。 周期长度最多1000 且至少为1

示例:

110110110110 周期长度为3(图案重复为110)

000000 周期长度为1(图案重复为0)

1101101101 周期长度为3(图案重复为110)

我试图理解Floyd's cycle detection algorithm,但我无法理解如何申请这个问题。

如何有效地解决这个问题? (我想要一个在O(NlogN)或更好的情况下运行的算法。)

4 个答案:

答案 0 :(得分:3)

以下是此问题的线性解决方案:

  1. 设定给定字符串的计算前缀函数(如Knuth-Morris-Pratt算法)。

  2. 答案始终是n - p[n],其中n是给定字符串的长度,p[i]i-th位置的前缀函数的值在字符串中。证明:

    • 期间不小于n - p[n]。情况就是这样,因为对于任何k,任何时段s[i] = s[i + k]i。因此,由于前缀函数的定义,n - p[n]至少为k

    • 期间不大于k = n - p[n]。情况是因为s[i] = s[i + k]由于前缀函数的定义导致所有i,这意味着k是句点。

答案 1 :(得分:1)

Floyd的循环检测算法被认为用于稍微不同的问题,即图形,其中有循环,但不是整个图形必须是一个循环。

例如,比较这两个图:

1 -> 2 -> 3 -> 4 -> 1 -> ...

1 -> 2 -> 3 -> 4 -> 2 -> ...

两者都有一个循环,但第二个循环在一部分节点上只有一个循环(即1没有出现在循环中)。

您对示例2中的周期不感兴趣,只对“完整周期”感兴趣。


此外,当您使用位时,您的算法将与使用整数(例如)时略有不同。原因是您可以只用一次比较一次比较多个位(只要总位数<=一个整数)。

以下是您可以解决问题的可能方法:

要检查周期是否为1,请将整数移一,并与自身进行比较:

000000000000
 000000000000
-yyyyyyyyyyy-
=> Matches!

110110110110
>110110110110
-ynnynnynnyn-
=> Nope

因此000000000000的周期为1,110110110110没有,所以继续使用2进行测试:

110110110110
>>110110110110
--nynnynnynn--
=> Nope

继续3:

110110110110
>>>110110110110
---yyyyyyyyy---
=> Matches!

当然,你必须实现我刚才用bit算法描述的东西,我会把它留给你。

答案 2 :(得分:1)

当它始终以第一个周期开始时,它将很简单。你可以这样做:

public int GetCycleLength(string binary, out int cycles)
{
    for (int i = 1; i < 1000; i++)
    {
        if (binary.Length % i == 0)
        {
            cycles = 0;
            do
            {
                cycles++;
                if (cycles * i > binary.Length - i - 1)
                {
                    break;
                }
            }
            while (binary.Substring(cycles * i, i) == binary.Substring((cycles + 1) * i, i));
            cycles++;
            if (cycles * i == binary.Length)
            {
                return i;
            }
        }
    }
    cycles = 0;
    return 0;
}

答案 3 :(得分:1)

除了我已经有的答案,我有另一个想法。也许它根本不起作用,所以如果我错了,请纠正我(我无法在Google上找到关于这个主题的任何内容)。但是,它不会在位级别上工作,因此您的开销为32或64 ...

让我们调用我们正在分析的字符串S

您可以使用Knuth-Morris-Pratt算法(在线性时间内在字符串中查找子字符串)来查找字符串S中的SS(连接S两次) 。当然,你必须在索引2处开始搜索。然后算法返回的索引就是循环的长度。


编辑:正如kaktusito所说,这不会奏效。但是,您可以使用KMP算法(但稍微更改一下)从索引2开始在字符串S中查找字符串S。原始算法当然不会找到匹配项,但您可以修改它,继续搜索(即使您要查找的子字符串比原始字符串长)。然后,只要将子字符串与原始字符串的末尾匹配,就会找到一个循环的长度(即使子字符串更长)。