经典链表问题:解析链表中的关键挑战

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介: 经典链表问题:解析链表中的关键挑战


公共子节点

例如这样一道题:给定两个链表,找出它们的第一个公共节点。

具体的题目描述我们来看看牛客的一道题

这里我们有四种解决办法:

采用集合或者哈希

思路是这样的,我们先把其中一个链表遍历放入Map中,然后遍历第二个第二个链表与Map中的对比,第一个相同的即为公共节点。

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        Map<ListNode, Integer>  map = new HashMap<>();
        while (pHead1 != null) {
            map.put(pHead1, pHead1.val);
            pHead1 = pHead1.next;
        }
        while (pHead2 != null) {
            if (map.containsKey(pHead2)) {
                return pHead2;
            }
            pHead2 = pHead2.next;
        }
        return null;
    }

采用栈

这种方法,我们需要两个栈把两个链表分别遍历入栈,然后同时弹出,相同且最晚出栈的那一组即为公共节点。

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        Stack<ListNode>  stack1 = new Stack<>();
        Stack<ListNode>  stack2 = new Stack<>();
        while (pHead1 != null) {
            stack1.push(pHead1);
            pHead1 = pHead1.next;
        }
        while (pHead2 != null) {
            stack2.push(pHead2);
            pHead2 = pHead2.next;
        }
        ListNode ret = null;
        while (stack1.size() > 0 && stack2.size() > 0) {
            if (stack1.peek() == stack2.peek()) {
                ret = stack1.pop();
                stack2.pop();
            } else {
                break;
            }
        }
        return ret;
    }

拼接两个字符串

先看下面的两个链表:

A:1-4-6-2-3-5

B:2-3-5

我们试着拼接一个

AB:1-4-6-2-3-5-2-3-5

BA:2-3-5-1-4-6-2-3-5

我们会发现链表只要有公共的节点,那么我们遍历AB与BA就会找到公共节点。

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        ListNode p1 =  pHead1;
        ListNode p2 = pHead2;
        while (p1 != p2) {
            p1 = p1.next;
            p2 = p2.next;
            //防止陷入死循环
            if (p1 != p2) {
                if (p1 == null) {
                    p1 = pHead2;
                }
                if (p2 == null) {
                    p2 = pHead1;
                }
            }
        }
        return p1;
    }

差和双指针

遍历两个链表记录两个链表的长度,然后先遍历较长链表(len1-len2)绝对值个节点,然后两个链表同时向前走,节点一样的时候就是公共节点。

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
        if (pHead1 == null || pHead2 == null) {
            return null;
        }
        ListNode p1 = pHead1;
        ListNode p2 = pHead2;
        int len1 = 0, len2 = 0;
        while (p1 != null) {
            p1 = p1.next;
            len1++;
        }
        while (p2 != null) {
            p2 = p2.next;
            len2++;
        }
        int sub = Math.abs(len1 - len2);
        ListNode current1 = pHead1;
        ListNode current2 = pHead2;
        if (len1 > len2) {
            int a = 0;
            while (a < sub) {
                current1 = current1.next;
                a++;
            }
        }
        if (len2 > len1) {
            int a = 0;
            while (a < sub) {
                current2 = current2.next;
                a++;
            }
        }
        while (current1 != current2) {
            current1 = current1.next;
            current2 = current2.next;
        }
        return current2;
    }

这段代码是一个Java方法,用于查找两个链表中的第一个公共节点。方法名为FindFirstCommonNode,接收两个参数pHead1和pHead2,分别表示两个链表的头节点。

首先,判断两个链表是否为空,如果有一个为空,则返回null。

然后,使用两个指针p1和p2分别遍历两个链表,计算它们的长度len1和len2。

接下来,计算两个链表长度之差的绝对值sub。

再接着,创建两个新的指针current1和current2,分别指向两个链表的头节点。如果链表1的长度大于链表2的长度,将current1向后移动sub个节点;如果链表2的长度大于链表1的长度,将current2向后移动sub个节点。

最后,同时遍历两个链表,直到找到第一个相同的节点,将其返回。

旋转链表

我们有两种思路:

  • 将前k部分与N-k部分分别反转,连接起来就解决了。
  • 用双指针找到倒数K的位置,具体实现如下:
public ListNode rotateRight(ListNode head, int k) {
     if(head==null || k==0){
         return head;
     }
     ListNode fast = head;
     ListNode slow = head;
     ListNode temp = head;
     int len = 0;
     while (head!=null){
         head = head.next;
         len++;
     }
     if(k%len==0){
         return temp;
     }
     while (k%len>0){
         k--;
         fast = fast.next;
     }
     while (fast.next!=null){
         fast = fast.next;
         slow = slow.next;
     }
     ListNode res = slow.next;
     fast.next = temp;
     slow.next=null;
return res;
    }
  1. 首先,判断链表是否为空或旋转位置数是否为0,如果满足任一条件,则直接返回原链表头节点。
  2. 初始化三个指针:fast、slow和temp,都指向链表头节点。同时,定义一个变量len用于记录链表的长度。
  3. 遍历链表,计算链表的长度。
  4. 判断旋转位置数k是否能被链表长度整除,如果能整除,则不需要旋转,直接返回原链表头节点。
  5. 如果旋转位置数k不能被链表长度整除,需要找到k对链表长度取模后的余数对应的节点位置。通过fast指针先向前移动k%len个位置,然后fast和slow指针同时向前移动,直到fast指针到达链表尾部。此时,slow指针所在的位置就是需要旋转后的新头节点。
  6. 将新头节点的下一个节点作为新链表的尾节点,将原链表的尾节点接到新链表的头部,形成新的链表。
  7. 返回新的链表头节点。
相关文章
|
24天前
|
存储 算法 C语言
【C语言】深入浅出:C语言链表的全面解析
链表是一种重要的基础数据结构,适用于频繁的插入和删除操作。通过本篇详细讲解了单链表、双向链表和循环链表的概念和实现,以及各类常用操作的示例代码。掌握链表的使用对于理解更复杂的数据结构和算法具有重要意义。
246 6
|
2月前
|
存储
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(一)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
2月前
|
存储 缓存
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)(二)
【初阶数据结构】深入解析单链表:探索底层逻辑(无头单向非循环链表)
|
6月前
|
存储 算法 数据可视化
深入解析力扣160题:相交链表的解决方法(哈希表法与双指针法详细图解)
深入解析力扣160题:相交链表的解决方法(哈希表法与双指针法详细图解)
|
6月前
|
SQL 算法 数据可视化
LeetCode题目92:反转链表ll 【python 递归与迭代方法全解析】
LeetCode题目92:反转链表ll 【python 递归与迭代方法全解析】
|
7月前
|
存储 C语言
深入解析C语言的动态数据类型单项链表技术
深入解析C语言的动态数据类型单项链表技术
64 0
|
7月前
|
存储
数据结构基础:一篇文章教你单链表(头插,尾插,查找,头删等的解析和代码)
数据结构基础:一篇文章教你单链表(头插,尾插,查找,头删等的解析和代码)
|
7月前
|
存储 机器学习/深度学习 NoSQL
作者推荐 |【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(链表)(二)
作者推荐 |【Redis技术进阶之路】「底层源码解析」揭秘高效存储模型与数据结构底层实现(链表)
87 0
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
76 2
|
2天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

热门文章

最新文章

推荐镜像

更多