力扣K神图解算法数据结构解析05

本文介绍了力扣平台上的几道经典双指针算法题目,包括删除链表节点、数组元素奇偶排序、寻找链表倒数第k个节点、合并两个排序链表、查找两个链表的交点以及数组中和为目标值的两个数字。通过这些实例,展示了双指针在解决链表和数组问题时的时间复杂度为O(n)和空间复杂度为O(1)的优势。
摘要由CSDN通过智能技术生成

力扣K神图解算法数据结构点这里

五、双指针

  1. 剑指18,删除链表的节点

    //时间O(n),空间O(1)
    //基本操作,情况要考虑清楚
    class Solution {
    public:
        ListNode* deleteNode(ListNode* head, int val) 
        {
            if(!head) return nullptr;
            if(head->val == val) return head->next;
            auto cur = head->next;
            auto pre = head;
            while(cur)
            {
                if(cur->val == val) 
                {
                    pre->next = cur->next;
                    break;
                };
                pre = cur;
                cur = cur->next;
            }
            return head;
        }
    };
    
  2. 剑指21,奇数在前,偶数在后

    //时间O(n),空间O(1)
    //基本操作,快速排序中的一部分
    class Solution {
    public:
        vector<int> exchange(vector<int>& nums) 
        {
            int i = 0;
            int j = nums.size()-1;
            while(i < j)
            {
                while(i < j && nums[i]%2 == 1) ++i;
                while(i < j && nums[j]%2 == 0) --j;
                swap(nums[i],nums[j]);
            }
            return nums;
        }
    };
    
  3. 剑指22,链表中倒数第k个节点

    //时间O(n),空间O(1)
    //一次遍历,cur先走k步,pre=head,然后一起走直到cur指向nullptr,pre所指即为倒数第k个节点
    class Solution {
    public:
        ListNode* getKthFromEnd(ListNode* head, int k) 
        {
            if(!head) return nullptr;
            auto cur = head;
            for(int i=0;i<k;++i)
            {   
                cur = cur->next;
            }
            auto pre = head;
            while(cur)
            {
                cur = cur->next;
                pre = pre->next;
            }
            return pre;
        }
    };
    
  4. 剑指25,合并两个排序链表

    //时间O(m+n),空间O(1)
    //感觉写的又臭又长,虽然都能写出来
    class Solution {
    public:
        ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) 
        {
            ListNode* head1 = new ListNode(-1);
            ListNode* head2 = new ListNode(-1);
            ListNode* phead = new ListNode(-1);
            head1->next = l1;
            head2->next = l2;
            auto plast = phead;
            ListNode* p = nullptr;
    
            //1
            while(head1->next && head2->next)
            {
                if(head1->next->val < head2->next->val)
                {
                    p = head1->next;
                    head1->next = p->next;
                }
                else
                {
                     p = head2->next;
                    head2->next = p->next;
                }
                plast->next = p;
                p->next = nullptr;
                plast = plast->next;
            }
            //2
            if(!head1->next && head2->next)
            {
                plast->next = head2->next;
            }
            //3
            if(head1->next && !head2->next)
            {
                plast->next = head1->next;
            }
            return phead->next;
        }
    };
    
  5. 剑指52,两个链表的第一个公共节点

    //时间O(n),空间O(1)
    //head1走完走head2,head2走完走head1,如果相遇就是第一个公共节点,如果没有,返回nullptr
    class Solution {
    public:
        ListNode *getIntersectionNode(ListNode *head1, ListNode *head2) 
        {
            if(!head1 || !head2) return nullptr;
            auto p1 = head1;
            auto p2 = head2;
            int cnt1 = 0;
            while(p1 != p2)
            {
                p1 = p1->next;
                if(!p1 && cnt1 == 0) 
                {
                    p1 = head2;
                    ++cnt1;
                }
                else if(!p1 && cnt1 == 1) 
                {
                    return nullptr;
                }
                p2 = p2->next;
                if(!p2) p2 = head1;
            }
            return p1;
        }
    };
    
  6. 剑指57,和为s的两个数字

    //时间O(n),空间O(1)
    //此题为升序,因此使用对撞指针即可
    //若为无序,需要使用哈希表,空间复杂度为O(n)
    class Solution {
    public:
        vector<int> twoSum(vector<int>& nums, int target) 
        {
            if(nums.size() <= 1) return {};
            int i = 0;
            int j = nums.size()-1;
            int sum;
            while(i < j)
            {
                sum = nums[i] + nums[j];
                if(sum == target)
                {
                    return {nums[i],nums[j]};
                }
                else if(sum < target)
                {
                    ++i;
                }   
                else 
                {
                    --j;
                }
            }
            return {};
        }
    };
    
  7. 剑指58,翻转单词顺序

    //时间O(n),空间O(n)
    //简单,但是有许多点需要注意
    class Solution {
    public:
        string reverseWords(string s) 
        {
            string str;
            auto iter2 = s.crbegin();
            for(auto iter1 = s.crbegin();iter1 != s.crend();++iter1) 
            {
                if(*iter1 == ' ') continue;
                iter2 = iter1;
                while(iter1 != s.crend() && *iter1 != ' ')
                {
                    ++iter1;
                }
                str.append(iter1.base(),iter2.base());
                str.push_back(' ');
                //--防止下一次*iter1越界访问
                --iter1;
            }
            //只有非空的str才能erase
            if(!str.empty()) str.erase(str.size()-1);
            return str;
        }
    };
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值