数据结构---单链表(2)

1. 反转链表(剑指offer-16)

题目:输入一个链表的头结点,反转该链表,并返回反转后链表的头结点。

解法一:从头到尾遍历原链表,每遍历一个结点,将其摘下放在新链表的最前端。注意链表为空和只有一个结点的情况。时间复杂度为O(n)。

	//链表反转
	public LNode ReverseList(LNode head){
		
	    // 如果链表为空或只有一个结点,无需反转,直接返回原链表头指针  
	    if(head.next == null || head.next.next == null)    
	        return head.next;  
	  
	    LNode pReversedHead = head;  
	    LNode pCurrent = head.next;
	    pReversedHead.next=null;//先摘头节点,使得head.next=null
	    
	    while(pCurrent != null)  
	    {  
	        LNode  pTemp = pCurrent;  
	        pCurrent = pCurrent.next;  
	        pTemp.next = pReversedHead.next; // 将当前结点摘下,插入新链表的最前端  
	        pReversedHead.next = pTemp;  
	    }  
	    return pReversedHead.next; 
	}
解法二:考虑到一般情况,我们翻转指针,每次利用指针p和p->next也就是p1来改变p1元素的位置

	public LNode ReverseList(LNode head) {

		// 如果链表为空或只有一个结点,无需反转,直接返回原链表头指针
		if (head.next == null || head.next.next == null)
			return head.next;
		
		LNode p = head.next;
		LNode p1 = p.next;
	    while(p.next != null){
	        p.next = p1.next;
	        p1.next = head.next;
	        head.next = p1;
	        p1 = p.next;
	    }
	    return head.next;
	}

2. 合并两个排序的链表(剑指offer-17)
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的结点仍然是按照递增排序的。

解法一:递归实现(两个链表无头节点)

	//合并两个排序链表
	public static LNode Merge(LNode head1,LNode head2){
		if(head1 == null)
	        return head2;
	    else if(head2 == null)
	        return head1;
	 
	    LNode pMergedHead = null;
	 
	    if(head1.data < head2.data)
	    {
	        pMergedHead = head1;
	        pMergedHead.next = Merge(head1.next, head2);
	    }
	    else
	    {
	        pMergedHead = head2;
	        pMergedHead.next = Merge(head1, head2.next);
	    }
	 
	    return pMergedHead;
	}
解法二:非递归实现(带头节点)
	public static LNode Merge1(LNode head1, LNode head2) {
		if (head1.next == null)
			return head2;
		else if (head2.next == null)
			return head1;

		LNode pMergedHead = head1;
		LNode index1 = head1.next;
		LNode index2 = head2.next;

		while (index1 != null && index2 != null) {
			if (index1.data < index2.data) {
				pMergedHead.next = index1;
				pMergedHead = index1;
				index1 = index1.next;
			}else{
				pMergedHead.next = index2;
				pMergedHead = index2;
				index2 = index2.next;
			}
		}

		if(index1!=null){
			pMergedHead.next = index1;
		}
		if(index2!=null){
			pMergedHead.next = index2;
		}
		return head1;
	}

3.两个链表中的第一个公共节点(剑指offer-37)

题目:输入两个链表,找出它们的第一个公共节点。(注:输入链表为单链表非循环链表)

解析:首先遍历两个链表得到它们的长度,就能知道哪个链表比较长,以及长的链表比短的链表多几个节点。在第二次遍历的时候,先在较长的节点上走若干步,接着同时在两个链表上遍历,找到的第一个相同的节点就是它们的公共的节点。

java代码:

	// 两个链表中的第一个公共节点
	public static LNode FindFirstCommonNode(LNode head1, LNode head2) {

		// 得到两个链表的长度
		int nLength1 = getLength(head1);
		int nLength2 = getLength(head2);

		int nLengthDif;
		LNode pHeadLong;
		LNode pHeadShort;
		if (nLength2 > nLength1) {
			pHeadLong = head2;
			pHeadShort = head1;
			nLengthDif = nLength2 - nLength1;
		} else {
			pHeadLong = head1;
			pHeadShort = head2;
			nLengthDif = nLength1 - nLength2;
		}

		// 先在长链表上走几步,再同时在两个链表上遍历。
		for (int i = 0; i < nLengthDif; i++)
			pHeadLong = pHeadLong.next;

		while ((pHeadLong != null) && (pHeadShort != null)
				&& (pHeadLong.data != pHeadShort.data)) {
			pHeadLong = pHeadLong.next;
			pHeadShort = pHeadShort.next;
		}
		// 得到第一个公共节点

		LNode pFirstCommonNode = pHeadLong;
		return pFirstCommonNode;

	}

	// 获取单链表长度
	public static int getLength(LNode head) {
		int length = 0;
		LNode p = head;
		while (p.next != null) {
			length++;
			p = p.next;
		}
		return length;
	}


相关题目:

1.判断一个单链表中是否有环
这里也是用到两个指针。如果一个链表中有环,也就是说用一个指针去遍历,是永远走不到头的。因此,我们可以用两个指针去遍历,一个指针一次走两步,一个指针一次走一步,如果有环,两个指针肯定会在环中相遇。时间复杂度为O(n)。


2.判断两个单链表是否相交:
如果两个链表相交于某一节点,那么在这个相交节点之后的所有节点都是两个链表所共有的。也就是说,如果两个链表相交,那么最后一个节点肯定是共有的。先遍历第一个链表,记住最后一个节点,然后遍历第二个链表,到最后一个节点时和第一个链表的最后一个节点做比较,如果相同,则相交,否则不相交。时间复杂度为O(len1+len2),因为只需要一个额外指针保存最后一个节点地址,空间复杂度为O(1)。


3.已知一个单链表中存在环,求进入环中的第一个节点:

第一步:使用快、慢指针来判断链表是否存在环,若不存在结束。

第二步:若链表中存在环,我们从链表头、与两个指针的相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇的第一个点为环的入口点

分析:当pfast若与pslow相遇时,pslow肯定没有走遍历完链表,而pfast已经在环内循环了n圈(1<=n)。

假设pslow走了s步,则pfast走了2s步(pfast步数还等于s 加上在环上多转的n圈),设环长为r,则:2s = s + nr    s= nr

设整个链表长L,入口环与相遇点距离为x,起点到环入口点的距离为a。 a + x = nr  则  a + x = (n – 1)r +r = (n-1)r + L - a  a = (n-1)r + (L – a – x)
(L – a – x)为相遇点到环入口点的距离,由此可知,从链表头到环入口点等于(n-1)循环内环+相遇点到环入口点,于是我们从链表头、与相遇点分别设一个指针,每次各走一步,两个指针必定相遇,且相遇第一点为环入口点。


参考来源:

经典面试题:链表的相交与环问题 

轻松搞定面试中的链表题目





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值