双指针知识点

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:在做一个编程题,题目是找出数组中两个数的差值为特定值。一开始用的暴力破解,即两个for循环,时间复杂度为O(n²),题目判断为超时,看了别人的代码,用的快慢指针,一开始也没搞懂为啥这样就不会超时,后来想了一下,也查了一下,这个时间复杂度应该是O(n)。所以觉得有必要再次整理一下快慢指针。其实快慢指针也只是很基本的算法题了,但是事实上不常用也不会用。


提示:以下是本篇文章正文内容,下面案例可供参考

一、导火索

编程题:

题目描述

给定一个数组,每个元素的值是唯一的,找出其中两个元素相减等于给定差值 diff 的所有不同组合的个数。

  • 组合是无序的:如:(1, 4)和(4, 1)表示的是同一个组合。

解答要求时间限制:1000ms, 内存限制:256MB

输入

输入三行:
第一行为一个整数,表示给定差值diff;范围[-50000, 50000]
第二行也为一个数字,表示数组的长度;范围[2, 102400]
第三行为该数组,由单个空格分割的一组数字组成;其中元素的值范围[-20, 102400]

用例保证第三行数字和空格组成的字符串长度不超过 649999

输出

1个整数,表示满足要求的不同组合的个数

样例

输入样例 1 

3
5
1 3 2 5 4
输出样例 1
2

自己的编程

/*
 * Copyright. All rights reserved.
 * Description: 
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 */
#include "securec.h"

#define BUF_LEN 650000
#define MAX_N 102400

int Proc(int *arr, int arrLen, int diff)
{
    // 在此添加你的代码
    int count = 0;
    for(int i = 0; i < arrLen; i++)
    {
        for(int j = i + 1; j < arrLen; j++)
        {
            if(abs(arr[i] - arr[j]) == diff)
            {
                count++;
            }
        }
    }
    return count;
}

/* 代码仅供参考,注意避免圈复杂度过大 */
int main(void)
{
    int diff;
    if (scanf_s("%d\n", &diff) != 1) { return -1; };

    int n;
    if (scanf_s("%d\n", &n) != 1) { return -1; };

    static char buf[BUF_LEN];
    static int arr[MAX_N];
    int i = 0;
    char *sep = " ";
    char *sec = NULL;
    char *nt = NULL;
    if (gets_s(buf, sizeof(buf)) == NULL) {
        return -1;
    }
    sec = strtok_s(buf, sep, &nt);
    while (sec != NULL) {
        arr[i++] = atoi(sec);
        sec = strtok_s(NULL, sep, &nt);
    }

    int ret = Proc(arr, n, diff);
    (void)printf("%d", ret);
    return 0;
}

对于

3
5
1 3 2 5 4

这个测试用例,是可以的

但是对于

-1

5

-1 -2 1 2 0

这个测试用例是不行的。【2023年10月24日19:35:38最后发现这个测试用例是错的,正确答案是4,真啃爹啊】

同时还存在着超时的问题。

所以这个题目暴力破解是不行的,需要用双指针。

2023年10月24日19:35:34更新

/*
 * Copyright. All rights reserved.
 * Description: 
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除
 */
#include "securec.h"

#define BUF_LEN 650000
#define MAX_N 102400

int compare(const void* a, const void* b)
{
    return *(int*)a - *(int*)b;
}

int Proc(int *arr, int arrLen, int diff)
{
    if(diff == 0)
    {
        return 0;            //这个针对diff==0的测试用例才增加的,而且是看了别人的答案增加的
    }
    
    int count = 0;
    int r = 0;
    int l = 0;
    
    qsort(arr, arrLen, sizeof(int), compare);
    
    while(r < arrLen && l < arrLen )
    {
        if(arr[r] - arr[l] == diff)
        {
            count++;
            l++;
            r++;
        }
        else if(arr[r] - arr[l] < diff)
        {
            r++;
        }
        else if(arr[r] - arr[l] > diff)
        {
            l++;
        }
    }
    return count;
}


/*
int Proc(int *arr, int arrLen, int diff)
{
    // 在此添加你的代码
    int count = 0;
    for(int i = 0; i < arrLen; i++)
    {
        for(int j = i + 1; j < arrLen; j++)
        {
            if(abs(arr[i] - arr[j]) == diff)
            {
                count++;
            }
        }
    }
    return count;
}

*/


