Leetcode面试经典150题刷题记录 —— 数学篇

这篇具有很好参考价值的文章主要介绍了Leetcode面试经典150题刷题记录 —— 数学篇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Leetcode面试经典150题刷题记录-系列
Leetcod面试经典150题刷题记录——数组 / 字符串篇
Leetcod面试经典150题刷题记录 —— 双指针篇
Leetcod面试经典150题刷题记录 —— 矩阵篇
Leetcod面试经典150题刷题记录 —— 滑动窗口篇
Leetcod面试经典150题刷题记录 —— 哈希表篇
Leetcod面试经典150题刷题记录 —— 区间篇
Leetcod面试经典150题刷题记录——栈篇
Leetcod面试经典150题刷题记录——链表篇
Leetcod面试经典150题刷题记录——二叉树篇
Leetcod面试经典150题刷题记录——二叉树层次遍历篇
Leetcod面试经典150题刷题记录——二叉搜索树篇

1. 回文数

题目链接:回文数 - leetcode
题目描述:
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。例如,121 是回文,而 123 不是。
题目归纳:

解题思路:
解法: 回文数 - leetcode官方题解
(1)转换成字符串进行求解。比较原始字符串与反转字符串。
(2)将数字的每一位存储至一个双向队列中,依次比较队头和栈顶元素:回文数 - Pensive Albattanicrq题解
(3)官方题解。上面两种方式都要完整遍历整个数字的位数,而官方题解只需要遍历到其中一半的位置,并且从空间使用效率上来说更高效。时间复杂度是 O ( l o g n ) O(logn) O(logn) n n n是数字的大小, l o g n logn logn是指数字总共有几位,这应该不难理解。

解法1 字符串解法

class Solution:
    def isPalindrome(self, x: int) -> bool:
        mylist = list(str(x))
        while len(mylist) > 1:
            if mylist.pop(0) != mylist.pop():
                return False
        return True

解法2 官方解法

class Solution:
    def isPalindrome(self, x: int) -> bool:
        # 可以直接判断的特殊情况
        # (1)负数。不是回文数
        # (2)数值末尾为0,则开头也为0,那么只有0符合条件。
        if x < 0 or (x%10 == 0 and x != 0):
            return False

        revertX = 0
        while x > revertX:
            revertX = 10 * revertX + x % 10
            x //= 10
        
        # 位数为偶数个 or 位数为奇数个
        return x == revertX or revertX//10 == x

2. 加一

题目链接:加一 - leetcode
题目描述:
给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。你可以假设除了整数 0 之外,这个整数不会以零开头。
题目归纳:

解题思路:
解法: 加一 - leetcode官方题解

class Solution:
    def plusOne(self, digits: List[int]) -> List[int]:
        if len(digits) < 1: return [] # 空数组
        
        carry = 0 # 进位值
        digits = digits[::-1] # 翻转方便操作
        n = len(digits)
        p = 0

        while p < n:
            if p == 0: # 第1位数字要加1
                result = digits[0] + 1 + carry
                carry = result // 10
                digits[0] = result % 10
            else:
                result = digits[p] + 0 + carry
                carry = result // 10
                digits[p] = result % 10
            p += 1
        
        # 出来后若进位值carry仍大于0,数组需要append(carry)
        if carry > 0:
            digits.append(carry)
        
        return digits[::-1]

3. 阶乘后的零

题目链接:阶乘后的零 - leetcode
题目描述:
给定一个整数 n ,返回 n! 结果中尾随零的数量。提示 n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1
题目归纳:

解题思路:
解法: 阶乘后的零 - leetcode官方题解
(1)因为 10 = 2 ∗ 5 10=2*5 10=25,求末尾0的个数,即是求 m i n ( 质因子 5 的个数 , 质因子 2 的个数 ) min(质因子5的个数, 质因子2的个数) min(质因子5的个数,质因子2的个数)
(2)再优化下,质因子 5 的个数不会大于质因子 2 的个数,

解法1

