当前位置: 首页 > article >正文

双指针c++

双指针(Two Pointers)是一种常用的算法技巧,通常用于解决数组或链表中的问题,如滑动窗口、区间合并、有序数组的两数之和等。双指针的核心思想是通过两个指针的移动来优化时间复杂度,通常可以将 (O(n^2)) 的暴力解法优化到 (O(n))。

以下是双指针的常见模板和示例:


1. 双指针的基本模板

1.1 同向双指针

  • 特点:两个指针从同一侧开始移动,通常用于滑动窗口问题。
  • 模板
    int twoPointersSameDirection(vector<int>& nums) {
        int left = 0, right = 0; // 初始化指针
        while (right < nums.size()) {
            // 扩展右边界
            right++;
            // 根据条件收缩左边界
            while (/* 不满足条件 */) {
                left++;
            }
            // 更新结果
        }
        return result;
    }
    

1.2 对向双指针

  • 特点:两个指针从两侧向中间移动,通常用于有序数组的问题。
  • 模板
    int twoPointersOppositeDirection(vector<int>& nums) {
        int left = 0, right = nums.size() - 1; // 初始化指针
        while (left < right) {
            // 根据条件移动指针
            if (/* 满足条件 */) {
                left++;
            } else {
                right--;
            }
            // 更新结果
        }
        return result;
    }
    

2. 常见应用场景

2.1 滑动窗口

  • 问题描述:找到一个满足条件的子数组或子字符串。
  • 示例:求最长无重复字符的子字符串。
    int lengthOfLongestSubstring(string s) {
        int left = 0, right = 0; // 滑动窗口的左右边界
        unordered_set<char> window; // 记录窗口内的字符
        int maxLen = 0;
    
        while (right < s.size()) {
            char c = s[right];
            // 如果字符已存在,移动左边界
            while (window.count(c)) {
                window.erase(s[left]);
                left++;
            }
            // 扩展右边界
            window.insert(c);
            right++;
            // 更新结果
            maxLen = max(maxLen, right - left);
        }
    
        return maxLen;
    }
    

2.2 有序数组的两数之和

  • 问题描述:在有序数组中找到两个数,使它们的和等于目标值。
  • 示例
    vector<int> twoSum(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        while (left < right) {
            int sum = nums[left] + nums[right];
            if (sum == target) {
                return {left, right};
            } else if (sum < target) {
                left++;
            } else {
                right--;
            }
        }
        return {}; // 未找到
    }
    

2.3 区间合并

  • 问题描述:合并所有重叠的区间。
  • 示例
    vector<vector<int>> mergeIntervals(vector<vector<int>>& intervals) {
        if (intervals.empty()) return {};
    
        // 按区间起点排序
        sort(intervals.begin(), intervals.end());
    
        vector<vector<int>> merged;
        int left = intervals[0][0], right = intervals[0][1];
    
        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i][0] <= right) {
                // 合并区间
                right = max(right, intervals[i][1]);
            } else {
                // 保存当前区间
                merged.push_back({left, right});
                // 更新指针
                left = intervals[i][0];
                right = intervals[i][1];
            }
        }
        // 保存最后一个区间
        merged.push_back({left, right});
    
        return merged;
    }
    

2.4 三数之和

  • 问题描述:在数组中找到所有不重复的三元组,使它们的和等于目标值。
  • 示例
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
    
        for (int i = 0; i < nums.size(); i++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue; // 去重
    
            int left = i + 1, right = nums.size() - 1;
            while (left < right) {
                int sum = nums[i] + nums[left] + nums[right];
                if (sum == 0) {
                    result.push_back({nums[i], nums[left], nums[right]});
                    // 去重
                    while (left < right && nums[left] == nums[left + 1]) left++;
                    while (left < right && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else {
                    right--;
                }
            }
        }
    
        return result;
    }
    

2.5 链表的快慢指针

  • 问题描述:判断链表是否有环,或找到链表的中间节点。
  • 示例:判断链表是否有环。
    bool hasCycle(ListNode* head) {
        if (!head || !head->next) return false;
    
        ListNode* slow = head;
        ListNode* fast = head->next;
    
        while (fast && fast->next) {
            if (slow == fast) return true;
            slow = slow->next;
            fast = fast->next->next;
        }
    
        return false;
    }
    

3. 总结

  • 同向双指针:常用于滑动窗口问题。
  • 对向双指针:常用于有序数组的问题。
  • 快慢指针:常用于链表问题。

双指针技巧的核心是通过指针的移动来减少不必要的计算,从而优化时间复杂度。


http://www.kler.cn/a/527422.html

相关文章:

  • 5.4.1 结构化分析方法
  • Golang 并发机制-3:通道(channels)机制详解
  • 【C/C++】区分0、NULL和nullptr
  • 26.Word:创新产品展示说明会【9】
  • Keepalived 安装
  • 基于微信小程序的实习记录系统设计与实现(LW+源码+讲解)
  • DeepSeek的崛起与OpenAI的守擂:AI大模型时代的竞争新格局
  • 自动化数据备份与恢复:让数据安全无忧
  • 动态规划 (环形)
  • Spring的AOP的JoinPoint和ProceedingJoinPoint
  • 网络编程复习
  • 从0开始,来看看怎么去linux排查Java程序故障
  • Day31-【AI思考】-深度学习方法论全解析——科学提升学习效率的终极指南
  • Synology 群辉NAS安装(7)lsof指令和synogear
  • 半导体SAP管理系统:数字化转型的驱动力
  • ComfyUI使用教程、开发指导、资源下载
  • 微服务配置中心 Apollo解析——Portal 关联 Namespace
  • 什么是麦克斯韦方程
  • 2025年01月31日Github流行趋势
  • 3 Spark SQL