力扣热题100(前10道题目)

作者:少年姜太公日期:2025/10/30

前言

算法题几乎是面试必考的,许多同学一看到算法题就是一个头两个大,所以笔者这次准备把力扣热题100写成文章与jym一起学习,估计会分为10篇文章来写。在这个过程中会分享一些自己刷题的想法和思路,让大家能够轻松看懂,这些题目我会采用js来写,有看不懂js的同学可以看个思路然后换成自己熟悉的语言去写🔥 LeetCode 热题 HOT 100

在每道题目之前我都会把对应的题目链接贴出来,方便大家可以看完我的解法再去力扣上刷题,而且这些题目我会尽可能多种解法去写,大家可以参考一下。

160. 相交链表

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

自定义评测:

评测系统 的输入如下(你设计的程序 不适用 此输入):

  • intersectVal - 相交的起始节点的值。如果不存在相交节点,这一值为 0
  • listA - 第一个链表
  • listB - 第二个链表
  • skipA - 在 listA 中(从头节点开始)跳到交叉节点的节点数
  • skipB - 在 listB 中(从头节点开始)跳到交叉节点的节点数

评测系统将根据这些输入创建链式数据结构,并将两个头节点 headAheadB 传递给你的程序。如果程序能够正确返回相交节点,那么你的解决方案将被 视作正确答案

示例 1:

1输入: intersectVal = 8, listA = [4,1,8,4,5], listB = [5,6,1,8,4,5], skipA = 2, skipB = 3
2输出: Intersected at '8'
3解释: 相交节点的值为 8 (注意,如果两个链表相交则不能为 0)。
4从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,6,1,8,4,5]。
5在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。
6— 请注意相交节点的值不为 1,因为在链表 A 和链表 B 之中值为 1 的节点 (A 中第二个节点和 B 中第三个节点) 是不同的节点。换句话说,它们在内存中指向两个不同的位置,而链表 A 和链表 B 中值为 8 的节点 (A 中第三个节点,B 中第四个节点) 在内存中指向相同的位置。
7

示例 2:

