剑指Offer面试题37:两个链表的第一个公共节点
来源:互联网 发布:邓紫棋怎么不火了知乎 编辑:程序博客网 时间:2024/05/21 12:40
以下内容参考自博客:http://blog.csdn.net/derrantcm/article/details/46761093
题目:两个链表的第一个公共节点
输入两个链表,找出他们的第一个公共节点。
算法分析:
算法1.直接法
在链表上顺序遍历每个节点,每遍历一个节点的时候,在第二个链表上顺序遍历每个节点。如果在第二个链表上有一个节点和第一个链表上的节点相同,说明两个链表在这个节点上重合,于是就找到了他们的公共节点。如果第一个链表的长度为m,第二个链表的长度为n,显然该方法的时间复杂度为O(mn).
算法2.使用栈
由于两个链表是单向链表,因此从某一节点开始,他们的pNext都指向了下一节点,但由于是单向链表,每个节点只有一个pNext,因此从第一个公共节点开始后,他们的所有节点都是重合的,不可能再出现分叉。所以两个有公共节点的链表,拓扑形状看起来像Y,而不是X。
如果存在共同节点的话,那么从该节点起,两个链表之后的元素都是相同的。也就是说两个链表从尾部往前到某个点,节点都是一样的。我们可以用两个栈分别来装这两条链表。这样两个链表的尾节点有位于两个栈的栈顶,接下来比较两个栈顶节点是否相同。如果相同,则把栈顶弹出,接着比较下一个栈顶,直到找到最后一个相同的节点。
在上述思想中,我们需要用到两个辅助栈,如果两个链表的长度分别为m和n的话,那个空间复杂度为O(m+n)。这种思想的时间复杂度也是O(m+n)。和最开始的直接法相比,时间效率得到了提高,相当于用时间效率换取了空间效率。
算法3.先行法
首先遍历两个链表得到他们的长度,就能知道那个链表比较长,以及长的链表比短的链表多几个节点。在第二次遍历的时候,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共节点。
这种思想的时间复杂度也是O(m+n),但我们不再需要辅助栈,因此提高了空间的效率。
算法4.使用哈希表
利用hash表的特点,想将链表1放入hashMap中,并设置每个键对应的值为空(因为这里不需要用到hashMap的值),然后循环第二个链表,判断第二个链表的每一个节点在hashMap中是否都存在相同的键,如果是,则表明找到 了第一个相同的节点,返回该节点,即返回了第一个相同的公共节点。
遇到的问题:
1.一个警告:The static method test3() from the type Solution should be accessed in a static way
* 原因:静态方法在对象创建前就存在了,它的使用不依赖对象是否被创建,所以可以用"类.方法"的方式调用,而不需要使用“对象.方法”的方式进行调用。
2.Java中单向链表的建立:
private static class ListNode{int val;ListNode next;/*public ListNode(){ //无参构造函数,可以不写,下文没有用到}*/public ListNode(int val){this.val = val;}@Overridepublic String toString(){return val + "";}}增加链表中成员的方法:1-2-3\6-74-5/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n6;n6.next = n7;n4.next = n5;n5.next = n6;算法参考:http://blog.csdn.net/derrantcm/article/details/467610933、得到链表长度:private static int getListLength(ListNode head){int result = 0;while(head != null){result++;head = head.next;}return result;}算法2源程序:/************************************************************** * Copyright (c) 2016, * All rights reserved. * 版 本 号:v1.0 * 题目描述:两个链表的第一个公共节点* 输入两个链表,找出他们的第一个公共节点。* 1-2-3\ 6-7 4-5/* 例如,该链表的第一个公共节点为6。* 输入描述:无* 程序输出:找到的第一个公共节点是:6*找到的第一个公共节点是:null*找到的第一个公共节点是:7*找到的第一个公共节点是:1** 问题分析: 1.一个警告:The static method test3() from the type Solution should be accessed in a static way* 原因:静态方法在对象创建前就存在了,它的使用不依赖对象是否被创建,所以可以用"类.方法"的方式调用* 2.单向链表的生成方法:详见程序* 3.得到链表长度:详见程序* 算法描述:首先遍历两个链表得到他们的长度,就能知道那个链表比较长,以及长的链表比短的链表多几个节点。* 在第二次遍历的时候,在较长的链表上先走若干步,接着再同时在两个链表上遍历,找到的第一个相同的节点就是他们的第一个公共节点。*这种思想的时间复杂度也是O(m+n),但我们不再需要辅助栈,因此提高了空间的效率。* 完成日期:2016-09-24***************************************************************/ package org.marsguo.offerproject37;class Solution{/*链表节点类*/private static class ListNode{//ListNode被声明为了内部类int val;ListNode next;/*public ListNode(){//无参构造函数,可以不写,下文没有用到}*/public ListNode(int val){this.val = val;}@Overridepublic String toString(){return val + "";}} /** * 找两个结点的第一个公共结点,如果没有找到返回null,方法比较好,考虑了两个链表中有null的情况 * * @param head1 第一个链表 * @param head2 第二个链表 * @return 找到的公共结点,没有返回null */public static ListNode findFirstCommonNode(ListNode head1,ListNode head2){int length1 = getListLength(head1);//得到两个链表的长度int length2 = getListLength(head2);int diff = length1 - length2;ListNode longListHead = head1;//现在还不能确定head1就是长链表,head2就是短链表,但可通过下一步确定。ListNode shortListHead = head2;if(diff < 0){//如果head1短head2长则调换两个头指针的指向,非常好longListHead = head2;shortListHead = head1;diff = length2 - length1;}for(int i = 0; i < diff; i++){//让长的链表先走diff步,之后两个链表指针在同时移动,longListHead = longListHead.next;}/*while循环用于找到第一个相同的公共节点,如果没有则不断找向下一个节点,直到找到后退出循环*/while(longListHead != null && shortListHead != null && longListHead != shortListHead){longListHead = longListHead.next;shortListHead = shortListHead.next;}return longListHead;//返回第一个相同的公共节点,如果没有返回null;}/*得到单向链表长度*/private static int getListLength(ListNode head){int result = 0;while(head != null){result++;head = head.next;}return result;}public static void test1(){/*第一个公共节点在链表的中间1-2-3\ 6-7 4-5/ */ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n6;n6.next = n7;n4.next = n5;n5.next = n6;System.out.print("找到的第一个公共节点是:");System.out.println(findFirstCommonNode(n1, n4));//返回6}public static void test2(){/*没有公共节点1-2-3-45-6-7 */ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(findFirstCommonNode(n1, n5));//返回null}public static void test3(){/*公共节点是最后一个节点1-2-3-4\75-6/*/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n4.next = n7;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(findFirstCommonNode(n1, n5));//返回7}public static void test4(){/*公共节点是第一个节点1-2-3-4-5两个链表完全重合*/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n4.next = n5;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(findFirstCommonNode(n1, n1));//返回7}}public class FirstCommonNode {public static void main(String[] args){//Solution solution = new Solution();Solution.test1();Solution.test2();Solution.test3();//solution.test3();//The static method test3() from the type Solution should be accessed in a static waySolution.test4();}}
算法3源程序:/************************************************************** * Copyright (c) 2016, * All rights reserved. * 版 本 号:v1.0 * 题目描述:两个链表的第一个公共节点* 输入两个链表,找出他们的第一个公共节点。* 1-2-3\ 6-7 4-5/* 例如,该链表的第一个公共节点为6。* 输入描述:无* 程序输出:找到的第一个公共节点是:6*找到的第一个公共节点是:null*找到的第一个公共节点是:7*找到的第一个公共节点是:1** 问题分析: 1.一个警告:The static method test3() from the type Solution should be accessed in a static way* 原因:静态方法在对象创建前就存在了,它的使用不依赖对象是否被创建,所以可以用"类.方法"的方式调用* 2.单向链表的生成方法:详见程序* 3.得到链表长度:详见程序* 4.在Method1方法中,ListNode类被声明为了private,所以这里不能通过导入包的方式调用* 算法描述:如果存在共同节点的话,那么从该节点起,两个链表之后的元素都是相同的。也就是说两个链表从尾部往前到某个点,* 节点都是一样的。我们可以用两个栈分别来装这两条链表。这样两个链表的尾节点有位于两个栈的栈顶,* 接下来比较两个栈顶节点是否相同。如果相同,则把栈顶弹出,接着比较下一个栈顶,直到找到最后一个相同的节点。* 完成日期:2016-09-24***************************************************************/package org.marsguo.offerproject37;import java.util.Stack;//import org.marsguo.offerproject37.Solution.ListNode;//import org.marsguo.offerproject37.Solution.ListNode; //在Method1方法中,ListNode类被声明为了private,所以这里不能通过导入包的方式调用class Solution_Method2{public static class ListNode{int val;ListNode next;public ListNode(){//无参构造函数,可以不写,下文没有用到}public ListNode(int val){this.val = val;}@Overridepublic String toString(){return val + "";}}public static ListNode FindFirstCommonNode(ListNode head1,ListNode head2){if(head1 == null || head2 == null){return null;}/*用栈存储ListNode*/Stack<ListNode> stack1 = new Stack<>();Stack<ListNode> stack2 = new Stack<>();while(head1 != null){stack1.push(head1);//将链表1的内容压入栈head1 = head1.next;}while(head2 != null){stack2.push(head2);//将链表2的内容压入栈head2 =head2.next;}ListNode commonListNode = null;//共同节点标志位,初始值设为空/*用stack1的栈顶元素和stack2每次出栈元素相比较,如果相同,则stack1出栈,并把出栈元素赋给commonListNode*/while(!stack1.isEmpty() && !stack2.isEmpty() && stack1.peek() == stack2.pop()){commonListNode = stack1.pop();}return commonListNode;}public static void test1(){/*第一个公共节点在链表的中间1-2-3\ 6-7 4-5/ */ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n6;n6.next = n7;n4.next = n5;n5.next = n6;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n4));//返回6}public static void test2(){/*没有公共节点1-2-3-45-6-7 */ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n5));//返回null}public static void test3(){/*公共节点是最后一个节点1-2-3-4\75-6/*/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n4.next = n7;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n5));//返回7}public static void test4(){/*公共节点是第一个节点1-2-3-4-5两个链表完全重合*/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n4.next = n5;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n1));//返回7}}public class FindFirstCommonMethod2 {public static void main(String[] args){Solution.test1();Solution.test2();Solution.test3();Solution.test4();}}
算法4源程序:/************************************************************** * Copyright (c) 2016, * All rights reserved. * 版 本 号:v1.0 * 题目描述:两个链表的第一个公共节点* 输入两个链表,找出他们的第一个公共节点。* 1-2-3\ 6-7 4-5/* 例如,该链表的第一个公共节点为6。* 输入描述:无* 程序输出:找到的第一个公共节点是:6*找到的第一个公共节点是:null*找到的第一个公共节点是:7*找到的第一个公共节点是:1** 问题分析: 1.一个警告:The static method test3() from the type Solution should be accessed in a static way* 原因:静态方法在对象创建前就存在了,它的使用不依赖对象是否被创建,所以可以用"类.方法"的方式调用* 2.单向链表的生成方法:详见程序* 3.得到链表长度:详见程序* 4.在Method1方法中,ListNode类被声明为了private,所以这里不能通过导入包的方式调用* 算法描述:使用哈希表* 完成日期:2016-09-24***************************************************************/package org.marsguo.offerproject37;import java.util.HashMap;import org.marsguo.offerproject37.Solution_Method2.ListNode;//调用该包下的ListNode节点。class Solution_HashMap{public static ListNode FindFirstCommonNode(ListNode head1,ListNode head2){ListNode current1 = head1;ListNode current2 = head2;HashMap<ListNode,Integer> hashMap = new HashMap<ListNode,Integer>();while(current1 != null){hashMap.put(current1, null);//将链表值分别放入Hash表中,值都设为空current1 = current1.next;}while(current2 != null){/*判断hash表中是否有和链表2相同的键,有则返回该键,该键即为第一个相同的节点*/if(hashMap.containsKey(current2))//hashMap.containsKey():判断一个Map中是否包含指定Key的key-value键值对存在。return current2;current2 = current2.next;}return null;}public static void test1(){/*第一个公共节点在链表的中间1-2-3\ 6-7 4-5/ */ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n6;n6.next = n7;n4.next = n5;n5.next = n6;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n4));//返回6}public static void test2(){/*没有公共节点1-2-3-45-6-7 */ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n5));//返回null}public static void test3(){/*公共节点是最后一个节点1-2-3-4\75-6/*/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n4.next = n7;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n5));//返回7}public static void test4(){/*公共节点是第一个节点1-2-3-4-5两个链表完全重合*/ListNode n1 = new ListNode(1);ListNode n2 = new ListNode(2);ListNode n3 = new ListNode(3);ListNode n4 = new ListNode(4);ListNode n5 = new ListNode(5);ListNode n6 = new ListNode(6);ListNode n7 = new ListNode(7);n1.next = n2;n2.next = n3;n3.next = n4;n4.next = n5;n5.next = n6;n6.next = n7;System.out.print("找到的第一个公共节点是:");System.out.println(FindFirstCommonNode(n1, n1));//返回7}}public class FindNodeHashMapMethod {public static void main(String[] args){Solution_HashMap.test1();Solution_HashMap.test2();Solution_HashMap.test3();Solution_HashMap.test4();}}
程序运行结果:
0 0
- 剑指offer面试题37 两个链表的第一个公共节点
- [剑指offer][面试题37]两个链表的第一个公共节点
- 剑指offer 面试题37—两个链表的第一个公共节点
- 剑指Offer面试题37:两个链表的第一个公共节点
- 剑指offer——面试题37:两个链表的第一个公共节点
- 剑指offer-面试题37 两个链表的第一个公共节点
- 【面试题】剑指Offer-37-求两个链表的第一个公共节点
- 《剑指Offer》面试题:寻找两个链表的第一个公共节点
- 【剑指offer】面试题52:两个链表的第一个公共节点
- [剑指offer]面试题37.两个链表中的第一个公共节点
- 【剑指offer】面试题37:两个链表的第一个公共结点
- [剑指offer]面试题37:两个链表的第一个公共结点
- 剑指Offer:面试题37 两个链表的第一个公共结点
- 剑指offer 面试题37 两个链表的第一个公共结点
- 《剑指Offer》学习笔记--面试题37:两个链表的第一个公共结点
- 【剑指Offer学习】【面试题37:两个链表的第一个公共结点】
- 剑指Offer面试题37(Java版):两个链表的第一个公共结点
- 剑指offer之面试题37两个链表的第一个公共结点
- 如何制作表格(二)—— GridLayout
- 获取安装在手机中的所有应用包名
- 如何穿透内网
- ListView的 setOnScrollListener
- 手游实时对战初步解决方案
- 剑指Offer面试题37:两个链表的第一个公共节点
- iOS开发笔记--UIView中的坐标转换
- linux中crontab用法
- Spark广告点击项目技术骨架一
- python 实现多变量核密度评估函数
- ORA-14411
- 柬埔寨外资准入法律及政策简介
- 指数分布
- blkid反馈的uuid和mdadm.conf文件中记录的uuid 的值不一样