Algorithm O(nlogn)算法-在二进制字符串中查找三个等距的

Algorithm O(nlogn)算法-在二进制字符串中查找三个等距的,algorithm,big-o,Algorithm,Big O,我昨天在一次算法测试中遇到了这个问题,我想不出答案。这简直让我发疯,因为它值40分左右。我想全班大多数人都没有正确地解决这个问题,因为我在过去的24小时里没有想出一个解决方案 给定一个长度为n的任意二进制字符串,在该字符串中找到三个等距的字符串(如果存在)。写一个在O(n*log(n))时间内解决这个问题的算法 所以像这样的字符串有三个是“等距”的:111000000100 编辑:这是一个随机数,所以它应该能够适用于任何数字。我举的例子是为了说明“等间距”特性。所以1001011是一个有效的数字

我昨天在一次算法测试中遇到了这个问题,我想不出答案。这简直让我发疯,因为它值40分左右。我想全班大多数人都没有正确地解决这个问题,因为我在过去的24小时里没有想出一个解决方案

给定一个长度为n的任意二进制字符串,在该字符串中找到三个等距的字符串(如果存在)。写一个在O(n*log(n))时间内解决这个问题的算法

所以像这样的字符串有三个是“等距”的:111000000100


编辑:这是一个随机数,所以它应该能够适用于任何数字。我举的例子是为了说明“等间距”特性。所以1001011是一个有效的数字。1、4和7是等距排列的。

拉宾-卡普算法的自适应可能适用于您。 它的复杂性为0(n),因此它可以帮助您


看看

我怀疑一个看起来像O(n^2)的简单方法实际上会产生更好的结果,比如O(n ln(n))。测试时间最长的序列(对于任何给定的n)是不包含三元组的序列,这严重限制了序列中可以包含的1的数量


我提出了一些挥手致意的论点,但我还没有找到一个清晰的证据。我想暗中试探一下:答案是一个非常聪明的想法,教授早就知道了,这似乎是显而易见的,但对学生来说太难了。(要么是这样,要么就是你整个讲座都在睡觉。)

这似乎是一个有趣的问题,所以我决定尝试一下

我假设111000001将找到前3个并获得成功。从本质上讲,1后面的零的数量是很重要的,因为根据您的定义,0111000与111000是相同的。一旦你找到两个1的案例,下一个1就完成了三部曲

这是Python的版本:

def find_three(bstring):
    print bstring
    dict = {}
    lastone = -1
    zerocount = 0
    for i in range(len(bstring)):
        if bstring[i] == '1':
            print i, ': 1'
            if lastone != -1:
                if(zerocount in dict):
                    dict[zerocount].append(lastone)
                    if len(dict[zerocount]) == 2:
                        dict[zerocount].append(i)
                        return True, dict
                else:
                    dict[zerocount] = [lastone]
            lastone = i
            zerocount = 0
        else:
            zerocount = zerocount + 1
    #this is really just book keeping, as we have failed at this point
    if lastone != -1:
        if(zerocount in dict):
            dict[zerocount].append(lastone)
        else:
            dict[zerocount] = [lastone]
    return False, dict

这是第一次尝试,所以我相信这可以写得更干净。请在下面列出此方法失败的情况。

还不能想出解决方案:(,但有一些想法


如果我们从一个相反的问题开始:构造一个最大数量为1且没有任何等距三元组的序列。如果你能证明最大数量为0(n),那么你可以通过只迭代1的列表来改进你的估计。

对于简单的问题类型(即,你只搜索三个“1”)(即零或更多)“0”),它非常简单:您可以在每个“1”处拆分序列,并查找具有相同长度的两个相邻子序列(当然,第二个子序列不是最后一个子序列)。显然,这可以在O(n)时间内完成


对于更复杂的版本(即,搜索索引i和间隙g>0,使得
s[i]==s[i+g]==s[i+2*g]==“1”
),我不确定是否存在O(n log n)解决方案,因为可能有O(n²)个三元组具有此属性(想想所有的字符串,大约有n²/2个这样的三元组)当然,你只想找到其中的一个,但我目前不知道如何找到它…

这是一个解决方案吗?我不确定它是否是O(nlogn),但我认为它比O(n²)好,因为不找到三元组的唯一方法是素数分布

