leetcode双指针合集

在这里插入图片描述

27. 移除元素

class Solution {
public:
    
    int removeElement(vector<int>& nums, int val) {
    /**
        思路:使用快慢指针,快指针正常往后移动,并将获取的值给慢指针,但是当快指针所指向的值是val的
        时候慢指针便不再更新;
    **/    
      int slowIndex = 0;
      for(int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            if(nums[fastIndex] != val) {
                 nums[slowIndex] = nums[fastIndex];
                 slowIndex++;
            }
      }

       return slowIndex; 
    }
};

344. 反转字符串

class Solution {
public:
    void reverseString(vector<char>& s) {
      
      for(int i = 0,j = s.size()-1; i < s.size()/2; i++,j--) {
          swap(s[i],s[j]);
      }

    }
};

剑指 Offer 05. 替换空格


class Solution {
public:
    string replaceSpace(string s) {

       /**
            思路:
            1.双指针(一个指针指向旧的字符串末尾ptr1,一个指针指向扩容后的字符串末尾ptr2)
            2.对原字符串的扩容,因为%20是占3个空格的,所以要在原来一个空格基础上进行扩容
            3.当遇到不是空格的时候,两个指针指向的字符就正常赋值,如果当ptr1指向空格的时候
              ptr2就前面的3个空格 填上%20
       */

        int count = 0;//记录空格数
        int oldSize = s.size();

        for(int i = 0; i < s.size(); i++) {
            if(s[i] == ' '){
                count++;
            }
        }

        s.resize(oldSize+2*count);

        int newSize = s.size();
        //i和j模拟指针
        for(int i = oldSize-1,j = newSize-1; i>=0; i--,j--) {

           if(s[i] == ' '){
               s[j] = '0';
               s[j-1] = '2';
               s[j-2] = '%';
               j = j-2;
           }else{
               s[j] = s[i];
           } 
        }

        return s;
    }
};

151. 翻转字符串里的单词


class Solution {
public:
    /**
       思路:
        1.去除空格(字符串前面的空格 字符串中间冗余的空格 字符串后面的空格)
        2.反转字符串
        3.将每个单词进行反转
    **/
    
    void removespacing(string &s) {
        int slowIndex = 0,fastIndex = 0;//定义快慢指针(最终慢指针为去完冗余空格的字符串)
        
        //去除字符串前面的空格
        while(s[fastIndex] == ' '){
            fastIndex++;
        }

        for( ; fastIndex < s.size(); fastIndex++) {
            //去除冗余的空格
            if(fastIndex-1 > 0 &&
                s[fastIndex-1] == s[fastIndex] 
                && s[fastIndex] == ' '){
                    continue;
            }else {
                s[slowIndex] = s[fastIndex];
                slowIndex++;
            }            
        }

        //去除末尾的空格(如果字符串的末尾有多个空格的话  上方只能处理到末尾只有一个空格)
        if(slowIndex-1 > 0 && s[slowIndex - 1] == ' '){
            s.resize(slowIndex-1);
        }else{
            s.resize(slowIndex);
        }
    }

    void reverseStr(string &s,int start,int end){
        for(int i = start,j = end; i < j; i++,j--) {
            swap(s[i],s[j]);
        }
    }

    string reverseWords(string s) {
        
        removespacing(s);
        reverseStr(s,0,s.size() - 1);

        for(int i = 0; i < s.size(); i++) {
            int j = i;
            //找到空格
            while(j < s.size() && s[j] != ' ') {
                j++;
            }
            reverseStr(s,i,j-1);//这里j-1是因为s[j]已经表示的是空格了
            i = j;
        }

        return s;
    }
};

206. 反转链表


class Solution {
public:
    ListNode* reverseList(ListNode* head) {
      
        ListNode* temp;//存放临时结点
        ListNode* cur = head;
        ListNode* pre = NULL;

        while(cur) {
            temp = cur->next;
            cur->next = pre;//调转指针

            pre = cur;//往后移动一个结点
            cur =  temp;
        }

        return pre;//当cur指向5的时候 下一个就指向空  那么pre = cur 则就表示前指针表示指向的是5
    }
};

19. 删除链表的倒数第 N 个结点

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        /**
            思路:
            1.双指针(慢指针p1,快指针p2)
            2.要删除倒数第n个结点,也就是要正向删除 第(总的节点数 - n)个结点 
            3.为了处理倒数问题,先让p2往后移动n个结点,(这时候p2还剩下(总的节点数-n = sum)),那么此时
              p1和p2一块移动,等到p2指向末尾的时候,p1也就指向要删除的结点
        */

        ListNode* fakeNode = new ListNode(0);
        fakeNode->next = head;
        ListNode* slowNode = fakeNode;//慢指针
        ListNode* fastNode = fakeNode;//快指针

        while(n-- && fastNode != NULL) {
            fastNode = fastNode->next;
        }

        fastNode = fastNode->next;//让其再快一格是为了当快指针到末尾的时候,慢指针指向要删除结点的
                                  //的前一个结点              
        while(fastNode != NULL){
            fastNode = fastNode->next;
            slowNode = slowNode->next;
        }

        slowNode->next = slowNode->next->next;
        return fakeNode->next;

     

    }
};

