我正在hackerrank上解决这个问题
给出无符号整数的分子和除数,打印出商和余数。您不能使用除法,不能使用mod,并且要优化速度
我最初的想法是(使用python)
def divide_problem(num, div):
quotient = 1
while (div * quotient) < num:
quotient += 1
remainder = (div*quotient) - num
print(quotient, "quotient")
print(remainder, 'remainder')
print(divide_problem(31, 5))
但是使用这种方法,我得到的商为7,余数为4。我能够在线找到正确的解决方案,即:
def divide_problem(num, div):
quotient = 1
while num - (quotient * div) >= div:
print(num - (quotient * div), "loop")
quotient += 1
remainder = num - (quotient * div)
print(quotient, "quotient")
print(remainder, 'remainder')
print(divide_problem(31, 5))
我无法找出while循环的条件语句
while num - (quotient * div) >= div:
提出该陈述的思考过程是什么?
答案 0 :(得分:1)
这仅仅是因为remainder
不能大于divider
。
然后num - (quotient * div)
恰好给出了remainder
。
因此,如果num - (quotient * div)
大于divider
,则意味着quotient
不够大。
这就是为什么它需要继续做直到remainder
小于divider
。
答案 1 :(得分:1)
num - (quotient*div) >= div
在数学上与((quotient+1) * div) <= num
这与您的想法几乎相同,但是您犯了一个错误。当我在设计像这样的东西时,我总是测试边界条件。
您的条件为“如果quotient*div < num
,则商太小”。因此,请尝试使用quotient*div == num-1
的某些情况,并确保商数确实过小。并尝试使用quotient*div == num
的某些情况,并确保商数确实足够大。
现在,您可能不需要担心这里还有2级。精心编写了第二个循环中使用的精确形式num - (quotient*div) >= div
,以免产生任何大于num
和div
的中间结果。即使您为num
和/或div
使用尽可能大的整数,这也可以确保您得到正确的答案。
如果将其写为((quotient+1) * div) <= num
,则(quotient+1)*div
可能太大而无法表示为整数,这可能导致条件得到错误的答案(在许多语言中,至少在某些版本的python IIRC中)。
答案 2 :(得分:0)
官方解决方案只是重复减法的低效实现,它用更复杂的乘法代替了简单的减法;如果要使用重复减法,则至少应消除乘法:
def divide(num, div):
quot = 0
while div <= num:
quot += 1
num -= div
return quot, num
重复减法未针对速度进行“优化”,因为您会看到是否调用divide(1000000000,3)
。取而代之的是,我们可以重复使用除数的平方或除数的平方,或...重复进行减法运算,直到...除数的平方的平方超过数字为止。例如,请考虑上面提到的问题divide(1000000000,3)
。我们首先列出一个正方形列表:
3 * 3 = 9
9 * 9 = 81
81 * 81 = 6561
6561 * 6561 = 43046721
我们停在那里,因为下一次平方超出目标。现在,我们在每个余数上重复调用朴素的除以除法算法:
divide(1000000000, 43046721) = (23, 9925417)
divide(9925417, 6561) = (1512, 5185)
divide(5185, 81) = (64, 1)
divide(1, 9) = (0, 1)
divide(1, 3) = (0, 1)
最后的余数是1。商是:
0*3/3 + 0*9/3 + 64*81/3 + 1512*6561/3 + 23*43046721/3 = 333333333
,我们只执行了23 + 1512 + 64 = 1599的减法运算,而不是官方解决方案的333,333,333减法运算。这是代码:
def divide(num, div):
divs, sqs, sum = [div], [1], 0
while divs[-1] * divs[-1] < num:
divs.append(divs[-1] * divs[-1])
sqs.append(sqs[-1] * sqs[-1] * div)
while divs:
div, sq = divs.pop(), sqs.pop()
quot = 0
while div <= num:
quot += 1
num -= div
sum += (quot * sq)
return sum, num
第一个while
计算并堆叠平方,每个平方也被 div 除以,因此最终代码中没有除法。在第一个while
之后, divs 和 sqs 堆栈如下所示:
divs = [3, 9, 81, 6561, 43046721]
sqs = [1, 3, 27, 2187, 14348907]
第二个while
重复弹出两个堆栈,在第三个while
中执行幼稚的重复除法算法,并累积 sum 。这比官方解决方案要快得多,而且也没有那么复杂。
您可以在https://ideone.com/CgVT1i上运行程序。