双指针|豆包MarsCode AI刷题

99 阅读4分钟

双指针|豆包MarsCode AI刷题

一、双指针

双指针算法是一种常用的算法技巧,主要用于处理数组和链表等线性结构。它通过使用两个指针(索引位置)来遍历数据结构,从而达到减少时间复杂度的目的。双指针算法有多种变体,包括快慢指针、对撞指针和滑动窗口等。双指针比较灵活,可以大大降低时间复杂度,可用在数组,单链表等数据结构中。

快慢指针:一快一慢,步长一大一小。例如,是否有环问题(看慢指针是否能追上快指针),单链表找中间节点问题(快指针到单链表结尾,慢指针到一半)。

对撞指针:一左一右向中间逼近。

滑动窗口:类似计算机网络中的滑动窗口,一般是右端向右扩充,达到停止条件后右端不动,左端向右端逼近,逼近达到停止条件后,左端不动,右端继续扩充。

快慢指针

快慢指针通常用于解决链表中的问题,如检测链表是否有环,或者找到链表的中间节点。快指针的移动速度是慢指针的两倍,如果快指针最终追上了慢指针,那么链表就存在环。

对撞指针

对撞指针常用于有序数组的问题,如两数之和。它们从数组的两端开始向中间移动,直到满足某个条件或者两个指针相遇。

滑动窗口

滑动窗口是一种特殊的双指针技巧,用于处理数组或字符串中的连续子序列问题。窗口由两个指针定义,一个指向子序列的开始,另一个指向结束。根据问题的需要,可以调整窗口的大小和位置。

题目:最小替换字串长度

问题描述

小F得到了一个特殊的字符串,这个字符串只包含字符ASDF,其长度总是4的倍数。他的任务是通过尽可能少的替换,使得ASDF这四个字符在字符串中出现的频次相等。求出实现这一条件的最小子串长度。


测试样例

样例1:

输入:input = "ADDF"
输出:1

样例2:

输入:input = "ASAFASAFADDD"
输出:3

样例3:

输入:input = "SSDDFFFFAAAS"
输出:1

样例4:

输入:input = "AAAASSSSDDDDFFFF"
输出:0

样例5:

输入:input = "AAAADDDDAAAASSSS"
输出:4

思路

  1. 初始化变量

    • minT:用于存储找到的最小长度子串的长度,初始值设为一个很大的数。
    • walk:接收输入的字符串。
    • avg:计算字符串长度的四分之一。
    • fsad:分别计算'F'、'S'、'A'、'D'字符的数量与avg之差的绝对值。
  2. 定义containstr函数

    • head:子串的起始指针。
    • tail:子串的结束指针。
    • minT:当前找到的最小长度。

    containstr函数的逻辑是:

    • 如果tail超出了字符串的长度,返回minT,表示已经检查完所有可能的子串。
    • 如果当前子串包含足够的'F'、'S'、'A'、'D',则更新minTtail-head(当前子串的长度),并将head指针向右移动一位,继续检查。
    • 如果当前子串不满足条件,则将tail指针向右移动一位,继续检查。
  3. 特殊情况处理

    • 如果fsad都为0,表示字符串中每个字符的数量正好是字符串长度的四分之一,这种情况下不需要任何子串,返回0。
  4. 主函数逻辑

    • 调用containstr函数,从head=0tail=int(f+s+a+d-1)开始搜索,即从字符串的开始到可能的最大长度(所有额外字符数量之和减1)。

这里的双指针工作机制是通过维护两个指针headtail来遍历字符串walk,寻找满足特定条件的最小长度子串。这里的“双指针”实际上是指两个索引,分别代表子串的起始位置和结束位置。

代码

def solution(input):
    minT=10000000000
    walk=input
    avg=len(walk)/4
    f=max(walk.count("F")-avg,0)
    s=max(walk.count("S")-avg,0)
    a=max(walk.count("A")-avg,0)
    d=max(walk.count("D")-avg,0)
        #print (containstr(0,int(f+s+a+d-1),minT))
    
    def containstr(head:int,tail:int,minT:int):
        if(tail> len(walk)):
            return minT#越界即结束
        if(walk[head:tail].count("A")>=a and walk[head:tail].count("S")>=s and walk[head:tail].count("F")>=f and walk[head:tail].count("D")>=d):#我们只需要考虑多余的fasd数量即可
            minT=min(tail-head,minT)#更新minT
            return containstr(head+1,tail,minT)#右边框右滑
        else:
            return containstr(head,tail+1,minT)#左边框右滑
 
    if(f==s==d==a):#完美情况
            return 0
    return containstr(0,int(f+s+a+d-1),minT)