18. 四数之和

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int> >ans;
        vector<int> v;

        sort(nums.begin(),nums.end());

        for(int i = 0; i < nums.size(); i++) {
            
            if(i > 0 && nums[i-1] == nums[i]) {
                continue;
            }

            for(int j = i+1; j < nums.size(); j++) {

                if(j-1 > i &&nums[j-1] == nums[j]){//这里的j-1大于i主要考虑的是我们去重复的是从
                    continue;                    //j开始指向的元素
                }

                int left = j+1;
                int right = nums.size() - 1;

                while(left < right) {
                    
                    if(nums[i]+nums[j] > target - (nums[left]+nums[right])) right--;
                    else if(nums[i]+nums[j] < target - (nums[left]+nums[right])) left++;
                    else {
                        v.push_back(nums[i]);
                        v.push_back(nums[j]);
                        v.push_back(nums[left]);
                        v.push_back(nums[right]);
                        ans.push_back(v);

                        //去重处理
                        while(left < right && nums[right-1] == nums[right]) right--;
                        while(left > right && nums[left+1] == nums[left]) left++;

                        //换下一组
                        right--;
                        left++;
                        v.clear();

                    }

                } 

            }
        }

        return ans;
    }
};

15. 三数之和

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
    /**
    思路:
        1.我们将所有元素进行升序处理(这样处理的话,我们可以知道当前面的元素大于0的时候,那么便一定
           不会出现 a+b+c=0 
        2.这里我们设置三个指针(模拟的) 第一个指针(i)指向数组的第一个元素,第二个指针(left)指向数组的
           第二个元素,第三个指针(right)指向数组的最后的元素
        3.nums[i] + nums[left] + nums[right] > 0; right-- ,i和left不动
          nums[i] + nums[left] + nums[right] < 0; left++,i和right不动
          nums[i] + nums[left] + nums[right] = 0;left++,right--,i也移动一个单位

          当我们找到一组答案的时候,就要同时移动三个指针;因为当我们找到一组答案的时候,如果不移动
          i,只移动left和right,因为是升序的,那么的话nums[left] + nums[right] 只会更小
          与nums[i]相加也不会等于0;如果我们想要最终的和为0,那么的话nums[i] < 0,nums[left] < 0,
          nums[right] > 0,那么往后移动i,如果和为0的话 nums[left] + nums[right]的结果只会更小
          因此我们每确定一组答案的时候,需要同时移动left,right,i

        4.这里的去重,我们是当遇到相同的元素跳过它

    */
    
        vector<vector<int> >ans;
        vector<int>v;

        sort(nums.begin(),nums.end());

        for(int i = 0; i < nums.size(); i++) {
            
            if(nums[i] > 0){//如果首元素大于0的话那么就不会有和为0了
                return ans;
            }

            if(i > 0 && nums[i] == nums[i-1]){
                continue;
            }

            int left = i+1;
            int right = nums.size() - 1;

            while(left < right) {

                int sum = nums[i] + nums[left] + nums[right];

                if(sum > 0) right--;
                else if(sum < 0) left++;
                else {
                    v.push_back(nums[i]);
                    v.push_back(nums[left]);
                    v.push_back(nums[right]);
                    ans.push_back(v);

                    //去重处理(相邻的元素出现了重复)
                    while(left < right && nums[right-1] == nums[right]) right--;
                    while(left < right && nums[left+1] == nums[left]) left++;

                    //换下一组答案(上方的去重处理只是指针移动到最后一个重复的元素)
                    right--;
                    left++;
                    v.clear();
                }       

            }

        }

        return ans;
    }
};

142. 环形链表 II

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
    /**
    思路:
        1.定义快慢指针(快指针一次移动一个节点,慢指针一次移动两个结点)
        2.如果有环的话那么的话快慢指针一定会相遇(因为如果没环的话快慢指针永远不相遇)
        3.那么我们接下来就要确认出口在哪里,(根据以证明的结论,定义一个新的结点头指针指向它,然后快指针
          和其一块移动,当其相遇的时候,就是出口.
    **/

    ListNode* slowNode = head;
    ListNode* fastNode = head; 

  //当fastNode->next != NULL的时候  是允许fastNode->next->next 为空的
  //如果没有此条件的话,那么当指针指向最后一个结点的时候,fast->next 已经为空了,它便不能再指向空了
  //即fast->next->next (不能空指向空)
    while(fastNode != NULL && fastNode->next != NULL) {
        
        fastNode = fastNode->next->next;
        slowNode = slowNode->next;

        if(slowNode == fastNode){

            ListNode* temp1 = fastNode;
            ListNode* temp2 = head;

            while( temp1 != temp2) {
                temp1 = temp1->next;
                temp2 = temp2->next;
            }
            return temp1;
        }   
    }
    
    return NULL;

    }
};

面试题 02.07. 链表相交

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
      /**
        思路:1.双指针(一个指针指向长链表,一个指针指向短链表)
             2.我们需要将两个链表右对齐
             3.将其右对齐的目的是为了让长链表的指针移动到和短链表指针相同的位置
               这样就可以方便找到相同的指针(只要指针相同那么其接下来的数也相同)
             4.所以我们需要确定出长链表是谁  
      */

       ListNode* node1 = headA;//新定义一个结点方便操作,保存头结点 
       ListNode* node2 = headB;
       
       int lenA = 0;
       int lenB = 0;

       while(node1 != NULL) {
           node1 = node1->next;
           lenA++;
       }

       while(node2 != NULL) {
           node2 = node2->next;
           lenB++;
       } 

        node1 = headA;//上方已经将node1和node2移到最后了
       node2 = headB;

       //因为我们需要将长链表的指针进行移动  所以我们需要确定出长链表
       if(lenB > lenA){
           swap(lenA,lenB);
           swap(node1,node2);
       }


       int poor = lenA - lenB; //长链表比短链表多的长度
       
       while(poor--) {
           node1 = node1->next;
       } 

       while(node1 != NULL) {
           if(node1 == node2) {
               return node1;
           }
           node1 = node1->next;
           node2 = node2->next;
       } 

        return NULL;
    }   
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天天向上的菜鸡杰!!

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

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

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

打赏作者

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

抵扣说明:

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

余额充值