两个链表的第一个公共节点

题目描述

输入两个链表,找出它们的第一个公共节点,链表结点定义如下:

public class ListNode
{
    public int val;
    public ListNode next;
    public ListNode (int x)
    {
        val = x;
    }
}

总共三种解法:

方法一,蛮力法

        在第一个链表上顺序遍历每个节点,每遍历到一个节点,就在第二个链表上顺序遍历每个节点。如果在第二个链表上有一个节点和第一个链表上的节点相同,则说明两个链表在这个节点上重合。
        如果第一个链表的长度为m,第二个链表的长度为n,那么该方法的时间复杂度为O(nm)。

方法二,辅助栈法

        经过观察可以发现,如果两个链表有公共节点,那么公共节点出现在两个链表的尾部。如果我们从两个链表的尾部开始往前比较,那么最后一个相同的节点就是我们要找的节点。
        在单链表中,只能从头节点开始按顺序遍历,最后到达尾节点。最后的节点却要最先比较,符合“后进先出”的规律。
        所以可以通过栈的特点来解决这个问题:分别把两个链表的节点放入两个栈里,接下来比较两个栈的栈顶是否相同,如果相同,则把栈顶弹出来接着比较下一个栈顶元素,直到找到最后一个相同的元素。
        上述思路中,需要两个辅助栈。如果两个链表的长度分别为m和n,空间复杂度是O(m+n),时间复杂度也是O(m+n),和最开始的蛮力法比起来,相当于用空间消耗换取了时间效率。

方法三,先保证两链表剩余相同个节点再遍历查找法

        首先遍历两个链表,得到他们的长度,就能知道哪个链表长以及长的链表比短的链表长多少,让长的链表先走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点就是它们的第一个公共节点。
        接下来为方法三的AC代码:

using System;

namespace 两个链表的第一个公共节点
{
    public class ListNode
    {
        public int val;
        public ListNode next;
        public ListNode(int x)
        {
            val = x;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Test1();
        }

        private static void Test1()
        {
            ListNode list1 = null, list2 = null;
            CreateList(ref list1, ref list2);
            Solution s = new Solution();
            Console.WriteLine(s.FindFirstCommonNode(list1, list2).val);
            Console.WriteLine("链表1的所有节点:");
            while (list1 != null)
            {
                Console.Write(list1.val + "\t");
                list1 = list1.next;
            }
            Console.WriteLine("\n链表2的所有节点:");
            while (list2 != null)
            {
                Console.Write(list2.val + "\t");
                list2 = list2.next;
            }
        }

        /// <summary>
        /// 创建两个链表
        /// </summary>
        /// <param name="list1">链表1的头指针</param>
        /// <param name="list2">链表2的头指针</param>
        static void CreateList(ref ListNode list1, ref ListNode list2)
        {
            list1 = new ListNode(1);
            list2 = new ListNode(5);
            ListNode pNode1 = list1, pNode2 = list2;
            ListNode temp;
            pNode1.next = new ListNode(3);
            pNode1 = pNode1.next;
            pNode1.next = new ListNode(9);
            pNode1 = pNode1.next;
            pNode1.next = new ListNode(7);
            pNode1 = pNode1.next;
            pNode1.next = new ListNode(2);
            pNode1 = pNode1.next;
            pNode2.next = new ListNode(4);
            pNode2 = pNode2.next;
            pNode2.next = new ListNode(7);
            pNode2 = pNode2.next;
            for (int i = 1; i < 3; i++)
            {
                temp = new ListNode(i + 10);
                pNode1.next = temp;
                pNode2.next = temp;
                pNode1 = pNode1.next;
                pNode2 = pNode2.next;
            }
        }
    }

    class Solution
    {
        /// <summary>
        /// 输入两个链表,找出它们的第一个公共结点。
        /// </summary>
        /// <param name="pHead1">链表1的头指针</param>
        /// <param name="pHead2">链表2的头指针</param>
        /// <returns>第一个公共结点</returns>
        public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2)
        {
            if (pHead1 == null || pHead2 == null)
                return null;

            //链表1的长度和链表2的长度
            int list1Length = 0, list2Length = 0;
            //链表1的头指针和链表2的头指针
            ListNode pNode1 = pHead1, pNode2 = pHead2;

            //统计链表1和链表2的长度
            while (pNode1 != null)
            {
                list1Length++;
                pNode1 = pNode1.next;
            }
            while (pNode2 != null)
            {
                list2Length++;
                pNode2 = pNode2.next;
            }

            pNode1 = pHead1;
            pNode2 = pHead2;
            //得到链表1和链表2的长度差
            int subOfList1BetweenList2 = list1Length - list2Length;

            //让长的链表1往后移动若干位
            while (subOfList1BetweenList2 < 0)
            {
                pNode2 = pNode2.next;
                subOfList1BetweenList2++;
            }
            while (subOfList1BetweenList2 > 0)
            {
                pNode1 = pNode1.next;
                subOfList1BetweenList2--;
            }

            while (pNode1 != pNode2)
            {
                pNode1 = pNode1.next;
                pNode2 = pNode2.next;
            }

            return pNode1;
        }
    }
}

从下图的运行结果可以看出,找到了第一个公共节点:
这里写图片描述
第三种思路和第二种思路比起来,时间复杂度都是O(m+n),但是不再需要辅助栈,因此提高了空间效率。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值