在堆栈中查找最长的字符序列

时间:2016-05-17 15:44:54

标签: c# arrays algorithm loops stack

您好我正在解决问题:

  

给定一个基数为10的整数n,将其转换为二进制(base-2)。然后找到并且   打印基数为10的整数,表示连续1的最大数量   在n的二进制表示中。对于例如对于n = 5,base-2 = 101所以输出应该是1,对于n = 439,base-2 = 110110111,所以输出应该是3.

以下是我的代码解决方案:

class Solution {

    static int CalcBinary (int n) {
        Stack<int> binRep = new Stack<int>();
        while (n > 0) {
            int i = n%2;
            binRep.Push (i);
            n = n/2;
        }
        int oldCount = 0, newCount = 0;
        while (binRep.Count > 0){
            int val = binRep.Pop();
            if (val == 1) {
                newCount++;
            } else {
                if (newCount > oldCount) {
                    oldCount = newCount;
                }
                newCount = 0;
            }
        }
        return (newCount > oldCount) ? newCount : oldCount;
    }

    static void Main(String[] args) {
        int n = Convert.ToInt32(Console.ReadLine());
        Console.WriteLine (CalcBinary(n));
    }
}

代码运行良好并通过所有测试用例,例如n = 5,6,439等。只有问题是,如果有任何优化的解决方案来做同样的事情。其他人发布了相同的问题here,但对该问题的所有回复似乎与O(n)时间复杂度相同。另一件事是我可以使用数组而不是Stack,但它会有什么不同吗?

3 个答案:

答案 0 :(得分:5)

public int CalcBinary(int n)
{
    int result = 0;
    int current = 0;
    for (int i = 0; i + result < 32 && (n >> i) != 0; i++)
    {
        if (((n >> i) & 1) == 1)
            current += 1;
        else
        {
            if (current > result) 
                result = current;
            current = 0;
        }
    }

    return result == 0 ? current : result;
}

我不太擅长大O算术,但我认为这个解决方案应该更快,因为我不使用任何其他类而是简单的位移。

如果不再有解决方案,我提前停止i + result < 32)。

注意,这仅适用于 32位整数。对于64位调整上述条件。它仅适用于值(设置符号位可能会产生错误的结果,例如111....111101)。

更新:根据@ Scott-Chamberlain的建议添加了(n >> i) != 0条件(它会检查是否还有1个。)

答案 1 :(得分:2)

为什么不在转换二进制文件而不是等待转换完成时计算maximum_consecutive,然后再从堆栈中计算maximum_consecutive

我认为你应该改变这一点。

class Solution {

static int CalcBinary (int n) {
    int oldCount = 0, newCount = 0;
    while (n > 0) {
        int i = n%2;
        n = n/2;

        if (i == 1) {
            newCount++;
        }
        else {
            if (newCount > oldCount) {
                oldCount = newCount;
            }
            newCount = 0;
        }

    }
    return (newCount > oldCount) ? newCount : oldCount;
}

static void Main(String[] args) {
    int n = Convert.ToInt32(Console.ReadLine());
    Console.WriteLine (CalcBinary(n));
}
}

答案 2 :(得分:1)

对于有点小小的乐趣和最小的分支:

int[] lookup = new[]
{
  0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 
  31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
int LongestRunOfBits(uint value)
{
    int max = 0;
    while(1 << max < value + 1)
    {
        uint testValue = ~value;
        uint lookupIndex = ((uint)((testValue & -testValue) * 0x077CB531U)) >> 27;
        int trailingZeros = lookup[lookupIndex];
        max = trailingZeros - ((trailingZeros - max) & ((trailingZeros - max) >> 31));
        value >>= 1;
    }
    return max;
}

这结合了以下操作:

Compute the maximum of two integers without branching(QuAD版本)

Count the consecutive zero bits (trailing) on the right with multiply and lookup(如果它计算value上的尾随零位,则计算~value上的一位尾随

让我们按照value 6或110进行此操作:

现在我们有:

             value : 00000000000000000000000000000110
            ~value : 11111111111111111111111111111001
trailing zero bits : 0
   value after rsh : 00000000000000000000000000000011
            ~value : 11111111111111111111111111111100
trailing zero bits : 2
   value after rsh : 00000000000000000000000000000001 //skip this last iteration
            ~value : 11111111111111111111111111111110 //as it will now be impossible
trailing zero bits : 1                                //to find a value > 2

通过查找~value的尾随零位的最大数量,我们有效地找到value的最后一位尾随位数。如果我们继续进行右移,直到没有剩余比特,则最长的设置比特运行是我们在~value上执行的尾随零比特操作的最大值。万岁。一旦我们找到值2并且值中剩余2个或更少的位,我们可以提前保释,因为我们可以确定不会找到大于2的值,因此可以跳过最后一次迭代。