news 2026/4/23 12:18:11

LeetCode136/169/75/31/287 算法技巧题核心笔记

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
LeetCode136/169/75/31/287 算法技巧题核心笔记

目录

一、136. 只出现一次的数字

题目概述

核心理论

解题思路

解法实现(Java)

复杂度分析

重难点分析

同类题拓展

二、169. 多数元素

题目概述

核心理论

解题思路

解法实现(Java)

复杂度分析

重难点分析

同类题拓展

三、75. 颜色分类

题目概述

核心理论

解题思路

解法实现(Java)

复杂度分析

重难点分析

同类题拓展

四、31. 下一个排列

题目概述

核心理论

解题思路

解法实现(Java)

复杂度分析

重难点分析

同类题拓展

五、287. 寻找重复数

题目概述

核心理论

解题思路

解法实现(Java)

复杂度分析

重难点分析


本笔记涵盖 5 道高频算法技巧题的核心解法、理论依据、重难点及拓展,适用于笔试 / 面试复习。

一、136. 只出现一次的数字

题目概述

给定非空整数数组,仅一个元素出现 1 次,其余元素出现 2 次,找出该唯一元素。

核心理论

位运算 异或(^)的三大特性:

  1. 相同数异或为 0:a ^ a = 0
  2. 0 与任意数异或为其本身:0 ^ a = a
  3. 满足交换 / 结合律:a ^ b ^ c = a ^ c ^ b

解题思路

遍历数组,将所有元素依次异或,出现 2 次的元素会相互抵消为 0,最终结果即为 “只出现 1 次的元素”。

解法实现(Java)

class Solution { public int singleNumber(int[] nums) { int res = 0; for (int num : nums) res ^= num; return res; } }

复杂度分析

  • 时间复杂度:O(n)(遍历数组 1 次)
  • 空间复杂度:O(1)(仅用一个变量)

重难点分析

  • 易错点:容易优先想到 “哈希表统计频率”,但会额外占用O(n)空间,不符合最优解要求。
  • 关键:理解 “异或抵消重复元素” 的本质,避免冗余空间开销。

同类题拓展

  • 只出现一次的数字 II(其余元素出现 3 次)
  • 只出现一次的数字 III(有 2 个元素各出现 1 次)

二、169. 多数元素

题目概述

给定整数数组,找出出现次数 ** 大于n/2** 的元素(多数元素)。

核心理论

  1. 摩尔投票法:多数元素的出现次数超过其他所有元素之和,可通过 “抵消” 筛选候选元素。
  2. 排序特性:排序后数组的中间元素(索引n/2)必然是多数元素。

解题思路

摩尔投票法

  1. 初始化 “候选元素” 和 “计数”。
  2. 遍历数组:遇相同元素则计数 + 1,不同则 - 1;计数为 0 时更换候选元素。
  3. 最终候选元素即为多数元素。

解法实现(Java)

class Solution { public int majorityElement(int[] nums) { int candidate = nums[0]; int count = 1; for (int i = 1; i < nums.length; i++) { if (nums[i] == candidate) count++; else { count--; if (count == 0) { candidate = nums[i]; count = 1; } } } return candidate; } }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

重难点分析

  • 易错点:摩尔投票法中 “计数为 0 时更换候选” 的逻辑容易遗漏,导致候选元素错误。
  • 关键:理解 “多数元素必然能抵消所有非多数元素” 的核心逻辑,无需统计具体次数。

同类题拓展

  • 求众数 II(找出出现次数超过n/3的元素)

三、75. 颜色分类

题目概述

给定包含0、1、2的数组(代表红、白、蓝),原地排序0→1→2的顺序,禁止使用库排序函数。

核心理论

三指针法(荷兰国旗问题):用 3 个指针划分 3 个区域(0 的区域、1 的区域、2 的区域),一次遍历完成排序。

解题思路

  1. 定义指针:
    • left:0 的右边界(下一个 0 的位置)
    • right:2 的左边界(下一个 2 的位置)
    • i:当前遍历指针
  2. 遍历逻辑:
    • 遇 0:与left交换,left++i++
    • 遇 2:与right交换,right--i不移动,需检查交换后的元素)
    • 遇 1:直接i++

解法实现(Java)

class Solution { public void sortColors(int[] nums) { int left = 0, right = nums.length - 1, i = 0; while (i <= right) { if (nums[i] == 0) { swap(nums, i++, left++); } else if (nums[i] == 2) { swap(nums, i, right--); } else { i++; } } } private void swap(int[] nums, int a, int b) { int temp = nums[a]; nums[a] = nums[b]; nums[b] = temp; } }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

重难点分析

  • 易错点:交换 2 时,i容易误加 1,导致未检查交换后的元素(可能是 0)。
  • 关键:明确三指针的 “区域划分” 作用,避免指针移动逻辑混乱。

同类题拓展

  • 移动零(将 0 移到数组末尾)
  • 合并两个有序数组(双指针原地合并)

四、31. 下一个排列

题目概述

找出数组的下一个字典序更大的排列;若不存在,则重排为升序(最小排列),要求原地修改、常数空间。

核心理论

字典序 “最小增幅” 规律:

  1. 升序断点:从后往前找第一个nums[i] < nums[i+1]的索引ii可增大)。
  2. 最小增幅数:从后往前找第一个nums[j] > nums[i]的索引j(保证增幅最小)。
  3. 调整后续顺序:交换i、j后,反转i+1后的元素(将降序转为升序,保证后续最小)。

