双指针算法(超详细版)

希望大家多多关注,有三必回

1.双指针

1.1快慢双指针

快慢双指针常用来解决循环问题,或是查找中间节点

1.1.1循环链表(141. 环形链表 - 力扣(LeetCode)

解题思路:

1.定义快慢指针fast和slow,让fast每次走两步,slow每次走一步

2.如果(slow==fast)相遇则证明有环,如果fast为空,则证明无环

为什么有环一定相遇?

因为我们假设两人赛跑,慢的人相对快的人就是静止的,如果有环,快慢人之间的距离就会不断减小,所以有环一定相遇

cpp 复制代码
//C++版
class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode *slow = head, *fast = head; // 同时从起点出发
        while (fast && fast->next) {
            slow = slow->next; // 慢的走一步
            fast = fast->next->next; // 快的走两步
            if (fast == slow) // 相遇,说明有环
                return true;
        }
        return false; // 访问到了链表末尾,无环
    }
};
cpp 复制代码
//C语言
typedef struct ListNode ListNode;
bool hasCycle(struct ListNode *head) {
    ListNode*fast,*slow;
    fast=slow=head;
    while(fast&&fast->next)
    {
        fast=fast->next->next;
        slow=slow->next;
        if(fast==slow)
        return true;
    }
    return false;
}
1.1.2中间节点(876. 链表的中间结点 - 力扣(LeetCode)

解题思路:

1.定义快慢指针fast和slow,让fast每次走两步,slow每次走一步

2.如果fast为空,则证明有此时的slow即为所求位置

cpp 复制代码
//C++版
class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
};
cpp 复制代码
//C语言版
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode*fast,*slow;
    fast=slow=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
    }
    return slow;
}

1.2对撞指针

1.2.1双变化趋势对撞指针(11. 盛最多水的容器 - 力扣(LeetCode)

解题思路:

设两指针 right , left ,分别指向⽔槽板的最左端以及最右端,此时容器的宽度为 right - left 。由于 容器的⾼度由两板中的短板决定,因此可得容积公式 : v = (right - left) * min( height[i], height[j])

注意点:

1.此时的容器宽度只会变小

2.当容器高度发生变化时,容积才会变化

3.不能改变数组的顺序

cpp 复制代码
//C++版本
class Solution {
public:
    int maxArea(vector<int>& height) {
        int right = height.size() - 1, left = 0, ret = 0;
        while (right > left) 
        {
            int v1 = min(height[right], height[left]) * (right - left);
            ret = max(v1, ret);
            if (height[right] < height[left])
                right--;
            else
                left++;
        }
        return ret;
    }
};
cpp 复制代码
//C语言版本
#define MIN(a, b) ((b) < (a) ? (b) : (a))
#define MAX(a, b) ((b) > (a) ? (b) : (a))

int maxArea(int* height, int heightSize) {
    int ans = 0, left = 0, right = heightSize - 1;
    while (left < right) {
        int area = (right - left) * MIN(height[left], height[right]);
        ans = MAX(ans, area);
        height[left] < height[right] ? left++ : right--;
    }
    return ans;
}
1.2.2单变化趋势对撞指针(611. 有效三角形的个数 - 力扣(LeetCode)

如果能构成三⻆形,需要满⾜任意两边之和要⼤于第三边。但是实际上只需让较⼩的两条边 之和⼤于第三边即可。

解题步骤:

1.定义左右指针,即数组下标(lef=0,right=nums.size()-1),来固定三角形种

2.定义变量i来表示中间的边如果nums[i]+nums[left]>nums[right]则可以组成三角形

3.让left不断接近i

cpp 复制代码
class Solution {
public:
    int triangleNumber(vector<int>& nums) {
        sort(nums.begin(),nums.end());//让数组从小到大排列
        int n=nums.size()-1,ret=0;
        for(int right=n;right>=2;right--)//固定right最长边
        {
            int left=0,i=right-1;//固定第二长边i
            while(left<i)//让left不断变化
            {
                if(nums[i]+nums[left]>nums[right])//成立则说明可以组成三角形
                {
                    ret+=i-left;//即[left,i)都可以组成三角形
                    i--;
                }
                else//不成立让最短边边长
                {
                    left++;
                }
            }
        }
        return ret;
    }
};
相关推荐
智算菩萨4 分钟前
强化学习从单代理到多代理系统的理论与算法架构综述
人工智能·算法·强化学习
lhn4 分钟前
大模型强化学习总结
算法
Gigavision18 分钟前
MMPD数据集 最新Mamba算法 源码+数据集 下载方式
算法
Xの哲學27 分钟前
Linux UPnP技术深度解析: 从设计哲学到实现细节
linux·服务器·网络·算法·边缘计算
歌_顿28 分钟前
GPT 系列学习总结(1-3)
算法
业精于勤的牙31 分钟前
最长特殊序列(三)
算法
柏木乃一31 分钟前
进程(6)进程切换,Linux中的进程组织,Linux进程调度算法
linux·服务器·c++·算法·架构·操作系统
皮卡蛋炒饭.31 分钟前
前缀和与差分
算法
0x7F7F7F7F1 小时前
算法竞赛数学知识大全
算法
业精于勤的牙1 小时前
最长特殊序列(二)
java·开发语言·算法