大厂算法指南:优选算法 ——双指针篇(上)

这篇具有很好参考价值的文章主要介绍了大厂算法指南:优选算法 ——双指针篇(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


大厂算法指南:优选算法 ——双指针篇(上),算法指南,C++经典收录,算法,c++,leetcode,笔记,神经网络

📕作者简介:非科班在读,纯技术博客分享,致力于C/C++,涉及Python、C/C++、Linux,数据结构,git企业级开发,Mysql等。
📗本文收录于算法指南,旨在帮助读者应对各大互联网大厂笔试题,构建完整的算法体系!
📘相关专栏C语言、C++、数据结构、Linux、前言科技喜欢C/C++/Linux/算法的朋友们可以关注一下哦!
————————————————
版权声明:本文为CSDN博主「小宇成长录」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://editor.csdn.net/md?not_checkout=1&spm=1011.2124.3001.6183&articleId=134906130

前言:双指针简介

常⻅的双指针有两种形式,⼀种是对撞指针,⼀种是左右指针。
对撞指针:⼀般⽤于顺序结构中,也称左右指针。

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

快慢指针:⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。
这种⽅法对于处理环形链表或数组⾮常有⽤。其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使⽤快慢指针的思想。
快慢指针的实现⽅式有很多种,最常⽤的⼀种就是:

。 在⼀次循环中,每次让慢的指针向后移动⼀位,⽽快的指针往后移动两位,实现⼀快⼀慢。

话不多说,现在来看看大厂们比较有代表性的面试题吧!


一、283.移动零

「数组分两块」是⾮常常⻅的⼀种题型,主要就是根据⼀种划分⽅式,将数组的内容分成左右两部
分。这种类型的题,⼀般就是使⽤「双指针」来解决。

题目描述:
大厂算法指南:优选算法 ——双指针篇(上),算法指南,C++经典收录,算法,c++,leetcode,笔记,神经网络

1.1 算法思想(快排的思想:数组划分区间 - 数组分两块)

在本题中,我们可以⽤⼀个 cur 指针来扫描整个数组,另⼀个 dest 指针⽤来记录⾮零数序列的最后⼀个位置。根据 cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。在 cur 遍历期间,使 [0, dest] 的元素全部都是⾮零元素, [dest + 1, cur - 1] 的元素全是零。

1.2 算法流程

  1. 初始化 cur = 0 (⽤来遍历数组), dest = -1 (指向⾮零元素序列的最后⼀个位置。因为刚开始我们不知道最后⼀个⾮零元素在什么位置,因此初始化为 -1 )
  2. cur 依次往后遍历每个元素,遍历到的元素会有下⾯两种情况:
    ①遇到的元素是 0 , cur 直接 ++ 。因为我们的⽬标是让 [dest + 1, cur - 1] 内的元素全都是零,因此当 cur 遇到 0 的时候,直接 ++ ,就可以让 0 在 cur - 1的位置上,从⽽在 [dest + 1, cur - 1] 内;
    ② 遇到的元素不是 0 , dest++ ,并且交换 cur 位置和 dest 位置的元素,之后让cur++ ,扫描下⼀个元素。
    。因为 dest 指向的位置是⾮零元素区间的最后⼀个位置,如果扫描到⼀个新的⾮零元素,那么它的位置应该在 dest + 1 的位置上,因此 dest 先⾃增 1 ;
    。dest++ 之后,指向的元素就是 0 元素(因为⾮零元素区间末尾的后⼀个元素就是0 ),因此可以交换到 cur 所处的位置上,实现 [0, dest] 的元素全部都是⾮零元素, [dest + 1, cur - 1] 的元素全是零。

1.3 代码实现

class Solution
{
public:
	 void moveZeroes(vector<int>& nums) 
	 {
		 for(int cur = 0, dest = -1; cur < nums.size(); cur++)
		 if(nums[cur]) // 处理⾮零元素
			 swap(nums[++dest], nums[cur]);
	 }
};

二、1089. 复写零

大厂算法指南:优选算法 ——双指针篇(上),算法指南,C++经典收录,算法,c++,leetcode,笔记,神经网络

2.1 算法思路

如果「从前向后」进⾏原地复写操作的话,由于 0 的出现会复写两次,导致没有复写的数「被覆盖掉」。因此我们选择「从后往前」的复写策略。
但是「从后向前」复写的时候,我们需要找到「最后⼀个复写的数」,因此我们的⼤体流程分两
步:

  1. 先找到最后⼀个复写的数;
  2. 然后从后向前进⾏复写操作

2.2 算法流程

  • ①初始化两个指针 cur = 0 , dest = -1 ;
  • ② 找到最后⼀个复写的数:
    • 当 cur < n 的时候,⼀直执⾏下⾯循环:
      • 如果是 0 的话, dest 往后移动两位;否则, dest 往后移动⼀位。
    • 判断 dest 时候已经到结束位置,如果结束就终⽌循环;
    • 如果没有结束, cur++ ,继续判断。
  • ③判断 dest 是否越界到 n 的位置:
    • 如果越界,执⾏下⾯三步:
        1. n - 1 位置的值修改成 0 ;2. cur 向移动⼀步;3. dest 向前移动两步。
  • ④从 cur 位置开始往前遍历原数组,依次还原出复写后的结果数组:
    • 判断 cur 位置的值:
        1. 如果是 0 : dest 以及 dest - 1 位置修改成 0 , dest -= 2 ;
        1. 如果⾮零: dest 位置修改成 0 , dest -= 1 ;
    • cur-- ,复写下⼀个位置。

2.3 代码实现

class Solution {
public:
    void duplicateZeros(vector<int>& arr) {
        int cur=0, dest=-1, n=arr.size();
        //1. 先找到最后一个数
        while(cur<n)
        {
            if(arr[cur]) 
                dest++;
            else 
                dest+=2;
            if(dest+1>=n)
                break;
            cur++;
        }

        //2. 边界处理(dest可能超出范围)
        if(dest==n)
        {
            arr[n-1]=0;
            cur--, dest-=2;
        }

        //从后向前完成复学
        while(cur>=0)
        {
            if(arr[cur])
                arr[dest--]=arr[cur--];
            else
            {
                arr[dest--]=0;
                arr[dest--]=0;
                cur--;
            }
        }
    }
};

三、202. 快乐数

大厂算法指南:优选算法 ——双指针篇(上),算法指南,C++经典收录,算法,c++,leetcode,笔记,神经网络

3.1 算法思路(快慢指针)

根据上述的题⽬我们可以知道,当重复执⾏ x 的时候,数据会陷⼊到⼀个「循环」之中。
⽽「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会
相遇在⼀个位置上。如果相遇位置的值是 1 ,那么这个数⼀定是快乐数;如果相遇位置不是 1
的话,那么就不是快乐数。

3.2 代码实现

class Solution {
public:
    //用于求每个位置的平方和
    int BitSum(int x)
    {
        int sum=0;
        while(x)
        {
            int t = x % 10;//余数
            sum += t * t;
            x /= 10;
        }
        return sum;
    }

    //判断是否为快乐数
    bool isHappy(int n)
    {
        int slow=n, fast=BitSum(n);
        while(slow != fast)
        {
            slow=BitSum(slow);
            fast=BitSum(BitSum(fast));
        }
        //相遇,判断
        return slow == 1;
    }
};

四、11. 盛最多水的容器

大厂算法指南:优选算法 ——双指针篇(上),算法指南,C++经典收录,算法,c++,leetcode,笔记,神经网络

4.1 算法思路(对撞指针)

设两个指针 left , right 分别指向容器的左右两个端点,此时容器的容积 :
v = (right - left) * min( height[right], height[left])
容器的左边界为 height[left] ,右边界为 height[right] 。


为了⽅便叙述,我们假设「左边边界」⼩于「右边边界」。

  • 如果此时我们固定⼀个边界,改变另⼀个边界,⽔的容积会有如下变化形式:
    • 容器的宽度⼀定变⼩。
    • 由于左边界较⼩,决定了⽔的⾼度。如果改变左边界,新的⽔⾯⾼度不确定,但是⼀定不会超过右边的柱⼦⾼度,因此容器的容积可能会增⼤。
    • 如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的。

由此可⻅,左边界和其余边界的组合情况都可以舍去。所以我们可以 left++ 跳过这个边界,继续去判断下⼀个左右边界。当我们不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到 left 与 right 相遇。期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案。文章来源地址https://www.toymoban.com/news/detail-759360.html

代码实现

class Solution {
public:
    int maxArea(vector<int>& height) {
        int ret=0;
        int left=0, right=height.size()-1;
        while(left < right)
        {
            int capacity = min(height[left], height[right])*(right - left);
            ret =max(ret, capacity);
            if(height[left] < height[right])
                left++;
            else
                right--;
        }
        return ret;
    }
};

到了这里,关于大厂算法指南:优选算法 ——双指针篇(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【算法优选】双指针专题——贰

    常⻅的双指针有两种形式,⼀种是 对撞指针 ,⼀种是 左右指针 对撞指针 :⼀般⽤于顺序结构中,也称左右指针。 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能

    2024年02月08日
    浏览(53)
  • 【优选算法】—— 双指针问题

    从今天开始,整个暑假期间。我将不定期给大家带来有关各种算法的题目,帮助大家攻克面试过程中可能会遇到的算法这一道难关。 目录 (一) 基本概念 (二)题目讲解 1、难度:easy 1️⃣移动零 2️⃣复写零 2、难度:medium 1️⃣快乐数 2️⃣盛⽔最多的容器 3、难度:di

    2024年02月13日
    浏览(26)
  • 算法通关村第一关——链表经典问题之双指针笔记

    基本结构 1.寻找中间结点 2.寻找倒数第k个元素 3.旋转链表

    2024年02月14日
    浏览(40)
  • 【优选算法】专题1 -- 双指针 -- 复写0

    前言: 补充一下前文没有写到的双指针入门知识:专题1 -- 双指针 -- 移动零 目录 基础入门知识: 1. 复写零(easy) 1. 题⽬链接:1089.复习0 - 力扣(LeetCode) 2. 题⽬描述: 3.算法原理: 异地操作 本地操作 【从后向前的复写过程】 整体思路: 🎯1.先找到最后一个“复写”的

    2024年04月17日
    浏览(33)
  • 算法通关村第一关——链表经典问题之双指针专题笔记

    我一直觉得双指针是一个非常好用的方法,在链表中可以使用,在数组中依然可以,很灵活。 1. 寻找中间结点         用两个指针 slow 与 fast 一起遍历链表。slow 一次走一步, fast 一次走两步。那么当 fast 到达链表的末尾时,slow 必然位于中间。 2. 寻找倒数第K个元素 在这

    2024年02月15日
    浏览(41)
  • Leetcode | 对撞指针算法笔记

    对撞指针的基本思想是在 数组或链表等数据结构 中使用两个指针( left 或 right 、 start 或 end 等表示),分别从不同的方向(通常是数组的两端)移动,以便有效地进行 搜索、遍历或判断 。 对撞指针常见的运用场景包括: 排序数组的查找 :对撞指针可以用于在已排序的数

    2024年02月12日
    浏览(86)
  • 【优选算法】双指针 -- 快乐数 和 盛最多水的容器

    前言: 🎯个人博客:Dream_Chaser 🎈刷题专栏:优选算法篇 📚本篇内容:03快乐数 和 04盛最多水的容器 目录 一、快乐数(medium) 1. 题⽬链接:202. 快乐数 2. 题⽬描述: 3. 题⽬分析: 4.算法原理 二、盛最多水的容器 1. 题⽬链接:11.盛最多水的容器 - 力扣(LeetCode) 2. 题⽬描述

    2024年04月17日
    浏览(34)
  • 【双指针】经典数组双指针题LeetCode

    27. 移除元素 简单 题目链接 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间, 你必须仅使用 O(1) 额外空间并原地修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的

    2024年02月12日
    浏览(37)
  • 【leetcode刷题之路】面试经典150题(2)——双指针+滑动窗口+矩阵

    2 双指针 2.1 【双指针】验证回文串 题目地址:https://leetcode.cn/problems/valid-palindrome/description/?envType=study-plan-v2envId=top-interview-150   详见代码。 2.2 【双指针】判断子序列 题目地址:https://leetcode.cn/problems/is-subsequence/description/?envType=study-plan-v2envId=top-interview-150   双指针挨个遍

    2024年02月19日
    浏览(50)
  • 【数据结构与算法】之多指针算法经典问题

    本文为 【数据结构与算法】多指针算法经典问题 相关介绍,下边将对 链表反转 (包含 迭代反转链表 、 递归反转 、 头插法反转 ), 双指针-快慢指针 (包含 寻找单向无环链表的中点 、 判断单向链表是否有环及找环入口 ), 双指针-左右指针 (包含 两数之和 、 二分查

    2024年02月03日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包