【Java】【python】leetcode刷题记录--双指针

双指针也一般称为快慢指针,主要用于处理链表和数组等线性数据结构。这种技巧主要涉及到两个指针,一个快指针(通常每次移动两步)和一个慢指针(通常每次移动一步)。快指针可以起到’探路‘的作用,给慢指针修改。
适用范围:

  1. 一般适用于字符串/数组/链表。
  2. 对数组/字符串/链表进行更改(反转、删除、增添)。

27 移除元素

题目链接
对于数组的移动、删除、插入,都可以使用双指针来处理。数组不像是链表或者以链表为底层设计的数据结构,可以从中间移除元素(例如python的list或者cpp的vector),因此如果每次都要使用暴力解法(双重for循环,每次把后面的元素进行前移),那就会导致时间复杂度为O(n^2),非常低效。而双指针(或者叫快慢指针)可以有效的利用一快一慢的特点,用快指针去”探路“,查看是否需要更改内容,而慢指针则用来配合快指针进行数组的修改,非常好用。
对于本题,我们的目标是将给定的val进行覆盖,因此可以快慢指针,快指针和慢指针开始都在同一位置,如果没有需要val,则两个指针同时前进。而如果遇到了需要覆盖的元素,就将快指针后移,直到其指向的值不为val,也就可以在下一次循环中覆盖慢指针的值,也就是val。

class Solution {
    public int removeElement(int[] nums, int val) {
       int fast=0,slow=0;
       if(nums.length == 0){
        return 0;
       }

       while(fast<nums.length){
            if(nums[fast] == val){
                fast++;
            }else{
                nums[slow] = nums[fast];
                slow++;
                fast++;
            }
       }
       return slow;
    }
}

344.反转字符串

题目链接
本题就是双指针比较简单的用法,一头一尾进行交换即可。左右指针不断缩紧直到左指针大于等于右指针为主。

class Solution {
    public void reverseString(char[] s) {
        int left=0,right=s.length-1;

        while(left<right){
            char tmp = s[left];
            s[left++] = s[right];
            s[right--] = tmp;
        }
    }
}

151 反转字符串中的单词

题目链接
在java里,字符串是不可变的,即无法修改。使用split方法可以将字符串转化为字符串数组。用trim和split一起处理字符串的格式(防止错误的空格),然后只需要对字符串数组进行双指针的操作即可。

res是经过处理的字符串数组,例如s是”hello world",则res[0]是hello,res[1]为world。

class Solution {
    public String reverseWords(String s) {
        String res[] = s.trim().split("\\s+");

        int slow=0,fast=res.length-1;
        while(slow<fast){
            String tmp=res[fast];
            res[fast--] = res[slow];
            res[slow++] = tmp;

        }

        return String.join(" ",res);
    }
}

上述的内容都是针对数组,而双指针在链表里也及其常用。

206 反转链表

题目链接
如果单独定义一个链表会导致空间的浪费,而如果暴力做会导致时间复杂度为O(n^2),因此可以定义一个空指针,并且将整个链表倒转。比如我们一开始可以理解是这样:
在这里插入图片描述
可以申请一个空指针prev,在1的左边,让1的指针指向prev,也就是只改变指针的方向即可。代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode cur = head;
        ListNode temp = null;

        while(cur!=null){
            temp = cur.next;
            cur.next = prev;
            prev = cur;
            cur = temp;
        }

        return prev;       

    }
}

19. 删除链表的倒数第 N 个结点

题目链接
如果不止一趟遍历来做这个题也是可以的,但是很麻烦,这里可以用快慢指针来做:先让快指针走n次,再让快慢指针同时走,最后去掉slow后的结点即可。
但对于链表的题目,我们最好准备一个虚拟头节点,因为会涉及到很多删除头节点的情况。比如我们的链表只有1个节点,或者两个节点但是要删除头节点,加入特判语句会让代码不那么优雅。
同时返回的时候,也不能返回head,如果只有一个节点,那么我们返回的就是被删除的节点了(或者两个节点但是要删除头节点也是一样的)。代码如下:

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;

        ListNode slow = dummy;
        ListNode fast = dummy;
        
        for(int i=0; i<n; i++){
            fast = fast.next;
        }

        while(fast.next!=null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;

        return dummy.next;
    }
}

面试题 02.07. 链表相交

题目链接
这题只是稍稍麻烦了点,但是思路还是很简单的。先进行a和b的遍历,计算出a和b链表的长度,再让两个指针在同一起跑线上,即是双指针的方法。例如a的长度更长,那么就可以让a先走(cnt_a - cnt_b)步,这样指针就在同一起跑线,然后进行节点的对比即可。

