算法中关于大数除法的精度问题

问题

大数除法会有浮点数误差(精度问题)。

解决方案

示例:294力扣周赛第3题表示一个折线图的最少线段数
其中需要计算斜率并比较。

转换为乘法

通常相到直接比较斜率(y3-y2)/(x3-x2)==(y2-y1)/(x2-x1)?
然而除法计算涉及到精度问题。
不妨将公式转化为乘法,乘法一定不存在精度问题!

(y3-y2)×(x2-x1)==(y2-y1)×(x3-x2) ?

class Solution:
    def minimumLines(self, stockPrices):
        n=len(stockPrices)
        if n==1:
            return 0
        stockPrices.sort()
        t=1
        for i in range(2,n):
            if (stockPrices[i][1]-stockPrices[i-1][1])*(stockPrices[i-1][0]-stockPrices[i-2][0])!=(stockPrices[i-1][1]-stockPrices[i-2][1])*(stockPrices[i][0]-stockPrices[i-1][0]):
                t+=1
        return t

辗转相除法

欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。计算公式gcd(a,b) = gcd(b,a mod b)。

gcd(greatest common divisor):最大公约数

e.g.,求 1997 和 615 两个正整数的最大公约数:

  • 1997 / 615 = 3 (余 152)
  • 615 / 152 = 4(余7)
  • 152 / 7 = 21(余5)
  • 7 / 5 = 1 (余2)
  • 5 / 2 = 2 (余1)
  • 2 / 1 = 2 (余0)

至此,最大公约数为1。

回到示例,核心思路是利用辗转相除法,化简斜率k的分子分母,将最简式进行比较。

from math import gcd
class Solution:
    def minimumLines(self, stockPrices):
        n=len(stockPrices)
        if n==1:
            return 0
        stockPrices.sort()
        prex=stockPrices[1][0]-stockPrices[0][0]
        prey=stockPrices[1][1]-stockPrices[0][1]
        g=gcd(abs(prex),abs(prey))
        prex,prey=prex/g,prey/g
        t=1
        for i in range(2,n):
            x = stockPrices[i][0] - stockPrices[i-1][0]
            y = stockPrices[i][1] - stockPrices[i-1][1]
            g=gcd(abs(x),abs(y))
            x,y=x/g,y/g
            if prex!=x or prey!=y:
                t+=1
                prex,prey=x,y
        return t
posted @ 2022-05-22 14:51  岸南  阅读(74)  评论(0)    收藏  举报