1输入: intersectVal = 2, listA = [1,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
2输出: Intersected at '2'
3解释: 相交节点的值为 2 (注意,如果两个链表相交则不能为 0)。
4从各自的表头开始算起,链表 A 为 [1,9,1,2,4],链表 B 为 [3,2,4]。
5在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。
6
解法一
思路

如果我们从两个链表的最后一个节点往前遍历,那么相交的这个节点其实就是两个链表最后一个相等的节点,一旦不相等了,说明这个节点的前一个节点就是相交节点,所以我们可以把这两个链表分别放进两个数组里,然后倒序遍历

1var getIntersectionNode = function (headA, headB) {
2    const list1 = []
3    const list2 = []
4    while (headA) {
5        list1.push(headA)
6        headA = headA.next
7    }
8    while (headB) {
9        list2.push(headB)
10        headB = headB.next
11    }
12    let i = list1.length - 1
13    let j = list2.length - 1
14    let temp
15    while (i && j && list1[i] === list2[j]) {
16        temp = list1[i]
17        i--
18        j--
19    }
20    return temp
21};
22

因为新增了数组,所以这其实并不是最优解,他的时间复杂度和空间复杂度都为O(m+n),m为headA的长度,n为headB的长度。

解法二
思路

:双指针法,先初始化两个指针p = headA,q = headB,然后不断循环直到p = q,每次循环让pq各向后走一步,当p为空时,让pheadBq为空时,qheadA,在循环结束时,如果两个链表相交,那么pq都会在相交的起始节点处就可以返回p了,如果不相交,那么他们都到空节点了,也可以返回p,即空节点

代码如下:

1var getIntersectionNode = function (headA, headB) {
2    let p = headA
3    let q = headB
4    while (p !== q) {
5        p = p ? p.next : headB
6        q = q ? q.next : headA
7    }
8    return p
9};
10

这种解法的时间复杂度为O(m+n),空间复杂度为O(1)

236. 二叉树的最近公共祖先

示例 1:

1输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
2输出: 3
3解释: 节点 5 和节点 1 的最近公共祖先是节点 34

示例 2:

1输入: root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
2输出: 5
3解释: 节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
4

示例 3:

1输入: root = [1,2], p = 1, q = 2
2输出: 1
3
思路

如果当前节点是空节点,就返回当前节点,如果当前节点是p或者q也就返回当前节点,当左右子树都能找到时,他们的公共祖先也就是当前节点,只有左子树能找到就返回左子树递归的结果,只有右子树能找到就返回右子树递归的结果。

1var lowestCommonAncestor = function (root, p, q) {
2    if (!root || root === p || root === q) return root
3    let left = lowestCommonAncestor(root.left, p, q)
4    let right = lowestCommonAncestor(root.right, p, q)
5    if (left && right) return root
6    if (left) return left
7    if (right) return right
8};
9
10

234. 回文链表

给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false

示例 1:

1输入: head = [1,2,2,1]
2输出: true
3

示例 2:

1输入: head = [1,2]
2输出: false
3

提示:

  • 链表中节点数目在范围[1, 105]
  • 0 <= Node.val <= 9

进阶: 你能否用 O(n) 时间复杂度和 O(1) 空间复杂度解决此题?

解法一
思路

将链表的每个值都存进数组里,然后使用双指针来比较前后两端的元素,一个指针从起点向中间移动看,另一个指针从终点向中间移动。

1var isPalindrome = function (head) {
2    const res = []
3    while (head) {
4        res.push(head.val)
5        head = head.next
6    }
7    for (let i = 0, j = res.length - 1; i < j; i++, j--) {
8        if (res[i] !== res[j]) return false
9    }
10    return true
11};
12

由于要逐个访问n个元素,所以他的时间复杂度和空间复杂度都是O(n),来看下面的这个解法,就能让他的空间复杂度变成O(1)。

解法二
思路

找到中间节点并反转链表,如果链表有奇数个节点,就找他正中间的节点,如果链表有偶数个节点,就找他正中间右边的节点。

image.png

image.png找到中间节点后把中间节点到链表末尾反转如上图所示,把他的头节点记为head2,然后从head2开始,依次遍历原链表的最后一个节点、倒数第二个节点...,最后同时遍历head和head2,循环比较两个值是否相等,相等就返回true,不等就返回false,循环结束后如果没有返回false,就说明链表是回文的。用这个解法前可以先刷下这两道题目876. 链表的中间结点206. 反转链表

1function midNode(head) {
2    let slow = head
3    let fast = head
4    while (fast && fast.next) {
5        slow = slow.next
6        fast = fast.next.next
7    }
8    return slow
9}
10function reverseList(head) {
11    let p1 = head
12    let p2 = null
13    while (p1) {
14        let tem = p1.next
15        p1.next = p2
16        p2 = p1
17        p1 = tem
18    } return p2
19}
20var isPalindrome = function (head) {
21    const mid = midNode(head)
22    let head2 = reverseList(mid)
23    while (head2) {
24        if (head.val !== head2.val) return false
25        head = head.next
26        head2 = head2.next
27    }
28    return true
29};
30

739. 每日温度

给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

1输入: temperatures = [73,74,75,71,69,72,76,73]
2输出: [1,1,4,2,1,1,0,0]
3

示例 2:

1输入: temperatures = [30,40,50,60]
2输出: [1,1,1,0]
3

示例 3:

1输入: temperatures = [30,60,90]
2输出: [1,1,0]
3

提示:

解法一
思路

直接暴力解法,对于每个温度,向后遍历查找第一个比他高的温度,然后计算间隔天数,用一个数组来存放0,对于比他高的温度后者-前者就是这个天数

1/**
2 * @param {number[]} temperatures
3 * @return {number[]}
4 */
5var dailyTemperatures = function (temperatures) {
6    const res = new Array(temperatures.length)
7    for (let i = 0; i < temperatures.length; i++) {
8        res[i] = 0
9        for (let j = i + 1; j < temperatures.length; j++) {
10            if (temperatures[j] > temperatures[i]) {
11                res[i] = j - i
12                break
13            }
14        }
15    }
16    return res
17};
18

这种解法是最直观的,但是这种解法在力扣上提交会超时 ,因为他的时间复杂度是O(n²),而力扣上的测试用例包含长度高达10⁵的数组,在最坏情况下要执行10¹⁰次比较操作,所以会超时

解法二
思路

单调栈,不主动寻找每个温度后面的第一个高温,当遇到高温时,回头解决之前没有解决的低温问题,用栈来存储温度索引,保持栈中的温度值单调递增。

1/**
2 * @param {number[]} temperatures
3 * @return {number[]}
4 */
5var dailyTemperatures = function (temperatures) {
6    const res = new Array(temperatures.length).fill(0)
7    const stack = []
8    for (let i = 0; i < temperatures.length; i++) {
9        while (stack && temperatures[i] > temperatures[stack[stack.length - 1]]) {
10            const index = stack.pop()
11            res[index] = i - index
12        }
13        stack.push(i)
14    }
15    return res
16};
17

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例 1:

转存失败,建议直接上传图片文件

1输入: root = [4,2,7,1,3,6,9]
2输出: [4,7,2,9,6,3,1]
3

示例 2:

转存失败,建议直接上传图片文件

1输入: root = [2,1,3]
2输出: [2,3,1]
3

示例 3:

1输入: root = []
2输出: []
3

提示:

  • 树中节点数目范围在 [0, 100]
  • -100 <= Node.val <= 100
思路

用深度优先搜索(DFS)递归的交换每个节点的左右子节点,核心就是利用分治思想将大问题分解为小问题,然后递归的解决每个子问题

1var invertTree = function (root) {
2    if (!root) return null
3    return {
4        val: root.val,
5        left: invertTree(root.right),
6        right: invertTree(root.left)
7    }
8};
9
10

221. 最大正方形

在一个由 '0''1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。

示例 1:

转存失败,建议直接上传图片文件

1输入: matrix = [["1","0","1","0","0"],["1","0","1","1","1"],["1","1","1","1","1"],["1","0","0","1","0"]]
2输出: 4
3

示例 2:

转存失败,建议直接上传图片文件

1输入: matrix = [["0","1"],["1","0"]]
2输出: 1
3

示例 3:

1输入: matrix = [["0"]]
2输出: 0
3

提示:

思路

用动态规划来解决,以每个位置为右下角,计算能形成的最大正方形的边长,用dp[i][j]来表示以(i,j)为右下角顶点的,只包含'1'的最大正方形的边长,其状态转移方程为dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1,比如说要形成一个边长为k的正方形,就必须满足上方能形成变成为k-1的正方形,左方能形成边长为k-1的正方形,左上方能形成边长为k-1的正方形,只有这三个条件都满足时,才能在当前位置扩展成边长为k的正方形

1var maximalSquare = function (matrix) {
2    let maxSideLen = 0
3    let dp = new Array(matrix.length)
4    for (let i = 0; i < matrix.length; i++) {
5        dp[i] = new Array(matrix[i].length).fill(0)
6        for (let j = 0; j < matrix[i].length; j++) {
7            if (matrix[i][j] === '1') {
8                if (i === 0 || j === 0) {
9                    dp[i][j] = 1
10                } else {
11                    dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1],dp[i - 1][j - 1]) + 1
12                }
13                maxSideLen = Math.max(maxSideLen, dp[i][j])
14            }
15        }
16    }
17    return maxSideLen * maxSideLen
18}
19
20

