Algorithm 仅使用+;1,-1和#xF7;2.
我遇到了这个问题,在给定任何数量的Algorithm 仅使用+;1,-1和#xF7;2.,algorithm,performance,math,time-complexity,Algorithm,Performance,Math,Time Complexity,我遇到了这个问题,在给定任何数量的x的情况下,找到最小操作数,其中一个操作是x-1,x+1,或x/2,这样在所有操作结束时x=1 我理解仅仅通过查看执行操作(基于位操作)的解决方案。然而,结果是类似于O(logn)。这个问题有O(1)解决方案吗?如果没有,是否有更好的解决方案,只运行实际操作?是的,如果您只想知道操作的数量,那么应该有一种方法可以做到这一点,而不需要实际进行所有计算。这将是非常大的数字快得多。诸如此类: public int countOps(String bits) { //
x
的情况下,找到最小操作数,其中一个操作是x-1
,x+1
,或x/2
,这样在所有操作结束时x=1
我理解仅仅通过查看执行操作(基于位操作)的解决方案。然而,结果是类似于O(logn)。这个问题有O(1)解决方案吗?如果没有,是否有更好的解决方案,只运行实际操作?是的,如果您只想知道操作的数量,那么应该有一种方法可以做到这一点,而不需要实际进行所有计算。这将是非常大的数字快得多。诸如此类:
public int countOps(String bits) { // bit string with only 1 and 0 and first bit is 1
int count = 0, i = bits.length - 1, b = bits.charAt(i) - '0';
for (;;) {
// remove 0s with /2
while (b == 0) {
count++;
b = bits.charAt(--i) - '0';
}
// lowest bit b is now 1
if (i < 1)
return count;
if (i == 1) // the 3 edge case
return count + 1;
int a = bits.charAt(i - 1) - '0';
if (a == 0) { // have to do -1
i -= 2;
count += 3; // -1, /2, /2
if (i < 1)
return count;
b = bits.charAt(i) - '0';
} else { // have to do +1 and propagate
count += 2; // +1, /2 (the /2 at the end of the propagation)
while (a == 1) {
count++; // /2
if (--i == 0)
return count;
a = bits.charAt(i - 1) - '0';
}
i--;
}
}
}
public int countOps(字符串位){//只有1和0的位字符串,第一位是1
int count=0,i=bits.length-1,b=bits.charAt(i)-'0';
对于(;;){
//使用/2删除0
而(b==0){
计数++;
b=位字符(--i)-“0”;
}
//最低位b现在是1
if(i<1)
返回计数;
if(i==1)//3边情况
返回计数+1;
int a=位字符(i-1)-“0”;
如果(a==0){//必须执行-1
i-=2;
计数+=3;/-1,/2,/2
if(i<1)
返回计数;
b=位字符(i)-“0”;
}否则{//必须执行+1并传播
计数+=2;//+1,/2(传播结束时的/2)
while(a==1){
计数+++;///2
如果(--i==0)
返回计数;
a=位字符(i-1)-“0”;
}
我--;
}
}
}
提出的重复问题的第二部分显示了一种算法,该算法根据输入数字的最低有效位确定最佳操作
然而,结果是类似于O(logn)。这个问题有O(1)解决方案吗?如果没有,是否有一个更好的解决方案,只是在实际操作中运行
为了优化该解决方案,我们可以直接计算每个位模式所需的操作数,然后删除这些位
请注意,我们必须仅在执行加法时更改高位,否则只需要进行位移位
还注意到,当输入为0时,下面的C++代码返回1,与上述答案相反,不考虑角情况。
size_t steps_count(size_t n)
{
size_t count{};
while (n > 3) {
switch ( n % 4 ) {
case 0b00:
count += 2;
n >>= 2;
break;
case 0b01:
count += 3;
n >>= 2;
break;
case 0b10:
++count;
n >>= 1;
break;
case 0b11:
count += 3;
n >>= 2;
++n;
break;
}
}
switch ( n ) {
case 1:
return count;
case 3:
return count + 2;
default:
return count + 1;
}
}
这种方法可以推广到一次处理更多位,还可以引入查找表。这是否值得,留给读者来决定。Big-O不是一切,特别是如果您已经有了O(logn)解决方案 理论推理 当谈到大O时间复杂性时,不断增加的值的渐近行为是相关的。所以,本质上我们不能局限于一些固定长度的整数计算 由于现在没有CPU可以在恒定时间内对无限位整数进行运算(可能永远也不会),所以除了大多数位都不相关的非常特殊的情况外,严重的O(1)本身是不可能的(例如,O(1)决定一个数是否为偶数,只看最低有效位) 所以,O(logn)是你能期望的最好的 如果您限制位长度(因此违反了渐近行为方面!),您可以通过计算一个包含所有解的表(与n无关的常数时间,表示O(1)),然后对该表进行索引(也是O(1)),轻松实现O(1) 通常,在大O分析中,我们将加法等假设为O(1)运算,如果我们的算法的运行时间已经在32位整数的限制范围内爆炸,我们可以这样做,因此可以故意忽略关于更大整数的推理。但是对于O(logn),32位内没有爆炸 实践方面 通常,我们对一些理论结果不感兴趣,但希望得到一个估计,给定一些预期的输入值范围,我们的算法需要多长时间。如果Big-O告诉我们像O(2^n)这样的结果,我们知道如果n增长超过20左右,我们就会遇到问题 但是对于像O(logn)这样的结果,最重要的不是n值越高的渐近增长,而是实际需要的计算步骤数。因此,优化Big-O复杂性不再会带来现实世界中的改进(请参阅上面我的O(1)“解决方案”——没有人会这样做) 在现实世界中
- 使用一个合理的、可理解的算法,并具有可接受的时间和空间复杂性
- 根据需求在相关输入范围内测试应用程序的运行时行为
- 如果发现性能问题,请使用分析工具查找原因
- 精确地优化您看到的热点,可能通过做一些局部改进,可能通过使用更高级的算法
+1
操作导致进位到此块的情况
表格必须提供两条信息:
- 此区块所需的步骤数
- 是否对下一个块进行正进位的标志