一、题目:两个链表的第一个公共节点

题目:输入两个链表,找出它们的第一个公共结点。

  链表结点定义如下,这里使用C#语言描述:

    public class Node{public int key;public Node nextNode;public Node(int key){this.key = key;}}

二、解题思路

2.1 蛮力法

  碰到这道题,很多人的第一反应就是蛮力法:在第一链表上顺序遍历每个结点,每遍历到一个结点的时候,在第二个链表上顺序遍历每个结点。如果在第二个链表上有一个结点和第一个链表上的结点一样,说明两个链表在这个结点上重合,于是就找到了它们的公共结点。如果第一个链表的长度为m,第二个链表的长度为n,显然该方法的时间复杂度是O(mn)

2.2 借助外部空间法

  首先,经过分析我们发现两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可能像X,如下图所示,两个链表在值为6的结点处交汇:

  如果两个链表有公共结点,那么公共结点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,最后一个相同的结点就是我们要找的结点。But,在单链表中只能从头结点开始按顺序遍历,最后才能到达尾结点。最后到达的尾结点却要最先被比较,这是“后进先出”的特性。于是,我们可以使用栈的特点来解决这个问题:分别把两个链表的结点放入两个栈里,这样两个链表的尾结点就位于两个栈的栈顶,接下来比较两个栈顶的结点是否相同。如果相同,则把栈顶弹出接着比较下一个栈顶,直到找到最后一个相同的结点

    public static Node FindFirstCommonNode(Node head1, Node head2){if(head1 == null || head2 == null){return null;}Stack<Node> stack1 = new Stack<Node>();Stack<Node> stack2 = new Stack<Node>();while(head1 != null){stack1.Push(head1);head1 = head1.nextNode;}while(head2 != null){stack2.Push(head2);head2 = head2.nextNode;}Node node1 = null;Node node2 = null;Node common = null;while(stack1.Count > 0 && stack2.Count > 0){node1 = stack1.Peek();node2 = stack2.Peek();if (node1.key == node2.key){common = node1;stack1.Pop();stack2.Pop();}else{break;}}return common;}

  在上述思路中,我们需要用两个辅助栈。如果链表的长度分别为m和n,那么空间复杂度是O(m+n)。这种思路的时间复杂度也是O(m+n)。和最开始的蛮力法相比,时间效率得到了提高,相当于是用空间消耗换取了时间效率