215. 数组中的第K个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。

请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。

示例 1:

1输入: [3,2,1,5,6,4], k = 2
2输出: 5
3

示例 2:

1输入: [3,2,3,1,2,4,5,5,6], k = 4
2输出: 4
3

提示:

思路

可以使用快速选择的思想来解决,要找第k个最大元素,其实就相当于找第(n-k)小的元素,我们可以先选中一个基准值,然后使用双指针从数组两端向中间扫描,将小于基准值的元素移到左边,大于基准值的元素移到右边,完成一次分区操作后,再根据目标元素应该所在区域来决定继续在左半部分还是右半部分进行递归搜索,这样的话每次都能排除掉一部分元素而不需要处理整个数组

1/**
2 * @param {number[]} nums
3 * @param {number} k
4 * @return {number}
5 */
6var findKthLargest = function (nums, k) {
7  const n = nums.length;
8  return quickSelect(nums, 0, n - 1, n - k); // n-1是数组长度-1,n-k是第k大的元素对应的下标
9};
10
11function quickSelect(nums, l, r, k) {
12  // l 和 r 是左右边界,k 是要找的第 k 小元素的下标
13  if (l === r) return nums[k];
14  const x = nums[l];
15  let i = l - 1,
16    j = r + 1; // 因为下面的do while循环会先自增或自减一次,所以这里要-1和+1
17  while (i < j) {
18    // i<j 说明还没有扫描完的数组
19    do i++;
20    while (nums[i] < x);
21    do j--;
22    while (nums[j] > x);
23    if (i < j) {
24      [nums[i], nums[j]] = [nums[j], nums[i]];
25    }
26  }
27  if (k <= j) {
28    return quickSelect(nums, l, j, k);
29  } else {
30    return quickSelect(nums, j + 1, r, k);
31  }
32}
33
34