class Solution:
    def trailingZeroes(self, n: int) -> int:
        # 寻找阶乘的末尾有几个0
        # n! 尾0的个数即 n!中,因子10的个数,而10=2*5,因此转换成:求n!中质因子2的个数和质因子5的个数的较小值,即有多少个10参与了乘法,是由质因子2和5更小的那个数量来决定的
        # 质因子 5 的个数不会大于质因子 2 的个数
        # 而n!中质因子5的个数 = [1,n]的每个数的质因子5的个数之和,因此通过遍历[1,n]的所有5的倍数求出
        ans = 0
        for i in range(5, n+1, 5):
            while i%5 == 0: # (1)i要是5的倍数。
                i //= 5
                ans += 1    # (2)将i中质因子5的个数累加起来,比如25 = 5*5,两个质因数都为5
        return ans

解法2 考虑 [1,n] 中质因子 p 的个数。

class Solution:
    def trailingZeroes(self, n: int) -> int:
        # 仅考虑额外贡献的质因子个数 floor(n/p)
        # n 不变,p 越大,质因子个数越少,因此 [1,n] 中质因子 5 的个数不会大于质因子 2 的个数;
        ans = 0
        while n:
            n = n // 5
            ans += n
        return ans

4. x 的平方根 (扩展了解 快速平方根算法)

题目链接:x 的平方根 - leetcode
题目描述:
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5
题目归纳:
既然考察的是数学,那就请出牛顿提出的牛顿迭代法。这里可以拓展了解下 快速平方根倒数算法,还有那句著名的 what the xxxx?

解题思路:
解法: x 的平方根 - leetcode官方题解

class Solution:
    def mySqrt(self, x: int) -> int:
        # 牛顿迭代法
        if x == 0: return 0
        C, x0 = float(x), float(x)

        while True:
            xi = 0.5*(x0 + C/x0)
            if abs(x0 - xi) < 1e-7: # 两次求解的结果差距小于指定误差,可以返回
                return int(x0)
            x0 = xi
        return int(x0)
参考文章或视频资料
【什么代码让程序员之神感叹“卧槽”?改变游戏行业的平方根倒数算法】- bilibili
【没那么神秘的快速平方根倒数,给你解释一下这个数是怎么来的】- bilibili

5. Pow(x,n)

题目链接:Pow(x,n) - leetcode
题目描述:
实现 pow(x, n) ,即计算 x 的整数 n 次幂函数(即,xn )。
题目归纳:
(1)常规思路。 x n = x ⋅ x ⋅ x ⋅ x    . . .    ⋅ x x^n = x · x · x · x \space\space ... \space\space· x xn=xxxx  ...  x,这样方便理解,但计算并不快速。
(2)快速幂运算思路。其实快速幂运算就像微信小程序里的召唤神龙游戏,回忆下,召唤神龙是3只蝌蚪合成1只青蛙3只青蛙合成1条鲤鱼 … … ,实际中你几乎不会真的拿9只蝌蚪来合成鲤鱼,而是遇到和自己一样大的动物就拉入自己的队伍,朝着更大型的动物合成迈进,这样的方式合并次数是最少的,直到 … … 召唤神龙。数学术语的描述具体可以看leetcode官方题解。

解题思路:
解法: Pow(x,n) - leetcode官方题解

class Solution:
    # 快速幂运算
    def quickMul(self, x: float, n: int) -> float:
        ans = 1.0
        while n > 0:
            if n & 1 == 1: # 末尾为1
                ans *= x
            x = x*x # x = x**2 反而会有问题
            n = n >> 1
        return ans


    def myPow(self, x: float, n: int) -> float:
        if n >= 0:
            return self.quickMul(x, n)
        else:
            return 1.0 / self.quickMul(x, -n)

6. 直线上最多的点数

题目链接:直线上最多的点数 - leetcode
题目描述:
给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。
题目归纳:
n n n个点,可以画出 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n1)条直线,如果再把每个点代入看是否符合该直线的方程,那时间复杂度将达到 O ( n 3 ) O(n^3) O(n3),这种算法绝对不可能被采用。
这里我插句题外话,这个算法只在平面上适用,比如说在《几何原本》中被奉为绝对真理的“两点确定一条直线”,在教科书上的表述并不是“两点只能确定一条直线”,因为在非欧几何中这个假设就不成立,若考虑地球是完美球体,那么地球的南极点到北极点有无数条经线,对于地球上的蚂蚁而言,这些经线毫无疑问就是其所处平面的直线,我们人类对宇宙的探索又何尝不是火鸡呢,谁知道两点之间有多少的连接可能性被空间本身的结构抛弃了。只做个人意见,如有错误请指正。
如果向量数据库采用的仍旧是占据主流的平面几何的学说,这是否符合大多数实际情况呢?会不会有些情况是需要用到非欧几何的呢?