还有改进的余地,第二个发现的1可能是下一个第一个1。也没有错误检查

#include <iostream>

#include <string>

int findIt(std::string toCheck) {
    for (int i=0; i<toCheck.length(); i++) {
        if (toCheck[i]=='1') {
            std::cout << i << ": " << toCheck[i];
            for (int j = i+1; j<toCheck.length(); j++) {
                if (toCheck[j]=='1' && toCheck[(i+2*(j-i))] == '1') {
                    std::cout << ", " << j << ":" << toCheck[j] << ", " << (i+2*(j-i)) << ":" << toCheck[(i+2*(j-i))] << "    found" << std::endl;
                    return 0;
                }
            }
        }
    }
    return -1;
}

int main (int agrc, char* args[]) {
    std::string toCheck("1001011");
    findIt(toCheck);
    std::cin.get();
    return 0;
}
#包括
#包括
int findIt(std::string toCheck){

对于(inti=0;i问题的一个切入点是考虑因素和转移

使用移位时,将1和0字符串与自身的移位版本进行比较。然后取匹配的1。以本例为例,移位2:

1010101010
  1010101010
------------
001010101000
结果1(按位AND)必须表示所有以2等距排列的1。同一个示例移动了3:

1010101010
   1010101010
-------------
0000000000000
在这种情况下,没有一个1是三个相等间隔的

那么这告诉你什么呢?你只需要测试素数的移位。例如,假设你有两个相距6的1。你只需要测试“2”移位和“3”移位(因为它们除以6)。例如:

10000010 
  10000010 (Shift by two)
    10000010
      10000010 (We have a match)

10000010
   10000010 (Shift by three)
      10000010 (We have a match)
10010001 gives the following tree

      3
     / \
  2 /   \ 3
   /     \
  0       7
所以你需要检查的唯一移位是2,3,5,7,11,13等等,直到最接近数字串大小平方根的素数

几乎解决了?

我想我离解决方案更近了。基本上:

  • 扫描字符串中的1。对于每个1音符,在取其位置的模后,它是剩余的。模的范围从1到字符串大小的一半。这是因为最大可能的分隔大小是字符串的一半。这是在O(n^2)中完成的。但是。只需要检查素模,所以O(n^2/log(n))
  • 首先按照最大模数的顺序对模数/余数列表进行排序,这可以在O(n*log(n))时间内完成
  • 寻找三个相同的连续模/余数
  • 以某种方式恢复一个的位置
  • 我认为答案的最大线索是,最快的排序算法是O(n*log(n))

    错误


    正如一位同事所指出的,步骤1是错误的。如果我们在位置2、12和102处有1。然后取模10,它们都有相同的余数,但间隔不是相等的!对不起。

    一个有趣的问题,但一旦你意识到两个'1'之间的实际模式无关紧要,算法就会变成:

    • 扫描查找“1”
    • 从另一个“1”的下一个位置扫描开始(到阵列末端减去与当前第一个“1”的距离,否则第三个“1”将超出范围)
    • 如果在第二个'1'的位置加上到第一个'1'的距离处发现第三个'1',我们有相等的空间
      proc get-triplet {input} {
          for {set first 0} {$first < [string length $input]-2} {incr first} {
              if {[string index $input $first] != 1} {
                  continue
              }
              set start [expr {$first + 1}]
              set end [expr {1+ $first + (([string length $input] - $first) /2)}]
              for {set second $start} {$second < $end} {incr second} {
                  if {[string index $input $second] != 1} {
                      continue
                  }
                  set last [expr {($second - $first) + $second}]
                  if {[string index $input $last] == 1} {
                      return [list $first $second $last]
                  }
              }
          }
          return {}
      }
      
      get-triplet 10101      ;# 0 2 4
      get-triplet 10111      ;# 0 2 4
      get-triplet 11100000   ;# 0 1 2
      get-triplet 0100100100 ;# 1 4 7
      
      public static int testString(String input){
      //n is the number of array/list accesses in the algorithm
      int n=0;
      
      //Put the indices of all the ones into a list, O(n)
      ArrayList<Integer> ones = new ArrayList<Integer>();
      for(int i=0;i<input.length();i++){
          if(input.charAt(i)=='1'){
              ones.add(i);
          }
      }
      
      //If less than three ones in list, just stop
      if(ones.size()<3){
          return n;
      }
      
      int firstIndex, secondIndex, thirdIndex;
      for(int x=0;x<ones.size()-2;x++){
          n++;
          firstIndex = ones.get(x);
      
          for(int y=x+1; y<ones.size()-1; y++){
              n++;
              secondIndex = ones.get(y);
              thirdIndex = secondIndex*2 - firstIndex;
      
              if(thirdIndex >= input.length()){
                  break;
              }
      
              n++;
              if(input.charAt(thirdIndex) == '1'){
                  //This case is satisfied if it has found three evenly spaced ones
                  //System.out.println("This one => " + input);
                  return n;
              }
          }
      }
      
      return n;
      
      100000000000011
      10000000000001101
      100000000000011011
      10000000000001101100001
      100000000000011011000011
      10000000000001101100001101
      100000000000011011000011010000000001
      100000000000011011000011010000000001001
      1000000000000110110000110100000000010011
      1000000000000110110000110100000000010011001
      10000000000001101100001101000000000100110010000000001
      10000000000001101100001101000000000100110010000000001000001
      1000000000000110110000110100000000010011001000000000100000100000000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011
      1000000000000110110000110100000000010011001000000000100000100000000000001101
      100000000000011011000011010000000001001100100000000010000010000000000000110100001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001
      1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001
      1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011
      1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001
      1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001
      1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001000001
      100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011001000000000000000000000010010000010000001
      1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001001000000000000000000000000000000000000110010000000000000000000000100100000100000011
      10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001000001000000110000000000001
      
      char *binaryStr = "0000010101000100";
      
      int main() {
         int head, tail, pos;
         head = 0;
         tail = strlen(binaryStr)-1;
         if( (pos = find3even(head, tail)) >=0 )
            printf("found it at position %d\n", pos);
         return 0;
      }
      
      int find3even(int head, int tail) {
         int pos = 0;
         if(head >= tail) return -1;
         while(binaryStr[head] == '0') 
            if(head<tail) head++;
         while(binaryStr[tail] == '0') 
            if(head<tail) tail--;
         if(head >= tail) return -1;
         if( (tail-head)%2 == 0 && //true if odd numbered
             (binaryStr[head + (tail-head)/2] == '1') ) { 
               return head;
         }else {
            if( (pos = find3even(head, tail-1)) >=0 )
               return pos;
            if( (pos = find3even(head+1, tail)) >=0 )
               return pos;
         }
         return -1;
      }
      
      #include <iostream>
      using namespace std;
      
      bool HasEvenBits (string &sequence, int &num_compares)
      {
        bool
          has_even_bits = false;
      
        num_compares = 0;
      
        for (unsigned i = 1 ; i <= (sequence.length () - 1) / 2 ; ++i)
        {
          for (unsigned j = 0 ; j < sequence.length () - 2 * i ; ++j)
          {
            ++num_compares;
            if (sequence [j] == '1' && sequence [j + i] == '1' && sequence [j + i * 2] == '1')
            {
              has_even_bits = true;
              // we could 'break' here, but I want to know the worst case scenario so keep going to the end
            }
          }
        }
      
        return has_even_bits;
      }
      
      int main ()
      {
        int
          count;
      
        string
          input = "111";
      
        for (int i = 3 ; i < 32 ; ++i)
        {
          HasEvenBits (input, count);
          cout << i << ", " << count << endl;
          input += "0";
        }
      }
      
       n  Tests  n log (n)
      =====================
       3     1     1.43
       4     2     2.41
       5     4     3.49
       6     6     4.67
       7     9     5.92
       8    12     7.22
       9    16     8.59
      10    20    10.00
      11    25    11.46
      12    30    12.95
      13    36    14.48
      14    42    16.05
      15    49    17.64
      16    56    19.27
      17    64    20.92
      18    72    22.59
      19    81    24.30
      20    90    26.02
      21   100    27.77
      22   110    29.53
      23   121    31.32
      24   132    33.13
      25   144    34.95
      26   156    36.79
      27   169    38.65
      28   182    40.52
      29   196    42.41
      30   210    44.31
      31   225    46.23
      
      def IsSymetric(number):
          number = number.strip('0')
      
          if len(number) < 3:
              return False
          if len(number) % 2 == 0:
              return IsSymetric(number[1:]) or IsSymetric(number[0:len(number)-2])
          else:
              if number[len(number)//2] == '1':
                  return True
              return IsSymetric(number[:(len(number)//2)]) or IsSymetric(number[len(number)//2+1:])
          return False
      
      using System;
      using System.Collections.Generic;
      
      namespace spacedOnes
      {
          class Program
          {
              static int[] _bits = new int[8] {128, 64, 32, 16, 8, 4, 2, 1};
      
              static void Main(string[] args)
              {
                  var bytes = new byte[4];
                  var r = new Random();
                  r.NextBytes(bytes);
                  foreach (var b in bytes) {
                      Console.Write(getByteString(b));
                  }
                  Console.WriteLine();
                  var bitCount = bytes.Length * 8;
                  var done = false;
                  var onePositions = new List<int>();
                  for (var i = 0; i < bitCount; i++)
                  {
                      if (isOne(bytes, i)) {
                          if (onePositions.Count > 0) {
                              foreach (var knownOne in onePositions) {
                                  var spacing = i - knownOne;
                                  var k = i + spacing;
                                  if (k < bitCount && isOne(bytes, k)) {
                                      Console.WriteLine("^".PadLeft(knownOne + 1) + "^".PadLeft(spacing) + "^".PadLeft(spacing));
                                      done = true;
                                      break;
                                  }
                              }
                          }
                          if (done) {
                              break;
                          }
                          onePositions.Add(i);
                      }
                  }
                  Console.ReadKey();
              }
      
              static String getByteString(byte b) {
                  var s = new char[8];
                  for (var i=0; i<s.Length; i++) {
                      s[i] = ((b & _bits[i]) > 0 ? '1' : '0');
                  }
                  return new String(s);
              }
      
              static bool isOne(byte[] bytes, int i)
              {
                  var byteIndex = i / 8;
                  var bitIndex = i % 8;
                  return (bytes[byteIndex] & _bits[bitIndex]) > 0;
              }
          }
      }
      
      101
      101001
      1010010001
      101001000100001
      101001000100001000001
      
      k=2  101
      k=3  101001
      k=4  1010010001
      k=5  101001000100001
      k=6  101001000100001000001
      
      k=2  n= 3  101
      k=3  n= 6  101001
      k=4  n=10  1010010001
      k=5  n=15  101001000100001
      k=6  n=21  101001000100001000001
      
      k=2  n= 3  p= 1  101
      k=3  n= 6  p= 3  101001
      k=4  n=10  p= 6  1010010001
      k=5  n=15  p=10  101001000100001
      k=6  n=21  p=15  101001000100001000001
      
      #!/usr/bin/perl
      
      # read input as first argument
      my $s = $ARGV[0];
      
      # validate the input
      $s =~ /^[01]+$/ or die "invalid input string\n";
      
      # strip leading and trailing 0's
      $s =~ s/^0+//;
      $s =~ s/0+$//;
      
      # prime the position list with the first '1' at position 0
      my @p = (0);
      
      # start at position 1, which is the second character
      my $i = 1;
      
      print "the string is $s\n\n";
      
      while ($i < length($s)) {
         if (substr($s, $i, 1) eq '1') {
            print "found '1' at position $i\n";
            my @t = ();
            # assuming this is the middle '1', go through the positions
            # of all the prior '1's and check whether there's another '1'
            # in the correct position after this '1' to make a solution
            while (scalar @p) {
               # $p is the position of the prior '1'
               my $p = shift @p;
               # $j is the corresponding position for the following '1'
               my $j = 2 * $i - $p;
               # if $j is off the end of the string then we don't need to
               # check $p anymore
               next if ($j >= length($s));
               print "checking positions $p, $i, $j\n";
               if (substr($s, $j, 1) eq '1') {
                  print "\nsolution found at positions $p, $i, $j\n";
                  exit 0;
               }
               # if $j isn't off the end of the string, keep $p for next time
               push @t, $p;
            }
            @p = @t;
            # add this '1' to the list of '1' positions
            push @p, $i;
         }
         $i++;
      }
      
      print "\nno solution found\n";
      
      10010001 gives the following tree
      
            3
           / \
        2 /   \ 3
         /     \
        0       7
      
      using System;
      using System.Collections.Generic;
      
      namespace StackOverflow1560523
      {
          class Program
          {
              public struct Pair<T>
              {
                  public T Low, High;
              }
              static bool FindCandidate(int candidate, 
                  List<int> arr, 
                  List<int> pool, 
                  Pair<int> pair, 
                  ref int iterations)
              {
                  int lower = pair.Low, upper = pair.High;
                  while ((lower >= 0) && (upper < pool.Count))
                  {
                      int lowRange = candidate - arr[pool[lower]];
                      int highRange = arr[pool[upper]] - candidate;
                      iterations++;
                      if (lowRange < highRange)
                          lower -= 1;
                      else if (lowRange > highRange)
                          upper += 1;
                      else
                          return true;
                  }
                  return false;
              }
              static List<int> BuildOnesArray(string s)
              {
                  List<int> arr = new List<int>();
                  for (int i = 0; i < s.Length; i++)
                      if (s[i] == '1')
                          arr.Add(i);
                  return arr;
              }
              static void BuildIndexes(List<int> arr, 
                  ref List<int> even, ref List<int> odd, 
                  ref List<Pair<int>> evenIndex, ref List<Pair<int>> oddIndex)
              {
                  for (int i = 0; i < arr.Count; i++)
                  {
                      bool isEven = (arr[i] & 1) == 0;
                      if (isEven)
                      {
                          evenIndex.Add(new Pair<int> {Low=even.Count-1, High=even.Count+1});
                          oddIndex.Add(new Pair<int> {Low=odd.Count-1, High=odd.Count});
                          even.Add(i);
                      }
                      else
                      {
                          oddIndex.Add(new Pair<int> {Low=odd.Count-1, High=odd.Count+1});
                          evenIndex.Add(new Pair<int> {Low=even.Count-1, High=even.Count});
                          odd.Add(i);
                      }
                  }
              }
      
              static int FindSpacedOnes(string s)
              {
                  // List of indexes of 1s in the string
                  List<int> arr = BuildOnesArray(s);
                  //if (s.Length < 3)
                  //    return 0;
      
                  //  List of indexes to odd indexes in arr
                  List<int> odd = new List<int>(), even = new List<int>();
      
                  //  evenIndex has indexes into arr to bracket even numbers
                  //  oddIndex has indexes into arr to bracket odd numbers
                  List<Pair<int>> evenIndex = new List<Pair<int>>(), 
                      oddIndex = new List<Pair<int>>(); 
                  BuildIndexes(arr, 
                      ref even, ref odd, 
                      ref evenIndex, ref oddIndex);
      
                  int iterations = 0;
                  for (int i = 1; i < arr.Count-1; i++)
                  {
                      int target = arr[i];
                      bool found = FindCandidate(target, arr, odd, oddIndex[i], ref iterations) || 
                          FindCandidate(target, arr, even, evenIndex[i], ref iterations);
                      if (found)
                          return iterations;
                  }
                  return iterations;
              }
              static IEnumerable<string> PowerSet(int n)
              {
                  for (long i = (1L << (n-1)); i < (1L << n); i++)
                  {
                      yield return Convert.ToString(i, 2).PadLeft(n, '0');
                  }
              }
              static void Main(string[] args)
              {
                  for (int i = 5; i < 64; i++)
                  {
                      int c = 0;
                      string hardest_string = "";
                      foreach (string s in PowerSet(i))
                      {
                          int cost = find_spaced_ones(s);
                          if (cost > c)
                          {
                              hardest_string = s;
                              c = cost;
                              Console.Write("{0} {1} {2}\r", i, c, hardest_string);
                          }
                      }
                      Console.WriteLine("{0} {1} {2}", i, c, hardest_string);
                  }
              }
          }
      }
      
      0 <= L < M < U <= X-1
      
      A[M] - A[L] = A[U] - A[M]
      
      2*A[M] = A[L] + A[U]
      
      M  L  U
      0  0  0
         1  2
         2  1
      1  0  2
         1  1
         2  0
      2  0  1
         1  0
         2  2
      
      M  L  U
      0  0  0
         1  5
         2  4
         3  3
         4  2
         5  1
      
      def solve(Str):
          indexes=[]
          #O(n) setup
          for i in range(len(Str)):
              if Str[i]=='1':
                  indexes.append(i)
      
          #O((number of 1's)^2) processing
          for i in range(len(indexes)):
              for j in range(i+1, len(indexes)):
                                  indexDiff = indexes[j] - indexes[i]
                  k=indexes[j] + indexDiff
                  if k<len(Str) and Str[k]=='1':
                      return True
          return False
      
      #assumes final char hasn't been added, and would be a 1 
      def lastCharMakesSolvable(Str):
          endIndex=len(Str)
          j=endIndex-1
          while j-(endIndex-j) >= 0:
              k=j-(endIndex-j)
              if k >= 0 and Str[k]=='1' and Str[j]=='1':
                  return True
              j=j-1
          return False
      
      
      
      def expandString(StartString=''):
          if lastCharMakesSolvable(StartString):
              return StartString + '0'
          return StartString + '1'
      
      n=1
      BaseStr=""
      lastCount=0
      while n<1000000:
          BaseStr=expandString(BaseStr)
          count=BaseStr.count('1')
          if count != lastCount:
              print(len(BaseStr), count)
          lastCount=count
          n=n+1
      
      strlength   # of 1's
          1    1
          2    2
          4    3
          5    4
         10    5
         14    8
         28    9
         41    16
         82    17
        122    32
        244    33
        365    64
        730    65
       1094    128
       2188    129
       3281    256
       6562    257
       9842    512
      19684    513
      29525    1024
      
      foreach character in the string
        if the character equals 1 {         
           if length cache > 0 { //we can skip the first one
              foreach location in the cache { //last in first out kind of order
                 if ((currentlocation + (currentlocation - location)) < length string)
                    if (string[(currentlocation + (currentlocation - location))] equals 1)
                       return found evenly spaced string
                 else
                    break;
              }
           }
           remember the location of this character in a some sort of cache.
        }
      
      return didn't find evenly spaced string
      
      public static Boolean FindThreeEvenlySpacedOnes(String str) {
          List<int> cache = new List<int>();
      
          for (var x = 0; x < str.Length; x++) {
              if (str[x] == '1') {
                  if (cache.Count > 0) {
                      for (var i = cache.Count - 1; i > 0; i--) {
                          if ((x + (x - cache[i])) >= str.Length)
                              break;
      
                          if (str[(x + (x - cache[i]))] == '1')
                              return true;                            
                      }
                  }
                  cache.Add(x);                    
              }
          }
      
          return false;
      }
      
      iteration 1:
      x
      |
      101101001
      // the location of this 1 is stored in the cache
      
      iteration 2:
       x
       | 
      101101001
      
      iteration 3:
      a x b 
      | | | 
      101101001
      //we retrieve location a out of the cache and then based on a 
      //we calculate b and check if te string contains a 1 on location b
      
      //and of course we store x in the cache because it's a 1
      
      iteration 4:
        axb  
        |||  
      101101001
      
      a  x  b  
      |  |  |  
      101101001
      
      
      iteration 5:
          x  
          |  
      101101001
      
      iteration 6:
         a x b 
         | | | 
      101101001
      
        a  x  b 
        |  |  | 
      101101001
      //return found evenly spaced string
      
      using System;
      
      namespace ThreeNumbers
      {
          class Program
          {
              const int uint32Length = 32;
      
              static void Main(string[] args)
              {
                  Console.Write("Please enter your integer: ");
                  uint input = UInt32.Parse(Console.ReadLine());
      
                  uint[] distancesLower = Distances(input);
                  uint[] distancesHigher = Distances(Reverse(input));
      
                  PrintHits(input, distancesLower, distancesHigher);
              }
      
              /// <summary>
              /// Returns an array showing how far the ones away from each bit in the input.  Only 
              /// considers ones at lower signifcant bits.  Index 0 represents the least significant bit 
              /// in the input.  Index 1 represents the second least significant bit in the input and so 
              /// on.  If a one is 3 away from the bit in question, then the third least significant bit 
              /// of the value will be sit.
              /// 
              /// As programed this algorithm needs: O(n) time, and O(n*log(n)) space.  
              /// (Where n is the number of bits in the input.)
              /// </summary>
              public static uint[] Distances(uint input)
              {
                  uint[] distanceToOnes = new uint[uint32Length];
                  uint result = 0;
      
                  //Sets how far each bit is from other ones. Going in the direction of LSB to MSB
                  for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
                  {
                      distanceToOnes[arrayIndex] = result;
                      result <<= 1;
      
                      if ((input & bitIndex) != 0)
                      {
                          result |= 1;
                      }
                  }
      
                  return distanceToOnes;
              }
      
              /// <summary>
              /// Reverses the bits in the input.
              /// 
              /// As programmed this algorithm needs O(n) time and O(n) space.  
              /// (Where n is the number of bits in the input.)
              /// </summary>
              /// <param name="input"></param>
              /// <returns></returns>
              public static uint Reverse(uint input)
              {
                  uint reversedInput = 0;
                  for (uint bitIndex = 1; bitIndex != 0; bitIndex <<= 1)
                  {
                      reversedInput <<= 1;
                      reversedInput |= (uint)((input & bitIndex) != 0 ? 1 : 0);
                  }
      
                  return reversedInput;
              }
      
              /// <summary>
              /// Goes through each bit in the input, to check if there are any bits equally far away in 
              /// the distancesLower and distancesHigher
              /// </summary>
              public static void PrintHits(uint input, uint[] distancesLower, uint[] distancesHigher)
              {
                  const int offset = uint32Length - 1;
      
                  for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
                  {
                      //hits checks if any bits are equally spaced away from our current value
                      bool isBitSet = (input & bitIndex) != 0;
                      uint hits = distancesLower[arrayIndex] & distancesHigher[offset - arrayIndex];
      
                      if (isBitSet && (hits != 0))
                      {
                          Console.WriteLine(String.Format("The {0}-th LSB has hits 0x{1:x4} away", arrayIndex + 1, hits));
                      }
                  }
              }
          }
      }
      
      package com.example.math;
      
      import java.io.PrintStream;
      import java.util.BitSet;
      import java.util.Random;
      
      public class EvenlySpacedOnesTest {
          static public class StatisticalSummary
          {
              private int n=0;
              private double min=Double.POSITIVE_INFINITY;
              private double max=Double.NEGATIVE_INFINITY;
              private double mean=0;
              private double S=0;
      
              public StatisticalSummary() {}
              public void add(double x) {
                  min = Math.min(min, x);
                  max = Math.max(max, x);
                  ++n;
                  double newMean = mean + (x-mean)/n;
                  S += (x-newMean)*(x-mean);
                  // this algorithm for mean,std dev based on Knuth TAOCP vol 2
                  mean = newMean;
              }
              public double getMax() { return (n>0)?max:Double.NaN; }
              public double getMin() { return (n>0)?min:Double.NaN; }
              public int getCount() { return n; }
              public double getMean() { return (n>0)?mean:Double.NaN; }
              public double getStdDev() { return (n>0)?Math.sqrt(S/n):Double.NaN; } 
              // some may quibble and use n-1 for sample std dev vs population std dev    
              public static void printOut(PrintStream ps, StatisticalSummary[] statistics) {
                  for (int i = 0; i < statistics.length; ++i)
                  {
                      StatisticalSummary summary = statistics[i];
                      ps.printf("%d\t%d\t%.0f\t%.0f\t%.5f\t%.5f\n",
                              i,
                              summary.getCount(),
                              summary.getMin(),
                              summary.getMax(),
                              summary.getMean(),
                              summary.getStdDev());
                  }
              }
          }
      
          public interface RandomBernoulliProcess // see http://en.wikipedia.org/wiki/Bernoulli_process
          {
              public void setProbability(double d);
              public boolean getNextBoolean();
          }
      
          static public class Bernoulli implements RandomBernoulliProcess
          {
              final private Random r = new Random();
              private double p = 0.5;
              public boolean getNextBoolean() { return r.nextDouble() < p; }
              public void setProbability(double d) { p = d; }
          }   
          static public class TestResult {
              final public int k;
              final public int nsteps;
              public TestResult(int k, int nsteps) { this.k=k; this.nsteps=nsteps; } 
          }
      
          ////////////
          final private int n;
          final private int ntrials;
          final private double pmin;
          final private double pmax;
          final private Random random = new Random();
          final private Bernoulli bernoulli = new Bernoulli();
          final private BitSet bits;
          public EvenlySpacedOnesTest(int n, int ntrials, double pmin, double pmax) {
              this.n=n; this.ntrials=ntrials; this.pmin=pmin; this.pmax=pmax;
              this.bits = new BitSet(n);
          }
      
          /*
           * generate random bit string
           */
          private int generateBits()
          {
              int k = 0; // # of 1's
              for (int i = 0; i < n; ++i)
              {
                  boolean b = bernoulli.getNextBoolean();
                  this.bits.set(i, b);
                  if (b) ++k;
              }
              return k;
          }
      
          private int findEvenlySpacedOnes(int k, int[] pos) 
          {
              int[] bitPosition = new int[k];
              for (int i = 0, j = 0; i < n; ++i)
              {
                  if (this.bits.get(i))
                  {
                      bitPosition[j++] = i;
                  }
              }
              int nsteps = n; // first, it takes N operations to find the bit positions.
              boolean found = false;
              if (k >= 3) // don't bother doing anything if there are less than 3 ones. :(
              {       
                  int lastBitSetPosition = bitPosition[k-1];
                  for (int j1 = 0; !found && j1 < k; ++j1)
                  {
                      pos[0] = bitPosition[j1];
                      for (int j2 = j1+1; !found && j2 < k; ++j2)
                      {
                          pos[1] = bitPosition[j2];
      
                          ++nsteps;
                          pos[2] = 2*pos[1]-pos[0];
                          // calculate 3rd bit index that might be set;
                          // the other two indices point to bits that are set
                          if (pos[2] > lastBitSetPosition)
                              break;
                          // loop inner loop until we go out of bounds
      
                          found = this.bits.get(pos[2]);
                          // we're done if we find a third 1!
                      }
                  }
              }
              if (!found)
                  pos[0]=-1;
              return nsteps;
          }
      
          /*
           * run an algorithm that finds evenly spaced ones and returns # of steps.
           */
          public TestResult run()
          {
              bernoulli.setProbability(pmin + (pmax-pmin)*random.nextDouble());
              // probability of bernoulli process is randomly distributed between pmin and pmax
      
              // generate bit string.
              int k = generateBits();
              int[] pos = new int[3];
              int nsteps = findEvenlySpacedOnes(k, pos);
              return new TestResult(k, nsteps); 
          }
      
          public static void main(String[] args)
          {
              int n;
              int ntrials;
              double pmin = 0, pmax = 1;
              try {
                  n = Integer.parseInt(args[0]);
                  ntrials = Integer.parseInt(args[1]);
                  if (args.length >= 3)
                      pmin = Double.parseDouble(args[2]);
                  if (args.length >= 4)
                      pmax = Double.parseDouble(args[3]);
              }
              catch (Exception e)
              {
                  System.out.println("usage: EvenlySpacedOnesTest N NTRIALS [pmin [pmax]]");
                  System.exit(0);
                  return; // make the compiler happy
              }
      
              final StatisticalSummary[] statistics;
              statistics=new StatisticalSummary[n+1];
              for (int i = 0; i <= n; ++i)
              {
                  statistics[i] = new StatisticalSummary();
              }
      
              EvenlySpacedOnesTest test = new EvenlySpacedOnesTest(n, ntrials, pmin, pmax);
              int printInterval=100000;
              int nextPrint = printInterval;
              for (int i = 0; i < ntrials; ++i)
              {
                  TestResult result = test.run();
                  statistics[result.k].add(result.nsteps);
                  if (i == nextPrint)
                  {
                      System.err.println(i);
                      nextPrint += printInterval;
                  }
              }
              StatisticalSummary.printOut(System.out, statistics);
          }
      }
      
      # <algorithm>
      def contains_evenly_spaced?(input)
        return false if input.size < 3
        one_indices = []
        input.each_with_index do |digit, index|
          next if digit == 0
          one_indices << index
        end
        return false if one_indices.size < 3
        previous_indexes = []
        one_indices.each do |index|
          if !previous_indexes.empty?
            previous_indexes.each do |previous_index|
              multiple = index - previous_index
              success_index = index + multiple
              return true if input[success_index] == 1
            end
          end
          previous_indexes << index
        end
        return false
      end
      # </algorithm>
      
      def parse_input(input)
        input.chars.map { |c| c.to_i }
      end