算法基础之数组双指针(Leetcode题型归纳)

开发者福利!热门AI工具限时免费用 购周边即赠Coding Plan Lite,Claude Code、Cursor等20+工具畅享,效率翻倍! 阅读详情


1.前言

在系统复习一遍数组的理论基础后,我们开始归纳Leetcode中的一种题型:数组双指针。归纳是很痛苦的过程,也是最有成就感的事情,希望大家也能多指出我的不足。

2.双指针基础

所谓双指针算法,就是指的是在遍历的过程中,不是普通的使用单个指针进行循环访问,而是使用两个相同方向或者相反方向的指针进行扫描,从而达到相应的目的。双指针法充分使用了数组有序这一特征,从而在某些情况下能够简化一些运算,降低时间复杂度。
在这里插入图片描述
一般来说,双指针算法分成下面四类:

  • 相向双指针
  • 同向双指针 - 快慢指针
  • 同向双指针 - 滑动窗口
  • 分离双指针

3.相向双指针

3.1定义

指在有序数组中,将指向最左侧的索引定义为左指针 (left),最右侧的定义为右指针 (right),然后从两头向中间进行数组遍历。
相关题目如下:
在这里插入图片描述

3.2真题分析

3.2.1两数之和(1)

Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

You can return the answer in any order.

Example 1:

Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Output: Because nums[0] + nums[1] == 9, we return [0, 1].

Example 2:

Input: nums = [3,2,4], target = 6
Output: [1,2]

Example 3:

Input: nums = [3,3], target = 6
Output: [0,1]

Constraints:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • Only one valid answer exists.

Follow-up: Can you come up with an algorithm that is less than O(n2) time complexity?

后面也会尽量附上中文版本题目方便大家读题:
在这里插入图片描述
一开始,我会想到去用暴力解法吧:枚举数组中的每一个数 x,寻找数组中是否存在 target - x。当我们使用遍历整个数组的方式寻找 target - x 时,需要注意到每一个位于 x 之前的元素都已经和 x 匹配过,因此不需要再进行匹配。而每一个元素不能被使用两次,所以我们只需要在 x 后面的元素中寻找 target - x

