双指针算法(超详细带8道例题及算法解析) —— 包含力扣题目有283移动零、1089复写零、202快乐数、11盛水最多的容器、611有效三角形的个数、179双数之和、15三数之和、18四数之和

本文详细介绍了双指针算法的概念,以及如何应用在LeetCode中的八个经典问题,如移动零、复写零、快乐数等,并提供了对应的Java代码示例。

🧸欢迎来到dream_ready的博客,📜相信您对博主首页也很感兴趣o (ˉ▽ˉ;)

📜学生邮箱白嫖/免费安装JetBrains全家桶(IDEA/pycharm等) —— 保姆级教程

目录

双指针算法解析

1、力扣283.移动零

2、力扣1089复写零

3、力扣202快乐数

4、力扣11盛水最多的容器

5、力扣611有效三角形的个数

6、力扣179 查找总价为目标值的两个商品/ 原剑指Offer和为s的两个数字

7、力扣15三数之和

8、力扣18四数之和


双指针算法解析

双指针是一种思想,而不是说真的就是定义了两个指针,它和语言没有关系,比如C++,Java,Python等都可以使用双指针算法解题,而且是一种非常常见的算法

本篇博客适合所有语言学者阅读,因为算法是思想,每个题目除超详细的算法解析外后面还附赠了Java代码来供参考

常见的双指针有两种形式,一种是左右指针,一种是快慢指针

左右指针

  • 一般用于顺序结构中,也称对撞指针
  • 左右指针从两端向中间移动。一个指针从最左端开始,另一个从最右端开始,然后逐渐往中间逼近
  • 左右指针的终止条件一般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:
  • left == right (两个指针指向同一个位置)
  • left > right (两个指针错开)

快慢指针

  • 又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列结构上移动
  • 这种方法对于处理环形链表或数组非常有用
  • 其实不单单是环形链表或者数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快慢指针的思想
  • 快慢指针的实现方式有很多种,最常用的一种就是:
  • 在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位,实现一快一慢

1、力扣283.移动零

题目链接:283.移动零

题目描述:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

  • 1 <= nums.length <= 104
  • -231 <= nums[i] <= 231 - 1

算法思路:

快排的思想:数组划分区间 - 数组分两块

在本题中,我们可以用一个 cur 指针来扫描整个数组,另一个 dest 指针用来记录非零数序列的最后一个位置。

根据 cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。

在cur遍历期间,使  [0, dest] 的元素全部都是非零元素, [dest + 1, cur - 1] 的元素全是零, 这两部分属于处理过的区间,存放处理过的元素,单论处理过的区间的话,是符合题中结果的,而 [cur, n-1] 是待处理的区间,里面存放还未处理的元素

算法流程:

Java算法代码:

class Solution
{
    public void moveZeroes(int[] nums)
    {
        for(int cur = 0, dest = -1; cur < nums.length; cur++)
            if(nums[cur] != 0) // 仅需处理⾮零元素
            {
                dest++; // dest 先向后移动⼀位
                // 交换
                int tmp = nums[cur];
                nums[cur] = nums[dest];
                nums[dest] = tmp;
            }
    }
}

2、力扣1089复写零

题目链接:力扣1089复写零

题目描述:

给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

示例 1:

输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4]

示例 2:

输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]

提示:

  • 1 <= arr.length <= 104
  • 0 <= arr[i] <= 9

算法思路:

原地复写 + 双指针

如果「从前向后」进⾏原地复写操作的话,由于 0 的出现会复写两次,导致没有复写的数「被覆 盖掉」。因此我们选择「从后往前」的复写策略。

但是「从后向前」复写的时候,我们需要找到「最后⼀个复写的数」,因此我们的⼤体流程分两 步:

        i. 先找到最后⼀个复写的数;

        ii. 然后从后向前进⾏复写操作

值得注意如何找最后一个复写的数,咱可以这样想,就先按另外开辟数组的方法,一个指针原数组用,另一个指针新开辟的数组用,把新开辟的数组完成复写后,原数组的指向不就是咱需要的最后一个复写的数么,当然,此题不能另外开辟空间,咱可以用这种思想,不复写只移动来找到那个复写的数

算法流程:

<

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

dream_ready

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

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

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

打赏作者

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

抵扣说明:

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

余额充值