Leetcode双指针法应用

news2024/12/23 6:07:33

1.双指针法

文章目录

    • 1.双指针法
      • 1.1什么是双指针法?
      • 1.2解题思路
      • 1.3扩展

1.1什么是双指针法?

双指针算法是一种在数组或序列上操作的技巧,实际上是对暴力枚举算法的一种优化,通常涉及到两个索引(或指针)从两端或从某个特定起点开始向中间靠拢,以解决特定问题。这种算法在处理数组中的元素对、查找、排序和去除重复元素等问题上特别有效。

  • 初始化:设定两个指针,它们可以同时从序列的两端开始,也可以从同一端以不同速度移动。
  • 移动规则:根据问题需求定义指针如何移动。比如,在排序数组中查找一对数之和,一个指针可以从左向右移动,另一个从右向左移动,直到两者相遇。
  • 终止条件:当指针相遇、错过彼此或是达到某种特定条件时,算法结束。

典型应用场景:

  1. 查找问题

    • 在排序数组中查找目标对:给定一个排序数组和一个目标值,找到两个数,使它们的和为目标值。如 LeetCode 的 “Two Sum II - Input array is sorted” 问题。
  2. 删除问题

    • 移除数组中的重复元素:例如,给定一个排序数组,原地删除重复出现的元素,使得每个元素最多出现两次。双指针一个用来遍历,另一个用来记录新的非重复元素的位置。
  3. 排序与翻转

    • 反转数组:可以使用双指针快速地原地反转数组的一部分或全部。两个指针一前一后交换元素直至相遇。
  4. 滑动窗口

    • 最大/最小滑动窗口:维护一个大小固定的窗口,在数组上滑动以找到窗口内的最大值或最小值,或某些统计量,如窗口内的最大和。

1.2解题思路

题目原文:

给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。

示例 1:

输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100]
排序后,数组变为 [0,1,9,16,100]

示例 2:

输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]

思路:

对于这个问题,双指针算法可以非常高效地解决。由于原始数组是非递减排序的,我们可以通过双指针从数组两端开始向中间遍历,比较两个指针所指向元素的平方值,将较大的平方值先放入结果数组中。这样可以确保结果数组始终是按非递减顺序排列的。

  1. 初始化两个指针,left指向数组的起始位置,right指向数组的末尾位置。
  2. 初始化一个空数组或列表来存放结果。
  3. left <= right时,执行以下步骤:
    • 计算leftright指针所指向元素的平方值。
    • 比较这两个平方值,将较大的那个平方值添加到结果数组的前端。
    • 移动指向较小原数值的指针。如果平方值相等,可以任选一个指针移动。
  4. left > right时,所有元素都已经处理完毕,返回结果数组。

通过这种方法,我们可以在一次遍历中完成所有计算和排序工作,时间复杂度为O(n),空间复杂度也为O(n),其中n为数组的长度。

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int>result(nums.size(),0);
        int left = 0;
        int right = nums.size() - 1;
        int k =  nums.size() - 1;
        while(left <= right){
            if(nums[left]*nums[left] < nums[right]*nums[right]){
                result[k--] = nums[right]*nums[right];
                right--;
            }
            else{
                result[k--] = nums[left]*nums[left];
                left++;
            }
        }
        return result;
    }
};

在这里插入图片描述

1.3扩展

题目原文:

给你两个按 非递减顺序 排列的整数数组 nums1nums2,另有两个整数 mn ,分别表示 nums1nums2 中的元素数目。

请你 合并 nums2nums1 中,使合并后的数组同样按 非递减顺序 排列。

**注意:**最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n

示例 1:

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。

示例 2:

输入:nums1 = [1], m = 1, nums2 = [], n = 0
输出:[1]
解释:需要合并 [1] 和 [] 。
合并结果是 [1] 。

示例 3:

输入:nums1 = [0], m = 0, nums2 = [1], n = 1
输出:[1]
解释:需要合并的数组是 [] 和 [1] 。
合并结果是 [1] 。
注意,因为 m = 0 ,所以 nums1 中没有元素。nums1 中仅存的 0 仅仅是为了确保合并结果可以顺利存放到 nums1 中。

思路:

