当前位置: 首页 > news >正文

链表双指针经典习题

链表双指针经典习题

  • 链表的分解
    • 删除排序链表中的重复元素2(重复元素彻底删除)
      • 方法一:分解链表
      • 方式二:快慢指针
      • 递归解法
  • 链表的合并
    • 丑数2
    • 有序矩阵中第k小的元素
    • 查找和最小的k对数字
    • 两数相加
    • 两数相加2
  • 回文单链表
    • 回文链表
  • 迭代和递归翻转单链表
    • 反转链表
      • 方一:迭代
      • 方二: 递归

链表的分解

删除排序链表中的重复元素2(重复元素彻底删除)

链接
在这里插入图片描述

方法一:分解链表

/**
 * 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 {
    //1.分解链表 方式
    public ListNode deleteDuplicates(ListNode head) {
        ListNode uniqueDummy = new ListNode(101);
        ListNode repeatDummy = new ListNode(101);
        ListNode res=uniqueDummy;
        ListNode cur=head;
        //遍历原链表
        while(cur!=null){
            //cur节点是重复节点
            if(cur.next!=null && cur.val==cur.next.val || cur.val==repeatDummy.val){
                repeatDummy.next=cur;
                repeatDummy=repeatDummy.next;
            }else{
                //cur不是重复节点
                uniqueDummy.next=cur;
                uniqueDummy=uniqueDummy.next;
            }
            cur=cur.next;
        }
        uniqueDummy.next=null;

        return res.next;
    }
}

方式二:快慢指针


class Solution {
    //快慢指针方法,快指针探路 慢指针更新答案链表
    public ListNode deleteDuplicates(ListNode head) {
        ListNode dummy = new ListNode(101);
        dummy.next=head;
        ListNode slow=dummy;
        ListNode preFast=dummy;
        ListNode fast=head;
        while(fast!=null){
            if(fast.next!=null && fast.val!=preFast.val && fast.val!=fast.next.val){
                //fast节点不重复
                slow.next=fast;
                slow=slow.next;
            }
            if(fast.next==null && fast.val!=preFast.val){
                slow.next=fast;
                slow=slow.next;
            }
            fast=fast.next;
            preFast=preFast.next;
        }
        slow.next=null;
        return dummy.next;
    }
}

递归解法

/**
 * 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 {
    //递归解法
    //定义:给你一条头结点是head的链表 删除重复元素后返回头结点
    public ListNode deleteDuplicates(ListNode head) {
        //如果 只有一个节点 或者没有节点 就不用删除
        if(head==null || head.next==null){
            return head;
        }

        //如果head节点与后面的节点不同
        if(head.val!=head.next.val){
           head.next= deleteDuplicates(head.next);
           return head;
        }

        //如果head节点与后面的节点相同
        while(head.next!=null && head.val==head.next.val){
            head=head.next;
        }
       return deleteDuplicates(head.next);
    }
}

链表的合并

丑数2

链接在这里插入图片描述

class Solution {
    public int nthUglyNumber(int n) {
        int p2=1,p3=1,p5=1;//指向ugly中的第一个丑数
        int val2=1,val3=1,val5=1;//表示三个链表的当前节点
        int p=1;//指向ugly的索引,便于更新ugly
        int[]ugly=new int[n+1];//ugly[i]:第i个丑数
        while(p<=n){
            //找出三个链表中当前节点的最小值
            int minVal=Math.min(Math.min(val2,val3),val5);
            ugly[p++]=minVal;
            //更新三个链表的当前节点
            if(minVal==val2){
                val2=2*ugly[p2++];
            }
            if(minVal==val3){
                val3=3*ugly[p3++];
            }
            if(minVal==val5){
                val5=5*ugly[p5++];
            }
        }
        return ugly[n];
    }
}

有序矩阵中第k小的元素

链接在这里插入图片描述

class Solution {
    //用优先级队列辅助
    //思路:合并多条链表
    public int kthSmallest(int[][] matrix, int k) {
        //队列里存{matrix[i][j],i,j} 以便找到后面的元素
       PriorityQueue<int[]> pq=new PriorityQueue<int[]>(new Comparator<int[]>() {
                @Override
                public int compare(int[] o1, int[] o2) {
                    return o1[0]-o2[0];
                }
            });
        //maxtrix每一行相当于一条链表
        //先把各链表的头结点入队列
        for(int i=0;i<matrix.length;i++){
            pq.add(new int[]{matrix[i][0],i,0});
        }
        int res=0;
        while(!pq.isEmpty()&&k>0){
            int[] pollEle=pq.poll();
            res=pollEle[0];
            int i=pollEle[1],j=pollEle[2];
            //把(i,j+1)的元素入队列
            if(j+1<matrix[i].length){
                pq.add(new int[]{matrix[i][j+1],i,j+1});
            }
            k--;
        }
        return res;
    }
}

查找和最小的k对数字

链接在这里插入图片描述

//优先级队列+合并链表
class Solution {
    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        //队列里存{sum,i,j},sum是nums[i]+nums[j]
        PriorityQueue<int[]> pq=new PriorityQueue<int[]>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[0]-o2[0];
            }
        });
        int sz1=nums1.length;
        int sz2=nums2.length;
        //有sz1条链表,先把各链表的头结点入队列
        for(int i=0;i<sz1;i++){
            pq.add(new int[]{nums1[i]+nums2[0],i,0});
        }
        List<List<Integer>> res=new LinkedList<>();
        while(!pq.isEmpty()&&k>0){
            int[]pollEle=pq.poll();
            int i=pollEle[1];
            int j=pollEle[2];
            LinkedList<Integer> ele=new LinkedList();
            ele.add(nums1[i]);
            ele.add(nums2[j]);
            res.add(ele);

            //把[i,j+1]入队列
            if(j+1<nums2.length){
                pq.add(new int[]{nums1[i]+nums2[j+1],i,j+1});
            }
            k--;
        }
        return res;
    }
}

两数相加

链接
在这里插入图片描述

/**
 * 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 addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode p1=l1;
        ListNode p2=l2;
        ListNode dummy=new ListNode(-1);
        ListNode p=dummy;
        int carry=0,add=0;
        while(p1!=null&&p2!=null){
            add=p1.val+p2.val+carry;
            carry=add/10;//进位的
            add%=10;
            ListNode newNode=new ListNode(add);
            p.next=newNode;
            p=p.next;
            p1=p1.next;
            p2=p2.next;
        }
       while(p1!=null){
            add=p1.val+carry;
            carry=add/10;
            add%=10;
            ListNode newNode=new ListNode(add);
            p.next=newNode;
            p=p.next;
            p1=p1.next;
        }
          while(p2!=null){
            add=p2.val+carry;
            carry=add/10;
            add%=10;
            ListNode newNode=new ListNode(add);
            p.next=newNode;
            p=p.next;
            p2=p2.next;
        }
        if(carry!=0){
            //还有进位
            ListNode newNode=new ListNode(carry);
            p.next=newNode;
            p=p.next;
        }
        p.next=null;
        return dummy.next;
    }
}

两数相加2

链接在这里插入图片描述


class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Stack<Integer> stack=new Stack();
        //翻转l1链表
        while(l1!=null){
            stack.add(l1.val);
            l1=l1.next;
        }
        ListNode head1= new ListNode(stack.pop());
        ListNode p1=head1;
        while(!stack.isEmpty()){
            int cur=stack.pop();
            ListNode newNode=new ListNode(cur);
            p1.next=newNode;
            p1=p1.next;
        }
        p1.next=null;
        //翻转l2链表
        while(l2!=null){
            stack.add(l2.val);
            l2=l2.next;
        }
        ListNode head2= new ListNode(stack.pop());
        ListNode p2=head2;
        while(!stack.isEmpty()){
            int cur=stack.pop();
            ListNode newNode=new ListNode(cur);
            p2.next=newNode;
            p2=p2.next;
        }
        p2.next=null;
        //开始计算 跟两数相加1一样的
        p1=head1;
        p2=head2;
        int add=0,carry=0;
        while(p1!=null && p2!=null){
            add=p1.val+p2.val+carry;
            carry=add/10;
            add%=10;
            stack.add(add);
            p1=p1.next;
            p2=p2.next;
        }
        while(p1!=null){
            add=p1.val+carry;
            carry=add/10;
            add%=10;
            stack.add(add);
            p1=p1.next;
        }
        while(p2!=null){
            add=p2.val+carry;
            carry=add/10;
            add%=10;
            stack.add(add);
            p2=p2.next;
        }
        if(carry!=0){
            stack.add(carry);
        }
        ListNode dummy=new ListNode(-1);
        ListNode p=dummy;
        while(!stack.isEmpty()){
            int cur=stack.pop();
            ListNode newNode=new ListNode(cur);
            p.next=newNode;
            p=p.next;
        }
        p.next=null;
        return dummy.next;
    }
}

回文单链表

回文链表

链接
在这里插入图片描述
方法一:用栈来辅助

/**
 * 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 boolean isPalindrome(ListNode head) {
        Stack<Integer> stack=new Stack();
        ListNode cur=head;
        while(cur!=null){
            stack.add(cur.val);
            cur=cur.next;
        }
        cur=head;
        while(cur!=null){
            int val=cur.val;
            int stackVal=stack.pop();
            if(val!=stackVal){
                return false;
            }
            cur=cur.next;
        }
        return true;
    }
}

方法二:快慢指针

/**
 * 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 boolean isPalindrome(ListNode head) {
        ListNode fast=head,slow=head;
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
        }
        if(fast!=null){
            //奇数个 slow需要+1
            slow=slow.next;
        }
        //从①head->slow-1 ②fast->slow

       ListNode head2= reverse(slow); 

       while(head2!=null){
        if(head.val!=head2.val){
            return false;
        }
        head=head.next;
        head2=head2.next;
       }
       return true;
    }
    //返回翻转后的链表
    ListNode reverse(ListNode head){
        if(head==null){
            return null;
        }
        if(head.next==null){//一个节点
            return head;
        }
        ListNode pre=head;
        ListNode cur=head.next;
        pre.next=null;
        while(cur!=null){
            ListNode next=cur.next;
            cur.next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
    }
}

迭代和递归翻转单链表

反转链表

在这里插入图片描述

方一:迭代

/**
 * 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) {
        if(head==null){
            return null;
        }
        ListNode pre=head,cur=head.next;
        pre.next=null;
        while(cur!=null){
            ListNode next=cur.next;
            cur.next=pre;
            pre=cur;
            cur=next;
        }
        return pre;
    }
}

方二: 递归

/**
 * 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 {
    //递归翻转
    //定义:翻转以head为头结点的链表后并返回头结点
    public ListNode reverseList(ListNode head) {
        //只有一个节点或者是没有节点 不用翻转直接返回
        if(head==null||head.next==null){
            return head;
        }
        //翻转head.next链表 然后head接在他的后面
        ListNode realHead=reverseList(head.next);
        ListNode tail=head.next;
        tail.next=head;
        head.next=null;
        return realHead;
    }
}
http://www.dtcms.com/a/55176.html

相关文章:

  • 为什么要开源?
  • lsblk命令linux查询设备信息
  • 深度学习入门指南
  • while-经典面试题实战
  • c++ 类成员指针及其与`std::bind`交互使用的简单说明
  • 使用 Docker 部署 BaGet 并推送 NuGet 包
  • 前端小食堂 | Day10 - 前端路由の时空裂隙
  • Java是值传递还是引用传递
  • 特征选择之特征重要性排序(基于树模型)
  • 如何用Kimi生成PPT?秒出PPT更高效!
  • 学习threejs,Animation、Core、CustomBlendingEquation、Renderer常量汇总
  • Java 依赖冲突终极解法:Maven 依赖树分析与强制版本锁定
  • 最左侧冗余覆盖子串
  • 【接口封装】——18、添加目录项列表响应
  • AMD(xilinx) FPGA书籍推荐
  • RabittMQ保证消息不丢失的几种手段
  • Spring Boot 项目中慢SQL优化方案
  • 基于微信小程序的超市购物系统+论文源码调试讲解
  • 【文心索引】搜索引擎测试报告
  • 【计算机网络】计算机网络的性能指标——时延、时延带宽积、往返时延、信道利用率
  • Trae IDE新建C#工程
  • 双目立体视觉(6.1)测距
  • 2025年科技趋势深度解析:从“人工智能+”到量子跃迁的技术革命
  • 练习题:72
  • 时序数据库 TDengine 化工新签约:存储降本一半,查询提速十倍
  • 基于NIST后量子算法的混合加密系统
  • 动态规划背包刷题
  • 量化交易全面入门指南(2025最新版)
  • 智能疫苗查漏补种智能体创建逻辑和步骤
  • Nodemailer使用教程:在Node.js中发送电子邮件