首页 > 其他分享 >练12:双指针

练12:双指针

时间:2024-12-16 19:31:40浏览次数:11  
标签:cnt 12 min tot right 指针 left

欢迎大家订阅【蓝桥杯Python每日一练】 专栏,开启你的 Python数据结构与算法 学习之旅!

文章目录


前言

双指针是一种常用于数组和链表类问题中,指的是用两个指针在问题的输入数据结构中进行遍历。根据应用的场景和指针的运动方向,双指针可以分为同向扫描反向扫描两种类型。
在这里插入图片描述

1 同向扫描

同向扫描指的是两个指针从同一位置或相近的位置开始,向相同的方向移动。常见的应用场景包括:

  • 滑动窗口问题:通过一个窗口的左右边界来实现对区间的处理。
  • 寻找数组中满足某些条件的子数组
  • 合并两个已排序的数组(例如合并两个有序链表)。

优点

  • 使用双指针的技术可以在 O(n) 时间内完成遍历。
  • 避免了暴力搜索的 O(n²) 时间复杂度。

在这里插入图片描述


2 反向扫描

反向扫描指的是两个指针从不同的位置开始,分别向相反的方向移动。这种方法通常用于:

  • 排序问题:寻找两个数的和等于某个目标值,通常应用于已排序的数组。
  • 双端队列问题:需要同时从两端处理数据的场景。
  • 快排:快速排序算法通过反向扫描来处理左右子数组的元素。

优点

  • 反向扫描减少了重复计算,快速找到符合条件的解。
  • 适用于有序数据结构的情境,利用有序性减少搜索空间。

在这里插入图片描述


3 同向扫描与反向扫描的对比

特性同向扫描(Same Direction)反向扫描(Opposite Directions)
初始位置两个指针通常从相同的地方开始(例如同一个位置或相邻位置)两个指针通常从相反的地方开始(例如数组的两端)
指针移动方向指针沿着相同的方向逐步推进两个指针沿相反方向逐步推进
应用场景滑动窗口问题、子数组和问题、数组合并等排序数组中寻找目标和、快排、双端队列等
复杂度O(n),可以高效处理多个子数组和的情况O(n),适用于排序数组和快速排除不符合条件的解

4 例题分析

2.1 回文判定

在这里插入图片描述

题目地址:https://www.lanqiao.cn/problems/1371/learning/

样例输入

abcba

样例输出

Y

【示例代码】

s = input()
# 初始化左右指针 l 和 r,l 指向字符串的开始,r 指向字符串的结束
l, r = 0, len(s) - 1 
ok = 'Y' 
# 循环,直到左右指针交错(即 l > r)
while l <= r:  
    # 如果左右指针对应的字符相等
    if s[l] == s[r]:  
        l += 1  # 左指针向右移动
        r -= 1  # 右指针向左移动
    else:  # 如果
        ok = 'N'  
        break 
print(ok)  

【运行结果】
在这里插入图片描述

2.2 美丽的区间

在这里插入图片描述

题目地址:https://www.lanqiao.cn/problems/1372/learning/

样例输入

5 6
1 2 3 4 5

样例输出

2

【示例代码】

# 读取两个整数 n 和 S。n 是数组的长度,S 是最小和的阈值
n, S = map(int, input().split())  
# 读取一个数组 a,数组的长度是 n,包含 n 个整数
a = list(map(int, input().split()))  

# 初始化左右指针,均指向数组的开始位置
left, right = 0, 0  
# 初始化 tot 变量为 0,用于记录当前区间 [left, right) 的和
tot = 0
# 初始化 min_len 为 n+1(一个大于数组长度的值),用于记录最小子数组长度  
min_len = n + 1  