208. 实现 Trie (前缀树)

207. 课程表

206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

1输入: head = [1,2,3,4,5]
2输出: [5,4,3,2,1]
3

示例 2:

1输入: head = [1,2]
2输出: [2,1]
3

示例 3:

1输入: head = []
2输出: []
3
思路

迭代法,先创建一个空链表,然后用头插法依次把节点插入到这个新链表的头部,就得到了反转后的链表

1var reverseList = function (head) {
2    let p1 = head
3    let p2 = null
4    while (p1) {
5        let temp = p1.next
6        p1.next = p2
7        p2 = p1
8        p1 = temp
9    }
10    return p2
11};
12

力扣热题100(前10道题目)》 是转载文章,点击查看原文


相关推荐


从原型到类:JavaScript面向对象编程的终极进化指南
良山有风来2025/10/27

你是不是也曾经被JavaScript的原型链绕得头晕眼花?每次看到__proto__和prototype就感觉在看天书?别担心,这几乎是每个前端开发者都会经历的阶段。 今天我要带你彻底搞懂JavaScript面向对象编程的进化之路。从令人困惑的原型到优雅的class语法,再到实际项目中的设计模式应用,读完本文,你不仅能理解JS面向对象的本质,还能写出更优雅、更易维护的代码。 原型时代:JavaScript的"上古时期" 在ES6之前,JavaScript面向对象编程全靠原型链。虽然语法看起来有点


Redis(81)Redis的缓存雪崩是什么?
Victor3562025/10/24

缓存雪崩的概念 缓存雪崩(Cache Avalanche)是指在某一时间段内,缓存中的大量数据同时过期,或者由于缓存服务器宕机导致大量请求直接打到数据库,导致数据库瞬时压力剧增,甚至可能导致数据库崩溃。 解决缓存雪崩的方法 为了解决缓存雪崩问题,可以采取以下几种策略: 缓存数据的过期时间设置为随机值:避免在同一时间大量缓存数据同时失效。 加锁或队列:在缓存失效时,通过机制控制对数据库的访问,避免大量请求同时打到数据库。 双写策略:更新缓存的同时也更新数据库,保证数据的一致性。 数据预热:在系统


KuiklyUI利用Kotlin Lambda函数实现声明式UI系统的深入分析
风冷2025/10/22

KuiklyUI利用Kotlin Lambda函数实现声明式UI系统的深入分析 KuiklyUI通过巧妙地利用Kotlin的lambda函数特性,构建了一套灵活、高效的声明式UI系统。本文将深入分析其实现机制和核心技术点。 一、Lambda函数在声明式UI中的核心应用 1. 接收器作用域函数的巧妙运用 KuiklyUI的声明式语法核心基于Kotlin的接收器作用域函数。在按钮组件ButtonView中,我们可以看到典型的实现: class ButtonView : ComposeView<But


面试问题—上家公司的离职原因
mapbar_front2025/10/21

面试结尾HR必问的问题,就是上一家公司的离职原因,作为多年的资深架构师,我做过多次终面,听到过千奇百怪的答案,有的真诚,有的官方,有的遮遮掩掩,有的情绪愤怒,这个问题是有正确答案的,今天就来和你分享一下。 1、真实的离职原因 其实离职无非就是两类原因,一类主动,一类被动。 主动,要么钱少,要么心累,但大多数情况都是钱少心又累。 被动,要么被行情拖累,要么末位淘汰,要么违纪被发现,这个问题只要不回答的稀碎,都不会影响你被录用。 2、避开下面两个错误答案 2.1、 破口大骂前公司前领导 有可能真的是


