力扣hot100—系列1

1. 只出现一次的数字 (Single Number)

难度:简单

🎯 核心技巧:位运算(异或 XOR)

💡 解题思路:

题目要求线性时间复杂度且不使用额外空间。

利用异或运算(^)的性质:

  1. 归零律 : a ⊕ a = 0 a \oplus a = 0 a⊕a=0(任何数和自己异或归零)
  2. 恒等律 : a ⊕ 0 = a a \oplus 0 = a a⊕0=a(任何数和 0 异或不变)
  3. 交换律和结合律 : a ⊕ b ⊕ a = ( a ⊕ a ) ⊕ b = 0 ⊕ b = b a \oplus b \oplus a = (a \oplus a) \oplus b = 0 \oplus b = b a⊕b⊕a=(a⊕a)⊕b=0⊕b=b

解法:将数组中所有数字进行异或,成对出现的数字会互相抵消变成 0,最终剩下的结果就是那个只出现一次的数字。

💻 代码:

python 复制代码
class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        res = 0
        for num in nums:
            res ^= num
        return res

2. 多数元素 (Majority Element)

难度:简单

🎯 核心技巧:摩尔投票法 (Boyer-Moore Voting Algorithm)

💡 解题思路:

题目定义多数元素是指出现次数大于 ⌊ n/2 ⌋ 的元素。

可以将这个问题看作"诸侯争霸":

  1. 维护一个 candidate(候选人)和一个 count(票数)。
  2. 遍历数组:
    • 如果 count 为 0,假设当前数字为新的 candidate,并将 count 设为 1。
    • 如果当前数字等于 candidate,票数 count + 1
    • 如果当前数字不等于 candidate,票数 count - 1(互相抵消)。
  3. 因为多数元素的数量超过一半,经过抵消后,最终剩下的 candidate 一定是多数元素。

💻 代码:

python 复制代码
class Solution:
    def majorityElement(self, nums: List[int]) -> int:
        candidate = None
        count = 0
        
        for num in nums:
            if count == 0:
                candidate = num
            
            if num == candidate:
                count += 1
            else:
                count -= 1
        
        return candidate

3. 颜色分类 (Sort Colors)

难度:中等

🎯 核心技巧:三指针 (双指针的变种,荷兰国旗问题)

💡 解题思路:

要求原地排序且仅扫描一遍。我们需要将 0 放在左边,2 放在右边,1 自动就在中间了。

定义三个指针:

  • p0:指向 0 的右边界(下一个放 0 的位置)。
  • p2:指向 2 的左边界(下一个放 2 的位置)。
  • curr:当前遍历的指针。

逻辑

  1. 如果 nums[curr] == 0:与 p0 交换,p0 右移,curr 右移。
  2. 如果 nums[curr] == 2:与 p2 交换,p2 左移。注意:此时 curr 不移动,因为交换过来的数字可能是 0 或 2,需要再次判断。
  3. 如果 nums[curr] == 1curr 直接右移(不管它)。
  4. curr > p2 时停止。

💻 代码:

python 复制代码
class Solution:
    def sortColors(self, nums: List[int]) -> None:
        p0 = 0
        curr = 0
        p2 = len(nums) - 1
        
        while curr <= p2:
            if nums[curr] == 0:
                nums[curr], nums[p0] = nums[p0], nums[curr]
                p0 += 1
                curr += 1
            elif nums[curr] == 2:
                nums[curr], nums[p2] = nums[p2], nums[curr]
                p2 -= 1
                # 这里 curr 不自增,因为从后面换过来的数还需要判断
            else:
                curr += 1

4. 下一个排列 (Next Permutation)

难度:中等

🎯 核心技巧:两遍扫描(找"小数" -> 找"大数" -> 交换 -> 翻转)

💡 解题思路:

