C++双指针详解

双指针从广义上来说,是指用两个变量在线性结构上遍历而解决的问题。狭义上说,
对于数组,指两个变量在数组上相向移动解决的问题;
对于链表,指两个变量在链表上同向移动解决的问题,也称为「快慢指针」问题。

1.左右指针

模版

//左闭右开[left,right)
int left = 0, right = nums.size(), middle = left + (right-left)/2;
while(left < right){
    
    
	if(nums[middle]>target)
		right = middle;
	else if(nums[middle]<target)
		left = middle + 1;
	else
		return middle;
}
//左闭右闭[left,right]
int left = 0, right = nums.size()-1, middle = left + (right-left)/2;
while(left <= right){
    
    
	if(nums[middle]>target)
		right = middle-1;
	else if(nums[middle]<target)
		left = middle + 1;
	else
		return middle;
}

leetcode42

/*
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
*/
class Solution {
    
    
public:
    int trap(vector<int>& height) {
    
    
        int n = height.size();
        int left = 1, right = n-2;
        int lmax = height[0], rmax = height[n-1];
        int ans = 0;
        while(left <= right){
    
    
            if(lmax <= rmax){
    
    
                ans += max(lmax-height[left],0);
                lmax = max(lmax,height[left]);
                left++;
            }
            else{
    
    
                ans += max(rmax-height[right],0);
                rmax = max(rmax,height[right]);
                right--;
            }
        }
        return ans;
    }
};

leetcode41

/*
给你一个未排序的整数数组 nums ,请你找出其中没有出现的最小的正整数。
请你实现时间复杂度为 O(n) 并且只使用常数级别额外空间的解决方案。
输入:nums = [3,4,-1,1]
输出:2
*/
class Solution {
    
    
public:
    int firstMissingPositive(vector<int>& nums) {
    
    
        int left=0, right = nums.size();
        while(left < right){
    
    
            if(nums[left] == left+1)
                left++;
            else if(nums[left]<=left||nums[left]>right||nums[nums[left]-1]==nums[left]){
    
    
                right--;
                swap(nums[left],nums[right]); 
            }
            else
                swap(nums[left],nums[nums[left]-1]);
        }
        return left + 1;
    }
};

2.快慢指针

leetcode27

/*
给你一个数组nums和一个值val,你需要原地移除所有数值等于val的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且nums中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案
*/
class Solution {
    
    
public:
    int removeElement(vector<int>& nums, int val) {
    
    
        int n = nums.size();
        int fast=0, slow=0;
        while(fast<n){
    
    
            if(nums[fast] == val)
                fast++;
            else{
    
    
                nums[slow]=nums[fast];
                fast++;
                slow++;
            }
        }
        return slow;
    }
};

leetcode283

/*
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
*/
class Solution {
    
    
public:
    void moveZeroes(vector<int>& nums) {
    
    
        int n = nums.size();
        int fast=0, slow=0;
        while(fast<n){
    
    
            if(nums[fast]==0)
                fast++;
            else{
    
    
                nums[slow]=nums[fast];
                fast++;
                slow++;
            }
        }
        for(int i = slow; i < n; i++)
            nums[i] = 0;
    }
};

leetcode287

/*
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums 且只用常量级 O(1) 的额外空间。
输入:nums = [1,3,4,2,2]
输出:2
*/
class Solution {
    
    
public:
    int findDuplicate(vector<int>& nums) {
    
    
        int n = nums.size();
        if(n<2)
            return -1;
        int fast = nums[nums[0]];
        int slow = nums[0];
        while(fast != slow){
    
    
            fast = nums[nums[fast]];
            slow = nums[slow];
        }
        fast = 0;//第一次相遇了,fast回到开头
        while(fast != slow){
    
    
            fast = nums[fast];
            slow = nums[slow];
        }
        return fast;
    }
};

leetcode136

/*
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
输入:nums = [4,1,2,1,2]
输出:4
*/
class Solution {
    
    
public:
    int singleNumber(vector<int>& nums) {
    
    
        int n = nums.size();
        if(n<2)
            return nums[0];
        
        sort(nums.begin(),nums.end());
        int fast = 1, slow = 0;
        while(fast < n-1){
    
    
            if(nums[fast] == nums[slow]){
    
    
                fast += 2;
                slow += 2;
            }
            else{
    
    
                return nums[slow];
            }
        }
        return nums[n-1];
    }
};

leetcode141

/*
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
*/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    bool hasCycle(ListNode *head) {
    
    
        if(head == NULL || head->next == NULL || head->next->next == NULL)
            return false;
        
        ListNode* fast = head->next->next;
        ListNode* slow = head->next;
        while(fast != slow){
    
    
            if(fast->next == NULL || fast->next->next == NULL)
                return false;
            fast = fast->next->next;
            slow = slow->next;
        }
        return true;
    }
};

leetcode142

/*
给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。
不允许修改 链表。
输入:head = [3,2,0,-4], pos = 1
输出:返回索引为 1 的链表节点
解释:链表中有一个环,其尾部连接到第二个节点。
*/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
    
    
public:
    ListNode *detectCycle(ListNode *head) {
    
    
        if (head == NULL || head->next == NULL || head->next->next == NULL) {
    
    
			return NULL;
		}
        ListNode* slow = head->next;
        ListNode* fast = head->next->next;
        while(fast != slow){
    
    
            if(fast->next == NULL || fast->next->next == NULL)
                return NULL;
            fast = fast->next->next;
            slow = slow->next;
        }
        fast = head;
        while(fast != slow){
    
    
            fast = fast->next;
            slow = slow->next;
        }
        return fast;
    }
};

参考:
https://leetcode.cn/tag/two-pointers/problemset/
https://www.bilibili.com/video/BV1V841167Rg/?spm_id_from=333.337.search-card.all.click&vd_source=f1c65f89fc3b6299ff0fcd42c1a8d57b

猜你喜欢

转载自blog.csdn.net/qq_44961737/article/details/132718870