# 进入循环:通过左指针遍历每个子数组的起始位置
while left < n:
    # 不断拓展右端点,直到子数组的和大于或等于 S
    while right < n and tot < S:
        tot += a[right]  # 将右端点元素加入 tot
        right += 1  # 右端点向右移动

    # 如果当前区间的和满足大于或等于 S
    if tot >= S:
        # 更新最小长度,right - left 是当前区间的长度
        min_len = min(min_len, right - left)  

    # 左端点右移一位,缩小区间,继续寻找下一个合法区间
    # 将左端点元素从 tot 中移除
    tot -= a[left]  
    # 左端点右移
    left += 1  

# 如果没有找到满足条件的子数组,min_len 会保持为 n+1
if min_len == n + 1:
    min_len = 0  # 如果没有找到合法区间,设置 min_len 为 0

# 输出最小子数组长度
print(min_len)

【执行流程】
①初始化

  • n = 5S = 6
  • a = [1, 2, 3, 4, 5]
  • left = 0right = 0
  • tot = 0min_len = n + 1 = 6

②循坏处理

第一轮:left = 0

  • 进入 while left < n 循环。
  • 内层 while right < n and tot < S 开始:
    • right = 0tot = 0tot < S,因此进入循环:
      • tot += a[0] = 0 + 1 = 1right += 1right = 1
    • right = 1tot = 1tot < S,继续循环:
      • tot += a[1] = 1 + 2 = 3right += 1right = 2
    • right = 2tot = 3tot < S,继续循环:
      • tot += a[2] = 3 + 3 = 6right += 1right = 3
    • right = 3tot = 6,此时 tot >= S,跳出内层循环。
  • tot >= S 时,更新 min_len
    • min_len = min(min_len, right - left) = min(6, 3 - 0) = 3
  • 然后缩小区间,tot -= a[0] = 6 - 1 = 5left += 1left = 1

第二轮:left = 1

  • 进入 while left < n 循环。
  • 内层 while right < n and tot < S 继续执行:
    • right = 3tot = 5tot < S,继续循环:
      • tot += a[3] = 5 + 4 = 9right += 1right = 4
    • right = 4tot = 9,此时 tot >= S,跳出内层循环。
  • tot >= S 时,更新 min_len
    • min_len = min(min_len, right - left) = min(3, 4 - 1) = 3
  • 然后缩小区间,tot -= a[1] = 9 - 2 = 7left += 1left = 2

第三轮:left = 2

  • 进入 while left < n 循环。
  • 内层 while right < n and tot < S 继续执行:
    • right = 4tot = 7tot < S,继续循环:
      • tot += a[4] = 7 + 5 = 12right += 1right = 5
    • right = 5tot = 12,此时 tot >= S,跳出内层循环。
  • tot >= S 时,更新 min_len
    • min_len = min(min_len, right - left) = min(3, 5 - 2) = 3
  • 然后缩小区间,tot -= a[2] = 12 - 3 = 9left += 1left = 3

第四轮:left = 3

  • 进入 while left < n 循环。
  • 内层 while right < n and tot < S 不再执行,因为 right 已经达到数组的末尾。
  • tot >= S 时,更新 min_len
    • min_len = min(min_len, right - left) = min(3, 5 - 3) = 2
  • 然后缩小区间,tot -= a[3] = 9 - 4 = 5left += 1left = 4

第五轮:left = 4

  • 进入 while left < n 循环。
  • 内层 while right < n and tot < S 不再执行,因为 right 已经达到数组的末尾。
  • 此时,min_len = 2,退出外层循环。

③结果输出
最终 min_len = 2,即最小的子数组长度为 2。

【运行结果】
在这里插入图片描述

2.3 挑选子串

在这里插入图片描述

题目地址:https://www.lanqiao.cn/problems/1621/learning/

样例输入

7 4 2
4 2 7 7 6 5 1

样例输出

18

【示例代码】

# 读取三个整数 n (数组长度), m (阈值), k (至少有 k 个数 >= m)
n, m, k = map(int, input().split())  
# 读取数组 a,包含 n 个整数
a = list(map(int, input().split()))  
# 初始化左右指针,均指向数组的起始位置
left, right = 0, 0  

ans = 0  # 用来记录满足条件的子数组数量
cnt = 0  # 记录当前窗口中大于等于 m 的元素个数

