dylanin1999

导航

LeetCode解题总结--双指针

双指针解题多用于链表、数组等问题当中。

双指针的难度在于:

        1、一开始可能很难想到

        2、变式很多

        3、指针并不是具体指的函数中的“指针”,而是一种思想。例如设置两个不同的可动标志位,也是”双指针“

 

下面以具体的LeetCode题目补充解释:

题目汇总:

        26. 删除排序数组中的重复项

        80. 删除排序数组中的重复项 II

        86. 分隔链表

        141. 环形链表 (经典题,引入快慢指针思想)

        845. 数组中的最长山脉(双指针的变式应用)

 

1、LeetCode 141. 环形链表

        环形链表这道题在我看来,是理解快慢指针思想的最典型的题目。

        通过利用快慢指针的步长差,并且结合链表的环状结构,只要链表中存在着环,那么,不论时间的长短,快指针和慢指针总会相遇。

        想象这么一个场景:两辆车一快一慢,在一段直线距离后驶入环形跑道,那么只要给予一定时间,快的车一定会比慢的车快上一整圈,从而相遇。而用快慢指针正是模拟了这种思想,来检测环形。

        一旦我们了解了快慢指针的思想,那么,在很多问题上,我们都可以想到使用双指针来解决问题。需要注意的问题只不过是在于双指针的变式很多,需要我们结合题目来具体分析。

        快慢指针解题的思路图解:

双指针-环形链表

 

class Solution {
public:
    bool hasCycle(ListNode *head)
    {
        if(head==nullptr||head->next==nullptr)
            return false;   

        ListNode* fast = head;
        ListNode* slow = head;
        while(slow->next!=nullptr&&fast->next!=nullptr)
        {
            slow = slow->next;//慢指针每次前进一步
            if(fast->next->next == nullptr)
                return false;
            fast = fast->next->next;//快指针每次前进两步
            if(fast==slow)
                return true;
        }
        return false;
    }
};

2、LeetCode 26. 删除排序数组中的重复项

本题的目标是为了删除重复项,但是不需要删除所有的重复项,只需要将不同的项提到前面即可。这样第一个想到的思路就是:

遍历整个数组,每当遇到不一样的元素就将其提到前面。这样就会产生一个问题,如何确保在交换时,可以确定位置。只要我们使用一个标志位记录不重复的元素的最后位置,每次遇到不同的元素就将元素放在标志位的后一个,并更新标志位即可。

具体的过程可以看下图:

 

class Solution {
public:
    int removeDuplicates(vector<int>& nums) 
    {
        if(nums.size()==0)
            return 0;
        int p1 = 0;
        int cur = nums[0];
        for(int i=0;i<nums.size();i++)
        {
            if(cur!=nums[i])
            {
                cur = nums[i];
                nums[++p1] = nums[i];
            }
        }
        return p1+1;
    }
};

3、80. 删除排序数组中的重复项 II

        本题和上一题的差别其实并不算很大,因为只要搞懂了LeetCode 26,其实差别就在于,如何多使用一个计数器,来实现“最多出现两次”的这一限定条件。

class Solution {
public:
    int removeDuplicates(vector<int>& nums) 
    {
        if(nums.size()==0)
            return 0;
        if(nums.size()==1)
            return 1;
        int numCounter=1;
        int P1 = 0;
        int cur = nums[0];
        for(int i=1;i<nums.size();i++)
        {
            if(cur!=nums[i])
            {
                cur=nums[i];
                P1++;
                nums[P1] = nums[i];
                numCounter=1;
                continue;
            }
            if(numCounter<2)
            {
                P1++;
                numCounter++;
                nums[P1] = cur;
            }
        }
        return P1+1;
    }
};

4、845. 数组中的最长山脉(双指针的变式应用)

    这道题中,我的做法是,结合“中心扩张”思想和双指针来解题的。

        ①首先,找到一个符合条件的山脉顶点

        ②在顶点两侧使用双指针向两端扩张,直到不符合要求为止。

        ③两个指针最终的坐标值的差即为长度,不断更新max值即可。

 

 

个人感觉只要掌握了上述的几个解题思路,遇到类似的问题,第一时间也会想到利用双指针来结题,接下来就是根据题目具体制定解题步骤了!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted on 2022-08-13 16:15  DylanYeung  阅读(40)  评论(0编辑  收藏  举报