• 【代码随想录】二刷-双指针法


    双指针

    27. 移除元素

    // 时间复杂度 O(n)
    // 空间复杂度 O(1)
    class Solution {
    public:
        int removeElement(vector& nums, int val) {
            int slow = 0;
            int fast = 0;
            int n = nums.size();
            while(fast < n){
                if(nums[fast] != val){
                    swap(nums[slow++],nums[fast]);
                }
                fast++;
            }
            return slow;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    344. 反转字符串

    // 时间复杂度 O(n)
    // 空间复杂度 O(1)
    class Solution {
    public:
        void reverseString(vector& s) {
            for(int i =0,j=s.size()-1;i < j;i++,j--){
                swap(s[i],s[j]);
            }
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    剑指 Offer 05. 替换空格

    // 时间复杂度O(n)
    // 空间复杂度O(n)
    class Solution {
    public:
        string replaceSpace(string s) {
            int count = 0;
            int oldSize = s.size();
            for(char& c:s){
                if(c == ' ')count++;
            }
            s.resize(oldSize+count*2);
            int newSize = s.size();
            // "We are happy    ."
            //             i    j
            // %20
            // i越界之前,j肯定可以追上,从而终止循环。
            for(int i = oldSize-1,j=newSize-1;i < j;i--,j--){
                if(s[i] != ' '){
                    s[j] = s[i];
                }else{
                  s[j]='0';
                  s[j-1]='2';
                  s[j-2]='%';
                  j -= 2;
                }
            }
            return s;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    151. 反转字符串中的单词

    • 去掉多余空格
    • 整体反转
    • 反转每个单词
    // 时间复杂度O(n)
    // 空间复杂度O(1)
    class Solution {
    public:
        // 左闭右闭
        void myReverse(string& s,int begin,int end){
            for(int i =begin,j=end;i
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    206. 反转链表

    // 时间复杂度 O(n)
    // 空间复杂度 O(1)
    class Solution {
    public:
        ListNode* reverseList(ListNode* head) {
            ListNode* tmp;
            ListNode* pre = nullptr;// 想下可以理解,调转过来,第一个结点的next为nullpter
            ListNode* cur = head;
            while(cur){
                tmp = cur->next;// 保存下一个结点
                
                cur->next = pre;
                pre = cur;// 当前结点为下一个的next
                cur = tmp;// 当前结点变为next
            }
            return pre;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 递归
    // 时间复杂度O(n)
    // 空间复杂度O(1)
    class Solution {
    public:
        ListNode* dfs(ListNode* cur,ListNode* pre){
            if(cur == nullptr)return pre;
            ListNode* tmp = cur->next;
            cur->next = pre;
            // pre = cur; 直接在下面传cur即可
            return dfs(tmp,cur);
        }
    
        ListNode* reverseList(ListNode* head) {
            return dfs(head,nullptr);
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

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

    • 至于为什么要让fast先走n+1步,感觉是这图独有的技巧性,还是主要理解虚拟头结点的使用。——统一处理所有结点。
    // 时间复杂度O(n)
    // 空间复杂度O(1)
    class Solution {
    public:
        ListNode* removeNthFromEnd(ListNode* head, int n) {
            ListNode* tmpHead = new ListNode(0);
            tmpHead->next = head;
            ListNode* fast = tmpHead;
            ListNode* slow = tmpHead;
            n++;// 因为要删除结点,所以要停在目标结点前。fast先走n+1步
            while(fast && n--){
                fast = fast->next;
            }
            while(fast){
                fast = fast->next;
                slow = slow->next;
            }
            ListNode* tmp = slow->next;
            slow->next = tmp->next;
            delete tmp;
            return tmpHead->next;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    面试题 02.07. 链表相交

    • 让我想起了【设计链表那道题】,有关虚拟头结点的使用,一是可以统一管理所有结点,二来说也是为了删除结点,给出删除第几个,第几个指的是索引,从0开始,while(n–)会停在对应结点的前一个结点。
      • 联想出,删除第几个,如果这个第几个不是索引,就是字面意思的第几个,从1开始,那么我们可以将n-1,然后开始while(n–),最终停在指定结点的前一个。
    // 时间复杂度O(n)
    // 空间复杂度O(1)
    class Solution {
    public:
        ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
            int lenA = 0;
            int lenB = 0;
            ListNode* curA = headA;
            ListNode* curB = headB;
            while(curA){
                lenA++;
                curA = curA->next;
            }
            while(curB){
                lenB++;
                curB = curB->next;
            }
            // 默认A为更长的
            if(lenB > lenA){
                swap(headA,headB);
                swap(lenA,lenB);
            }
    
            int dis = lenA - lenB;
            curA = headA;
            curB = headB;
            while(dis-- && curA){
                curA = curA->next;
            }
            // 同一个起跑线
            while(curA){
                if(curA == curB)return curA;
                curA = curA->next;
                curB = curB->next;
            }
            return NULL;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    142. 环形链表 II

    • 感觉上面这几个链表的双指针偏具体题的特殊性一些。
    // 时间复杂度 O(n)
    // 空间复杂度 O(1)
    class Solution {
    public:
        ListNode *detectCycle(ListNode *head) {
            ListNode* slow = head;
            ListNode* fast = head;
            while(fast && fast->next){
                slow = slow->next;
                fast = fast->next->next;
                if(slow == fast){
                    ListNode* tmp = head;
                    while(tmp != fast){
                        tmp = tmp->next;
                        fast = fast->next;
                    }
                    return fast;
                }
            }
            return NULL;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    15. 三数之和

    // 时间复杂度 O(n²)
    // 空间复杂度 O(n)
    class Solution {
    public:
        vector> threeSum(vector& nums) {
            vector>ret;
            sort(nums.begin(),nums.end());
            int n = nums.size();
            for(int i = 0;i < n;i++){// a=nums[i]
                if(nums[i] > 0)break;// 去掉无意义的计算
                if(i > 0 && nums[i] == nums[i-1]){// a去重
                    continue;
                }
                int left = i+1;
                int right = n-1;
                while(left < right){
                    int tmpSum = nums[i]+nums[left]+nums[right];
                    if(tmpSum > 0)right--;
                    else if(tmpSum < 0)left++;
                    else{
                        // 收集结果
                        ret.push_back({nums[i],nums[left],nums[right]});
                        
                        // 去重
                        // left ->left                 right<-right
                        while(left < right && nums[left] == nums[left+1])left++;
                        while(left < right && nums[right] == nums[right-1])right--;
                        // 经过上述两个循环后,left right分别指向最后一个与上面收集结果时候相等的元素,经过下面再次++后,指向第一个与上述结果不相等我两个元素。
                        // 收缩-调整位置
                        left++;
                        right--;
                    }
                }
            }
            return ret;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 哈希表去重
    // 时间复杂度O(n²)
    // 空间复杂度O(n)
    class Solution {
    public:
        vector> threeSum(vector& nums) {
            vector>ret;
            sort(nums.begin(),nums.end());
            int n = nums.size();
            for(int i = 0;i < n;i++){// a=nums[i]
                if(nums[i] > 0)break;// 去掉无意义的计算
                if(i > 0 && nums[i] == nums[i-1]){// a去重
                    continue;
                }
                unordered_setset;
                for(int j = i+1;j < n;j++){// b=nums[j]
                    if(j > i + 2 && 
                        nums[j] == nums[j-1] &&
                        nums[j-1] == nums[j-2]){// b去重
                        continue;
                    }
                    int c = 0 - nums[i] - nums[j];//  c
                    if(set.find(c) != set.end()){// 找到了
                        ret.push_back({nums[i],nums[j],c});
                        set.erase(c);// c去重
                    }else{// 没找到
                        set.emplace(nums[j]);
                    }
                }
            }
            return ret;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    18. 四数之和

    • 即在三数之和的基础上加一层for循环。
    // 时间复杂度O(n³)
    // 空间复杂度O(n)
    class Solution {
    public:
        vector> fourSum(vector& nums, int target) {
            vector>ret;
            sort(nums.begin(),nums.end());
            int n = nums.size();
            for(int i = 0;i < n;i++){// a = nums[i]
                if(nums[i] > target && nums[i] >= 0)break;// 剪枝,去掉无意义计算
    
                if(i > 0 && nums[i] ==  nums[i-1])continue;// 去重
    
                for(int j = i+1; j < n;j++){// b = nums[j]
                    if(nums[i] + nums[j] > target && 
                        nums[i]+ nums[j] >= 0){// 剪枝,去掉无意义计算
                           continue;
                    }
                    if( j > i + 1 && nums[j] == nums[j-1])continue;// b去重
                    int left = j + 1;
                    int right = n-1;
                    while(left < right){
                        // 防止溢出,转long
                        long tmpSum = (long)nums[i] + nums[j] + nums[left] + nums[right];
                        if(tmpSum > target)right--;
                        else if(tmpSum < target)left++;
                        else{// 收集结果
                            ret.push_back({nums[i],nums[j],nums[left],nums[right]});
                            while(left < right && nums[left] == nums[left+1])left++;
                            while(left < right && nums[right] == nums[right-1])right--;
    
                            right--;
                            left++;
                        }
                    }
    
                }
            }
            return ret;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

  • 相关阅读:
    dumpstate log总结
    YBTOJ 递推算法合集
    深入理解Docker
    【Docker】入门指南(基础篇)
    STM32中GPIO工作原理
    1. 算法简介
    拉格朗日插值法的推导
    PLC开放式以太网通信网络状态查看工具netstat
    202204 RAC环境归档满
    Map常见的遍历方式-keySet 和 entrySet
  • 原文地址:https://blog.csdn.net/qq_51604330/article/details/127767083