25.12.27 算法日记——双指针

文章目录

一、两数之和 II - 输入有序数组

167. 两数之和 II - 输入有序数组 - 力扣(LeetCode)

思路

数组有序是「双指针」的核心信号:

  • 暴力解:嵌套for循环,时间复杂度 O ( n 2 ) O (n²) O(n2),包超时
  • 最优解:双指针( O ( n ) O (n) O(n) 时间 + O ( 1 ) O (1) O(1) 空间),利用数组递增特性,左指针从左,右指针从右向中间收敛,通过和与target的比较调整指针

复杂度分析

  • 时间复杂度: O ( n ) O (n) O(n),双指针仅遍历数组一次
  • 空间复杂度: O ( 1 ) O (1) O(1),仅使用 left/right 两个变量,无额外空间开销

坑点

题目要求返回1 ≤ index1 ≤ index2 ≤ n,在返回时要对指针 + 1

C++ 知识点

  1. 初始化列表:C++11 的{}std::initializer_list语法糖,可快速初始化 vector,比push_back更高效
  2. 有序数组的双指针:"两端收敛" 是有序数组找目标和的通用解法,可迁移到多数有序数组求和问题

代码

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int left = 0, right = numbers.size() - 1;
        while (left < right) {
            int sum = numbers[left] + numbers[right];
            if (sum > target) right--;  // 和过大 右指针左移
            else if (sum < target) left++; // 和过小 左指针右移
            else return {left + 1, right + 1}; // 坑
        }
        return {}; 
    }
};

二、三数之和

15. 三数之和 - 力扣(LeetCode)

思路

将三数之和转化为「两数之和」问题:

  1. 排序数组( O ( n l o g n ) O (nlogn) O(nlogn)),为双指针和去重打基础
  2. 枚举nums[i],找nums[left] + nums[right] = -nums[i]left=i+1,right=n-1
  3. 双指针收敛找目标和,同时通过 "跳过重复值" 避免结果重复

复杂度分析

  • 时间复杂度: O ( n 2 ) O (n²) O(n2)(排序 O ( n l o g n ) O (nlogn) O(nlogn) + 双指针遍历 O ( n 2 ) O (n²) O(n2)
  • 空间复杂度: O ( l o g n ) O (logn) O(logn)(std::sort 的栈空间开销)

坑点

  1. 去重逻辑:基准数nums[i]需判断i>0 && nums[i]==nums[i-1] left/right需要跳过连续重复值
  2. 边界条件:数组长度 < 3 时直接返回空,避免越界
  3. 指针移动:找到有效解后,去重需停在最后一个重复值,再移动指针找下一组解

优化

排序后若nums[i] > 0,直接 break:数组递增,后续所有数≥nums [i],三数之和必 > 0

C++ 心知识点

  1. 二维 vector 构造:ret.push_back({a,b,c})依赖 C++11 初始化列表,底层是std::initializer_list(只读数组,不可修改)
  2. sort排序:std::sort 默认升序,基于快排实现,空间复杂度 O (logn)

代码

cpp 复制代码
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> ret;
        int n = nums.size();
        if (n < 3) return ret; // 边界条件:长度不足直接返回
        
        sort(nums.begin(), nums.end()); // 排序是双指针的基础
        for (int i = 0; i < n; ++i) {
            if (i > 0 && nums[i] == nums[i-1]) continue; // 跳过重复基准数
            if (nums[i] > 0) break; // 优化:三数和必>0 直接终止
            
            int left = i + 1, right = n - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum > 0) right--; // 和过大 右指针左移
                else if (sum < 0) left++; // 和过小 左指针右移
                else {
                    ret.push_back({nums[i], nums[left], nums[right]});
                    // 跳过left/right重复值,避免结果重复
                    while (left < right && nums[left] == nums[left+1]) left++;
                    while (left < right && nums[right] == nums[right-1]) right--;
                    // 移动指针找下一组解(离开重复值)
                    // [-1,0,0,1,1]
                    left++;
                    right--;
                }
            }
        }
        return ret;
    }
};
相关推荐
naruto_lnq15 小时前
分布式系统安全通信
开发语言·c++·算法
Jasmine_llq15 小时前
《P3157 [CQOI2011] 动态逆序对》
算法·cdq 分治·动态问题静态化+双向偏序统计·树状数组(高效统计元素大小关系·排序算法(预处理偏序和时间戳)·前缀和(合并单个贡献为总逆序对·动态问题静态化
爱吃rabbit的mq16 小时前
第09章:随机森林:集成学习的威力
算法·随机森林·集成学习
(❁´◡`❁)Jimmy(❁´◡`❁)16 小时前
Exgcd 学习笔记
笔记·学习·算法
YYuCChi17 小时前
代码随想录算法训练营第三十七天 | 52.携带研究材料(卡码网)、518.零钱兑换||、377.组合总和IV、57.爬楼梯(卡码网)
算法·动态规划
CSDN_RTKLIB17 小时前
【四个场景测试】源文件编码UTF-8 BOM
c++
不能隔夜的咖喱17 小时前
牛客网刷题(2)
java·开发语言·算法
VT.馒头17 小时前
【力扣】2721. 并行执行异步函数
前端·javascript·算法·leetcode·typescript
进击的小头17 小时前
实战案例:51单片机低功耗场景下的简易滤波实现
c语言·单片机·算法·51单片机
肉包_51118 小时前
两个数据库互锁,用全局变量互锁会偶发软件卡死
开发语言·数据库·c++