Leetcode160. 相交链表练习

打题目来源 相交链表

题目描述

给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构 。

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

解法1

利用A,B两个表头节点同时往前走,如其中一个走到末尾则将节点指向另一个链表的表头,设链表A长度为m,链表B长度为n
1. 若链表A,B没有相交
A走到表尾后,指向链表B的头节点,接着走完链表B,指向null,共走长度 m+n
B走到表尾后,指向链表A的头节点,接着走完链表A,指向null,共走长度 m+n
因此A,B会同时指向null,返回null

2. 若链表A,B会相交,重复第1点中的操作,仍会相遇,走到相交节点时可能会重复多次更换表头动作,若是有缘总会相聚

时间复杂度:O(m+n) 空间复杂度:O(1)

JAVA代码示例


    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == headB) {
            return headA;

        }
        ListNode nodeA = headA;
        ListNode nodeB = headB;
        while (nodeA != nodeB) {
            nodeA = nodeA == null ? headB : nodeA.next;
            nodeB = nodeB == null ? headA : nodeB.next;
        }
        return nodeA;
    }


方法2:

 使用hashmap记录一个链表节点,便利第2个链表,一次判断是否存在hashmap中,如存在则就是相交节点
 时间复杂度:O(m+n) 空间复杂度:O(m)  A长度为m,链表B长度为n

JAVA代码示例

 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        Map<ListNode, Integer> listMap = new HashMap<>();
        if (headA == null || headB == null) return null;
        ListNode p1 = headA;
        ListNode p2 = headB;
        while (p1 != null) {
            listMap.put(p1, p1.val);
            p1 = p1.next;
        }
        while (p2 != null) {
            if (listMap.containsKey(p2)) {
                return p2;
            }
            p2 = p2.next != null ? p2.next : null;
        }
        return null;
    }

C++代码示例

class Solution{
public:
	ListNode *FindFirstCommonNode(ListNode *pHead1,ListNode *pHead2)
	{
		map<ListNode*,int > M;
		ListNode *pNode = pHead1;
		while(pNode!=NULL)
		{
			M[pNode] =1;
			pNode = pNode->next;
		}
		pNode = pHead2;
		while(pNode!=NULL)
		{
			if(M[pNode])
			{
				return pNode;
			}
			pNode = pNode->next;
		}
		return NULL;
	}
};

解法3:

 利用快慢指针,较长的表头节点先走,设链表A长度为m,链表B长度为n 且m>n
 A表头先走(m-n)步后,A,B再同时走,只到节点相同
 时间复杂度:O(2m+2n) 空间复杂度:O(1)

JAVA代码示例

 public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        if (headA == headB) {
            return headA;

        }

        ListNode nodeA = headA;
        ListNode nodeB = headB;
        //找出较长的链表
        int lenA = 0, lenB = 0;
        while (nodeA != null && nodeB != null) {
            lenA++;
            lenB++;
            nodeA = nodeA.next;
            nodeB = nodeB.next;
        }
        while (nodeA != null) {
            lenA++;
            nodeA = nodeA.next;
        }
        while (nodeB != null) {
            lenB++;
            nodeB = nodeB.next;
        }
        int sub = lenA - lenB;
        ListNode fast = headA;
        ListNode slow = headB;
        if (sub < 0) {
            fast = headB;
            slow = headA;
            sub = -sub;
        }
        //较长的链表先走m-n步
        while (sub > 0) {
            fast = fast.next;
            sub--;
        }
        //两个链表同时走
        while (fast != null && slow != null) {
            if (fast == slow) return fast;
            fast = fast.next;
            slow = slow.next;
        }
        return null;
    }

C++代码示例

struct ListNode {
	int val;
	struct ListNode *next;
	ListNode(int x) :
			val(x), next(NULL) {
};

class Solution{
public:

	ListNode* FindFirstCommonNode(ListNode *pHead1,ListNode *pHead2)
	{
		int length1 = GetListLength(pHead1);
		int length2 = GetListLength(pHead2);
		int lengthDif =0;
		ListNode *pListHeadLong =NULL;
		ListNode *pListHeadShort =NULL;
		//得到两个链表的长度差,并用连个结点标记长短链表
		if(length1>length2)
		{
			pListHeadLong = pHead1;
			pListHeadShort =pHead2;
			lengthDif = length1-length2;
		}
		else
		{
			pListHeadLong = pHead2;
			pListHeadShort = pHead1;
			lengthDif = length2-length1;
		}
		//较长的链表先走几步
		for(int i=0;i<lengthDif;i++)
			pListHeadLong = pListHeadLong->next;
		//此时两个链表同时遍历
		while((pListHeadLong!=NULL)&&(pListHeadShort!=NULL)&&(pListHeadShort!=pListHeadLong))
		{
			pListHeadShort=pListHeadShort->next;
			pListHeadLong = pListHeadLong->next;
		}
		return pListHeadShort;
	}

	int GetListLength(ListNode *pHead)
	{
		int length =0;
		ListNode *pNode =pHead;
		while(pNode!=NULL)
		{
			pNode= pNode->next;
			length++;
		}
		return length;
	}
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值