双指针解题思路在这种合并有序数组的问题中非常有效。这里的关键是利用两个数组已经是非递减顺序的特点,通过两个指针分别从两个数组的末尾开始比较,并将较大的数逆序填入nums1的末尾
解题步骤:

  1. 初始化两个指针 ij,分别指向 nums1nums2 的末尾,即 i = m - 1j = n - 1。同时,设置另一个指针 k 指向 nums1 数组的最后一个有效位置,即 k = m + n - 1

  2. i >= 0j >= 0 时,进行以下操作:

    • 比较 nums1[i]nums2[j] 的值。
    • 将较大的数赋值给 nums1[k],然后对应的指针向前移动一位。如果 nums1[i] 大,则 i--;如果 nums2[j] 大或相等,则 j--
    • k--,因为每次操作都是在数组的末尾进行的。
  3. 如果 j >= 0,说明 nums2 中还有剩余元素,直接将剩余的 nums2[j] 逐个复制到 nums1 的前面,因为 nums2 的元素在 nums1 的末尾已经被正确地放置了。

class Solution {
public:
    void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
        vector<int> arr(m + n, 0); // 创建一个足够大的临时数组
        int k = m + n - 1; // 初始化k为新数组的最后一个位置索引
        m--; // nums1的有效元素索引需要减1,因为m是原始长度
        n--; // nums2的同理

        // 注意循环条件应该是 k >= 0,因为我们要从末尾开始填充
        while (k >= 0) {
            if (n < 0) { // 如果nums2已经全部处理完了
                arr[k] = nums1[m];
                m--;
            } else if (m < 0) { // 如果nums1已经全部处理完了
                arr[k] = nums2[n];
                n--;
            } else if (nums1[m] > nums2[n]) { // 比较条件
                arr[k] = nums1[m];
                m--;
            } else {
                arr[k] = nums2[n];
                n--;
            }
            k--; // 移动到下一个待填充的位置
        }

        // 最后把合并的结果复制回nums1
       nums1.swap(arr);
    }
};

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

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

相关文章

ubuntu 安装图形化界面

前言&#xff1a; 如果在首次安装操作系统的时候是最小化安装&#xff0c;可以参照本文进行安装 安装图形化界面软件包 下载源最好提前换成国内源 sudo apt-get install ubuntu-desktop设置图形化启动 sudo systemctl set-default graphical.target重启系统 reboot验证&…

《Techporters架构搭建》-Day02 集成Mybatis-plus

集成Mybatis-plus Mybatis-plus集成Mybatis-plus步骤小结 Mybatis-plus Mybatis-plus官网 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。它引入了一些新的特性&…

免费的数字孪生平台助力产业创新,让新质生产力概念有据可依

关于新质生产力的概念&#xff0c;在如今传统企业现代化发展中被反复提及。 那到底什么是新质生产力&#xff1f;它与哪些行业存在联系&#xff0c;我们又该使用什么工具来加快新质生产力的发展呢&#xff1f;今天我将介绍一款为发展新质生产力而量身定做的数字孪生工具。 新…

java学校--Object类方法--toString

第一点解析&#xff1a; 全类名就是包名加类名 getClass&#xff08;&#xff09;.getName()是得到其包名和类名如图&#xff0c;包名是com.hspedu.object_类名是Monster。 Integer.toHexString&#xff08;hashCode&#xff08;&#xff09;&#xff09;&#xff1b;是得到其…

【2024最新版】Vue前端面试篇,看这一篇就够了

文章目录 Vue常用的指令都有哪些v-bind和v-model的区别Vue2的生命周期有哪些Vue3的生命周期有哪些vue3中创建响应式变量的方法ref和reactive原理vuex有哪些方法vue-router生命周期钩子vue框架和原生JavaScript有什么区别对于提升项目加载速度和运行效率是怎么做的webpack能做什…

栈及栈的应用(有效的括号 力扣20)

栈的概念 栈是一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out&#xff09;的原则。 画个图理解一下 咱们可以观…

【笔记:3D航路规划算法】一、随机搜索锚点(python实现,讲解思路)

目录 关键概念3D路径规划算法1. A*算法2. 快速随机锚点1. 初始化&#xff1a;2. 实例化搜索算法&#xff1a;3. 路径生成&#xff1a;4. 绘制图像&#xff1a; 3D路径规划是在三维空间中寻找从起点到终点的最短或最优路径的一种技术。它广泛应用于无人机导航、机器人运动规划、…

关于垂直领域大模型的探索和尝试

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、算法项目落地经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 总结链接如…

SpringCloud—08—高级之SpringCloud Alibaba中—Sentinel

文章目录 提前预知18、Sentinel是什么&#xff1f;18.1、sentinel是什么&#xff1f;18.2、Sentinel下载安装运行18.3、Sentinel初始化监控18.4、Sentinel流控规则1、流控规则基本介绍2、流控规则之-QPS-直接-快速失败3、流控规则之-线程数-直接失败4、流控规则之-QPS-关联-快速…