# 主循环:左指针从0到n遍历数组
while left < n:
    # 内循环:扩展右指针,直到窗口中有至少 k 个元素大于等于 m
    while right < n and cnt < k:
        if a[right] >= m:  # 如果右指针指向的元素大于等于 m
            cnt += 1  # 计数窗口中大于等于 m 的元素数量
        right += 1  # 右指针向右移动,扩大窗口

    # 当窗口中有至少 k 个大于等于 m 的元素时
    if cnt >= k:
        # 计算从 left 到 right-1 的子数组的数量
        # 窗口为 [left, right-1],[left, right], [left, right+1], ..., [left, n-1],这些子数组都满足条件
        ans += n - right + 1  # right 已经移动到不满足条件的位置,所有从 left 到 [right, n-1] 的子数组都满足条件

    # 向右移动左指针,缩小窗口,准备进入下一轮
    if a[left] >= m:  # 如果左指针指向的元素大于等于 m
        cnt -= 1  # 移除左边界元素,更新窗口中大于等于 m 的元素数量
    left += 1  # 左指针右移

# 输出满足条件的子数组数量
print(ans)


【执行流程】

①初始化
left = 0, right = 0, cnt = 0, ans = 0

②循坏处理
第一轮外循环 (left = 0)

  • 内循环拓展右指针,直到 cnt >= 2
    • right = 0: a[right] = 4 >= 4, cnt = 1
    • right = 1: a[right] = 2 < 4, cnt = 1
    • right = 2: a[right] = 7 >= 4, cnt = 2 → 窗口 [0, 2] 满足条件。
  • 当前 cnt = 2 >= 2,则有 n - right + 1 = 7 - 3 + 1 = 5 个符合条件的子数组,ans = 5
  • 左指针右移,left = 1cnt 减少 1

第二轮外循环 (left = 1)

  • 内循环继续拓展右指针,直到 cnt >= 2
    • right = 3: a[right] = 7 >= 4, cnt = 3 → 窗口 [1, 3] 满足条件。
  • 当前 cnt = 3 >= 2,则有 n - right + 1 = 7 - 4 + 1 = 4 个符合条件的子数组,ans = 5 + 4 = 9
  • 左指针右移,left = 2cnt 减少 1

第三轮外循环 (left = 2)

  • 内循环继续拓展右指针,直到 cnt >= 2
    • right = 4: a[right] = 6 >= 4, cnt = 3 → 窗口 [2, 4] 满足条件。
  • 当前 cnt = 3 >= 2,则有 n - right + 1 = 7 - 5 + 1 = 3 个符合条件的子数组,ans = 9 + 3 = 12
  • 左指针右移,left = 3cnt 减少 1

第四轮外循环 (left = 3)

  • 内循环继续拓展右指针,直到 cnt >= 2
    • right = 5: a[right] = 5 >= 4, cnt = 3 → 窗口 [3, 5] 满足条件。
  • 当前 cnt = 3 >= 2,则有 n - right + 1 = 7 - 6 + 1 = 2 个符合条件的子数组,ans = 12 + 2 = 14
  • 左指针右移,left = 4cnt 减少 1

第五轮外循环 (left = 4)

  • 内循环继续拓展右指针,直到 cnt >= 2
    • right = 6: a[right] = 1 < 4, cnt = 2 → 窗口 [4, 6] 满足条件。
  • 当前 cnt = 2 >= 2,则有 n - right + 1 = 7 - 7 + 1 = 1 个符合条件的子数组,ans = 14 + 1 = 15
  • 左指针右移,left = 5cnt 减少 1

第六轮外循环 (left = 5)

  • 右指针不再需要移动,cnt 少于 k,继续右移左指针,直到遍历结束。

③最终输出

18

【运行结果】
在这里插入图片描述

标签:cnt,12,min,tot,right,指针,left
From: https://blog.csdn.net/2302_80253507/article/details/144444924

