LeetCode之LinkList刷题记录博

写在前面:

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

1290. Convert Binary Number in a Linked List to Integer <倒序>

我做链表的第一道题:

class Solution:
    def getDecimalValue(self, head: ListNode) -> int:
        n = 0
        total = 0
        plist = []
        
        while(head):
            n += 1
            if head.val == 1:
                plist.append(n)
            head = head.next
        
        for x in plist:
            total += pow(2,n-x) 
            print(n,total)
            
        return total

中心思想是要把给的head倒过来计算。有两种比较直接的思路:首先就是一一存出来倒着算,当然还有一种类似的看有人读了一遍长度,再重新读了一遍链表直接算;第二种就是把需要加的index记下来单独拿出来算。我写的是第二种思路。
如果对链表和python的指针不熟,比如像我现在这样,这题的重点就是从非常浅的层次来告诉你head.val == 1head = head.next,以及直接从链表下手能干什么不能干什么。


<Floyd龟兔系列>

876. Middle of the Linked List

明明可以简单做的一道题,翻了很久discussion有绝妙的感悟。还记得大二数据结构课老师讲的检测loop吗!这个快慢指针思想就是可以放进去。放一下快慢指针最经典的用法 :

141. Linked List Cycle

def hasCycle(self, head):
    try:
        slow = head
        fast = head.next
        while slow is not fast:
            slow = slow.next
            fast = fast.next.next
        return True
    except:
        return False

142. Linked List Cycle II

追加一道题,除了判断是否是环以外,还有确定起点的位置。需要用到Floyd算法的思想:

  • 确定有环:slow和fast相遇
  • 确定起点的位置:一个在起点一个在相遇点,一次一步,相遇点即为起点。
    参考代码:
def detectCycle(self, head):
    slow = fast = head
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
        if slow == fast:
            break
    else:
        return None
    while head != slow:
        slow = slow.next
        head = head.next
    return head

comeback 回到876这道题(求中点),相当于一个快一倍的指针fast和一个正常的指针slow。slow刚好就是指向一半的水平:

class Solution:
    def middleNode(self, head: Optional[ListNode]) -> Optional[ListNode]:
        slow = head
        fast = head
        
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        
        return slow

160. Intersection of Two Linked Lists

变形有点多, 这个题应该是实现了功能的,但是没有检查输出是否符合要求,看个思路:

class Solution:
    def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> ListNode:
        if not headA or not headB: return None
        # 1 - concate A and B
        last = headA
        while last.next: last = last.next
        last.next = headB
        
        # 2 - slow & fast -> check loop and find the intersections:
        slow = fast = headA
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            if slow == fast:
                slow = headA
                break
        else:
            return None
        while fast != slow:
            slow = slow.next
            fast = fast.next
        return slow

234. Palindrome Linked List

这个题一定要加在这个大类里面分享一下!!细想回文其实是mid的部分应用,加上反转链表两个部分。如果说一个链表有奇数位,那一定不是回文了;如果是偶数位,有可能是回文。思路其实就是前半段和后半段去一一匹配,如果都能匹配上那么就是回文。答案参照discussion区的一个大佬回答,代码稍微整理贴在下面。但是我在LC上跑不过,说是时间超了。anyway,不管那么多,我是支持这个思路的。

class Solution:
    def isPalindrome(self, head: Optional[ListNode]) -> bool:
        slow = head
        fast = head
        reverse = None
        while fast and fast.next:
            reverse = slow
            reverse.next = reverse
            slow = slow.next
            fast = fast.next.next
        
        if fast is None:
            return False
        else:
            slow = slow.next
            while slow.val == reverse.val:
                slow = slow.next
                reverse = reverse.next
            return not slow

<删除点系列>

237. Delete Node in a Linked List

这个题要注意看下最上面注释给的ListNode的标准写法。说白了人要的也不多,就是要一个node.val和node.nextd的定义。也不难。

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

class Solution:
    def deleteNode(self, node):
        node.val = node.next.val
        node.next = node.next.next

1474. Delete N Nodes After M Nodes of a Linked List

算是237的一个follow-up。但是因为定义的对象是原本给的Linklist, 而不是上题的那个Node,所以定义过程不至于这么麻烦。主要就是操纵指针的位置。
这题我在解的时候用了两个指针:p和post。其中post就一直在后面观望,因为考虑到我们进了删除的列m还没结束之前就已经到最后一位了

class Solution:
    def deleteNodes(self, head: ListNode, m: int, n: int) -> ListNode:
        p = head
        post = head 
        countm = m
        countn = n
        while p:
            if countm != 0:                      # 1.判断是正常位还是要删的位
                countm -= 1
                post = p
                p = p.next
            else:
                if countn != 0:                  # 2.判断删除位是否到头
                    print("delete",p.val)
                    if p.next is None:           # 最后一位
                        post.next = None
                    p = p.next
                    countn -= 1
                else:
                    post.next = p
                    countn = n
                    countm = m
    
        return head
                

83. Remove Duplicates from Sorted List

看起来是去重,实际上是一个道理。少用多余的指针,而是用简单的.next.next这种表达方式解决问题。

class Solution:
    def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
        cur = head
        while cur and cur.next:
            if cur.next.val != cur.val:
                cur = cur.next
            else:
                cur.next = cur.next.next
                
        return head

21. Merge Two Sorted Lists

这绝对是熟悉链表的好题:
重点就是抓住我一开始给的那个模板,我们先声明一个新链表。特别的是这个开头p指向的第一位是0,所以最后返回新链表l的时候要return l.next。整体类似于两个指针对l1和l2当前指的位一一比较,小的被解开并接到原来的表后面。因为不是在复制字串,所以不用去声明赋值之类的东西。

class Solution:
    def mergeTwoLists(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        l = ListNode(0)
        p = l
        while l1 and l2:
            if l1.val <= l2.val:
                p.next = l1
                l1 = l1.next
            else:
                p.next = l2
                l2 = l2.next
            p = p.next
        p.next = l1 or l2
        
        return l.next

上一篇:【MySQL 数据库】数据库的约束及数据表的设计思想


下一篇:链表的理解