实战篇(十):使用Processing创建可爱花朵:实现随机位置、大小和颜色的花朵

使用Processing创建可爱花朵 0.效果预览1. 引言2. 设置Processing环境3. 创建花朵类4. 实现花瓣绘制5. 绘制可爱的笑脸6. 鼠标点击生成花朵7. 完整代码8. 总结与扩展0.效果预览 在本教程中,我们将使用Processing编程语言来创建一个可爱的花朵生成器。通过封装花朵为一个类,并…

git教程, 命令行版

前言 git就是代码版本管理系统&#xff0c;很简单的作用就是每一次commit之后&#xff0c;修改文件都是跟上一次commit的仓库文件做对比&#xff0c;也可以调出历史的文件查看某次commit修改了什么东西 0环境准备&#xff1a; 安装git, 百度一下&#xff0c;然后打开cmd&…

教室管理系统的开发与实现(Java+MySQL)

引言 教室管理系统是学校和培训机构日常运营中不可或缺的工具。本文将介绍如何使用Java、Swing GUI、MySQL和JDBC开发一个简单而有效的教室管理系统&#xff0c;并涵盖系统的登录认证、教室管理、查询、启用、暂停和排课管理功能。 技术栈介绍 Java&#xff1a;作为主要编程…

[数据集][目标检测]导盲犬拐杖检测数据集VOC+YOLO格式4635张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4635 标注数量(xml文件个数)&#xff1a;4635 标注数量(txt文件个数)&#xff1a;4635 标注…

base SAS programming学习笔记(read raw files3)

使用LIST INPUT 来读入位置不固定的外部文件&#xff0c;如下所示&#xff1a; 1.LIST input格式 INPUT variable <$> :$符合表示字符&#xff0c;variable是读入的变量名&#xff1b;默认的数值和字符长度为8&#xff1b;可以使用length 语句为字符变量设置长度&#xf…

学习测试10-1自动化 python基础

下载python 要配置环境变量 进入Python的官方下载页面 http://www.python.org/download/安装PyCharm工具&#xff0c;网上可以下载&#xff0c;很多资源&#xff0c;也有免安装的版本&#xff0c;在网上找激活码 链接: https://pan.baidu.com/s/1Y6S_n3KbnjOdE9EDZ5nixw?pwdd…

使用Windows Linux 子系统安装 Tensorflow,并使用GPU环境

在Microsoft Store商店安装Ubuntu 20.04 使用 nvidia-smi 命令查看GPU信息&#xff0c;查看支持的CUDA版本&#xff0c;这里最高支持11.7 安装cuda工具集 进入官网&#xff1a;CUDA Toolkit Archive | NVIDIA Developer&#xff0c;现在对应版本&#xff0c;点击 配置平台&…

走进数组的奇妙之旅(1)

引言&#xff1a; 在前几篇文章中&#xff0c;我们深入探讨了函数的奥秘。在讲述函数知识的过程中&#xff0c;我们邂逅了一个新的概念&#xff0c;你或许还记得在演示 strcpy函数时&#xff0c;出现的这行代码&#xff1a;char1[20]{0};。当时&#xff0c;你是否感到好奇&…

前端组件化实践:Vue自定义加载Loading组件的设计与实现

摘要 随着前端技术的飞速发展&#xff0c;组件化开发已成为提高开发效率、降低维护成本的重要方法。本文介绍了前端Vue自定义加载Loading组件的设计思路与实现过程&#xff0c;该组件通过设置gif动画实现加载效果&#xff0c;可广泛应用于页面请求加载场景。通过该组件的实践&…

银行业务知识全篇(财务知识、金融业务知识)

第一部分 零售业务 1.1 储蓄业务 4 1.1.1 普通活期储蓄(本外币) 4 1.1.2 定期储蓄(本外币) 5 1.1.3 活期一本通 9 1.1.4 定期一本通 10 1.1.5 电话银行 11 1.1.6 个人支票 11 1.1.7 通信存款 13 1.1.8 其他业务规…

解决AI训练中的“Convergence Warning”报错:提高模型稳定性 ️‍♂️

解决AI训练中的“Convergence Warning”报错&#xff1a;提高模型稳定性 &#x1f3cb;️‍♂️ 解决AI训练中的“Convergence Warning”报错&#xff1a;提高模型稳定性 &#x1f3cb;️‍♂️摘要引言“Convergence Warning”报错的成因分析 &#x1f914;1. 学习率设置不当2…