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

news2024/11/27 9:38:26

文章目录

  • 😎前言
  • 🌲[快乐数](https://leetcode.cn/problems/happy-number/)
    • 🚩题目描述
    • 🚩题⽬分析:
    • 🚩算法思路:
    • 🚩代码实现:
  • 🎋[盛水最多的容器](https://leetcode.cn/problems/container-with-most-water/)
    • 🚩题目描述
    • 🚩算法思路:
    • 🚩代码实现
  • 🎍[有效三角形个数](https://leetcode.cn/problems/valid-triangle-number/)
    • 🚩题目描述
    • 🚩算法思路:
    • 🚩代码实现:
  • ⭕总结

😎前言

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

  • 对撞指针从两端向中间移动。⼀个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼近。

  • 对撞指针的终⽌条件⼀般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循环),也就是:

left == right (两个指针指向同⼀个位置)
left > right (两个指针错开)

快慢指针:⼜称为⻳兔赛跑算法,其基本思想就是使⽤两个移动速度不同的指针在数组或链表等序列结构上移动。

这种⽅法对于处理环形链表或数组⾮常有⽤。其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使⽤快慢指针的思想。快慢指针的实现⽅式有很多种,最常⽤的⼀种就是:

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

🌲快乐数

🚩题目描述

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

  • 示例 1:
    输入:n = 19
    输出:true
    解释:
    12 + 92 = 82
    82 + 22 = 68
    62 + 82 = 100
    12 + 02 + 02 = 1

  • 示例 2:
    输入:n = 2
    输出:false
    解释:(这⾥省去计算过程,只列出转换后的数)
    2 -> 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> 16
    往后就不必再计算了,因为出现了重复的数字,最后结果肯定不会是 1

class Solution {
    public boolean isHappy(int n) {

    }
}

🚩题⽬分析:

为了⽅便叙述,将「对于⼀个正整数,每⼀次将该数替换为它每个位置上的数字的平⽅和」这⼀个操作记为x 操作;
题⽬告诉我们,当我们不断重复 x 操作的时候,计算⼀定会「死循环」,死的⽅式有两种:

  • 情况⼀:⼀直在1 中死循环,即1 -> 1 -> 1 -> 1…
  • 情况⼆:在历史的数据中死循环,但始终变不到1

由于上述两种情况只会出现⼀种,因此,只要我们能确定循环是在「情况⼀」中进⾏,还是在「情况⼆」中进⾏,就能得到结果

简单证明:

  1. 经过⼀次变化之后的最⼤值 9^2 * 10 = 810 ( 2^31-1=2147483647 。选⼀个更⼤的最⼤ 9999999999),也就是变化的区间在 [1, 810] 之间;

  2. 根据「鸽巢原理」,⼀个数变化 811 次之后,必然会形成⼀个循环;

  3. 因此,变化的过程最终会⾛到⼀个圈⾥⾯,因此可以⽤「快慢指针」来解决

🚩算法思路:

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

补充知识:
如何求⼀个数n每个位置上的数字的平⽅和。

  1. 把数 n 每⼀位的数提取出来:
    循环迭代下⾯步骤:

int t = n % 10 提取个位;
n /= 10 ⼲掉个位;

直到 n 的值变为 0 ;

  1. 提取每⼀位的时候,⽤⼀个变量 tmp 记录这⼀位的平⽅与之前提取位数的平⽅和

tmp = tmp + t * t

🚩代码实现:

class Solution
{
    // 返回 n 这个数每⼀位上的平⽅和
    public int bitSum(int n) {
        int sum = 0;
        while(n != 0) {
            int t = n % 10;
            sum += t * t;
            n /= 10;
        }
        return sum;
    }
    public boolean isHappy(int n) {
        int slow = n;
        int fast = bitSum(n);
        while(slow != fast) {
            //走一步
            slow = bitSum(slow);
            //走两步
            fast = bitSum(bitSum(fast));
        }
        return slow == 1;
    }
}

🎋盛水最多的容器

🚩题目描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

  • 示例 1:
    输入:[1,8,6,2,5,4,8,3,7]
    输出:49
    在这里插入图片描述解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

  • 示例 2:
    输入:height = [1,1]
    输出:1

class Solution {
    public int maxArea(int[] height) {

    }
}

🚩算法思路:

设两个指针 left , right 分别指向容器的左右两个端点,此时容器的容积

v = (right - left) * min( height[right], height[left])

容器的左边界为 height[left] ,右边界为 height[right] 。为了⽅便叙述,我们假设「左边边界」⼩于「右边边界」。

如果此时我们固定⼀个边界,改变另⼀个边界,⽔的容积会有如下变化形式:

  • 容器的宽度⼀定变⼩。

  • 由于左边界较⼩,决定了⽔的⾼度。如果改变左边界,新的⽔⾯⾼度不确定,但是⼀定不会超过右边的柱⼦⾼度,因此容器的容积可能会增⼤。

  • 如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的。

由此可⻅,左边界和其余边界的组合情况都可以舍去。所以我们可以 left++ 跳过这个边界,继续去判断下⼀个左右边界。

当我们不断重复上述过程,每次都可以舍去⼤量不必要的枚举过程,直到 left 与 right 相遇。期间产⽣的所有的容积⾥⾯的最⼤值,就是最终答案

🚩代码实现

public class Solution {
    public int maxArea(int[] height) {
        int left = 0, right = height.length - 1, ret = 0;
        while(left < right) {
            int v = Math.min(height[left], height[right]) * (right - left);
            ret = Math.max(ret, v);
            if(height[left] < height[right]) {
                left++;
            } else {
                right--;
            }
        }
        return ret;
    }
}

🎍有效三角形个数

🚩题目描述

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

  • 示例 1:
    输入: nums = [2,2,3,4]
    输出: 3
    解释:有效的组合是:
    2,3,4 (使用第一个 2)
    2,3,4 (使用第二个 2)
    2,2,3

  • 示例 2:
    输入: nums = [4,2,3,4]
    输出: 4

class Solution {
    public int triangleNumber(int[] nums) {

    }
}

🚩算法思路:

先将数组排序。我们固定⼀个「最⻓边」,然后在⽐这条边⼩的有序数组中找
出⼀个⼆元组,使这个⼆元组之和⼤于这个最⻓边。由于数组是有序的,我们可以利⽤「对撞指针」来优化。
设最⻓边枚举到 i 位置,区间 [left, right] 是 i 位置左边的区间(也就是⽐它⼩的区
间):

  • 如果 nums[left] + nums[right] > nums[i] :

▪ 说明 [left, right - 1] 区间上的所有元素均可以与 nums[right] 构成⽐ nums[i]⼤的⼆元组
▪ 满⾜条件的有right - left 种
▪ 此时 right 位置的元素的所有情况相当于全部考虑完毕,right-- ,进⼊下⼀轮判断

  • 如果 nums[left] + nums[right] <= nums[i] :

▪ 说明 left 位置的元素是不可能与 [left + 1, right] =位置上的元素构成满⾜条件 的⼆元组
▪ left 位置的元素可以舍去, left++ 进⼊下轮循环

🚩代码实现:

class Solution {
    public int triangleNumber(int[] nums) {
        // 1. 优化:排序
        Arrays.sort(nums);
        // 2. 利⽤双指针解决问题
        int ret = 0, n = nums.length;
        // 先固定最⼤的数
        for(int i = n - 1; i >= 2; i--)  {
            // 利⽤双指针快速统计出符合要求的三元组的个数
            int left = 0;
            int right = i - 1;
            while(left < right) {
                if(nums[left] + nums[right] > nums[i]) {
                    ret += right - left;
                    right--;
                } else {
                    left++;
                }
            }
        }
        return ret;
    }
}

⭕总结

关于《【算法优选】双指针专题——贰》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!一起加油

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1056046.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第四十章 持久对象和SQL - Object IDs

文章目录 第四十章 持久对象和SQL - Object IDsObject IDsID是如何确定的访问 ID 第四十章 持久对象和SQL - Object IDs Object IDs 每个对象在其所属的每个范围内都有一个唯一的 ID。在大多数情况下&#xff0c;使用此 ID 来处理对象。此 ID 是类中 %Persistent 的以下常用方…

如何制作在线流程图?6款在线工具帮你轻松搞定

流程图&#xff0c;顾名思义 —— 用视觉化的方式来描述一种过程或流程。它可以应用于各种领域&#xff0c;从业务流程&#xff0c;算法&#xff0c;到计算机程序等。然而&#xff0c;在创建流程图时&#xff0c;可能会遇到许多问题或者困惑&#xff0c;如缺乏专业的设计技能&a…

锚框_的标定

一、查漏补缺、熟能生巧&#xff1a; 1.关于fix.axis.add_patch在原来图像的坐标系同添加 边框的函数的使用&#xff1a; 2.torch.arange( h , device)生成tensor的等差数组: 3.torch.T&#xff08;&#xff09;就是transpose转置操作的函数咯: 4.torch.repeat操作&#xff0c…

静态数码管显示+动态数码管显示——“51单片机”

各位CSDN的uu们好呀&#xff0c;今天小雅兰的内容还是51单片机的知识&#xff0c;是为静态数码管显示和动态数码管显示&#xff0c;下面&#xff0c;让我们进入51单片机的世界吧&#xff01;&#xff01;&#xff01; 静态数码管显示 动态数码管显示 源代码 静态数码管显示 …

网络运营推广过程中客户说需要资质

大家好&#xff0c;我是网络工程师成长日记实验室的郑老师&#xff0c;您现在正在查看的是网络工程师成长日记专栏&#xff0c;记录网络工程师日常生活的点点滴滴 一个同学跟我学网络运营&#xff0c;他说他现在也学我做弱电。然后他说他接到电话&#xff0c;对方都是问资质&am…

首发Orin N芯片,腾势追赶「智驾第一梯队」

张祥威 编辑 | 德新 英伟达最新一代芯片—— Orin N&#xff0c;腾势拿下 首发。 9月26日&#xff0c;腾势N7推出「高快智驾包」。官方描述中&#xff0c;这一选装将“基于新一代NIVIDIA DRIVE ORIN的 高性能平台”&#xff0c;可以实现高速NOA。 此前&#xff0c;腾势的…

Acwing 843. n-皇后问题

Acwing 843. n-皇后问题 知识点题目描述思路讲解代码展示 知识点 DFS剪枝 题目描述 思路讲解 代码展示 第一种搜索方式&#xff1a; #include <iostream>using namespace std;const int N 20;int n; char g[N][N]; bool col[N], dg[N * 2], udg[N * 2];void dfs(in…

常见开发、测试模型

开发模型瀑布模型螺旋模型增量、迭代敏捷开发模型 测试模型V模型W模型 开发模型 瀑布模型 瀑布模型的每一个阶段都只执行一次&#xff0c;是线性顺序进行的软件开发模式。 优点&#xff1a;每个阶段做什么&#xff1b;产生什么非常清晰&#xff1b; 缺点&#xff1a;风险往…

Python3数据科学包系列(三):数据分析实战

Python3中类的高级语法及实战 Python3(基础|高级)语法实战(|多线程|多进程|线程池|进程池技术)|多线程安全问题解决方案 Python3数据科学包系列(一):数据分析实战 Python3数据科学包系列(二):数据分析实战 一: 数据分析与挖掘认知升维 我们知道在数据分析与数据挖掘中,数据…

15: 8种GPIO模式和其他资源

目录 一:GPIO 1:简历 2:模式 3:位结构 4:八种模式 A: 浮空/上拉/下拉输入 B:模拟输入 ----GPIO_Mode_AIN C: 开漏/推挽输出 D:复用开漏/推挽输出 E: 模式总结 二:其他资源 1:片上资源/外设 2:引脚定义表 一:GPIO 1:简历 GPIO&#xff08;General Purpose Input …

排序---P1012 [NOIP1998 提高组] 拼数

思路&#xff1a; 这道题的思路就是进行排序&#xff0c;但不同于以往是根据数的大小排序&#xff0c;这道题是根据最高位最大就放在越前面。那么要怎么解决最高位越大排得越前这个问题呢&#xff0c;我们就会想到用字符串比较大小&#xff0c;就可以解决&#xff0c;所以我们…

RESTFul风格接口如何设计

RESTFul风格设计规范 HTTP协议请求方式要求 REST 风格主张在项目设计、开发过程中&#xff0c;具体的操作符合HTTP协议定义的请求方式的语义。 操作请求方式查询操作GET保存操作POST删除操作DELETE更新操作PUT 需求分析 数据结构&#xff1a; User {id 唯一标识,name 用户名&a…

车牌超分辨率:License Plate Super-Resolution Using Diffusion Models

论文作者&#xff1a;Sawsan AlHalawani,Bilel Benjdira,Adel Ammar,Anis Koubaa,Anas M. Ali 作者单位&#xff1a;Prince Sultan University 论文链接&#xff1a;http://arxiv.org/abs/2309.12506v1 内容简介&#xff1a; 1&#xff09;方向&#xff1a;图像超分辨率技术…

MySQL进阶_1.数据类型约束

文章目录 第一章、名词解释第二章、数据类型2.1、数据类型简介2.2、数据类型对应属性2.3、整数类型2.4、浮点类型2.5、定点数类型2.6、日期和时间类型2.7、文本字符串类型2.7.1、CHAR和VARCHAR区别2.7.2、TEXT 2.8、小结和建议 第三章、约束3.1 约束的定义3.2 非空约束3.3 唯一…

浅谈OV SSL 证书的优势

随着网络威胁日益增多&#xff0c;保护网站和用户安全已成为每个企业和组织的重要任务。在众多SSL证书类型中&#xff0c;OV&#xff08;Organization Validation&#xff09;证书以其独特的优势备受关注。让我们深入探究OV证书的优势所在&#xff0c;为网站安全搭建坚实的防线…

内网安全学习

域 域在我的理解就是一个局域网&#xff0c;管理员为了便于操作域内主机&#xff0c;通常会有一个DC&#xff08;domain control&#xff09;&#xff0c;域控主机可以直接控制其他域内主机&#xff0c;相当于域内的管理员权限&#xff0c;内网渗透的终极目的即拿到域控的权限…

嵌入式学习笔记(41)实时时钟RTC

7.6.1何为实时时钟 (1)real time clock&#xff0c;真实时间&#xff0c;就是所谓的xx年x月x日x时x分x秒星期x (2)RTC是SoC中一个内部外设&#xff0c;RTC有自己独立的晶振提供RTC时钟源&#xff08;32.768KHz&#xff09;&#xff0c;内部有一些寄存器用来记录时间&#xff…

Acwing 842. 排列数字

Acwing 842. 排列数字 知识点题目描述思路讲解代码展示 知识点 DFS 题目描述 思路讲解 DFS重点是&#xff1a;顺序&#xff01;&#xff08;暴力的手法&#xff09;&#xff08;递归&#xff09; 用 path 数组保存排列&#xff0c;当排列的长度为 n 时&#xff0c;是一种方…

pandas读取文件的时候出现‘OSError: Initializing from file failed’

报错原因&#xff1a; pandas.read_csv() 报错 OSError: Initializing from file failed&#xff0c;一般由两种情况引起&#xff1a;一种是函数参数为路径而非文件名称&#xff0c;另一种是函数参数带有中文。 原代码&#xff1a; data pd.read_csv(csv文件.csv) data导入文…

拒绝水文!八大排序(一)【适合初学者】直接插入排序和希尔排序

文章目录 直接插入排序希尔排序 大家好&#xff0c;我是纪宁。 这篇文章将向大家介绍直接插入排序算法和希尔排序算法。 直接插入排序 直接插入排序是一个简单的插入排序法&#xff0c;其基本思想是&#xff1a;把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有…