我们要找到一个比当前排列稍大一点点的排列。

  1. 从后往前 找第一个升序对 ( i , i + 1 ) (i, i+1) (i,i+1),即满足 nums[i] < nums[i+1]。此时 nums[i] 就是需要被替换的"较小数"。
  2. 如果找不到(整个数组是降序),说明这是最大的排列,直接翻转整个数组即可。
  3. 如果在步骤 1 找到了 i,再从后往前 找第一个比 nums[i] 大的数 nums[j]("较大数")。
  4. 交换 nums[i]nums[j]
  5. 此时 i 后面的部分是降序的,将其翻转为升序,以保证变大的幅度最小。

💻 代码:

python 复制代码
class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        n = len(nums)
        i = n - 2
        
        # 1. 从后往前找第一个升序对 (i, i+1)
        while i >= 0 and nums[i] >= nums[i + 1]:
            i -= 1
            
        if i >= 0:
            # 2. 从后往前找第一个比 nums[i] 大的数
            j = n - 1
            while j >= 0 and nums[j] <= nums[i]:
                j -= 1
            # 3. 交换
            nums[i], nums[j] = nums[j], nums[i]
        
        # 4. 翻转 i 之后的所有元素
        # (如果 i < 0,即没找到升序对,这里会翻转整个数组,符合题意)
        left, right = i + 1, n - 1
        while left < right:
            nums[left], nums[right] = nums[right], nums[left]
            left += 1
            right -= 1

5. 寻找重复数 (Find the Duplicate Number)

难度:中等

🎯 核心技巧:快慢指针 (Floyd 判圈算法 / 链表成环)

💡 解题思路:

题目限制:不能修改数组(不能排序)、 O ( 1 ) O(1) O(1) 空间(不能用哈希表)。

这就转化为了链表找环入口的问题。

  • 映射关系 :将数组下标 i i i 视为节点, n u m s [ i ] nums[i] nums[i] 视为 next 指针指向的下一个节点索引。
  • 因为有重复数,意味着有多个下标指向同一个值,这在图论中就形成了一个环。

步骤

  1. 快慢指针相遇slow 走一步,fast 走两步,直到它们相遇。
  2. 找环入口 :保持 slow 在相遇点,将 fast(或新建一个指针)重置回起点 0
  3. 同步前进:两个指针每次都走一步,再次相遇的点就是环的入口,也就是重复的数字。

💻 代码:

python 复制代码
class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        # 第一阶段:快慢指针找相遇点
        slow = nums[0]
        fast = nums[nums[0]]
        
        while slow != fast:
            slow = nums[slow]
            fast = nums[nums[fast]]
            
        # 第二阶段:找环入口
        ptr1 = 0
        ptr2 = slow
        
        while ptr1 != ptr2:
            ptr1 = nums[ptr1]
            ptr2 = nums[ptr2]
            
        return ptr1
相关推荐
晨曦夜月15 分钟前
map与unordered_map区别
算法·哈希算法
Morwit17 分钟前
QML组件之间的通信方案(暴露子组件)
c++·qt·职场和发展
图码40 分钟前
如何用多种方法判断字符串是否为回文?
开发语言·数据结构·c++·算法·阿里云·线性回归·数字雕刻
handler011 小时前
Linux 内核剖析:进程优先级、上下文切换与 O(1) 调度算法
linux·运维·c语言·开发语言·c++·笔记·算法
minglie11 小时前
实数列的常用递推模式
算法
代码小书生1 小时前
math,一个基础的 Python 库!
人工智能·python·算法
AI科技星1 小时前
全域数学·数术本源·高维代数卷(72分册)【乖乖数学】
人工智能·算法·数学建模·数据挖掘·量子计算
生成论实验室1 小时前
《事件关系阴阳博弈动力学:识势应势之道》第一篇:生成正在发生——从《即事经》到事件-关系网络
人工智能·科技·算法·架构·创业创新
漂流瓶jz1 小时前
UVA-1152 和为0的4个值 题解答案代码 算法竞赛入门经典第二版
数据结构·算法·二分查找·题解·aoapc·算法竞赛入门经典·uva
leoufung2 小时前
LeetCode 76:Minimum Window Substring 题解与滑动窗口思维详解
算法·leetcode·职场和发展