LeetCode | Linked List

206. Reverse Linked List

  • ver1是迭代版,但是一开始写while的判断条件写成cur.next,最后return的是cur,最后输出只有反转后的头节点,实际上最后一个节点还没有连上去,最后一个节点进不了循环,前面还是断开的orz。
  • ver2的递归版本实际上思想和迭代版是一样的,而且直接可以输出翻转后的节点;
  • ver3的递归版本则是deep到当前根节点再逐步往回,这里会很奇怪的点在于实际上它又回去了,最后要输出翻转链表后的头节点,怎么去保存翻转后的节点呢?别人写的题解好棒!!动图非常清楚!
    • 例子(1,2,3,4,5)实际上终止的时候cur = 5,但是此时head=4!!然后他去翻转之后return了cur 就是说下一步cur还是5!这就起到了保存反转后的头节点的作用了!
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def reverseList(self, head: ListNode):
        # if not head or not head.next:
        #     return head
        prev, cur = None, head
        while cur:
            tmp = cur.next
            cur.next = prev
            prev = cur
            cur = tmp
        return prev
        
     def reverseList2(self, head):
        def dfs(prev, cur):
            if not cur:
                return prev

            tmp = cur.next
            cur.next = prev
            return dfs(cur, tmp)
        return dfs(None, head)
        
    def reverseList3(self, head):
        if not head or not head.next:
            return head
        
        cur = self.reverseList3(head.next)
        head.next.next = head
        head.next = None
        return cur

