百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 文章教程 > 正文

C|双指针之快慢指针(读写指针)、左右端点指针、固定间距指针

yund56 2025-05-08 16:41 36 浏览

遍历是实现许多算法的基本操作。遍历数据或链表通常通过指针(或索引)在循环内实现指针的移动来进行。

我们遍历一个数组,并输出数组每一项,我们需要一个指针来记录当前遍历的项,这个指针我们可以叫单指针(index)。在某些情况下,可能使用两个这样的指针来遍历更方便问题求解,称为双指针。

伪代码:

// 单指针
for(int i = 0;i < nums.size(); i++) {
    输出(nums[i]);
}

// 双指针
int L = 0;
int R = nums.size() - 1;
while (L < R) {
    if(一定条件)
        return 合适的值,一般是 L 和 R 的中点
    if(一定条件) L++ 
    if(一定条件) R--
}
// 因为 L == R,因此返回 I 和 R 都是一样的 
return L

双指针是指对数据结构(如数组和链表)使用两个指针或两个索引来操作数据,其策略一般有:

I 步长不等的快慢指针(两个指针步长不同),如用来排除重复元素。

II 左右端点指针(两个指针分别指向头尾,并往中间移动,步长不确定),如实现二分查找。

III 步长相等的快慢指针(两个指针间距相同,步长相同),如一次遍历(OnePass)求链表的中点或求单链表的倒数第k个元素。

1 步长不等的快慢指针

步长不等的快慢指针是指针使用两个步长不同的指针,通常快指针用于读,慢指针用于写。

// 快慢指针
L = 0 
R = 0 
while 没有遍历完 
    if 一定条件
        L += 1 
    R += 1 
return 合适的值

典型实例:

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定 int nums[] = {1,1,1,2,2,3};

函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。

你不需要考虑数组中超出新长度后面的元素。

示例 2:

给定 int nums[] = {0,0,1,1,1,1,2,3,3};

函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。

你不需要考虑数组中超出新长度后面的元素。

实际上这种问题可以更抽象一步,即“删除排序数组中的重复项,使得相同数字最多出现 k 次” 。 那么这道题 k 就是 2,如果 k 为 1,则是删除重复元素。。

  • 初始化快慢指针 slow , fast ,全部指向索引为 0 的元素。
  • fast 每次移动一格
  • 慢指针选择性移动,即只有写入数据之后才移动。是否写入数据取决于 slow - 2 对应的数字和 fast 对应的数字是否一致。
  • 如果一致,我们不应该写。 否则我们就得到了三个相同的数字,不符合题意。
  • 如果不一致,我们需要将 fast 指针的数据写入到 slow 指针。
  • 重复这个过程,直到 fast 走到头,说明我们已无数字可写。

图解(红色的两个数字,表示我们需要比较的两个数字):

code:

#include <stdio.h> // 快慢指针(读写指针)
#include <vector>
using namespace std;

class Solution {
public:
    int removeDuplicates(vector<int>& nums,int k) {
        int i = 0;
        for(int j=0;j<nums.size();j++)
            if (i < k || nums[j] != nums[i - k]) {
                nums[i] = nums[j];
                i++;
            }
        return i;
    }
};

template <typename TT>
void print(TT tt,int n)
{
    for(int i=0;i<n;i++)
        printf("%d ",tt[i]);
    printf("\n");
}

int main()
{
    int nums[] = {0,0,1,1,1,1,2,3,3};
    int size = sizeof nums / sizeof *nums;
    vector<int> vc(nums,nums+size);
    Solution st;
    int n = st.removeDuplicates(vc,2);
    print(nums,size);
    print(vc,n);

    vector<int> vc2(nums,nums+size);
    n = st.removeDuplicates(vc2,1);
    print(vc2,n);
    getchar();
    return 0;
}
/*
0 0 1 1 1 1 2 3 3
0 0 1 1 2 3 3
0 1 2 3
*/

2 左右端点指针

两个指针分别指向头尾,并往中间移动,步长不确定。

// 左右端点指针
L = 0
R = n - 1
while L < R
    if 找到了
        return 找到的值
   if 一定条件1
     L += 1
   else if 一定条件2
     R -= 1
return 没找到

典型实例:二分查找:

先定义搜索区间(非常重要)

根据搜索区间定义循环结束条件

取中间元素和目标元素做对比(目标元素可能是需要找的元素或者是数组第一个,最后一个元素等)(非常重要)

根据比较的结果收缩区间,舍弃非法解(也就是二分)

如果是整体有序通常只需要nums[mid]和target比较即可。如果是局部有序,则可能需要与其周围的特定元素进行比较。