Redis(73)如何处理Redis分布式锁的死锁问题?
Victor3562025/10/20

处理Redis分布式锁的死锁问题,可以采取以下一些方法: 设置锁的自动过期时间: 使用EX和PX参数设置锁的超时时间,确保锁在持有过久后自动释放,避免死锁。 使用看门狗模式: 通过不断刷新锁的过期时间来维持锁的有效性,防止锁的持有者因为长时间操作而导致锁自动过期。 确保锁的唯一性和原子性: 使用具有唯一标识的锁值来确保释放锁时的准确性,避免因误删导致的死锁问题。 故障恢复机制: 在检测到锁持有者失效后,其他节点可以尝试获取锁,确保系统的高可用性。 下面是一个示


区块链技术的五大应用场景
终端域名2025/10/19

区块链技术凭借其去中心化、不可篡改和透明性等核心优势,已渗透至金融、供应链管理、医疗健康、知识产权保护及公共服务五大领域,成为重构信任机制与提升协作效率的关键技术。以下是对五大应用场景的详细阐述: 一、金融:重塑信任基石 跨境支付与清算 区块链通过分布式账本技术实现跨境交易的实时结算,显著降低传统SWIFT网络的中介成本和时间延迟。例如,Ripple、R3等区块链联盟已推动跨境汇款效率提升至分钟级,将跨国交易成本从每笔26美元降低至15美元。 数字货币与支付结算 央行数字货币(如中国


B站多模态精细画质分析模型在 ICCV2025 大赛获得佳绩
哔哩哔哩技术2025/10/17

前言 暑期,B站多媒体实验室带队参与了 ICCV MIPI (Mobile Intelligent Photography and Imaging) Workshop 的细粒度图像质量定位 (Detailed Image Quality Assessment Track) 国际挑战赛,提出创新的多模态训练策略,将综合指标提升了13.5%,最终获得了第二名的好成绩。本次参赛经历阶段性地验证了实验室在视频质量评价 (Video Quality Assessment,后文统称为 VQA) ,MLLM


【软件测试】性能测试工具 JMeter
清风~徐~来2025/10/16

性能测试工具 JMeter 一. JMeter 下载与环境配置二. JMeter 介绍1. JMeter 基本使用2. JMeter 元件作用域和执行顺序3. JMeter 重点组件(1). 线程组(2). HTTP 请求(3). 查看结果树(4). HTTP 请求默认值(5). HTTP 信息头管理器(6). JSON 提取器(7). 用户定义的变量(8). JSON 断言(9). 同步定时器(10). 事务控制器(11). CSV 数据文件设置(12). HTTP Cookie 管理器


Python 的内置函数 bytes
IMPYLH2025/10/14

Python 内建函数列表 > Python 的内置函数 bytes class bytes(x=b''): ''' 创建 bytes :param x: 要转换的变量 :return: x 转换为 bytes 后的值 ''' Python 的内置函数 bytes 用于创建不可变的字节序列对象。它是 Python 中处理二进制数据的基本类型之一,与 str 类型类似但专门用于表示字节数据而非文本。 bytes 函数有三种主要创建方式: 通过指定


电视盒子助手开心电视助手 v8.0 删除电视内置软件 电视远程控制ADB去除电视广告
2501_929382652025/10/13

电视盒子助手开心电视助手 v8.0 删除电视内置软件 电视远程控制ADB去除电视广告                                       “开心电视助手V8.0最新版”是一款功能强大的安卓电视/电视盒子管理软件,通常运行在Windows电脑上。它通过局域网(Wi-Fi)或USB数据线连接到您的电视或盒子,实现一系列高级管理、调试和控制功能。 它尤其受到开发者、电视发烧友和喜欢折腾智能电视/盒子的用户的欢迎。支持安卓设备的电视 盒子 安卓手机 安卓所有设备 下载地

首页编辑器站点地图

Copyright © 2025 聚合阅读

License: CC BY-SA 4.0