初探算法之双指针开篇

初探算法之双指针开篇

目录

前言:

此篇作为算法篇章的首篇文章,自然得简单说上几句。算法部分呢,多刷题是必不可少的。从暴力解法过渡到算法解法,过程着实有些艰辛,而算法的思考尤为关键。所以算法部分的讲解大多借助题目直接展开,以题目来传授算法知识。鉴于每个人对算法的接受程度有别,每篇通常涵盖两题左右,难题部分一般只设一道,且题目均取自LeetCode,本文会以最优解法来阐释不同的算法,通过题目解析、算法原理、算法编写这三个部分来解决问题。

双指针算法

题目一:

示例如下:

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

题目解析:
给定一个数组,需要将其中的0移动到数组末尾,同时无需考虑0的相对顺序,但要保留非零元素的相对顺序。若不使用双指针,有诸多解法,例如把所有非零元素移到开头,不过每移动一次得遍历一次,时间复杂度接近O(N²),这属于暴力解法。那该如何运用双指针呢?

算法原理:
借助双指针可将数组划分成三个区域:[0,dest]为非零元素区域,[dest,cur]是0元素区域,[cur,end]是未遍历区域。双指针并非传统意义上的指针,而是一种形象的指向概念。这里借助数组下标来定义两个指针。起始时二者均从0开始,dest初始可先不明确,cur遍历数组,遇到非零元素时,将其放到dest位置,具体操作是dest从-1开始,找到非零元素后,dest先自增,再与cur位置元素交换,cur继续往后遍历。

算法编写:

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]);
        }
    }
};

简单分析时间复杂度,此为一次遍历,时间复杂度为O(N),相较暴力解法有显著优化。

题目链接:283. 移动零 - 力扣(LeetCode)

题目二:

示例如下:

输入: n = 19
输出: true
解释: 1² + 9² = 82
8² + 2² = 68
6² + 8² = 100
1² + 0² + 0² = 1

题目解析:
题目叫做快乐数,来瞧瞧它有多“快乐”。快乐数的定义是:将一个数的每一位数字的平方相加,多次操作后若能得到1,那这个数就是快乐数;若一直循环却无法得到1,就不是快乐数。这类题目没有暴力解法,因为暴力的话很可能陷入死循环出不来,所以直接进入算法原理部分。

算法原理:
我们可以通过画图来看看变化情况。以19为例,经过4次变化得到1;而2经过多次变化后,会出现和第一次变化相同的值4。可以理解为2在变化时形成了一个环,且数的变化无法跳出这个环,所以不是快乐数。那19是否也有环呢?换个角度想,19变化时会不会形成一个仅包含1的环呢?此时大家应该明白了,我们可以用两个指针,一个走得快,一个走得慢,它们必定会相遇,相遇时判断是否为1即可。那为什么一定会出现环呢?这就要用到鸽巢原理了。LeetCode中给出了n的最大取值,我们考虑最大情况,比如10个9组成的数,计算其一次变化后的值为810,所以变化后的值最大不超过810。定义函数F(x)表示一次变化,那么一个数经过811次变化会产生811个数,但可能的取值区间只有810个,根据鸽巢原理,必然有重复的数,也就形成了环。

算法编写:

class Solution 
{
public:
    int _isHappy(int num)
    {
        int ans = 0,sum = 0;
        while(num)
        {
            sum = num % 10;
            ans = ans + sum * sum;
            num /= 10;
        }
        return ans;
    }
    bool isHappy(int n) 
    {
        int slow = n,fast = n;
        while(1)
        {
            slow = _isHappy(slow);
            fast = _isHappy(_isHappy(fast));
            if(slow == fast)
            {
                if(slow == 1)
                return true;
                else
                return false;
            }
        }
    }
};

今日算法分享至此,感谢阅读!

文章整理自互联网,只做测试使用。发布者:Lomu,转转请注明出处:https://www.it1024doc.com/13683.html

(0)
LomuLomu
上一篇 2025 年 9 月 20 日
下一篇 2025 年 9 月 20 日

相关推荐

  • 2025年最新PyCharm激活码及永久破解教程(支持2099年)

    本方法适用于Jetbrains全家桶,包括PyCharm、IDEA、DataGrip、Goland等开发工具! 先给大家看看最新PyCharm版本成功破解的截图,可以看到已经完美激活到2099年,非常稳定可靠! 下面我将用详细的图文教程,手把手教你如何将PyCharm永久激活至2099年。 这个方法不仅适用于最新版本,对之前的旧版本同样有效! 支持Windo…

    PyCharm激活码 2025 年 7 月 7 日
    26700
  • MySQL行锁的优劣剖析:怎样降低行锁对性能的阻碍?

    《MySQL行锁的利弊剖析:如何降低行锁对性能的消极影响》 行锁是针对数据表中行记录实施的锁定机制,由引擎层的相关引擎予以实现。 从两阶段锁说起 在InnoDB的事务场景下,行锁并非在需要时立即获取后就马上释放,而是要等到事务结束才会释放,此即为两阶段锁协议。 明确这一设定后,若事务需锁定多个行,需将最易引发锁冲突、最可能影响并发程度的锁尽量后置。 举个例子…

    2025 年 8 月 5 日
    11000
  • 三步申领clion激活码,送你最全clion破解教程

    声明:本教程中涉及的 CLion 破解补丁与激活码均源自网络公开资源,仅供个人学习研究之用,禁止任何商业用途。若条件允许,请支持正版! 先放一张成功截图:CLion 2025.2.1 已激活至 2099 年,爽到飞起! 下面用图文方式,手把手带你完成最新版 CLion 的激活流程。 前期准备 ⚠️ 如果你之前尝试过其他补丁但失败,建议先卸载旧版本或清理残留配…

    2025 年 10 月 15 日
    9000
  • 【Java 学习】详讲代码块:控制流语句代码块、方法代码块、实例代码块(构造代码块)、静态代码块、同步代码块

    💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助! 👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持! 🚀 传播技术之美:期待您将这篇文章推荐给更多对需要学习Java语言、低代码开发感兴趣的朋友,让我们共同学习、成长! 1. 什么是代码块? 在学习各种语言的时候,有些语句需要使用{}将代码围起来,有…

    2025 年 1 月 17 日
    61600
  • 🚀 2025年最新IDEA激活码 & 永久破解教程(100%有效)

    最近JetBrains发布了IDEA 2025.1版本,不少小伙伴升级后发现需要重新激活了!😱 网上各种方法试了个遍,结果都不行?别急!经过多次测试,我终于找到了一种简单快捷、100%成功的破解方法!无论你是什么系统(Windows/Mac/Linux),什么版本,都能稳定激活!💪 🔍 准备工作 卸载旧版本:如果之前安装过非官网版本或使用过其他破解工具,建议…

    2025 年 6 月 15 日
    4.6K00

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信