相关文章

  • Spark向量化计算在美团生产环境的实践12
     1什么是向量化计算1.1并行数据处理:SIMD指令让我们从一个简单问题开始:假设要实现“数组a+b存入c”,设三个整型数组的长度都是100,那么只需将“c[i]=a[i]+b[i]”置于一个100次的循环内,代码如下:voidaddArrays(constint*a,constint*b,int*c,intnum){for(in......
  • 20241216
    会议室类,会议中心类,管理员类,会议申请类,会议人员类会议室类:属性:会议室号,可容纳人数,状态,使用时间方法:会议中心类:属性:会议申请方法:通知开会(),制作代表证()管理员类属性:方法:修改会议(),调整会议()会议召开申请类:属性:申请人姓名,会议人数,开会时间,会议人员方法:修改会议申请(),取消会议......
  • 2024.12.10(周二)
    机器学习大作业importpandasaspdimportnumpyasnpimportseabornassnsimportmatplotlib.pyplotaspltfromsklearn.model_selectionimporttrain_test_split,cross_val_score,GridSearchCVfromsklearn.preprocessingimportStandardScalerfromsklearn.line......
  • 【2024-12-15】连岳摘抄
    23:59责任使我们看到自身的价值、生活的意义,并可摆脱人生的诸多烦恼。                                                 ——约翰卢伯克以我知天命的年龄,深知,平淡无......
  • 加图会计实操- 商业-杰丽尔童装商贸(2024.1)-一般纳税人-做账-20241216
    1.2024-01-11   业务15进项发票认证1月11日,1-10日待认证进项发票认证。不需要做账务处理;2.2024-01-12   业务17缴纳2023年12月份社保费和个税1月12日,缴纳社保费、个税。公司承担的社保费,计提时(管理费用、财务费用),直接应付职工薪酬-社保;缴纳时,应付职工薪酬-社保,银行存款......
  • 13_C语言 -指针
    预备知识内存地址字节:字节是内存的容量单位,英文名Byte,一个字节有8位,即1Byte=8bits地址:系统为了便于区分每一个字节而对它们逐一进行编号,称为内存地址,简称地址。inta=5;基地址单字节数据:对于单字节数据而言,其地址就是其字节编号。多字节数据:对于多字节数据而言,其地......
  • 11.12
    奔腾体系结构后,英特尔提供了一个叫作时间戳计数器(TimeStampCounter,TSC)的硬件寄存器。TSC 是一个从处理器时钟中计算时标数的 64 位寄存器。RDTSC 指令可以非常快地访问该寄存器。自 Windows2000 问世后,可以通过调用函数 BOOL Query PerformanceCounter(LARG......
  • 2025春招Java 面试必刷的1200 道Java大厂面试真题(含答案解析)
    2025春招即将来临,很多同学会问Java面试八股文有必要背吗?我的回答是:很有必要。你可以讨厌这种模式,但你一定要去背,因为不背你就进不了大厂。国内的互联网面试,恐怕是现存的、最接近科举考试的制度。而且,我国的八股文确实是独树一帜。以美国为例,北美工程师面试比较重视算法(Cod......
  • 函数指针(详细讲解)
    C语言中的函数指针函数指针是指向函数的指针变量,可以通过它调用函数。函数指针在编程中可以用于实现回调函数、动态调用函数和减少代码冗余。函数指针的基本概念1.函数指针的定义函数指针是一个特殊类型的指针,它指向一个具有特定签名(返回值类型和参数类型)的函数。语法:......
  • H7-TOOL自制Flash读写保护算法系列,为凌欧LKS32MC45x/MC05x/MC08x制作使能和解除算法,支
    说明:很多IC厂家仅发布了内部Flash算法文件,并没有提供读写保护算法文件,也就是选项字节算法文件,需要我们制作。实际上当前已经发布的TOOL版本,已经自制很多了,比如已经支持的兆易创新大部分型号,新唐的大部分型号等。但是依然有些厂家还没自制,所以陆续开始为这些厂家提供读写保护支......