zoukankan      html  css  js  c++  java
  • 链表常见题目--附具体分析和代码

    一、链表的反转

    示例:

    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL
    

    分析:刚开始的时候很自然的想到,创建一个列表,然后遍历链表,将每个节点保存在列表中,然后根据列表,反向构造一个新的链表。但是这个很明显很low,一方面是空间复杂度为O(n),一方面是要遍历两遍。后来想都到了另外一种方法,只需要遍历一遍,然后所需的额外空间也非常少。
    核心思想就是:遍历链表,创建一个新节点,保存当前节点的值。一个节点指向None,将第二个元素指向第一个节点,第三个指向第二个,以此类推。
    代码查考如下

    def reverseList( head):
            q = head
            f = None
            while q:
                new = ListNode(q.val)
                new.next = f
                f = new
                q = q.next
            return f
    

    二、删除链表的倒数第N个节点

    示例:

    给定一个链表: 1->2->3->4->5, 和 n = 2.
    
    当删除了倒数第二个节点后,链表变为 1->2->3->5.
    

    分析:
    最容易想到的思路大致如下:先遍历一遍链表,求链表的长度,然后再次遍历,删除倒数的第N个节点。这种思路比较简单,自然效率也比较低。这种思路的具体代码就不加上了。
    下面来看一种更为精妙的解法:设置两个指针,一个指针先走N步,然后两个指针一起走,当前面的指针走到链表尾部时,后面的指针下个元素就是要删除的元素。

    def removeNthFromEnd(head, n):
            p1, p2 = head, head
            while n:
                p2 = p2.next
                n -= 1
            if p2 is None:
                return head.next
            while 1:
                if p2.next is None:
                    p1.next = p1.next.next
                    return head
                p1, p2 = p1.next, p2.next
    

    三、求链表的中间节点

    给定一个带有头结点 head 的非空单链表,返回链表的中间结点。
    
    如果有两个中间结点,则返回第二个中间结点。
    

    分析:跟上面的那个题目类似,设置两个指针,一个走一步,一个走两步,当这快指针走到None时,返回慢指针即可

    def middleNode(self, head):
            """
            :type head: ListNode
            :rtype: ListNode
            """
            p1 = head 
            p2 = head
            while p2 and p2.next:
                p1 = p1.next
                p2 = p2.next.next
            return p1
     
    

    四、判断链表中是否有环

    分析:
    同样通过两个指针,一个每次移动一步,一个每次移动两步,如果存在环,那么这两个指针一定会相遇。

    代码如下:

    def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            p,q = head,head
            while 1:
                if q is None or q.next is None :return False
                p = p.next
                q = q.next.next
                if p is q: 
                    return True
    

    五、找到环的入口

    题目描述:
    给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
    分析:
    这题解法非常精妙,先按照上题思路,设置两个指针判断链表是否存在环,如果存在,让快指针回到链表开头,然后速度和慢指针一样设置为1,当再次相遇时,就是环的入口。
    设起点到环入口距离为a,环入口到相遇点距离为b,相遇时慢指针走了n步。然后从相遇的点开始,快指针回到链表表头,然后速度也变为。
    图解

    六判断两个链表是否相交

    分析:常见的解法有如下几种
    *直接循环一个链表,看看这个链表每个元素是否在另外一个链表中。显然这个方法非常低效,时间复杂度为。O(n^2)
    *针对第一个链表做一个哈希表,python中可以利用字典,然后再去遍历第二个链表,这种方法时间复杂度为O(n),但是空间复杂度也上升到O(n)
    *将一个链表接到另外一个链表之后,如果是相交这那么新链表一定会形成一个环,然后利用上面的方法进行判读即可。这里还有更简单的方法,就是如果成环,那么第二个链表的表头一定在环上,这时候只要直接遍历第二个链表,看看会不会回到表头即可。
    *最后这种是最简单的。如果两个链表相交,那么他们的最后一个为节点一定是相同的,所以只要判断最后一个节点是否相同即可,时间复杂度O(n)空间O(1)

    def fun(head1,head2):
        while head1.next:
            head1 = head1.next
        while head2.next:
            head2 = head2.next
        if head1 == head2:return True
        else:return  False
    

    七、找到相交链表的起始节点

    A:          a1 → a2
                       ↘
                         c1 → c2 → c3
                       ↗            
    B:     b1 → b2 → b3
    

    返回c1,如果不相交返回None
    分析:先用上面的方法判断时候相关,同时记录链表长度,若相关求出长度差n,然后利用两个指针,长的链表先走n步,然后同时开始遍历,第一个相同的节点就是相交节点。

    def getIntersectionNode(headA, headB):
            if headA is None or headB is None:return None
            l1 ,l2 = 0,0
            p1,p2 = headA,headB
            tail_1,tail_2 = None,None
            while 1:
                l1+=1
                if p1.next is None:
                    tail_1 = p1
                    break;
                p1 = p1.next
            while p2:
                l2 += 1
                if p2.next is None:
                    tail_2 = p2
                    break;
                p2 = p2.next
            if tail_1 != tail_2:return None
            else:
                n = abs(l1 -l2)
                if l1 >= l2:
                    while n:
                        headA = headA.next
                        n-=1
                else:
                    while n:
                        headB = headB.next
                        n-=1
                while 1:
                    if headA == headB:return headB
                    else:
                        headA,headB = headA.next,headB.next
    
  • 相关阅读:
    洛谷p1017 进制转换(2000noip提高组)
    Personal Training of RDC
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Eurasia
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof.
    Asia Hong Kong Regional Contest 2019
    XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Siberia
    XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix.
    XVIII Open Cup named after E.V. Pankratiev. GP of SPb
    卜题仓库
    2014 ACM-ICPC Vietnam National First Round
  • 原文地址:https://www.cnblogs.com/linshuhui/p/9734498.html
Copyright © 2011-2022 走看看