• 链表常见题目--附具体分析和代码


    一、链表的反转

    示例:

    输入: 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
    
  • 相关阅读:
    【04】Vue 之 事件处理
    【03】Vue 之列表渲染及条件渲染
    【02】 Vue 之 数据绑定
    传递参数的模式最适合向函数传入大量可先参数的情形
    ie6 PNG图片透明
    实现表单的输入框当光标为当前时,去掉默认值
    SSIS ->> Environment Variables
    SQL Server ->> FileTable
    SQL Server ->> 间接实现COUNT(DISTINCT XXX) OVER(PARTITION BY YYY)
    SQL Server ->> EXECUTE AS LOGIN/USER和Revert表达式
  • 原文地址:https://www.cnblogs.com/linshuhui/p/9734498.html
Copyright © 2020-2023  润新知