牛客面试必刷TOP101——双指针

双指针可以分为以下几种:
  1. 双撞指针,分别从头尾开始往中间遍历,比如接雨水、盛水最多容器,反转字符串等
  2. 访问同一个元素的同向指针。这种类型的双指针常常会结合滑动窗口法使用,快指针先右移增大窗口,慢指针右移缩小窗口。如最小覆盖子串、最小无重复子数组
  3. 访问不同元素的同向指针。比如合并两个有序数组中,定义双指针分别指向两个数组的尾部开始遍历

合并两个有序数组
判断是否为回文字符串
合并区间
最小覆盖子串
反转字符串
最长无重复子数组
盛水最多的容器
接雨水问题

合并两个有序数组【BM87】

给出一个有序的整数数组 A 和有序的整数数组 B ,请将数组 B 合并到数组 A 中,变成一个有序的升序数组

  1. 双指针i、j,分别指向A和B最后一个有序整数,定义一个指针p指向A末尾
  2. 向A后部空白区域填补元素,将AB中较大元素填到p指针处
  3. 时间复杂度O(m+n),空间复杂度O(1),因为A数组本来存在,没有新开辟数组
  4. 简易版空间复杂度O(m+n)、新开辟一个数组存储排序后的元素,再将其复制给A
def merge(self , A, m, B, n):
        # write code here
        i = m-1
        j = n-1
        p = m+n-1
        while i >= 0 and j >= 0:
            if A[i] < B[j]:
                A[p] = B[j]
                j -= 1
            else:
                A[p] = A[i]
                i -= 1
            p -= 1
        while j >= 0:
            A[j] = B[j]
            j -= 1
        return A
判断是否为回文字符串 【BM88】

给定一个长度为 n 的字符串,请编写一个函数判断该字符串是否回文。如果是回文请返回true,否则返回false。

字符串回文指该字符串正序与其逆序逐字符一致。

思路:双指针,分别从数组头尾开始往中间扫,如果两个指针指向的元素相等,则同时往中间移动;否则说明不是回文字符串,返回False。

class Solution:
    def judge(self , str: str) -> bool:
        # write code here
        i = 0
        j = len(str)-1
        while i <= j:
            if str[i] == str[j]:
                i += 1
                j -= 1
            else:
                return False
        return True
合并区间【BM89】

给出一组区间,请合并所有重叠的区间。请保证合并后的区间按区间起点升序排列。

数据范围:区间组数0≤n≤2×10^5,区间内 的值都满足0≤val≤2×10^5

要求:空间复杂度 O(n),时间复杂度 O(nlogn)

进阶:空间复杂度 O(val),时间复杂度O(val)

输入:[[10,30],[20,60],[80,100],[150,180]]

输出:[[10,60],[80,100],[150,180]]

思路:先将区间按照start进行排序,然后进行两两合并

  • res存放合并好的区间,每次取res中最后一个元素,将其与待合并区间的第一个区间进行合并
  • left和right区间存在三种情况
    • 两个区间不相交,不需要合并,即left.end > right.start
    • right可以合并到left中,即left.end > right.end
    • right可以增大left区间的长度,即right.end > left.end
    • 因为先做了排序,因此right的左边界要么包含在left中,要么比left的右边界还要大,因此只需要考虑以上三种情况,即可完成合并
# class Interval:
#     def __init__(self, a=0, b=0):
#         self.start = a
#         self.end = b
from functools import cmp_to_key
class Solution:
    def merge(self , intervals: List[Interval]) -> List[Interval]:
        # write code here
        if len(intervals) <= 1:
            return intervals 
        i = 1
        intervals.sort(key=cmp_to_key(lambda a,b:1 if a.start > b.start else -1))
        res = []
        res.append(intervals[0])
        while i < len(intervals):
            left = res.pop(-1)
            right = intervals[i]
            if left.end < right.start:
                res.append(left)
                res.append(right)
            elif left.end < right.end:
                l = left.start
                r = right.end
                res.append(Interval(l,r))
            else:
                res.append(left)
            i += 1
        return res
盛水最多的容器 【BM93】

给定一个数组height,长度为n,每个数代表坐标轴中的一个点的高度,height[i]是在第i点的高度,请问,从中选2个高度与x轴组成的容器最多能容纳多少水

1.你不能倾斜容器

2.当n小于2时,视为不能形成容器,请返回0

3.数据保证能容纳最多的水不会超过整形范围,即不会超过2^31-1

数据范围:

0<=height.length<=10^50

0<=height[i]<=10^40

class Solution:
    def maxArea(self , height: List[int]) -> int:
        i = 0
        j = len(height) - 1
        s = 0
        while i <= j:
            s = max(s,min(height[i],height[j])*(j-i))
            if height[i] <= height[j]:
                i += 1
            else:
                j -= 1
        return s               
接雨水

给定一个整形数组arr,已知其中所有的值都是非负的,将这个数组看作一个柱子高度图,计算按此排列的柱子,下雨之后能接多少雨水。(数组以外的区域高度视为0)

数据范围:数组长度 0≤n≤2×105,数组中每个值满足0<*v**a**l*≤109 ,保证返回结果满足 0 ≤ val ≤10^9

要求:时间复杂度 O(n)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4DVJH8bi-1651470799158)(常考编程题.assets/image-20220501144535500.png)]

【输入】[3,1,2,5,2,4]

【输出】5

题解:

双撞指针,雨水的最大容量取决于容器的最短边。

  • 记录容器的边界l和r
  • 从最短边开始向中间遍历,如果当前高度小于边界值,则承受雨水的容量为 【边界值—高度值】
  • 当前高度大于边界值,说明容器可以分割为两个,记录新的边界值,重新往中间遍历
class Solution:
    def maxWater(self , arr: List[int]) -> int:
        if not arr:
            return None
        i = 0
        j = len(arr)-1
        l = arr[i]
        r = arr[j]
        res = 0
        while i < j:
            if l <= r:
                i += 1
                if arr[i] <= l:
                    res += l - arr[i]
                else:
                    l = arr[i]
            else:
                j -= 1
                if arr[j] <= r:
                    res += r - arr[j]
                else:
                    r = arr[j]
            print(res)
        return res
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秃头嘤嘤魔

感谢厚爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值