创建除法程序而不在python中使用除法

时间:2019-03-08 07:04:44

标签: python algorithm math data-structures

我正在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:

提出该陈述的思考过程是什么?

3 个答案:

答案 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,以免产生任何大于numdiv的中间结果。即使您为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上运行程序。

相关问题