#两数之和-暴力解法
class Solution:
    def twoSum(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: List[int]
        """       
        l = len(nums)
        for i in range(l-1):
            for j in range(i+1,l):
                if nums[i] + nums[j] == target:
                    return [i,j]

然而,暴力解法时间复杂度是O(n*2),不太理想,原因是寻找target - x这部分时间复杂度比较高。所以,我又探索了用哈希表去解决这个问题。简单来说,我们可以把哈希表看作一个字典,这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#两数之和-哈希解法
class Solution:
    def twoSum(self, nums, target):
        map = {
   
   }  #创建一个哈希表
        for i in range(len(nums)):
            if target - nums[i] not in map:
                map[nums[i]] = i
            else:
                return map[target - nums[i]], i

这时时间复杂度是O(n)了。But,这好像跟双指针没什么关系欸,我们现在来讲双指针的思路:L指针用来指向第一个值,R指针用来从第L指针的后面查找数组中是否含有和L指针指向值和为目标值的数。两个指针分别从左从右开始扫描,每次判断这两个数相加是不是target,如果小了,那就把左边的指针向右移,同理右指针。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

#两数之和-双指针解法
class Solution:
    def twoSum(self, nums, target):
        array = nums.copy() #浅拷贝,保留原来数组
        nums.sort() #排序
        i, j = 0, len(nums)-1 #两指针一头一尾
        while i<j:
            s = nums[i] + nums[j]
            if s<target:
                i += 1
            elif s>target:
                j -= 1
            else:
                break
 
        res = []
        for k in range(len(nums)):
            if array[k] == nums[i] or array[k] == nums[j]:
                res.append(k)
        return res

这时候时间复杂度也是O(n)的。然而,如果我们把题目改一下:
在这里插入图片描述
此时我们不再需要返回index,而是返回值了。那么有个好处是,我不用再copy数组了,因为之前是为了防止index改变了。

#两数之和-魔改
class Solution:
    def twoSum(self, nums, target):
        nums.sort() #先对数组排序
        lo, hi = 0, len(nums)-1 #左右指针
        while lo<hi:
            s = nums[lo] + nums[hi]
            if s<target:
                lo += 1
            elif s>target:
                hi -= 1
            elif s == target:
                return [nums[lo],nums[hi]]

emmm我再改一下题目:
在这里插入图片描述
这个时候要返回所有和为target的元素对了,而且不能重复哦,那我就把这些元素对存到一个数组res里咯。另外如果有下图这样的情况,可能就会出现重复元素对的情况,就要去跳过了。
在这里插入图片描述

#两数之和-再魔改
class Solution:
    def twoSumTarget(self, nums, target):      
        nums.sort()#先对数组排序,这个内置的算法是O(nlogn)
        res = []          
        lo, hi = 0, len(nums)-1 #左右指针
        left = nums[lo]
        right = nums[hi]
        while lo<hi:
            s = nums[lo] + nums[hi]
            if s<target:
                lo += 1
            elif s>target:
                hi -= 1
            elif s == target:
                res.append([nums[lo],nums[hi]])
                while lo < hi and nums[lo] == left:
                     lo += 1
                while lo < hi and nums[hi] == right:
                     hi -= 1
        return res

这个例子的时间复杂度是O(nlogn)的(因为sort方法是这样),是比O(n)大的。

3.2.2两数之和-输入有序数组(167)

Given an array of integers numbers that is already sorted in non-decreasing order, find two numbers such that they add up to a specific target number.

Return the indices of the two numbers (1-indexed) as an integer array answer of size 2, where 1 <= answer[0] < answer[1] <= numbers.length.

The tests are generated such that there is exactly one solution. You may not use the same element twice.

Example 1:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.

Example 2:

Input: numbers = [2,3,4], target = 6
Output: [1,3]

Example 3:

Input: numbers = [-1,0], target = -1
Output: [1,2]

在这里插入图片描述
有了上一题的基础,这题不会太难。思路如下:

1. 使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
2. 如果两个指针指向元素的和 sum == target,那么得到要求的结果;
3. 如果 sum > target,移动较大的元素,使 sum 变小一些;如果 sum < target,移动较小的元素,使 sum变大一些。

#167两数之和
class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        low, high = 0, len(numbers) - 1
        while low < high:
            total = numbers[low] + numbers[high]
            if total == targe
详解双指针算法 一、双指针算法双指针算法是指利用两个指针遍历数组(链表),左右指针相向前进或同向前进,在遍历过程中根据某种限制条件进行筛选,通常可以把时间复杂度降低至O(n)。 二、双指针题目 2.1 leetcode80-删除排序数组中的重复项II 题目描述 给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数... 阅读详情

相关推荐

算法-双指针问题解决思路

算法中的双指针使用,有时候会觉得很巧妙,解决了很多的问题,有必要归纳总结一下,首先双指针也是个很宽泛的概念,它类似于遍历中的 i 和 j 但是其区别是,两个指针是同时移动的,即没有贡献复杂度从O(N) 到 O(N*N) ,所以被很多算法大佬所推崇,所以基于此归纳总结出双指针的常见解法和套路。 1.题型归纳 这里将题型归纳为三种,分别如下: 快慢指针(前后按不同步调的两个指针) 前后双端指针(一个在首,一个在尾部,向中间靠拢) 固定间隔的指针(以i, i + k的间距的两个指针) 前面讲到,这三种指

Hoult丶吴邪 329

LeetCode数组系列-双指针

双指针的一些例题

weixin_51368761的博客 1036

基本算法总结,力扣题目整理

系统性学习算法,扎实您的打码基本功! 作为算法初学者的我从19年8月份开始在力扣学习算法,到现在AC了700多道题目。 随着打卡题目数量的增多,我发现算法常见考察的知识点大概有十几种,包括:二分,滑动窗口,双指针,单调栈(单调队列),链表,二叉树,字符串处理,dfs + 回溯,并查集,动态规划,贪心,位运算,数论(质数、约数、欧拉函数、欧几里得算法、中国剩余定理、简单博弈论等),图论(dfs、b...

muyids的博客 3182

深入浅出双指针法——数组

文章目录一、数组篇1、引入2、例题说明(初级版)3、进阶版——滑动窗口法 <算法学习之深入浅出双指针> 相信双指针法对大多数人来说并不陌生。但它并不属于某一数据结构。 在数组,链表,字符串当中都有所应用。所以我认为需要对双指针法 进行一次总结学习。 一、数组篇 1、引入 提出一个很简单的问题:就地移除一位元素。很难吗?当然不,你会说我们只需要遍历然后把它找出来 就可以了。那么我们先来看一组对比: for (int i = 0; i < array.size(); i++) {

mohuanxiaoyuzhou的博客 518

leetcode算法题英文词汇&短语

leetcode算法题英文词汇&短语

m0_47027182的博客 426

【数据结构基础_数组Leetcode 15.三数之和

双指针

cwtnice的博客 236

第一章——数组基础LeetCode题型归纳篇——数组双指针python版)

LeetCode题型归纳——数组双指针(python版)

qq_40467656的博客 1328

算法基础算法001之双指针

本篇文章主要会讲解双指针的思想,双指针是一种非常优秀的算法思想,有对撞指针和快慢指针两种基本用法。双指针对于有序数据的处理是比较有优势的,当你遇到有序的数据时,你可以尝试着利用双指针或者二分来解题,当然本篇文章只会讲解双指针。那么双指针思想具体的应用,以及为什么双指针适用于有序数组的处理呢?

℉f的博客 2687

❤️导图整理大厂面试高频数组8: 移除元素的双指针优化, 力扣27❤️

此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容). 关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接. 想进大厂.

孤柒的博客 1万+

如何从零开始刷力扣算法题--2020年12月中旬

如何从零开始刷力扣算法题–2020年12月中旬 写本文目的:准备2021实习&&秋招 1、刚做力扣感觉很杂乱,不知从何下手? 刚开始刷力扣,不应该叫刷,就应该叫看,因为根本不会,也就只有第一题才会做。做了大部分的简单题以后感觉这么做下去效率太低,就果断借鉴力扣面经、经验贴以及刚毕业师兄的建议,做了一些规划,归纳一些题型去做题。 2、刷题顺序很重要 按照题目类别结构化地刷题的速度不仅更快,而且可以在刷完一类题之后进行总结。对于我这样的菜鸡来说,只有按照推荐顺序刷,能更好地掌握数据结构与算法基础

qq_39475829的博客 8696

LeetCode-双指针-移动零

LeetCode中“移动零”问题的双指针解法

Wneosy的博客 1062

思维导图整理大厂面试高频数组25: 有序数组的平方的两种双指针思想, 力扣977

此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容). 关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接. 想进大厂.

孤柒的博客 1606

力扣349 - 两个数组的交集【哈希表+数组+双指针

对应力扣349.两个数组的交集,三种思路三个方向,带你玩转LeetCode

做技术人 · 产优质博客 · 找好工作 697

思维导图整理大厂面试高频数组24: 合并两个有序数组的两种双指针思想, 力扣88

此专栏文章是对力扣上算法题目各种方法的总结和归纳, 整理出最重要的思路和知识重点并以思维导图形式呈现, 当然也会加上我对导图的详解. 目的是为了更方便快捷的记忆和回忆算法重点(不用每次都重复看题解), 毕竟算法不是做了一遍就能完全记住的. 所以本文适合已经知道解题思路和方法, 想进一步加强理解和记忆的朋友, 并不适合第一次接触此题的朋友(可以根据题号先去力扣看看官方题解, 然后再看本文内容). 关于本专栏所有题目的目录链接, 刷算法题目的顺序/注意点/技巧, 以及思维导图源文件问题请点击此链接. 想进大厂.

孤柒的博客 6418

算法妙趣生,代码启征程》---第一期:双指针算法

写这个系列是为了记录我所学习的模块,进行分析 + 总结 + 归纳。如果你也对算法感兴趣,可以跟着我一起学习总结,我会在我理解明白了的基础上,进行尽可能详细,通俗易懂的语言进行表达。

2405_85784684的博客 2041

力扣100题解及笔记 双指针

双指针法的主要优点是高效性,通常能够将问题的时间复杂度降低到线性(O(n))或线性对数(O(n log n))

hiahiakk的博客 1017

Leetcode快速入门之第二节课: 使用双指针+区间法解决数组问题

文章目录1. 问题引入2. 问题分析3. 双指针+区间法 引入 1. 问题引入   在学习Leetcode中,最忌讳的学习方法是:东一榔头西一棒槌。具体来说,就是今天做一道数组的题,明天做一道链表的题,后天再做一道二叉树的题目。如此一来,就把学习变成了纯粹了题海战术。而最有效的方法是通过归纳和分类,逐一攻克每个子类别。这是因为,在逐一攻克每个子类别的过程中,必然会深入思考一类题目的共同点,所以就更容易学到其中的精髓之处。   今天咱们要学习的内容使用双指针+区间法解决数组问题,在开始之前,先把题目链接列举一

herosunly的博客 1万+

双指针算法 ()

本文系统讲解双指针算法,通过三道典型例题展示其应用:1)"盛最多水的容器"使用相向双指针,在O(n)时间内通过贪心策略求解;2)"有效三角形的个数"采用排序+双指针,将O()优化为O();3)"和为s的两个数字"利用有序性实现O(n)查找。文章指出双指针适用于有序数组、链表等问题,其本质是通过指针移动减少冗余计算,并总结了不同问题的指针类型和核心思想,强调多总结思考才能掌握算法精髓。

nplplus的博客 2万+

【滑动窗口】算法总结/力扣题目整理

力扣链接给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。返回 k。

Mr_StrangerN的博客 1949
上一篇: 算法基础之数组理论
下一篇: 算法基础之栈的理论和应用
孤岛使者
博客等级 码龄6年 40粉丝 92原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值