2.3 不借助外部空间法

  那么,可不可以不借助栈来实现了呢?答案是可以的,我们可以首先遍历两个链表得到它们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个结点。在第二次遍历的时候,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到的第一个相同的结点就是它们的第一个公共结点

  比如在上图的两个链表中,我们可以先遍历一次得到它们的长度分别为5和4,也就是较长的链表与较短的链表相比多一个结点。第二次先在长的链表上走1步,到达结点2。接下来分别从结点2和结点4出发同时遍历两个结点,直到找到它们第一个相同的结点6,这就是我们想要的结果。

    public static Node FindFirstCommonNode(Node head1, Node head2){// 得到两个链表的长度int length1 = GetListLength(head1);int length2 = GetListLength(head2);int diff = length1 - length2;Node headLong = head1;Node headShort = head2;if (diff < 0){headLong = head2;headShort = head1;diff = length2 - length1;}// 先在长链表上走几步for (int i = 0; i < diff; i++){headLong = headLong.nextNode;}// 再同时在两个链表上遍历while (headLong != null && headShort != null && headLong != headShort){headLong = headLong.nextNode;headShort = headShort.nextNode;}Node commonNode = headLong;return commonNode;}private static int GetListLength(Node head){int length = 0;Node tempNode = head;while (tempNode != null){tempNode = tempNode.nextNode;length++;}return length;}

  上述思路与借助栈的方法的时间复杂度都是O(m+n),但我们不再需要辅助的栈,因此提高了空间效率。

三、单元测试

3.1 测试用例:功能测试与特殊输入测试

    [TestClass]public class CommonNodeHelperTest{private void DestoryNode(Node node){if (node != null){node = null;}}// 第一个公共结点在链表中间// 1 - 2 - 3 \//            6 - 7//     4 - 5 /
        [TestMethod]public void FindTest1(){Node node1 = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);Node node4 = new Node(4);Node node5 = new Node(5);Node node6 = new Node(6);Node node7 = new Node(7);// firstnode1.nextNode = node2;node2.nextNode = node3;node3.nextNode = node6;node6.nextNode = node7;// secondnode4.nextNode = node5;node5.nextNode = node6;Node actual = CommonNodeHelper.FindFirstCommonNode(node1, node4);Assert.AreEqual(actual.key, 6);DestoryNode(node1);DestoryNode(node2);DestoryNode(node3);DestoryNode(node4);DestoryNode(node5);DestoryNode(node6);DestoryNode(node7);}// 没有公共结点// 1 - 2 - 3 - 4//            // 5 - 6 - 7
        [TestMethod]public void FindTest2(){Node node1 = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);Node node4 = new Node(4);Node node5 = new Node(5);Node node6 = new Node(6);Node node7 = new Node(7);// firstnode1.nextNode = node2;node2.nextNode = node3;node3.nextNode = node4;// secondnode5.nextNode = node6;node6.nextNode = node7;Node actual = CommonNodeHelper.FindFirstCommonNode(node1, node5);Assert.AreEqual(actual, null);DestoryNode(node1);DestoryNode(node2);DestoryNode(node3);DestoryNode(node4);DestoryNode(node5);DestoryNode(node6);DestoryNode(node7);}// 公共结点是最后一个结点//         5 - 6 \//                7// 1 - 2 - 3 - 4 /
        [TestMethod]public void FindTest3(){Node node1 = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);Node node4 = new Node(4);Node node5 = new Node(5);Node node6 = new Node(6);Node node7 = new Node(7);// firstnode1.nextNode = node2;node2.nextNode = node3;node3.nextNode = node4;node4.nextNode = node7;// secondnode5.nextNode = node6;node6.nextNode = node7;Node actual = CommonNodeHelper.FindFirstCommonNode(node5, node1);Assert.AreEqual(actual.key, 7);DestoryNode(node1);DestoryNode(node2);DestoryNode(node3);DestoryNode(node4);DestoryNode(node5);DestoryNode(node6);DestoryNode(node7);}// 公共结点是第一个结点// 1 - 2 - 3 - 4 - 5// 两个链表完全重合
        [TestMethod]public void FindTest4(){Node node1 = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);Node node4 = new Node(4);Node node5 = new Node(5);Node node6 = new Node(6);Node node7 = new Node(7);// first & secondnode1.nextNode = node2;node2.nextNode = node3;node3.nextNode = node4;node4.nextNode = node5;Node actual = CommonNodeHelper.FindFirstCommonNode(node1, node1);Assert.AreEqual(actual.key, 1);DestoryNode(node1);DestoryNode(node2);DestoryNode(node3);DestoryNode(node4);DestoryNode(node5);DestoryNode(node6);DestoryNode(node7);}// 输入的两个链表有一个空链表
        [TestMethod]public void FindTest5(){Node node1 = new Node(1);Node node2 = new Node(2);Node node3 = new Node(3);Node node4 = new Node(4);Node node5 = new Node(5);// first & secondnode1.nextNode = node2;node2.nextNode = node3;node3.nextNode = node4;node4.nextNode = node5;Node actual = CommonNodeHelper.FindFirstCommonNode(node1, null);Assert.AreEqual(actual, null);DestoryNode(node1);DestoryNode(node2);DestoryNode(node3);DestoryNode(node4);DestoryNode(node5);}// 输入的两个链表均为空链表
        [TestMethod]public void FindTest6(){Node actual = CommonNodeHelper.FindFirstCommonNode(null, null);Assert.AreEqual(actual, null);}}

3.2 测试结果:用例通过情况与代码覆盖率

  (1)用例通过情况

  (2)代码覆盖率

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

转载于:https://www.cnblogs.com/edisonchou/p/4822675.html

剑指Offer面试题:31.两个链表的第一个公共节点相关推荐

  1. 剑指offer面试题52. 两个链表的第一个公共节点(双指针法)

    题目描述 输入两个链表,找出它们的第一个公共节点. 思路 详见链接 代码 class Solution:def getIntersectionNode(self, headA:ListNode, he ...

  2. 《剑指Offer》52:两个链表的第一个公共节点

    题目 输入两个链表,找出它们的第一个公共节点. public static class ListNode{public int val;public ListNode next;public List ...

  3. 剑指Offer+第37题+两个链表的第一个公共节点+java

    题目:输入两个链表,找出它们的第一个公共结点. 面试的时候碰到这道题,很多应聘者的第一反应就是蛮力法:在第一链表上顺序遍历每个结点,没遍历到一个结点的时候,在第二个链表上顺序遍历每个结点.如果在第二个 ...

  4. 剑指offer面试题[37]-两个链表的第一个公共结点

    题目描述 输入两个链表,找出它们的第一个公共结点. /* struct ListNode {int val;struct ListNode *next;ListNode(int x) :val(x), ...

  5. 剑指offer(C++)-JZ52:两个链表的第一个公共结点(数据结构-链表)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 题目描述: 输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空.(注意因 ...

  6. 【剑指offer-Java版】37两个链表的第一个公共结点

    两个链表中的第一个公共顶点: 解法一:两次遍历即可 第一次遍历找到两个链表的长度,求出差值k,然后较长的:链表先走k步,之后两个链表同时走,直到遇到第一个相同的结点为止 解法二:辅助栈,先顺序遍历并将 ...

  7. 剑指offer——面试题31:连续子数组的最大和

    剑指offer--面试题31:连续子数组的最大和 Solution1: 第一次做这道题.. 讲道理是这是标准的动态规划的题目,可是思路未完全想好. min_element(iterator, iter ...

  8. 剑指offer——面试题57:删除链表中重复的结点

    剑指offer--面试题57:删除链表中重复的结点 Solution1: 删两遍,自己想的破算法.理论上时间复杂度也是O(n)O(n)O(n),并非最优解. /* struct ListNode {i ...

  9. 【LeetCode】剑指 Offer 52. 两个链表的第一个公共节点

    [LeetCode]剑指 Offer 52. 两个链表的第一个公共节点 文章目录 [LeetCode]剑指 Offer 52. 两个链表的第一个公共节点 一.双指针 一.双指针 设 "第一个 ...

最新文章

  1. bat 命令返回结果_bat教程[284] unzip解压
  2. 深度学习核心技术精讲100篇(二十九)-基于内容和上下文的音乐推荐
  3. Web Deploy发布网站及常见问题解决方法(图文)
  4. C语言实用算法系列之学生管理系统_单向链表内操作_提取排序规则
  5. HDU 3555 Bomb (数位DP)
  6. 【LeetCode笔记】剑指 Offer 93. 复原 IP 地址(Java、DFS、字符串)
  7. 无法生成“F:\system voiume information”下的常规文件夹列表拒绝访问
  8. MVC3.0 中Razor 学习
  9. 自定义char类型字段
  10. 国产Linux二十年揭秘
  11. OPPO R9sPlus怎么刷机 OPPO R9sPlus的刷机教程 OPPO R9sPlus完美解除账号锁
  12. 人物-周鸿祎:周鸿祎
  13. 面向数字孪生城市的智能化全息测绘(论文摘抄)
  14. 什么是中台,为什么要中台?一篇文章带你了解中台的概念!
  15. 手机点餐系统概述_廖师兄 微信点餐系统 springcloud学习笔记
  16. Ubuntu 20.04 系统自带中文输入法在PyCharm只能输入3个字母的问题
  17. [AV1] DC Intra Prediction
  18. 如何让内容运营渗透产品,带动产品高速成长
  19. Ubuntu搭建深度学习环境(3090显卡)
  20. 什么是蓝筹股| 一线蓝筹股|二线蓝筹

热门文章

  1. wincc与SQL Server数据库通讯的方法介绍
  2. 小程序商城后台技术选型
  3. dw html5中怎么设置图片自动切换,DW制作九宫格全屏亮灯轮播图片且自动切换图片教程...
  4. VB 变量的声明及作用域
  5. 快来天津科技大学找我玩
  6. JavaScript对象 1
  7. 打印表格打印机没有反应_windows10下office2016文档和表格 hp打印机 按打印没反应解决办法...
  8. 关于Allan方差分析陀螺仪误差的几个摘要
  9. linux 计算标准差,shell计算均值和标准差的工具:datamash
  10. mysql使用jdbc进行批量插入时把事务设为手动提交比事务自动提交速度快了10倍