解题思路

  1. 找升序断点i:若未找到(数组降序),直接反转数组。
  2. 若找到i,找j并交换nums[i]、nums[j]
  3. 反转i+1到末尾的元素。

解法实现(Java)

class Solution { public void nextPermutation(int[] nums) { int n = nums.length, i = n - 2; // 步骤1:找升序断点 while (i >= 0 && nums[i] >= nums[i+1]) i--; // 步骤2:找j并交换 if (i >= 0) { int j = n - 1; while (nums[j] <= nums[i]) j--; swap(nums, i, j); } // 步骤3:反转后续元素 reverse(nums, i+1, n-1); } private void swap(int[] nums, int a, int b) { int temp = nums[a]; nums[a] = nums[b]; nums[b] = temp; } private void reverse(int[] nums, int l, int r) { while (l < r) swap(nums, l++, r--); } }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

重难点分析

  • 易错点:遗漏 “数组完全降序” 的情况(未找到i时,需反转整个数组)。
  • 关键:理解 “最小增幅” 的核心 —— 既让排列变大,又只变大 “一点点”。

同类题拓展

  • 全排列(生成所有字典序排列)
  • 第 k 个排列(找到第 k 个字典序排列)

五、287. 寻找重复数

题目概述

给定长度为n+1的数组(元素范围[1,n]),有且仅一个重复数,要求不修改数组、常数空间找出该数。

核心理论

快慢指针(弗洛伊德环检测):将数组转化为 “链表”(索引 = 节点,值 = 下一个节点索引),重复数是环的入口(重复数对应多个前驱节点)。

解题思路

  1. 找相遇点:慢指针slow走 1 步,快指针fast走 2 步,两者在环内相遇。
  2. 找环入口:新指针ptr从起点出发,slow从相遇点出发,两者同速前进,最终在环入口(重复数)相遇。

解法实现(Java)

class Solution { public int findDuplicate(int[] nums) { // 步骤1:找快慢指针相遇点 int slow = nums[0], fast = nums[nums[0]]; while (slow != fast) { slow = nums[slow]; fast = nums[nums[fast]]; } // 步骤2:找环入口(重复数) int ptr = 0; while (ptr != slow) { ptr = nums[ptr]; slow = nums[slow]; } return ptr; } }

复杂度分析

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

重难点分析

  • 易错点:难以想到 “数组转链表” 的思路,或不理解 “ptr 与 slow 相遇于环入口” 的数学逻辑。
  • 关键:记住结论:从起点和相遇点出发的同速指针,必然在环入口相遇

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 10:45:56

虚拟机与容器的差异与取舍

目录 引言1. 架构对比&#xff1a;从硬件到进程1.1 虚拟机&#xff1a;硬件级虚拟化1.2 容器&#xff1a;操作系统级虚拟化 2. 资源与性能&#xff1a;数据说话2.1 基准测试数据&#xff08;2024 AWS c7g.2xlarge&#xff0c;Graviton3 2.6GHz&#xff09;2.2 内存去重与Page C…

作者头像 李华
网站建设 2026/4/23 12:15:28

Forest项目数据库从Derby迁移至MySQL

Forest项目数据库从Derby迁移至MySQL 在开发Java EE应用时&#xff0c;我们常常会使用像Apache Derby这样的嵌入式数据库作为初期原型或教学示例的存储方案。它轻量、无需额外部署&#xff0c;非常适合快速上手——比如经典的示例项目 Duke’s Forest 就默认集成了Derby。但一旦…

作者头像 李华
网站建设 2026/4/20 23:54:10

查重率和AI率双降:大学生必备的3款免费论文辅助工具

写的文章明明是一个字一个字敲的&#xff0c;提交后却被导师批“满屏机器味”&#xff1f;自查AIGC率飙到87%&#xff0c;改了3遍还是降不下来&#xff1f; 我踩过替换同义词越改越假、用错降AI率工具反升的坑&#xff0c;今天把9个原创免费降AI率技巧3款实测工具深度测评分享…

作者头像 李华
网站建设 2026/4/18 21:32:39

盘点3款好用的免费降AI软件,附知网实测对比报告

写的文章明明是一个字一个字敲的&#xff0c;提交后却被导师批“满屏机器味”&#xff1f;自查AIGC率飙到87%&#xff0c;改了3遍还是降不下来&#xff1f; 我踩过替换同义词越改越假、用错降AI率工具反升的坑&#xff0c;今天把9个原创免费降AI率技巧3款实测工具深度测评分享…

作者头像 李华
网站建设 2026/4/19 16:55:44

MT8870A无线综合测试仪架设与软件安装指南

MT8870A无线综合测试仪架设与软件安装指南 在现代无线通信设备的开发与生产中&#xff0c;测试效率和精度直接决定了产品上市速度与质量稳定性。面对5G、Wi-Fi 6、蓝牙5.0等多标准共存的复杂场景&#xff0c;传统单功能射频仪表已难以满足“一站式”测试需求。安立&#xff08…

作者头像 李华
网站建设 2026/4/18 19:58:33

基于多款软件的电池包仿真分析之旅

基于Hypermesh、Nastran、Abaqus、LS_Dyna和Femfat的电池包仿真分析 动力电池作为新能源车动力系统的重要组成部分,电池包作为电池的支撑载体,起到保护电池组正常工作的作用,其结构安全性不容忽视。 本套课程采用Hypermesh、Optistruct、Nastran、Abaqus、LS_Dyna和Femfat软件对…

作者头像 李华