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

算法系列之双指针(待完善题目)

1.简介

双指针是指在遍历数据结构(如数组、链表等)时,使用两个指针变量来辅助解决问题的方法。这两个指针可以同时移动,也可以一个指针固定而另一个指针移动,通过对指针的操作和相互配合,能够更高效地处理数据,解决各种问题。

2.对向指针

也叫左右指针,两个指针分别从数据结构的两端开始,相向移动。常用于数组的排序、回文串的判断等问题。例如在快速排序算法中,就可以利用对向双指针来划分数据。

2.1分类

教练使用整数数组 actions 记录一系列核心肌群训练项目编号。为增强训练趣味性,需要将所有奇数编号训练项目调整至偶数编号训练项目之前。请将调整后的训练项目编号以 数组形式返回。

注意是数组

class Solution {
public:
    vector<int> trainingPlan(vector<int>& actions) {
        int i=0;
        int j=actions.size()-1;
        while(i<j)
        {
            while(i<j&&(actions[i]&1)==1)i++;
            while(i<j&&(actions[j]&1)==0)j--;
            swap(actions[i],actions[j]);
        }
        return actions;
        
    }
};

2.2回文串

给定一个链表的 头节点 head ,请判断其是否为回文链表。

如果一个链表是回文,那么链表节点序列从前往后看和从后往前看是相同的。

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        vector<int>res;
        while(head)
        {
            res.push_back(head->val);
            head=head->next;
        }
        for(int i=0,j=res.size()-1;
                    i<j;i++,j--)
                    {
                        if(res[i]!=res[j])
                        return false;
                    }
                    return true;
        

    }
};

链表不好用 双指针 建议转化为数组

3.同向指针(滑动窗口)

两个指针从同一端开始,向同一方向移动。例如在有序数组中寻找满足特定条件的元素对时,通常可以使用同向双指针。一个指针用于遍历数组,另一个指针在当前指针的基础上进行特定条件的搜索和判断。

3.1 文件组合

待传输文件被切分成多个部分,按照原排列顺序,每部分文件编号均为一个 正整数(至少含有两个文件)。传输要求为:连续文件编号总和为接收方指定数字 target 的所有文件。请返回所有符合该要求的文件传输组合列表。

输入:target = 18
输出:[[3,4,5,6],[5,6,7]]
解释:在上述示例中,存在两个连续正整数序列的和分别为 18,分别为 [3, 4, 5, 6] 和 [5, 6, 7]。

class Solution {
public:
    vector<vector<int>> fileCombination(int target) {
        vector<vector<int>>res;
        int i=0;
        int j=1;
        int s=i+j;
        while(i<j)
        {
            if(s==target)
        
            {
                vector<int>tmp;
                for(int k=i;k<=j;k++)
                {
                    tmp.push_back(k);
                }
                res.push_back(tmp);
            }
            if(s<target)
            {
                j++;
                s+=j;
            }
            if(s>=target)
            {
                s-=i;
                i++;
            }
            
        }
        return res; 
    }
};

 

满足条件==左边界才能移动

3.2 重复子串

给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。

示例 1:

输入: s = "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3
class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        // 哈希集合,记录每个字符是否出现过
        unordered_set<char> tmp;
        int n = s.size();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int right = -1, res = 0;
        // 枚举左指针的位置,初始值隐性地表示为 -1
        for (int left = 0; left < n; ++left) {
            if (left!= 0) {
                // 左指针向右移动一格,移除一个字符
                tmp.erase(s[left - 1]);
            }
            while (right + 1 < n && !tmp.count(s[right + 1])) {
                // 不断地移动右指针
                tmp.insert(s[right+ 1]);
                right++;
            }
            // 第 left到 right个字符是一个极长的无重复字符子串
            res = max(res, right - left + 1);
        }
        return res;
    }
};

 4 快慢指针

两个指针移动速度不同,快指针每次移动的步长大于慢指针。在链表相关问题中经常使用,比如判断链表是否有环、寻找链表的中间节点等。快指针一次移动两步,慢指针一次移动一步,如果链表有环,快指针最终会追上慢指针。

4.1回文链表

给你一个链表的头节点 head ,判断链表中是否有环。

如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        if(head==nullptr||head->next==nullptr)
        {
            return false;
        }
        ListNode*slow=head;
        ListNode*fast=head->next;
        while(slow!=fast)
        {
            if(fast==nullptr||fast->next==nullptr)
            {
                return false;
            }
            slow=slow->next;
            fast=fast->next->next;
        }
        return true;
        
      
    }
};

 4.2

给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

示例 1:

输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode *fast=head;
        ListNode *dum=new ListNode(0,head);
        ListNode *slow=dum;
        for(int i=0 ;i<n;i++)
        {
            fast=fast->next;
        }
        while(fast)
        {
            fast=fast->next;
            slow=slow->next;
        }
        slow->next=slow->next->next;
        return dum->next;}
      
};

 5.应用

 数组和字符串处理

          有序数组的元素查找:在有序数组中查找两个数之和等于给定值的问题,可以使用对向双指针。初始化左右指针分别指向数组的首尾,通过不断调整指针的位置来找到满足条件的元素对。

          字符串的回文判断:使用对向双指针,一个指针从字符串的开头,另一个指针从字符串的结尾,同时向中间移动,比较对应位置的字符是否相等,从而判断字符串是否为回文

  • 链表操作
    • 寻找链表的倒数第 k 个节点:先让快指针向前移动 k 步,然后快慢指针同时移动,当快指针到达链表末尾时,慢指针所指向的就是倒数第 k 个节点。

    • 判断链表是否有环:利用快慢双指针,快指针每次走两步,慢指针每次走一步,如果快指针追上慢指针,则说明链表有环。


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

相关文章:

  • openssl下aes128算法xts模式加解密运算实例
  • MySQL零基础教程13—分组查询(group by 和 having)
  • 消息中间件应用的常见问题与方案?
  • 华为 Open Gauss 数据库在 Spring Boot 中使用 Flyway
  • 【Delphi】如何解决使用webView2时主界面置顶,而导致网页选择文件对话框被覆盖问题
  • Python的那些事第三十四篇:基于 Plotly 的交互式图表与仪表板设计与应用
  • 【北京迅为】itop-3568 开发板openharmony鸿蒙烧写及测试-第1章 体验OpenHarmony—烧写镜像
  • 6-2JVM解释器
  • docker利用docker-compose-gpu.yml启动RAGFLOW,文档解析出错【亲测已解决】
  • 高效API开发:FastAPI中的缓存技术与性能优化
  • 前缀和算法 算法4
  • unsloth报错FileNotFoundError: [WinError 3] 系统找不到指定的路径。
  • Transformer 代码剖析2 - 模型训练 (pytorch实现)
  • 【大模型学习笔记】0基础本地部署dify教程
  • AI辅助学习vue第十四章
  • 欧拉22.03系统安装离线redis 6.2.5
  • vue3配置端口,比底部vue调试
  • logback日志输出配置范例
  • FPGA AXI-Stream协议详解与仿真实践
  • Git版本管理逻辑解析:从核心原理到工作流实践