public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int cnt_a=0,cnt_b=0;
        ListNode a = headA;
        ListNode b = headB;

        // a或者b为空

        //
        while(a!=null){
            a = a.next;
            cnt_a++;
        }
        while(b!=null){
            b = b.next;
            cnt_b++;
        }
        // 对齐
        a = headA;
        b = headB;
        if (cnt_a > cnt_b) {
            for (int i = 0; i < cnt_a - cnt_b; i++) {
                a = a.next;
            }
        } else if (cnt_a < cnt_b) {
            for (int i = 0; i < cnt_b - cnt_a; i++) {
                b = b.next;
            }
        }
        // 找交点
        while(a!=null&&b!=null){
            if(a == b){
                return a;
            }else{
                a = a.next;
                b = b.next;
            }
        }
        return null;

    }
}

142 环形链表 II

题目链接
顺带一提,如果判断链表是否成环,也可以用双指针进行判断,代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if (head == null || head.next == null) {
            return false;
        }

        ListNode slow = head;
        ListNode fast = head.next;

        while (fast != null && fast.next != null) {
            if (slow == fast) {
                return true; // 快指针和慢指针相遇,说明存在环
            }
            slow = slow.next; // 慢指针每次移动一步
            fast = fast.next.next; // 快指针每次移动两步
        }

        return false; // 快指针到达链表末尾,说明不存在环
    }
}

对于本题,需要动笔画一画:

在这里插入图片描述
我们将整个链表分为x y z三部分,而快指针和慢指针一开始都在head。slow每次走一步,而fast每次是两步。这样一定会有一个相遇点p(图中的y下面的点)。对走过的路径分析,slow走过了x+y,而fast是x+y+n*(y+z),而快指针走的长度是slow的二倍(可以自己试一试),因此可以计算得到x的值。
观察得到的表达式,也就是如果有一个新指针再从head开始出发,每次走一步,而slow从p点出发,那么两指针交点则为环入口。因此可以写代码如下:

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;

        while(fast!=null&&fast.next!=null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow==fast){
                ListNode res = head;
                while(slow!=res){
                    slow = slow.next;
                    res = res.next;
                }
                return res;
            }
        }
        return null;

    }
}

15 三数之和

题目链接

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Mybatis】映射文件中获取参数的符号#{}和${}的区别

在xml映射文件中获取参数的符号都是用的#{}的方式&#xff0c;其实Mybatis还支持另一种符号来接收传递过来的参数值&#xff0c;就是${}&#xff0c;他们是区别就在与底层使用jdbc的statement不一样 #{}对应的是PreparedStatementd对象来执行sql语句 ${}对应的是Statement对象…

C语言-01_HelloWord

文章目录 1.C程序运行机制2.HelloWorld的剖析① main()② 函数体③ printf()④ 标准库、头文件 3.输出3.1 printf()标准格式3.2 占位符3.3 输出格式 1.C程序运行机制 过程1&#xff1a;编辑 编写C语言源程序代码&#xff0c;并已文件的形式存储到磁盘中。源程序文件以“.c”作…

100个 Unity小游戏系列五 -Unity 抽奖游戏专题三老虎机游戏