code:

#include <stdio.h>
#include <vector>
using namespace std;

int binarySearch(vector<int>& nums, int target){
    if(nums.size() == 0)
        return -1;
    int left = 0, right = nums.size() - 1;
    while(left <= right){
        int mid = left + ((right - left) >> 1);
        if(nums[mid] == target){ return mid; }
        // 搜索区间变为 [mid+1, right]
        else if(nums[mid] < target)
            left = mid + 1;
        // 搜索区间变为 [left, mid - 1]
        else
            right = mid - 1;
    }
    return -1;
}

int main()
{
    int arr[] = {1,2,3,4,5,6,7};
    vector<int> vc(arr,arr+7);
    printf("%d\n",binarySearch(vc,5));
    getchar();
    return 0;
}

回文验证:

#include <stdio.h>
#include <string>
using namespace std;

bool isPalindrome(string s) {
    if (s.empty())
        return true;
    const char* left = s.c_str();
    const char* end = left + s.length() - 1;
    while (end > left) {
        if (!isalnum(*left)) {++left; continue;}
        if (!isalnum(*end)) {--end; continue;}
        if (tolower(*left) != tolower(*end)) return false;
        else {--end; ++left;}
    }
    return true;
}

int main()
{
    string s = "20122102";
    string t = "abcabc";
    printf("%d %d\n",isPalindrome(s),isPalindrome(t));
    getchar();
    return 0;
}

3 步长相等的快慢指针

两个指针步长相同。

// 步长相等的快慢指针 
L = 0
R = k
while没有遍历完
    自定义逻辑
    L += 1 
    R += 1
return 合适的值

典型实例:利用固定间距指针寻找链表中点

利用两个指针fast、slow同时指向头节点,fast指针每次走两步,slow指针每次走一步,当fast指针到达链表尽头时,slow指针就处于链表中点处。

Node* middle(Node* head) 
{
    Node* fast, *slow;
    fast = slow = head;
    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;    //slow即在中间位置
}

如果链表长度是奇数时,此时slow 正好为中点,如果为偶数,那么slow位置是中间偏右。

典型实例:一次遍历(OnePass)求单链表的倒数第k个元素:

#include<stdio.h>  // 一次遍历(OnePass)求单链表的倒数第k个元素
#include<stdlib.h>

typedef struct Node
{
    int num;
    Node *next;
}Linklist;

Linklist * creat_linklist();        //尾插法创建含有头结点的单链表
int Search_K(Linklist *h, int k)    //双指针算法查找节点
{
    Linklist *fast = h->next;	
    Linklist *slow = h->next;
    int count = 0;                  //  计数器
    while(fast!=NULL)
    {
        fast = fast->next;
        if(count < k)
            count++;
        else
            slow = slow->next;
    } 	 
    if(count < k)                   //如果K大于链表的长度情况 
    {
        printf("您要查找的节点不存在!"); 
        return 0;
    }
    else
    {
        printf("倒数第%d个节点的数据为:%d\n",k,slow->num);
        printf("*** 查找完成!***"); 
        return 1;
    }
}
Node* middle(Node* head) 
{
    Node* fast, *slow;
    fast = slow = head;
    while (fast != NULL && fast->next != NULL) {
        fast = fast->next->next;
        slow = slow->next;
    }
    return slow;    //slow即在中间位置
}
void print(Linklist* head)
{

    while(head->next != NULL)
    {
        printf("%d ",head->next->num);
        head = head->next;
    }
    printf("%\n");
}

int main()
{
    int k;
    Linklist *head;
    head = (Linklist *)malloc(sizeof(Linklist));
    head = creat_linklist();
    print(head);
    printf("中间节点是:%d\n",*middle(head));
    printf("请输入要查找的倒数第几个节点:"); 
    scanf("%d",&k); 
    
    
    Search_K(head,k);
    while(1);
    return 0;
}

Linklist * creat_linklist()
{
    int n=0,t=1;
    Linklist *h,*p,*q;
    h = q =(Linklist *)malloc(sizeof(Linklist));
    for(int i=0;i<100;i++)
    {
        p = (Linklist *)malloc(sizeof(Linklist)); 
        p->num = i+1;
        q->next = p;
        q = p;	
    }
    q->next = NULL;
    return h;	
} 