解题思路:
解法: 直线上最多的点数 - leetcode官方题解文章来源地址https://www.toymoban.com/news/detail-810552.html

# 给一个数组points,其中,points[i] = [x_i, y_i]
        # 求,最多有多少个点在同一条直线上
        # 这道题对 向量数据库 应该非常重要,是向量数据库的基础算法,比如求向量之间的相似度与距离或者聚类

        # 可以考虑枚举所有point,假设直线经过该point时,该直线所能经过的最多的点数
        # 假设当前枚举到point{i},若直线同时经过另外两个不同的点j、k,那么(i,j)所在直线的斜率 = (i,k)所在直线的斜率
        # 于是,我们可以统计其它所有点与point{i}所连直线的斜率,出现次数最多的斜率,即为经过点数最多的斜率,其经过点数为 该斜率出现的次数+1(+1指point{i}自身)
        # 不采用浮点数记录斜率,因为精度可能不够,换用元组记录斜率的(分子,分母)的形式,这种记录形式可能有以下问题需要解决
        # (A) 两个元组:(1,2), (2,4)的斜率一致,所以还涉及到约分,即GCD最大公约数的求解
        # (B) 分子分母存在负数,(-1,2), (1,-2)的斜率一致,因此规定分母为非负整数,如果分母为负数,将二元组的两个数同时取反
        # (C) 直线为y=C或x=C时,传统的斜截式无法表达,采用特判法。
        # 再加以下4个小优化
        # (1)点的数量<=2,用一条直线将所有点串联,直接返回点的数量
        # (2)枚举到点i时,只考虑编号 >=i的点 与 点i之间的斜率,例如,编号小于点i的点j,当枚举到j自己的时候,就已经计算过点j与点i的斜率,即两点之间经过一条直线,不重复计算两次
        # (3)当找到的一条直线,已经经过了图中超过半数的点时,直接确定该直线为经过最多点的直线,然后继续按照该直线求点数
        # (4)当枚举到点i(编号从0开始)时,最多只能找到n-i个点共线,因为按优化(2),只考虑比自己编号大的。假设此前找到的共线的点数量最大值为k,如果有k>=n-i,此时即可停止枚举,因为不可能再找到更大的答案了。
        
class Solution:
    def gcd(self, a, b): # 迭代法求最大公约数
        while b != 0:
            remain = a % b # 余数
            a = b
            b = remain
        return a

    def maxPoints(self, points: List[List[int]]) -> int:
        n = len(points)
        if n <= 2: # 优化(1)
            return n
        
        ret = 0
        for i in range(n):
            if ret >= n-i or ret > (n/2): # 优化(4)与优化(3)
                break
            mp = Counter()
            for j in range(i+1, n): # 优化(2),只考虑比自己编号大的点
                delta_x = points[i][0] - points[j][0] # △x
                delta_y = points[i][1] - points[j][1] # △y
                # 对记录形式的优化(C)。特例判断
                if delta_x == 0:
                    delta_y = 1
                elif delta_y == 0:
                    delta_x = 1
                else:
                    if delta_y < 0: # 对记录形式的优化(B)
                        delta_x = -delta_x
                        delta_y = -delta_y
                    gcdXY = self.gcd(abs(delta_x), abs(delta_y))
                    delta_x = delta_x / gcdXY
                    delta_y = delta_y / gcdXY
                mp[str(delta_y + delta_x*20001)] += 1 # 看官方题解
            
            maxn = 0
            for k,v in mp.items():
                maxn = max(maxn, v+1)
            ret = max(ret, maxn)
        
        return ret