一、演示效果 二、知识点讲解 2.1 布局 public void CreateItems(SlotsData[] slotsData){isInited false;slotsPrizeList new List<SlotsData>();for (int i 0; i < slotsData.Length; i){var item slotsData[i];slotsPrizeList.Add(item);}float bottomY -it…

AI赋能数字人:打造与语音节奏完美匹配的高质量手势动画

在数字化时代,人机交互正以前所未有的速度进化,而AI数字人的发展正是这一进程中的重要里程碑。近期,一项旨在根据语音内容自动生成匹配手势的技术方案引起了广泛关注,该技术不仅增强了数字人的表现力,也为远程沟通、教育、娱乐等多个领域带来了革新性的应用潜力。本文将深…

手机版AI写作软件哪个好用?5款AI写作软件分享

在这个快节凑的时代&#xff0c;人们对于高效、便捷的创作方式很是追求。尤其是在人工智能技术发展迅速的今天&#xff0c;AI写作软件的出现&#xff0c;让很多自媒体创作者都会想到在手机上面进内容创作&#xff0c;这样不仅能提高工作效率&#xff0c;而且工作的自由度会更高…

APM2.8如何做加速度校准

加速度的校准建议准备一个六面平整&#xff0c;边角整齐的方形硬纸盒或者塑料盒&#xff0c;如下图所示&#xff0c;我们将以它作为APM校准时的水平垂直姿态参考&#xff0c;另外当然还需要一块水平的桌面或者地面 首先用双面泡沫胶或者螺丝将APM主板正面向上固定于方形盒子上&…

农产品产品防伪防窜货+二维码防伪+溯源系统源码全平台一物一码数字化防伪防窜货和溯源查询系统

农产品产品防伪防防窜货二维码防伪溯源系统源码全平台一物一码数字化防伪防窜货和溯源查询系统 产品防伪防防窜货二维码防伪溯源系统源码&#xff0c;该系统采用最简单易用的phpMySQL进行搭建&#xff0c;拥有完善的网站前后台&#xff0c;通过对每件产品生产线上的单品、二级…

【数据结构与算法 经典例题】返回单链表的倒数第 k 个节点

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;数据结构与算法刷题系列&#xff08;C语言&#xff09; 期待您的关注 目录 一、问题描述 二、解题思路 方法一:计数器方式 方法…

leetCode.84. 柱状图中最大的矩形

leetCode.84. 柱状图中最大的矩形 题目思路 代码 class Solution { public:int largestRectangleArea( vector<int>& h ) {int n h.size();vector<int> left( n ), right( n );stack<int> st;// 求每个矩形的第一个小于左边界的矩形 - 用单调栈for ( …

Java基础:面向对象(二)

Java基础&#xff1a;面向对象&#xff08;二&#xff09; 文章目录 Java基础&#xff1a;面向对象&#xff08;二&#xff09;1. 面向对象编程思想2. 类与对象2.1 类2.1.1 类的定义2.1.2 成员变量2.1.3 局部变量 2.2 对象2.2.1 对象的定义2.2.2 对象的使用2.2.3 对象创建的原理…

gmssl vs2010编译

1、虚拟机win10 x64&#xff0c;离线安装vs2010和2010sp1补丁&#xff1b; 2、安装ActivePerl_v5.28.1.0000和nasm-2.16.03-installer-x64均是默认完整安装&#xff1b; nasm官网下载&#xff1a; Index of /pub/nasm/releasebuilds/2.16.03/win64https://www.nasm.us/pub/nas…

JavaScript基础(十)

上一篇学了各种数组方法&#xff0c;正好先做个练习回忆一下: 排序并去重 我随便写一组数&#xff0c;要求排好并去掉重复的: var arr [2,8,1,7,2,6,1,5,2,7,6,5]; for (var i0; i<arr.length; i){ for (var ji1; j<arr.length; j){ if(arr[i]arr[j]){ arr.splice(j,1)…

七个很酷的GenAI LLM技术性面试问题

不同于互联网上随处可见的传统问题库&#xff0c;这些问题需要跳出常规思维。 大语言模型(LLM)在数据科学、生成式人工智能(GenAI)和人工智能领域越来越重要。这些复杂的算法提升了人类的技能&#xff0c;并在诸多行业中推动了效率和创新性的提升&#xff0c;成为企业保持竞争…

PHP:phpmyadmin 将查询数据导出csv

1、输入你的SQL查询出结果 2、查出数据以后拖到最下方【导出】 3、导出CSV

搜维尔科技:拒绝毒品行为能力评估与训练系统应用案例

用户名称&#xff1a;山西医科大学 主要产品&#xff1a;虚拟现实复吸风险评估与干预系统 虚拟现实复吸风险评估与干预系统主要是为了解决物质使用障碍患者在临床治疗及康复回归正常生活出现的高复发现象⸺对毒品失控的渴求难以预测控制的问题。 整套系统由软件和硬件两部分…

RK3568平台(camera篇)V4L2查询获取设置设备

一.查询设备能力VIDIOC_QUERYCAP struct v4l2_capability cap; ioctl(fd, VIDIOC_QUERYCAP, &cap) struct v4l2_capability 结构体描述了视频采集设备的 driver 信息。 struct v4l2_capability { __u8 driver[16]; // 驱动名字 __u8 card[32]; // 设备名字 __u8 bus_inf…

基础技术-ELF系列2-ELF文件进阶与libelf库

成就更好的自己 本篇是基础技术系列中ELF相关技术的第二篇&#xff0c;将会详细介绍一下ELF文件的结构。 没有看过之前的文章的朋友请重新开始&#xff0c;博主观点比较清奇&#xff0c;否则可能会有一些不太明白的地方&#xff1a; 基础技术-ELF系列(1)-ELF文件基础-CSDN博…

STM32Cube系列教程11:使用STM32 RNG硬件随机数模块生成彩票号码

文章目录 配置RNG模块编写代码获取生成的随机数运行测试 今天写段代码测试一下STM32U083RC的(RNG)硬件随机数模块 顺便写个小demo生成7位真随机数的彩票号码&#xff0c;帮助那些买彩票还有选择困难症的人群 (doge)(手动狗头)。 全部代码以上传到github&#xff1a;https://gi…

Java注释

Java注释有三种&#xff1a; ①单行注释&#xff1a;// 注释内容 ②多行注释&#xff1a;/* 注释内容 */ ③文档注释&#xff1a;/** 注释内容(有要求) */ 文档注释内容必须为 Javadoc标签。 一行一个&#xff0c;以*开头&#xff0c;加标签和标签内容。 例如&#xff1a;…

【RocketMQ】安装RocketMQ5.2.0(单机版)

下载 官网下载地址&#xff1a;下载 | RocketMQ github地址&#xff1a;Tags apache/rocketmq GitHub 选择对应的版本下载。https://dist.apache.org/repos/dist/release/rocketmq/5.2.0/rocketmq-all-5.2.0-bin-release.zip 5.2.0的二进制包&#xff1a;下载地址 5.2.0的…