查找堆栈中最长的字符序列
Posted
技术标签:
【中文标题】查找堆栈中最长的字符序列【英文标题】:Find longest sequence of characters in stack 【发布时间】:2016-09-13 19:58:27 【问题描述】:您好,我正在解决一个问题:
给定一个以 10 为底的整数 n,将其转换为二进制(以 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) 时间复杂度相同。另一件事是我可以使用数组而不是堆栈,但这有什么不同吗??
【问题讨论】:
437 (110110101
) 的答案是什么? 2?
我认为计算一个数字中的 1 位(即 O(1 的数量))可能适用于这种情况,以获得比固定长度数字的 O(位数)更好... (只是猜测,不完全确定会不会成功)
我很确定您的意思是 O(log n)
,除非 n
是二进制位数而不是数字本身。
有什么理由需要使用堆栈或数组 - 您可以直接处理整数值吗? while (n > 0) if ((n%2) == 1) .......
@UweKeim,在此之前我遇到过问题,虽然我的问题在 *** 上有效,但在代码审查中却是负面的。所以我更愿意在这里问他们。
【参考方案1】:
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
s 会出现)。
【讨论】:
你也可以通过i + result < 32 && n >> i != 0
提前退出
@ScottChamberlain 我不明白,不应该是i + result < 32 || (n >> i) == 0
吗?所以 int 的“上其余部分”是零?
@ScottChamberlain 啊抱歉,我的错,for
循环的条件继续...我在脑海中将其转为退出条件【参考方案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));
【讨论】:
是的,实际上这使我免于创建堆栈。谢谢。【参考方案3】:为了有趣和最小的分支:
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
:
现在我们有了:
值:000000000000000000000000000000110 〜价值:1111111111111111111111111111001 尾随零位:0 rsh 后的值:000000000000000000000000000000011 〜价值:1111111111111111111111111111100 尾随零位:2 rsh 之后的值:00000000000000000000000000000001 //跳过最后一次迭代 ~value : 11111111111111111111111111111110 //因为现在不可能 尾随零位:1 //找到一个> 2的值通过找到~value
的最大尾随零位数,我们有效地找到了value
的最大尾随一位数。如果我们继续右移直到没有剩余的位,最长的设置位运行是我们在~value
上执行的尾随零位操作的最大值。万岁。一旦我们找到值 2 并且该值中剩余的位数为 2 或更少,我们可以提前放弃,因为我们可以确定找不到大于 2 的值,因此可以跳过最后一次迭代。
【讨论】:
以上是关于查找堆栈中最长的字符序列的主要内容,如果未能解决你的问题,请参考以下文章
[LCS] nwHJ65 查找两个字符串a,b中的最长公共子串(LCS+KMP+substr暴力)