到了这里,关于Leetcode面试经典150题刷题记录 —— 数学篇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 【leetcode刷题之路】面试经典150题(2)——双指针+滑动窗口+矩阵

    2 双指针 2.1 【双指针】验证回文串 题目地址:https://leetcode.cn/problems/valid-palindrome/description/?envType=study-plan-v2envId=top-interview-150   详见代码。 2.2 【双指针】判断子序列 题目地址:https://leetcode.cn/problems/is-subsequence/description/?envType=study-plan-v2envId=top-interview-150   双指针挨个遍

    2024年02月19日
    浏览(13)
  • LeetCode150道面试经典题-- 加一(简单)

    LeetCode150道面试经典题-- 加一(简单)

    给你一个非负整数 x ,计算并返回  x  的 算术平方根 。 由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。 注意: 不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。 示例 1: 输入:x=4 输出:2   示例 2: 输入: x = 8 输出: 2 解释: 8 的

    2024年02月12日
    浏览(10)
  • 【LeetCode-经典面试150题-day12】

    20.有效的括号 题意: 给定一个只包括  \\\'(\\\' , \\\')\\\' , \\\'{\\\' , \\\'}\\\' , \\\'[\\\' , \\\']\\\'  的字符串  s  ,判断字符串是否有效。 有效字符串需满足: 左括号必须用相同类型的右括号闭合。 左括号必须以正确的顺序闭合。 每个右括号都有一个对应的相同类型的左括号。 【输入样例】s=\\\"

    2024年02月11日
    浏览(9)
  • LeetCode面试经典150题(day 1)

    LeetCode面试经典150题(day 1)

    LeetCode是一个免费刷题的一个网站,想要通过笔试的小伙伴可以每天坚持刷两道算法题。 接下来,每天我将更新LeetCode面试经典150题的其中两道算法题,一边巩固自己,一遍希望能帮助到有需要的小伙伴。 88.合并两个有序数组 给你两个按  非递减顺序  排列的整数数组  nu

    2024年02月11日
    浏览(9)
  • 【LeetCode-面试经典150题-day14】

    【LeetCode-面试经典150题-day14】

      目录 19.删除链表的倒数第N个结点  82.删除排序链表中的重复元素Ⅱ  61. 旋转链表  86.分隔链表  146.LRU缓存 19.删除链表的倒数第N个结点 题意: 给你一个链表,删除链表的倒数第  n   个结点,并且返回链表的头结点。 【输入样例】head = [1,2,3,4,5],n=2 【输出样例】[1,2,3,5

    2024年02月11日
    浏览(8)
  • 【LeetCode-经典面试150题-day11】

    目录 128.最长连续序列  228.汇总区间  56.合并区间  57.插入区间  452.用最少数量的箭引爆气球   128.最长连续序列 题意: 给定一个未排序的整数数组  nums  ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。 请你设计并实现时间复杂度为  O(n)   的算法

    2024年02月12日
    浏览(12)
  • LeetCode面试经典150题(day 2)

    LeetCode面试经典150题(day 2)

    26. 删除有序数组中的重复项 难度: 简单    给你一个  升序排列  的数组  nums  ,请你  原地  删除重复出现的元素,使每个元素  只出现一次  ,返回删除后数组的新长度。元素的  相对顺序  应该保持  一致  。然后返回  nums  中唯一元素的个数。 考虑  nums  的唯一

    2024年02月11日
    浏览(9)
  • 【LeetCode-面试经典150题-day23】

    【LeetCode-面试经典150题-day23】

    目录 108. 将有序数组转换为二叉搜索树  148.排序链表  427.建立四叉树  23.合并K个升序链表   108. 将有序数组转换为二叉搜索树 题意: 给你一个整数数组  nums  ,其中元素已经按  升序  排列,请你将其转换为一棵  高度平衡  二叉搜索树。 高度平衡  二叉树是一棵满足「

    2024年02月09日
    浏览(8)
  • LeetCode150道面试经典题-- 快乐数(简单)

    LeetCode150道面试经典题-- 快乐数(简单)

    编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」  定义为: 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。 如果这个过程 结果为  1,那么这个数就是快乐数。 如果

    2024年02月12日
    浏览(11)
  • leetcode每日一题——189.轮转数组(面试经典150题)

    189. 轮转数组 - 力扣(LeetCode) 给定一个整数数组  nums ,将数组中的元素 向右轮转  k   个位置 ,其中  k   是非负数。 示例1: 示例2: 1 = nums.length = 105 -231 = nums[i] = 231 - 1 0 = k = 105        对题目进行分析可知,我们需要根据轮转量k,将数组后面的k个元素按照原来的顺

    2024年02月12日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包