2021.09.17-力扣刷题(02.02、19、876、141、142、160)

参考labuladong的文章: 单链表的六大解题套路,你都见过么?

题目:面试题 02.02. 返回倒数第 k 个节点

题目描述

 代码实现

方法一:暴力破解

这道题给了一个ListNode头结点代表一条单链表,因此我们不能直接得出这条链表的长度n,而需要先遍历一遍链表算出n的值,然后再遍历链表计算第n-k个节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def kthToLast(self, head: ListNode, k: int) -> int:
        # 遍历两次:
        # 第一次找出链表长度n
        # 第二次返回n-k的值

        if not head: return float('-inf')
        cur = node = head

        n = 0
        while node.next: 
            n += 1
            node = node.next
        n += 1
        
        i = 0
        while cur.next:
            if i == n-k:
                return cur.val
            i += 1
            cur = cur.next
        return cur.val

方法二:双指针

能不能只遍历一次链表,就算出倒数第k个节点?可以做到的,如果是面试问到这道题,面试官肯定也是希望我们给出只需遍历一次链表的解法。思路如下:

首先,我们先让一个指针p1指向链表的头节点head,然后走k步;

然后,此时p2指针和p1指针一起走,直到p1指针走到尾巴的时候,p2指针刚好指向倒数k的位置。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def kthToLast(self, head: ListNode, k: int) -> int:
        """双指针"""

        p1 = p2 = head
        # p1先走k步
        while k>0:
            p1 = p1.next
            k -= 1
        
        # p1和p2同时走n-k步
        while p1:
            p2 = p2.next
            p1 = p1.next
   
        # p2 现在指向第n-k个节点
        return p2.val


题目:19. 删除链表的倒数第 N 个结点

题目描述

代码实现

方法:双指针

 要删除倒数第n个节点,就得获得倒数第n+1个节点的引用,可以先写一个find函数来找节点。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int) -> ListNode:
        # 要删除倒数第n个节点,就得获得倒数第n+1个节点
        def find(head: ListNode, k: int) -> ListNode:
            p1 = p2 = head
            # p1先走k步
            while k>0:
                p1 = p1.next
                k -= 1
            
            # p1和p2同时走n-k步
            while p1:
                p2 = p2.next
                p1 = p1.next
    
            # p2 现在指向第n-k个节点
            return p2

        dummy = ListNode(0)
        dummy.next = head
        # 删除倒数第n个,要先找倒数第n+1个节点
        node = find(dummy, n+1)
        # 删掉倒数第n个节点
        node.next = node.next.next
        return dummy.next

题目:876. 链表的中间结点

题目描述

代码实现

方法:快慢指针

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def middleNode(self, head: ListNode) -> ListNode:
        """
        快慢指针:两个指针slow和fast分别指向链表头结点head
        (1)快指针走两步
        (2)慢指针走一步   
        每当慢指针slow前进一步,快指针fast就前进两步,
        这样,当fast走到链表末尾时,slow就指向了链表中点。  
        """
        slow = fast = head
        while fast and fast.next:
            # 慢指针走一步,快指针走两步
            slow = slow.next
            fast = fast.next.next

        # 慢指针指向中点
        return slow

题目:141. 环形链表

题目描述

代码实现

方法一:set()

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        """set()"""
        if not head: return False

        tmp = set()
        p1 = head
        # tmp.add(p1)

        while p1:
            if p1 not in tmp:
                tmp.add(p1)
            else:
                return True
            p1 = p1.next
        return False

方法二:快慢指针

每当慢指针slow前进一步,快指针fast就前进两步。

如果fast最终遇到空指针,说明链表中没有环;如果fast最终和slow相遇,那肯定是fast超过了slow一圈,说明链表中含有环。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def hasCycle(self, head: ListNode) -> bool:
        """快慢指针"""
        slow = fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next

            if fast==slow:
                return True
        return False
            

题目:142. 环形链表 II

题目描述

代码实现

方法一:set集合

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:

        """set()"""
        tmp = []
        p1 = head
 
        while p1:
            if p1 not in tmp:
                tmp.append(p1)
            else:
                return p1
            p1 = p1.next
        return None

方法二:快慢指针

假设快慢指针相遇时,慢指针slow走了k步,那么快指针fast一定走了2k步:

 fast一定比slow多走了k步,这多走的k步其实就是fast指针在环里转圈圈,所以k的值就是环长度的「整数倍」

假设相遇点距环的起点的距离为m,那么结合上图的slow指针,环的起点距头结点head的距离为k-m,也就是说如果从head前进k-m步就能到达环起点。

如果从相遇点继续前进k-m步,也恰好到达环起点。因为结合上图的 fast 指针,从相遇点开始走k步可以转回到相遇点,那走k-m步肯定就走到环起点了:

 所以,只要我们把快慢指针中的任一个重新指向head,然后两个指针同速前进,k-m步后一定会相遇,相遇之处就是环的起点了。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        if head is None or head.next is None:
            return None
        p = head
        slow = head.next
        fast = head.next.next
        while fast and fast.next:
            
            if slow == fast:
                while(p != slow):
                    p = p.next
                    slow = slow.next
                return slow
           
            slow = slow.next
            fast = fast.next.next

        return None
        

另一种写法 

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        slow = head
        fast = head

        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow==fast:
                break
                          
        if fast is None or fast.next is None:
            return None

        # 重新指向头节点
        slow = head
        while slow != fast:
            # 快慢指针同步前进,相交点就是环起点
            slow = slow.next
            fast = fast.next
            
        return slow

题目:160. 相交链表

题目描述

代码实现

方法一:set()

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        """set()"""

        if not headA or not headB: 
            return None
        
        p1 = headA
        p2 = headB
        tmp = set()
        
        while p1:
            if p1 not in tmp:
                tmp.add(p1)
            p1 = p1.next
        
        while p2:
            if p2 not in tmp:
                tmp.add(p2)
            else:
                return p2
            p2 = p2.next
        
        return None

方法二:双指针

如果用两个指针p1p2分别在两条链表上前进,并不能同时走到公共节点,也就无法得到相交节点c1

所以,解决这个问题的关键是,通过某些方式,让p1p2能够同时到达相交节点c1

所以,可以让p1遍历完链表A之后开始遍历链表B,让p2遍历完链表B之后开始遍历链表A,这样相当于「逻辑上」两条链表接在了一起。

如果这样进行拼接,就可以让p1p2同时进入公共部分,也就是同时到达相交节点c1

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        """set()"""

        if not headA or not headB: 
            return None
            
        p1 = headA
        p2 = headB
        while p1 != p2:
            if p1 == None:
                p1 = headB
            else:
                p1 = p1.next
            
            if p2 == None:
                p2 = headA
            else:
                p2 = p2.next
        return p1          

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值