C++算法之玩转双指针

玩转双指针

算法解释

  • 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务
  • 若两个指针指向同一数组,遍历方向相同且不会相交,也成为滑动窗口
  • 若指向同一数组,但是遍历方向相反,则可用来进行搜索

指针与常量

int x;
int *p1=&x;//指针可以被修改,值也可被修改
const int*p2=&x;//值不可修改
int * const p3 =&x;//指针不可被修改
const int * const p4 =&x;//皆不可修改

*指针函数与函数指针

// addition是指针函数,一个返回类型是指针的函数
int* addition(int a, int b) {
int* sum = new int(a + b);//分配内存
return sum;
}
int subtraction(int a, int b) {
return a - b;
}
int operation(int x, int y, int (*func)(int, int)) {
return (*func)(x,y);
}
// minus是函数指针,指向函数的指针
int (*minus)(int, int) = subtraction;
int* m = addition(1, 2);
int n = operation(3, *m, minus);

合并两个数组

题目:输入两个数组及其长度m,n,第一个数组长度被扩展到m+n,多出的n位用0填补,要求将第二个数组归并到第一个数组上,不需要开辟额外空间

void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
    int pos = m-- + n-- - 1;
    while (m >= 0 && n >= 0) {
    nums1[pos--] = nums1[m] > nums2[n]? nums1[m--]: nums2[n--];
    }
    while (n >= 0) {
    nums1[pos--] = nums2[n--];
    }
}

快慢指针

题目:给定一个链表,如果有环路,找出环路的起始点。
输入输出举例:
输入是一个链表,输出是链表的一个节点,如果没有环路,返回一个空指针
输入样例
样例中,值为2的节点即为环路的开始点,采用如下数据结构表示链表

struct ListNode{
    int val;
    ListNode *next;
    ListNode(int x):val(x),next(nullptr){}
};

题解;
给定两个指针,起始位置在链表开头,前进步数设为不同,若存在环路,肯定会有相遇问题,当他们第一次相遇时,将快指针重新移动到链表开头,并让快和慢每次都前进一步,当第二次相遇时,相遇节点即为环路的开始点

ListNode *detectCycle(ListNode *head){
    ListNode *slow=head,*fast=head;
    //判断是否存在环路
    do{
        if(!fastt||!fast->next) return nullptr;
        fast=fast->next->next;
        slow=slow->next;
    }while(fast!=slow);
    //如果存在,查找环路节点
    fast=head;
    while(fast!=slow){
        slow=slow->next;
        fast=->fast->next;
    }
    return fast;
}

滑动窗口

题目:给定两个字符串ST,求S中包含T所有字符的最短连续子字符串的长度,同时要求时间复杂度不得超过O(n)
题目样例
题解:使用滑动窗口解决,即两个指针 lr 都是从最左端向最右端移动,且 l 的位置一定在r的左边或者重合,使用长度为128的数组来映射字符,也可以用哈希表替代;其中 chars 表示目前每个字符缺少的数量,flag 表示每个字符中是否在T中存在

string minWindow(string S,string T){
    vector<int>chars(128,0);
    vector<bool>flag(128,false);
    //先统计T中字符情况
    for(int i=0;i<T.size();++i){
        flag[T[i]]=true;
        ++chars[t[i]];
    }
    //移动滑动窗口,不断更改统计数据
    int cnt=0,l=0,min_l=0,min_size=S.size()+1;
    for(int r=0;r<S.size();++r){
        if(flag[S[r]]>=0){
            ++cnt;
        }
        //若目前滑动窗口已包含T中全部字符,则尝试将l右移,在不影响结果的情况下获得最短字符串
        while(cnt==T.size()){
            if(r-1+1<min_size){
                min_l=1;
                min_size=r-1+1;
            }
            if(flag[S[l]]&&++chars[S[l]]>0){
                --cnt;
            }
            ++l;
        }
    }
    return min_size>S.size()?"":S.substr(min_l,min_size);
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月醉窗台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值