通过翻转一位二进制nubmer可以获得最大连续1或0

时间:2016-11-02 09:04:20

标签: c# algorithm math numbers number-theory

给定二进制数,找到只能翻转一位(1或0)可以获得的最大连续1或0

给出的代码是

    public int getMacCon(string[] A)
    {
        int n = A.Length;
        int result = 0;
        for (int i = 0; i < n - 1; i++)
        {
            if (A[i] == A[i + 1])
                result = result + 1;
        }
        int r = -2;

        for (int i = 0; i < n; i++)
        {
            int count = 0;
            if (i > 0)
            {
                if (A[i - 1] != A[i])
                    count = count + 1;
                else
                    count = count - 1;
            }
            if (i < n - 1)
            {
                if (A[i + 1] != A[i])
                    count = count + 1;
                else
                    count = count - 1;
            }
            r = Math.Max(r, count);
        }
        return result + r;
    }

我很难弄清楚这里的逻辑。特别是下面给出的部分

    for (int i = 0; i < n - 1; i++)
    {
        if (A[i] == A[i + 1])
            result = result + 1;
    }

如果任何人能够解释这个解决方案中的逻辑,我会非常高兴。 感谢

2 个答案:

答案 0 :(得分:2)

您突出显示的位只计算当前相邻相等值的数量,即一个值(A[i])等于下一个值(A[i+1])。然后,它依次询问(第二个循环),对于每个值,是否翻转它会增加vs减少而不改变相邻相等值的数量;因此,如果一个值当前与之前的值不同A[i-1] != A[i]),则翻转将增加 - 否则减少;同样是它之后的那个。最终结果是预先存在的相邻相等值(result)的数量,加上扫描中找到的最佳增量(r)。

public int getMacCon(string[] A)
{
    int n = A.Length;
    int result = 0;
    // find how many adjacent values are currently in the string
    for (int i = 0; i < n - 1; i++)
    {
        // if same as the next value, that's a hit
        if (A[i] == A[i + 1])
            result = result + 1;
    }
    // worst case delta from flipping one value is that me make it
    // worse on both sides, so -2
    int r = -2;

    // now consider each value in turn
    for (int i = 0; i < n; i++)
    {
        int count = 0;
        if (i > 0) // test value before, if not the first value
        {
            if (A[i - 1] != A[i])
                count = count + 1; // before is different; flip is incr
            else
                count = count - 1; // before is same; flip is decr
        }
        if (i < n - 1) // test value after, if not the last value
        {
            if (A[i + 1] != A[i])
                count = count + 1; // after is different; flip is incr
            else
                count = count - 1; // after is same; flip is decr
        }
        // compare that to the tracking counter, and keep the best value
        r = Math.Max(r, count);
    }
    // final result is sum of pre-existing count plus the delta
    return result + r;
}

顺便提一下,优化可能是将第二个循环测试从i < n更改为i < n && r != 2 - 即在找到最佳可能的delta后立即停止(使其在两侧都更好,+ 2)

答案 1 :(得分:1)

不是你问题的直接答案(正如Marc Gravell的答案所涵盖的那样)但我只想补充一下如何解决这个问题:

  1. 使用RLE(行程长度编码)对字符串进行编码

    因此您需要b,v,n个值的数组。如果b>=0是起始位置,v={0,1}是位值,n是后续发生的计数。例如:

    const int _max=100; // max number of bits
    int b[_max],v[_max],n[_max],bvns=0;
    

    bvns是数组中使用的b,v,n的数量。您也可以使用任何动态列表/模板。

  2. 重置您的实际解决方案

    您需要位位置来更改ix以及在其翻转sz之后产生的后续位数。将展位设置为零。

  3. 扫描RLE以查找n=1

    的项目

    如果发现这意味着在RLE之前和之后的项目是相同的,那么翻转将加入它们。因此,计算结果大小,如果更大,则存储为实际解决方案,如:

    for (int i=1;i<bvns-1;i++) // scann RLE except first and last item
     if (n[i]==1) // single bit found
      {
      l=n[i-1]+1+n[i+1]; // resulting size
      if (l>=sz) { sz=l; ix=b; } // update solution
      }
    
  4. 测试放大单个序列是否不大

    简单地:

    for (int i=0;i<bvns;i++) // scann RLE
     if (n[i]>=sz) // result is bigger?
      {
      sz=l; ix=b-1; // update solution
      if (ix<0) ix=b+n[i];
      }