【leetcode】(1)双指针

算法简述

在处理数组和链表有关的问题时,经常会用到双指针的方法,双指针技巧主要分为两类,左右指针快慢指针
而在针对的对象上,双指针技巧又可以分为 针对单个元素 的,和针对两个指针 锚定的窗口 的,其中第二种有其专有的名称- 滑动窗口
由于左右指针和快慢指针包含了所有针对单个元素的问题,所以本文分如下三类进行总结。

1、左右指针

所谓左右指针,就是两个指针相向而行或者相背而行。
由于其特性,需要指针能够 同时满足向前和向后 两种行走方式,所以通常用在数组和双向链表的题目中。(对这俩结构进行前后序遍历不受结构本身影响。)
这样一看,双向链表和数组除了是否拥有指针域之外,结构特性是非常相似的。

1)最长回文子串

题目

给你一个字符串 s,找到 s 中最长的回文子串。

实现思路

遍历字符串,尝试以每一个字符作为中心点向两边进行拓展,并判断是否为回文串,保留最长的回文串即为所求结果。

代码

class Solution(object):
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        lens = len(s)
        length = 0
        loc = 0
        flag = 1
        for i in range(lens):
            record = 1
            while ((i - record) >= 0) & ((i + record) < lens):
                if s[i - record] == s[i + record]:
                    record += 1
                else:
                    break
            if (record - 1) >= length:
                length = record - 1
                loc = i
                flag = 1
            record = 1
            while ((i - record + 1) >= 0) & ((i + record) < lens):
                if s[i- record + 1] == s[i + record]:
                    record += 1
                else:
                    break
            if (record - 1) > length:
                length = record -1
                loc = i
                flag = 0
            record = 1
        if lens == 1:
            return s[loc]
        if flag == 1:
            return s[(loc - length):(loc + length + 1)]
        else:
            return s[(loc - length +1):(loc + length + 1)]

580ms和13.4MB,分别超过82%和46%

2)排序数组查找元素第一个和最后一个位置

题目

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

实现思路

对排序数组进行一次普通的二分查找,若找到target,就跳出,没找到则循环结束再跳出。
出循环后根据lo是否小于等于hi,判断循环是否找到target,若找到则向左右两个方向延申,确定第一个和最后一个元素位置。
若以上都不满足,return [-1,-1]

代码

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        n = len(nums)
        lo, hi =0, (n - 1)
        while lo <= hi:
            mid = int((lo+hi)/2)
            if nums[mid] == target:
                break
            elif nums[mid] < target:
                lo = mid+1
            else:
                hi = mid-1
        if lo <= hi:
            l= mid
            r = mid
            while l>=0 and nums[l] == nums[mid]:
                l -= 1
            while r<=n-1 and nums[r] == nums[mid]:
                r += 1
            return [l+1,r-1]
        else:
            return [-1,-1]

36ms和16MB,分别超过73%和36%

2、快慢指针

顾名思义,快慢指针就是指利用一快一慢两个指针的方法,通常是同向而行。
同上,不难想象快慢指针适合用来处理 单链表 的问题或者 只需要往一个方向运行 的数组问题,因为单链表的结构只允许往一个方向走。

3、滑动窗口

相比于普通的双指针问题(以上两种),滑动窗口要解决的问题通常要难不少(我个人的刷题感受)主要因为其他双指针的问题大都只需要 对指针指到的单个元素进行操作,而滑动窗口问题需要 对两个指针锚定出来的窗口进行维护,直到得到最终结果,前者一次只要管一到两个元素,后者一次要管一串,具体对比如下两图。

在这里插入图片描述

在这里插入图片描述

1.)力扣03.无重复字符的最长子串

典型的双指针利用滑动窗口的问题。

题目

给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。

实现思路

先定义两个指针lo和hi,用hi不停地向前试探,观察lo和hi所确定的窗口包含的字串是否有重复的字符,如果没有,hi就向前继续试探,扩大窗口(用来确定最大不重复字串),如果有,就移动lo缩小窗口,更新结果。
直到hi遍历到字符串末尾,结束循环。

代码

class Solution:
    def lengthOfLongestSubstring(self, s: str) -> int:
        occ = set()
        rk, ans = 0, 0
        n = len(s)
        for i in range(n):
            if i != 0:
                occ.remove(s[i - 1])
            while rk < n and s[rk] not in occ:
                occ.add(s[rk])
                rk += 1
            ans = max(ans,rk - i)
        return ans

72ms和15.1MB,分别超过53%和35%

2)暴力实现strStr()

题目

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

实现思路
若needle为空或者haystack和needle相同,返回0。
慢指针从头开始遍历(n-m)个字符(n和m分别为haystack和needle的长度),快指针从每一个慢指针开始往后遍历m长度,若能遍历到m,则匹配成功·,返回下标。
若慢指针遍历完没有匹配成功,返回-1。

代码

class Solution:
    def strStr(self, haystack: str, needle: str) -> int:
        n = len(haystack)
        m = len(needle)
        if needle =="" or haystack == needle:
            return 0

        for i in range(n-m+1):
            flag = False
            p = i
            j = 0
            while j<m:
                if needle[j] == haystack[p]:
                    p += 1
                    j += 1
                    if j == (m):
                        flag = True
                        return i
                else:
                    break
                
        return -1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

事多做话少说

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值