news 2026/1/11 4:48:12

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进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/26 16:20:25

Ionic Framework发布Vue版本更新与修复

零样本语音克隆系统使用指南&#xff1a;从入门到批量生成 在AI语音合成技术飞速发展的今天&#xff0c;我们已经可以仅凭几秒钟的参考音频&#xff0c;精准复刻一个人的声音&#xff0c;并用它说出任意内容。这种“零样本语音克隆”能力正在被广泛应用于有声书制作、虚拟主播…

作者头像 李华
网站建设 2026/1/7 19:53:34

C语言结构体与typedef详解

C语言结构体与typedef详解 在开发高性能语音合成系统时&#xff0c;比如基于C/C深度优化的 IndexTTS2 V23 引擎&#xff0c;我们面对的不只是算法模型&#xff0c;还有大量底层数据结构的设计与管理。这些结构承载着文本参数、声学特征、音频帧信息等关键数据——而其中最核心、…

作者头像 李华
网站建设 2025/12/26 16:19:39

C语言实现GBK到Unicode的字符转换

GBK 到 Unicode 宽字符转换函数的实现与解析 在中文信息处理中&#xff0c;编码转换是绕不开的核心环节。尤其是在嵌入式系统、跨平台应用或遗留系统维护中&#xff0c;如何准确地将 GBK 编码的多字节字符转换为 Unicode&#xff08;UCS-2&#xff09;格式&#xff0c;直接影响…

作者头像 李华
网站建设 2025/12/26 16:19:07

Python进程池并发下载图片实战

Python进程池并发下载图片实战 在部署像 VibeVoice-WEB-UI 这类多角色语音合成系统时&#xff0c;一个常被忽略但极其耗时的环节是&#xff1a;准备配套图像资源。比如为每位说话人配置头像、背景图或节目封面——这些素材往往散落在 GitHub、Unsplash、Bilibili 等平台的 URL…

作者头像 李华
网站建设 2026/1/8 17:36:33

十六进制字符串转UIImage:iOS图片处理技巧

十六进制字符串转UIImage&#xff1a;iOS图片处理技巧 在开发一个需要动态加载验证码的登录模块时&#xff0c;你有没有遇到过这样的接口响应&#xff1f; {"code": 200,"message": "success","data": {"token": "abc1…

作者头像 李华
网站建设 2025/12/26 16:18:24

自动驾驶—CARLA仿真(29)传感器(Sensors and data)

传感器使用详解 carla.Sensor 类定义了一种特殊的参与者&#xff08;actor&#xff09;&#xff0c;能够测量并流式传输数据。 这些数据是什么&#xff1f; 数据类型因传感器种类而异。所有传感器数据均继承自通用的 carla.SensorData 类。 何时获取数据&#xff1f; 要么在每…

作者头像 李华