力扣热题100-技巧篇5题

454 阅读3分钟

🧠 1. 只出现一次的数字

🧩 题目描述

给定一个 非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出这个只出现一次的元素。

要求:

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

✅ 解题思路

利用异或运算的性质:

  • a ^ a = 0
  • a ^ 0 = a

所有数字都出现两次,异或后都变成 0,剩下的就是只出现一次的那个数字。

📌 举个例子:

2 ^ 3 ^ 3 = 2 (3 ^ 3 = 0, 2 ^ 0 = 2)

💻 C++ 实现

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int res = 0;
        for (auto num : nums) {
            res ^= num;
        }
        return res;
    }
};

🗳️ 2. 多数元素

🧩 题目描述

给定一个大小为 n 的数组,返回其中的多数元素(即出现次数 > ⌊n/2⌋)。

保证多数元素一定存在。

✅ 解题思路:摩尔投票法

  • 候选人初始为空,票数为 0;
  • 每遇到相同的数字票数 +1,不同的数字票数 -1;
  • 票数为 0 时更换候选人;
  • 最终留下的候选人就是多数元素。

💻 C++ 实现

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int x = 0, y = 0;
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] == nums[x]) y++;
            else y--;
            if(y == 0){ x = i; y = 1;}
        }
        return nums[x];
    }
};

🎨 3. 颜色分类

🧩 题目描述

将包含 0(红色)、1(白色)、2(蓝色)的数组排序,不能使用内置排序函数。

✅ 解题思路:双指针(三路快排思想)

  • 左指针放置 0,右指针放置 2;

  • 遍历数组时遇到:

    • 0:与左指针交换,左指针右移;
    • 2:与右指针交换,右指针左移;
    • 1:跳过。

💻 C++ 实现

class Solution {
public:
    void sortColors(vector<int>& nums) {
        int l = 0, r = nums.size()-1;
        for(int i = 0; i < nums.size(); i++){
            while(nums[i] == 2 && i < r){
                swap(nums[i], nums[r--]);
            }
           if(nums[i] == 0){
                swap(nums[i], nums[l++]);
            }
        }
    }
};

🔢 4. 下一个排列

🧩 题目描述

给定一个整数数组 nums,找出其下一个字典序排列。要求 就地修改,使用常数级空间。

✅ 解题思路

  1. 从后往前找到第一个递增的位置 i
  2. 再从后向前找到第一个比 nums[i] 大的元素 j
  3. 交换 nums[i]nums[j]
  4. 反转 i+1 到末尾这段子数组。

📌 举例:

从后往前找第一个逆序的位置

  1. 如果找不到则当前排列就是最大的,只需要全部翻转成为升序即可
  2. 如果存在这个位置 如 [1 2 3 5 4 2 1], 3 就是找到的位置,将 3 和第一个大于 3 的值进行替换
    更换后:[1 2 4 5 3 2 1],这样 4 后面的子数组一定就是逆序数组,将其翻转成升序即可得到
    答案:[1 2 4 1 2 3 5]

💻 C++ 实现

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        int l = -1;
        for(int i = nums.size()-1; i >= 1; i--){
            if(nums[i] > nums[i-1]){l = i-1; break;}
        }
        if(l == -1){
            reverse(nums.begin(), nums.end());
            return;
        }
        int r;
        for(int i = nums.size()-1;i >= l; i--){
            if(nums[i] > nums[l]){r = i; break;}
        }
        swap(nums[l], nums[r]);
        reverse(nums.begin() + l + 1, nums.end());
     }
};

🔍 5. 寻找重复数

🧩 题目描述

一个长度为 n+1 的数组,所有数在 [1,n] 范围内,只有一个重复数字,不能修改数组,空间复杂度 O(1)。

✅ 解题思路:快慢指针(Floyd 判圈)

视索引和值为链表的节点和指针,用快慢指针找环入口:

  • 慢指针每次走一步,快指针走两步;
  • 相遇后,将慢指针重置为起点;
  • 再次相遇处就是重复数字。

💻 C++ 实现

class Solution {
public:
    int findDuplicate(vector<int>& nums) {
       int slow=0, fast=0;
       while(1){
            slow = nums[slow];
            r = nums[nums[fast]];
            if(slow == fast)break;
       }
       slow = 0;
       while(slow != fast){
           slow = nums[slow];
           fast = nums[fast];
       }
       return slow;
    }
};