增加无限二进制计数器

时间:2013-02-21 20:59:50

标签: c# binary bit-manipulation

采取编码采访:

如何在O(1)时间复杂度中实现具有increment的无限二进制计数器?

我想要计算最右边0的第一和第二位置,但我不确定如何实现它。

“无限计数器”意味着您可以无限次地增加(大于MAX_INT)。

4 个答案:

答案 0 :(得分:7)

对于二元计数器......

如果你想让计数器处于“正常”位模式,你基本上不能 - 至少不能总是 O(1)而不是摊销 O(1)。

如果它是一个无限计数器,它可以有任意多位。这意味着你可以有多个N位,所有这些都是1.增加该计数器意味着将所有这些位设置为0,这可以合理地假设为O(N)操作。

我们可以在“正常”计算中考虑增量为O(1)的唯一原因是通常处理固定大小的类型,我们可以说(例如)“最多32位需要更改 - 这是一个常数,所以它可以说是一个O(1)操作。“

只是一个反击......

另一方面,如果只是希望能够在O(1)时间内增加,那么你拥有无限的内存,并且你不关心恢复该值需要多长时间,可以做,只需有效地使用长度为计数器大小的链表。

例如,在C#中:

public DodgySolution
{
    public static DodgySolution Zero = new DodgySolution(null);

    private DodgySolution tail;

    private DodgySolution(DodgySolution tail)
    {
        this.tail = tail;
    }

    // This bit is O(1)
    public DodgySolution Increment()
    {
        return new DodgySolution(this);
    }

    // This bit isn't...
    public BigInteger ToBigInteger()
    {
        return tail == null ? BigInteger.Zero
                            : BigInteger.One + tail.ToBigInteger();
    }
}

即使这假设引用赋值是O(1) - 但是对于无限数量的对象可能会变得棘手......

答案 1 :(得分:3)

  • 使用具有加倍策略的某种阵列存储。这意味着分配摊销O(1)
    链表也应该有用。
  • 使用琐碎的教科书。对于更高位,进位成倍增加。进位的平均成本是1 + 0.5 + 0.25 + ... = 2,其中O(1)

因此,直接实施已经摊销了O(1)表现。唯一的问题是你需要可变存储。

当查看数字n的单个增量运算时,平均时间为O(1),但最差情况为O(log(n))。内存使用率为O(log(n))。

var counter=new List<bool>{false};

void Inc()
{
  while(counter[i])
  {
      counter[i]=false;
      i++;
  }
  if(i==counter.Length)
    counter.Add(true);
  else
    counter[i]=true;
}

答案 2 :(得分:2)

如果问题要求增加O(1)计数器而没有任何其他限制,您的计数器可以实现为数字的链接列表,项目总和是您的计数器的值。

如果前面的值大于(Max-1),则递增相当于向最后一项添加1或添加新项= 1。

由于您总是最多检查列表中的2个项目,因此递增将为O(1)

请不要尝试用闪亮的新柜台做其他算术:D

答案 3 :(得分:-1)

我的尝试:

我们会在连续的10上保留一个汇总。

意味着111000111是&lt; 1,0&gt; &LT; 3,1&GT; &LT; 3,0&GT; &LT; 3,1&GT;

我可以使用以下DS表示:

节点列表{digit:bool,counter:long}

1)如果第一个批量为1。它变为0的大部分并将下一个0转为1。

我们现在检查是否可以聚合1的批量。

2)如果第一个批量为0,我们将第一个数字设为1.并查看我们是否可以汇总1个。

示例A:

意味着111000111是&lt; 1,0&gt; &LT; 3,1&GT; &LT; 3,0&GT; &LT; 3,1&GT;

阅读:三个1位数,三个0位数,三个1位数,一个0位数

增量()

&LT; 1,0&GT; &LT; 3,1&GT; &LT; 2,0&GT; &LT; 1,1 GT; &LT; 3,0&GT;

例B:

&LT; 1,0&GT; &LT; 3,1&GT; &LT; 1,0&GT; &LT; 3,1&GT;

增量()

&LT; 1,0&GT; &LT; 3,1&GT; &LT; 1,1 GT; &LT; 3,0&GT;

聚合:

&LT; 1,0&GT; &LT; 4,1&GT; &LT; 3,0&GT;

始终存在常数变化(最多0位数)

并转换1 s的大部分内容只是为了摆弄布尔成员。这是常数