在一些场合还需要考虑使用三个指针,如链表逆转:

    ListNode* reverseList(ListNode* head) {
        ListNode* prev = NULL;
        ListNode* cur = head;
        ListNode* next = NULL;
        while(cur != NULL) {
            next = cur->next;
            cur->next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }

ref:

https://leetcode-solution-leetcode-pp.gitbook.io/leetcode-solution/91/two-pointers

-End-

相关推荐

SM小分队Girls on Top,女神战队少了f(x)?

这次由SM娱乐公司在冬季即将开演的smtown里,将公司的所有女团成员集结成了一个小分队project。第一位这是全面ACE的大姐成员权宝儿(BoA),出道二十年,在日本单人销量过千万,韩国国内200...

韩国女团 aespa 首场 VR 演唱会或暗示 Quest 3 将于 10 月推出

AmazeVR宣布将在十月份举办一场现场VR音乐会,观众将佩戴MetaQuest3进行体验。韩国女团aespa于2020年11月出道,此后在日本推出了三张金唱片,在韩国推出了...

韩网热议!女团aespa成员Giselle在长腿爱豆中真的是legend

身高163的Giselle,长腿傲人,身材比例绝了...

假唱而被骂爆的女团:IVE、NewJeans、aespa上榜

在韩国,其实K-pop偶像并不被认为是真正的歌手,因为偶像们必须兼备舞蹈能力、也经常透过对嘴来完成舞台。由于科技的日渐发达,也有许多网友会利用消音软体来验证K-pop偶像到底有没有开麦唱歌,导致假唱这...

新女团Aespa登时尚大片 四个少女四种style

来源:环球网

韩国女团aespa新歌MV曝光 画面梦幻造型超美

12月20日,韩国女团aespa翻唱曲《DreamsComeTrue》MV公开,视频中,她们的造型超美!WINTER背后长出一双梦幻般的翅膀。柳智敏笑容甜美。宁艺卓皮肤白皙。GISELLE五官精致...

女网友向拳头维权,自称是萨勒芬妮的原型?某韩国女团抄袭KDA

女英雄萨勒芬妮(Seraphine)是拳头在2020年推出的第五位新英雄,在还没有正式上线时就备受lsp玩家的关注,因为她实在是太可爱了。和其他新英雄不同的是,萨勒芬妮在没上线时就被拳头当成虚拟偶像来...

人气TOP女团是?INS粉丝数见分晓;TWICE成员为何在演唱会落泪?

现在的人气TOP女团是?INS粉丝数见分晓!现在爱豆和粉丝之间的交流方法变得多种多样,但是Instagram依然是主要的交流手段。很多粉丝根据粉丝数评价偶像的人气,拥有数百、数千万粉丝的组合作为全球偶...

韩国女团MVaespa Drama MV_韩国女团穿超短裙子跳舞

WelcometoDrama.Pleasefollow4ruleswhilewatchingtheDrama.·1)Lookbackimmediatelywhenyoufe...

aespa师妹团今年将出道! SM职员亲口曝「新女团风格、人数」

记者刘宛欣/综合报导南韩造星工厂SM娱乐曾打造出东方神起、SUPERJUNIOR、少女时代、SHINee、EXO等传奇团体,近年推出的aespa、RIIZE更是双双成为新生代一线团体,深受大众与粉丝...

南韩最活跃的女团aespa,新专辑《Girls》即将发布,盘点昔日经典

女团aespa歌曲盘点,新专辑《Girls》即将发布,期待大火。明天也就是2022年的7月8号,aespa新专辑《Girls》即将发行。这是继首张专辑《Savage》之后,时隔19个月的第二张专辑,这...

章泽天女团aespa出席戛纳晚宴 宋康昊携新片亮相

搜狐娱乐讯(山今/文玄反影/图科明/视频)法国时间5月23日晚,女团aespa、宋康昊、章泽天等明星亮相戛纳晚宴。章泽天身姿优越。章泽天肩颈线优越。章泽天双臂纤细。章泽天仪态端正。女团aespa亮...

Aespa舞台暴露身高比例,宁艺卓脸大,柳智敏有“TOP”相

作为SM公司最新女团aespa,初舞台《BlackMamba》公开,在初舞台里,看得出来SM公司是下了大功夫的,虽然之前SM公司新出的女团都有很长的先导片,但是aespa显然是有“特殊待遇”。运用了...

AESPA女团成员柳智敏karina大美女

真队内速度最快最火达成队内首个且唯一两百万点赞五代男女团中输断层第一(图转自微博)...

对来学校演出的女团成员语言性骚扰?韩国这所男高的学生恶心透了

哕了……本月4日,景福男子高中相关人士称已经找到了在SNS中上传对aespa成员进行性骚扰文章的学生,并开始着手调查。2日,SM娱乐创始人李秀满的母校——景福高中迎来了建校101周年庆典活动。当天,S...