zoukankan      html  css  js  c++  java
  • 判断链表是否相交

    1. 判断两个均不含有环的单链表是否相交——编程之美3.6

    两个没有环的链表相交于一节点,则在这个节点之后的所有结点都是两个链表所共有的。如果它们相交,则最后一个结点一定是共有的,则只需要判断最后一个结点是否相同即可。时间复杂度为O(len1+len2)。

    struct Node
    {
    	int data;
    	Node *next;
    };
    
    bool isCross(Node *head1, Node *head2)
    {
    	Node *p1 = head1, *p2 = head2;
    	while (p1->next) p1 = p1->next;
    	while (p2->next) p2 = p2->next;
    	return p1 == p2;
    }
    

    对于相交的第一个结点,则可求出两个链表的长度,然后用长的减去短的得到一个差值 K,然后让长的链表先遍历K个结点,然后两个链表再开始遍历,进行比较,第一个相等的指针为目标节点。

    2. 判断链表是否存在环

    可以设置两个指针fast和slow,初始均指向头结点,slow每次向前一步,fast每次向前两步;如果链表中有环,则fast先进入环中,而slow后进入环中,两个指针在环中必定相遇;如果fast遍历到尾部为NULL,则无环。

    bool isExitsLoop(Node *head)
    {
    	if (head == NULL) return 0;
    	Node *slow = head, *fast = head;
    	while (fast && fast->next)
    	{
    		slow = slow->next;
    		fast = fast->next->next;
    		if (slow == fast) return 1;
    	}
    	return 0;
    }

    3. 如果链表为存在环,如何找到环的入口点?

    当fast与slow相遇时,slow肯定没有走遍历完链表,而fast已经在环内循环了n圈(1<=n)。假设slow走了s步,则fast走了2s步(fast步数还等于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)循环内环+相遇点到环入口点
    因而,可以在链表头,相遇点分别设定一个指针,每次各走一步,两个指针必定相遇,且第一个相遇点为环入口点。

    Node *findLoopPort(Node *head)
    {
    	Node *slow = head, *fast = head;
    	while (fast && fast->next)
    	{
    		slow = slow->next;
    		fast = fast->next->next;
    		if (slow == fast) break;
    	}
    
    	if (fast || fast->next) return NULL;
    
    	slow = head;
    	while (slow != fast)
    	{
    		slow = slow->next;
    		fast = fast->next;
    	}
    	return slow;
    }
    

    4. 现在也可以解决第1个问题的入口点问题:如果链表不含有环,如何找到第一个不相交的结点?

    将问题转化为上一个问题:将第二个链表首尾相连,然后判断第一个链表是否有环,如果有,则它们必然相交,否则不相交。如何找到相交的首个节点呢?其实也就是第一个链表的环的入口节点。

    Node *findPort(Node *head1, Node *head2)
    {
    	Node *tail2 = head2;
    	while (tail2->next)
    		tail2 = tail2->next;
    	tail2->next = head2;//给单链表建环
    
    	Node *temp = findLoopPort(head1);
    	tail2->next = NULL;//给单链表解环
    	return temp;
    }
    

    5. 删除非头结点单链表的指定节点(只给定待删除节点指针)——编程之美3.4

    随机给出单链表中一个非头节点或者尾节点,删除该节点,当传入空节点时,返回 。
    思路:由于没有头节点,非循环单链表,无法获取目标节点的前一节点,所以只能把它的next节点数据前移,并删除next节点。

    void deleteRandomNode(Node *pCur)
    {
    	assert(pCur != NULL);
    	Node *pNext = pCur->next;
    	if (pNext != NULL)
    	{
    		pCur->next = pNext->next;
    		pCur->data = pNext->data;
    		delete pNext;
    	}
    }
    
  • 相关阅读:
    定时器Timer的使用
    Queue和BlockingQueue的使用以及使用BlockingQueue实现生产者-消费者
    ReentrantReadWriteLock读写锁的使用
    利用Lucene与Nutch构建简单的全文搜索引擎
    再见了,DM
    互联网公司高并发图片(缩略图)处理中间层服务架构设计一
    poj 3131 双向搜索+hash判重
    [置顶] linux常用命令大全
    堆排序
    iOS UIView非常用方法及属性详解
  • 原文地址:https://www.cnblogs.com/li-chong/p/3271439.html
Copyright © 2011-2022 走看看