/* 代码仅供参考,注意避免圈复杂度过大 */
int main(void)
{
    int diff;
    if (scanf_s("%d\n", &diff) != 1) { return -1; };

    int n;
    if (scanf_s("%d\n", &n) != 1) { return -1; };

    static char buf[BUF_LEN];
    static int arr[MAX_N];
    int i = 0;
    char *sep = " ";
    char *sec = NULL;
    char *nt = NULL;
    if (gets_s(buf, sizeof(buf)) == NULL) {
        return -1;
    }
    sec = strtok_s(buf, sep, &nt);
    while (sec != NULL) {
        arr[i++] = atoi(sec);
        sec = strtok_s(NULL, sep, &nt);
    }

    int ret = Proc(arr, n, diff);
    (void)printf("%d", ret);
    return 0;
}

双指针问题(一) 对撞指针和快慢指针_快慢指针时间复杂度-CSDN博客

二、另外一个关于双指针的题目

题目描述

定义:当一个字符串只有元音字母(aeiouAEIOU)组成,称为元音字符串。
现给定一个字符串,请找出其中最长的元音字符子串,并返回其长度;如果找不到,则返回0。

子串:字符串中任意个连续的字符组成的子序列称为该字符串的子串。

解答要求时间限制:1000ms, 内存限制:256MB

输入

一个字符串,其长度范围: 0 < length <= 65535。

字符串仅由字符a-zA-Z组成。

输出

一个整数,表示最长的元音字符子串的长度。

样例

输入样例 1 

asdbuiodevauufgh

输出样例 1

3

解答

第一版

//
// Copyright (c) 
// Description: 考生实现代码
// Note: 缺省代码仅供参考,可自行决定使用、修改或删除
#include <stdio.h>
#include "securec.h"
#include <stdbool.h>

#define MAX_LEN 65536

_Bool IsTargetCharacter(char s)
{
    char temp = tolower(s);
    if(temp == 'a' || temp == 'e' || temp == 'i' || temp == 'o' || temp == 'u')
    {
        return true;
    }

    return false;
}

int getStrLen(char* str, int index, int len)
{
    int count = 0;
    int fast = index;
    while(fast < len && IsTargetCharacter(str[fast]))
    {
        count++;
        fast++;
    }

    return count;
}

int GetLongestVowelstrLen(char* str)
{
   // 添加你的代码
   int max = 0;
   int len = strlen(str);
   for(int i = 0; i < len; i++)
   {
       if(IsTargetCharacter(str[i]))
       {
           int data = getStrLen(str, i, len);
           max = max > data ? max : data;
       }
   }
   return max;
}
int main(void)
{
    char str[MAX_LEN];
    if (NULL == gets_s(str, sizeof(str))) { return -1; }
    int result = GetLongestVowelstrLen(str);
    (void)printf("%d", result);
    return 0;
}

这一版并没有用双指针,或者说没有充分利用到双指针,导致时间复杂度是O(n),有个测试用例超时了。

第二版

/*
 * Copyright (c) 
 * Description: 考生实现代码
 * Note: 缺省代码仅供参考,可自行决定使用、修改或删除 */
#include <stdio.h>
#include "securec.h"
#include <stdbool.h>

#define MAX_LEN 65536

_Bool IsTargetCharacter(char s)
{
    char temp = tolower(s);
    if(temp == 'a' || temp == 'e' || temp == 'i' || temp == 'o' || temp == 'u')
    {
        return true;
    }
    
    return false;
}

int getStrLen(char* str, int index, int len)
{
    int count = 0;
    int fast = index;
    while(fast < len && IsTargetCharacter(str[fast]))
    {
        count++;
        fast++;
    }
    
    return count;
}

int GetLongestVowelstrLen(char* str)      
{                     
   // 添加你的代码   
   int max = 0;
   int len = strlen(str);
   for(int i = 0; i < len; i++)
   {
       if(IsTargetCharacter(str[i]))
       {
           int fast = i;
           while(IsTargetCharacter(str[fast]))
           {
               fast++;
           }
           max = max > fast - i  ? max : fast - i;
           i = fast;
       }
   }
   return max;          
}                     
int main(void) 
{ 
    char str[MAX_LEN];   
    if (NULL == gets_s(str, sizeof(str))) { return -1; }   
    int result = GetLongestVowelstrLen(str);
    (void)printf("%d", result); 
    return 0;           
}                       

这个版本利用了双指针,时间复杂度降为O(2n),成功通过所有测试用例。还可以改进。

其中遇到的关于bool未定义,需要增加#include<stdbool.h>头文件

另外需要指出的是OJ的测试用例真的不靠谱!

三、关于双指针


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值