21. Merge Two Sorted Lists

  • ver2实际上把ver1每次加一个节点后断开的操作省了;
  • ver3是令我头疼的递归orz…尝试说明一下
    • 问题分解为比较当前两个链表的头节点的大小,假设list1的当前头节点值比较大,则把下一个要连接的就是list1.next和list2链表的最大值,嗯就是一样的问题了;
    • 还有就是返回的问题("总是学不会~再聪明一点"orz)【再补充吧 讲不来orz】
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def mergeTwo(self, list1, list2):
        dummy = ListNode(0)
        cur = dummy
        while list1 and list2:
            if list1.val < list2.val:
                cur.next = list1
                list1 = list1.next
                cur = cur.next
                cur.next = None
            else:
                cur.next = list2
                list2 = list2.next
                cur = cur.next
                cur.next = None
        if list1:
            cur.next = list1
        if list2:
            cur.next = list2
        return dummy.next
        
    def mergeTwoLists2(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
        dummy = ListNode(0)
        cur = dummy
        while list1 and list2:
            if list1.val < list2.val:
                cur.next = list1
                list1 = list1.next
            else:
                cur.next = list2
                list2 = list2.next
            cur = cur.next
        if list1:
            cur.next = list1
        if list2:
            cur.next = list2
        return dummy.next
        
    def mergeTwoLists3(self, list1, list2):
        if not list1 or not list2:
            return list1 or list2
        if list1.val < list2.val:
            list1.next = self.mergeTwoLists3(list1.next, list2)
            return list1
        else:
            list2.next = self.mergeTwoLists3(list1, list2.next)
            return list2

19. Remove Nth Node From End of List

  • ver1快慢指针k
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


class Solution:
    def removeNthFromEnd(self, head: ListNode, n: int):
        dummy = ListNode(0, head)
        left, right = dummy, dummy

        for _ in range(n):
            right = right.next

        while right.next:
            left = left.next
            right = right.next

        left.next = left.next.next
        return dummy.next

143. Reorder List

  • 我的v1初试,非常直观的想法就是left后指向left链表的最后一个元素,插到left后,left更新成left.next.next,继续找,知道left和最后一个节点重合;
  • 很不幸的是是的!超时了!!!!
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next


class Solution:
    def reorderList(self, head: ListNode) -> None:
        # 说是找到最后一个实际上是最后一个节点的前一个
        def last(head):
            if not head.next:
                return head
            right = head
            while right.next.next:
                right = right.next
            return right

        left = head
        right = last(left)
        t = 0
        while left != right:
            t += 1
            tmp1 = left.next
            tmp2 = right.next
            right.next = None
            left.next = tmp2
            tmp2.next = tmp1
            left = left.tmp1
            right = last(left)
  • 既然超时,我们想想有没有别的出路?
    • 问题拆分:实际上相当于把原链表对半砍断,第二个链表翻转,在两个链表按顺序merge。
      • 对半砍: 快慢指针,注意保留的是第一个list的尾部,即第二个list开头的前一个节点因为想把它断开[low.next=None]
      • 链表翻转:对第二个链表(迭代)
      • merge:第一个用完了就直接连上第二个(其实只会出现第二个剩1or2的情况)

好绝!用tmp成瘾了么2333

    def reorderList2(self, head: ListNode) -> None:
    	# 找到中点(low为中点的前一个节点)
        low, fast = head, head.next
        while fast and fast.next:
            low = low.next
            fast = fast.next.next
		
		# 断开
        l2 = low.next
        low.next = None
        l1 = head
		
		# 翻转链表
        def reverse(head):
            prev, cur = None, head
            while cur:
                tmp = cur.next
                cur.next = prev
                prev = cur
                cur = tmp
            return prev
		
		# 合并链表
        def merge(l1, l2):
            while l1.next:
                tmp1, tmp2 = l1.next, l2.next
                l1.next = l2
                l2.next = tmp1
                l1, l2 = tmp1, tmp2
            l1.next = l2
            return l1
		
		# 不用return你就自己做吧
        merge(l1, reverse(l2))

138. Copy List with Random Pointer

很好我又没看懂题目让我干嘛…
去看了下nc的思路,哦是创建一个和他一模一样的链表;

  • 如果一次创建就连起来(next和random)实际上是不可操作的,random指向的可能是你没有创建的节点;
  • 考虑两次遍历,用hash存储{old:new}
    1. 第一次遍历:创建节点,hash存储;
    2. 第二次遍历:next,random指向创建好的新的node(通过old的next,random + hash找到)
class Node:
    def __init__(self, x, next=None, random=None):
        self.val = int(x)
        self.next = next
        self.random = random

class Solution:
    def copyRandomList(self, head):
        odd2copy = {None: None}

        cur = head
        while cur:
            node = Node(cur.val)
            odd2copy[cur] = node
            cur = cur.next

        cur = head
        while cur:
            node = odd2copy[cur]
            node.next = odd2copy[cur.next]
            node.random = odd2copy[cur.random]
            cur = cur.next
        return odd2copy[head]

2. Add Two Numbers

  • ver1:考虑两种情况
    1. l1,l2位数不齐的,不足就补零(好像把原list给改了orz)
    2. 进位:位数上直接考虑进去(l1.val+l2.val+up)%10;超出长度的进位再加一个1就好了;
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def addTwoNumbers(self, l1, l2):
        dummy = ListNode(-1)
        cur = dummy
        up = 0
        while l1 or l2:
            if not l1:
                l1 = ListNode(0)
            if not l2:
                l2 = ListNode(0)
            tmp = l1.val + l2.val + up
            node = ListNode(tmp % 10)
            cur.next = node
            cur = cur.next
            l1, l2 = l1.next, l2.next
            up = 1 if tmp >= 10 else 0

        if up == 1:
            node = ListNode(1)
            cur.next = node

        return dummy.next
  • 上面提到ver1当两个list的位数不齐时修改了原list(补零),下面来一版没有补零的操作+合并了超出位的情况;((๑•̀ㅂ•́)و✧)
    def addTwoNumbers2(self, l1, l2):
        dummy = ListNode(-1)
        cur = dummy
        up = 0
        while l1 or l2 or up == 1:
            val1 = l1.val if l1 else 0
            val2 = l2.val if l2 else 0

            tmp = val1 + val2 + up
            node = ListNode(tmp % 10)
            up = tmp // 10

            cur.next = node
            cur = cur.next

            l1 = l1.next if l1 else None
            l2 = l2.next if l2 else None

        return dummy.next

141. Linked List Cycle

class Solution:
    def hasCycle(self, head):
        low, fast = head, head
        while fast and fast.next:
            low = low.next
            fast = fast.next.next
            if low == fast:
                return True
        return False

287. Find the Duplicate Number

*这道题有丢丢特殊竟然是Linked List类下的,主要还是他不能不修改 数组 nums 且只用常量级 O(1) 的额外空间 ∈ \in 不做就很难有思路的问题;

  • 首先要明确他的值是[1,n],长度是n+1,那么你的第一个位置的index=0这个位置实际上后面不用担心链表会回来,而且值为[1,n]确保后面的都能被访问到,所以把index0作为链表的头是没有问题的;
  • 下面就是链表的判断是否有环+环的交点的问题了 ∈ \in Floyd判圈算法;[挖🕳待补,fast low的case]
    def findDuplicate2(self, nums):
        fast, low = 0, 0
        while True:
            fast = nums[nums[fast]]
            low = nums[low]
            if low == fast:
                break

        fast = 0
        while True:
            fast = nums[fast]
            low = nums[low]
            if low == fast:
                return low

25. Reverse Nodes in k-Group

虽然写的很丑,但是竟然效果还不错!!!耶耶耶!hard耶!!!泪目了好吗!

  • 记录要reverse的list的前一个节点l1,以及后面的list的头l2;断开!reverse之后接起来(连l2时候把遍历到reverse的尾部)!
  • 处理不够的用t来计数,不足的直接break掉;
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next
        
class Solution:
    def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
        dummy = ListNode(-1, head)
        cur = dummy
        while cur.next:
            l1 = cur
            t = 0
            for _ in range(k):
                if not cur.next:
                    break
                cur = cur.next
                t += 1
            if t < k:
                break

            tmp = l1.next
            l2 = cur.next
            l1.next = None
            cur.next = None
            rev = self.reverse(tmp)
            l1.next = rev
            while rev.next:
                rev = rev.next
            rev.next = l2
            cur = rev
        return dummy.next

    def reverse(self, head):
        prev, cur = None, head
        while cur:
            tmp = cur.next
            cur.next = prev
            prev = cur
            cur = tmp
        return prev

23. Merge K Sorted Lists

  • 参考的neetcode~
  • 主要的思想是归并(本质是Divide and Conquer)
    在这里插入图片描述
  • 主要思路:两两合并直到只剩下一个;(复用merge 2 sorted lists模块)
  • 时间复杂度: O ( n l o g k ) O(nlogk) O(nlogk)
  • 学习的点:
    1. 考虑边界;
    2. range的step的设置,之前都用的默认233;
    3. l2边界的设置,考虑奇数个的情况!
# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]):
        if not lists or len(lists) == 0:
            return None
        while len(lists) > 1:
            mergedLists = []
            for i in range(0, len(lists), 2):
                l1 = lists[i]
                l2 = lists[i + 1] if (i + 1) < len(lists) else None
                mergedLists.append(self.merge2Lists(l1, l2))
            lists = mergedLists
        return lists[0]
    
    def merge2Lists(self, l1, l2):
        dummy = ListNode()
        cur = dummy

        while l1 and l2:
            if l1.val < l2.val:
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
            cur = cur.next
        
        if l1:
            cur.next = l1
        if l2:
            cur.next = l2
        return dummy.next

146. LRU Cache

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值