设为首页 加入收藏

TOP

链表重点问题(下)(一)
2018-10-22 02:13:21 】 浏览:125
Tags:重点 问题
 

1.判断单链表是否带环?若带环,求环的长度?求环的入口点?并计算每个算法的时间复杂度&空间复杂度

思路:还是通过快慢指针来解决,让fast指针每次走2个结点,慢指针一次走一个结点

时间复杂度为O(n)   空间复杂度O(1 )

注意fast每次走3个 4个.. 结点是不行的。分析如下:

 

考虑清楚后,便可以写下代码:

//(1)判断链表是否带环
SListNode* SListIsCycle(SListNode* list) { assert(list); SListNode* fast = list; SListNode* slow = list; while(fast && fast->_next){ fast = fast->_next->_next; slow = slow->_next; if(slow == fast){ return fast; //返回相遇点地址 } } return NULL; }


(2)求环长度
思路如下:
把相遇点的下一个结点地址赋给cur ,cur按环遍历一圈,通过计算器count便可求得环长
时间复杂度O(n) 空间复杂度O(1)
int
SListCycleLen(SListNode* meetNode){ assert(meetNode); size_t count = 0; SListNode* cur = meetNode->_next; while(cur != meetNode){ count++; cur = cur->_next; } return count+1
; }

(3) 求入口点

 

如果说不太理解“slow和fast第一次相遇,slow没绕环走超过一圈”。可以考虑这样一种情况:

注:slow和fast同时从一个地方走,这种情况下它们之间相差距离是最大的(刚好一圈)。v(fast) = 2v(slow), fast先进入环内。

 

有了以上分析,不难写得如下代码:

//meet的下一个结点地址赋给cur,list,cur同时往后走,相遇点即是入口点
时间复杂度O(n) 空间复杂度O(1)
SListNode* SListEntryNode(SListNode* list, SListNode* meetNode) { assert(list && meetNode); SListNode* cur = meetNode; while(cur != list){ cur = cur->_next; list = list->_next; } return cur; }

 

2.判断两个链表是否相交,若相交,求交点。(假设链表不带环)

 

思路:
1.先遍历两链表求得长度分别为x1,x2; 2.让指向长链表的指针先走|x1 - x2|的长度 3.
最后两指针同时走,直到相遇
SListNode* SListNonCircleIsCrossNode(SListNode* list1, SListNode* list2){
    assert(list1 && list2);
    
    size_t x1 = 0,x2 = 0;
    SListNode* cur1 = list1; //注意定义中间变量来遍历,list1、list2是两链表的头指针,不能改变其指向,故不能用来遍历, SListNode* cur2 = list2; while(cur1){
        cur1 = cur1->_next;
        x1++;
    } 
    while(cur2){
        cur2 = cur2->_next;
        x2++;
    }
    
    SListNode* longList = list1;
    SListNode* shortList = list2;
    if(x2 > x1){
        longList = list2;
        shortList = list1;
    }
    int gap = abs(x1 - x2);  //abs() 调用求绝对值函数 
    while(gap--){
        longList = longList->_next;
    } 
    //两指针同时走
    while(longList){
        longList = longList->_next;
        shortList = shortList->_next;
        if(longList == shortList){
            return longList;     //返回交点地址 
        }
    } 
    return NULL;
} 

3.判断两个链表是否相交,若相交,求交点。(假设链表可能带环)【升级版】

需分下面几种情况讨论:
(1)都不带环,转换成2题。

(2)一个带环,一个不带环。那一定不相交(若相交了,原链表结构肯定被改变了)。

(3)都带环。都带环也分为以下三种情况(利用两个相遇点(M1,M2) 判断是否带环——让M1不动,M2走一圈,如果两个能相遇,那就相交,反之不相交)

①不相交
 
从meet遍历一遍环,能找到meet2则判定两环是相交
 ②环外相交(入口点相同)——从入口点处把链表截断,问题就转换成求两个不带环链表相交点。 

            

 ③环内相交(入口点不同)

 

SListNode* SListCrossNode(SListNode* list1, SListNode* list2){
    assert(list1 && list2);
    //情况①:都不带环,转到上题 
    if(!SListIsCycle(list1) && !SListIsCycle(list2)){
        SListNonCircleIsCrossNode(list1,list2);
    }
    
    //情况②:都带环 
    else if(SListIsCycle(list1) && SListIsCycle(list2)){
        SListNode* pMeetNode1 = SListIsCycle(list1);  //上题函数 
        SListNode* pMeetNode2 = SListIsCycle(list2);     
        SListNode* cur = pMeetNode1->_next;
        
        while(cur != pMeetNode1 || pMeetNode1 == pMeetNode2){
            if(cur == pMeetNode2){ //相交的情况
                SListNode* entry1 = SListEntryNode(list1, pMeetNode1); //返回list1入口点 
                SListNode* entry2 = SListEntryNode(list2, pMeetNode2); //返回list2入口点 
                
                if(entry1 == entry2){   //两入口点相同,环外相交 
                    entry1->_next = NULL;
                    return SListNonCircleIsCrossNode(list1 , list2);
                }
            
                
                else{                //两入口点不同,环内相交 
                    printf("有两个交点,分别就是两个入口点\n");
                    int n = 0;
                    scanf("%d",&a
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++11/14学习(一)nullptr与cons.. 下一篇C++雾中风景5:Explicit's be..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目