2024.5.(23,25,2)力扣刷题记录

目录

一、每日一题-2831. 找出最长等值子数组

1.分组 + 滑动窗口

2.一次遍历

二、1441. 用栈操作构建数组

模拟

三、844. 比较含退格的字符串

1.栈 + 模拟

2.重构字符串

3.快慢指针

四、378. 有序矩阵中第 K 小的元素

1.直接排序-堆排序

2.归并排序

3.归并排序-最小堆实现

4.二分查找

五、23. 合并 K 个升序链表

1.归并排序-递归

2.最小堆


一、每日一题-2831. 找出最长等值子数组

1.分组 + 滑动窗口

来自灵神题解(. - 力扣(LeetCode))。

class Solution:
    def longestEqualSubarray(self, nums: List[int], k: int) -> int:
        # 分组 + 滑动窗口
        group = defaultdict(list)
        for i, x in enumerate(nums):
            # group[x].append(i)
            group[x].append(i - len(group[x]))
        ans = 0
        for g in group.values():
            if len(g) <= ans:
                continue
            left = 0
            for right, v in enumerate(g):
                # left <= right < n
                # left < n
                # if v - g[left] - right + left > k:
                if v - g[left] > k:
                    left += 1
            ans = max(ans, right - left + 1)
        return ans
                

2.一次遍历

来自官方题解(. - 力扣(LeetCode))。

class Solution:
    def longestEqualSubarray(self, nums: List[int], k: int) -> int:
        # 一次遍历
        # 寻找区间众数
        ans = 0
        cnt = collections.defaultdict(int)
        left = 0
        for right, x in enumerate(nums):
            cnt[x] += 1
            if right - left + 1 - cnt[nums[left]] > k:
                cnt[nums[left]] -= 1
                left += 1
            # 以右端点更新,包含了左右等和左右不等的情况
            # 而以左端点更新达不到这样的效果
            # 可以看成左端点是变化的,而右端点没变
            ans = max(ans, cnt[nums[right]])
        return ans

二、1441. 用栈操作构建数组

模拟

class Solution:
    def buildArray(self, target: List[int], n: int) -> List[str]:
        # 模拟
        # 遇见不一样的就push + pop
        if target[-1] > n:
            return []
        ans = []
        num = 1
        for x in target:
            while num < x:
                ans.extend(["Push", "Pop"])
                num += 1
            ans.append("Push")
            num += 1
        return ans

三、844. 比较含退格的字符串

1.栈 + 模拟

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        # 栈 + 模拟
        n1, n2 = len(s), len(t)
        st1, st2 = [0] * n1, [0] * n2
        top1, top2 = 0, 0
        for c in s:
            if c == '#':
                top1 = max(0, top1 - 1)
            else:
                st1[top1] = c
                top1 += 1
        for c in t:
            if c == '#':
                top2 = max(0, top2 - 1)
            else:
                st2[top2] = c
                top2 += 1
        if top1 != top2:
            return False
        for i in range(top1):
            if st1[i] != st2[i]:
                return False
        return True

2.重构字符串

来自官方题解(. - 力扣(LeetCode))。但是有点慢。

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        # 重构字符串
        def bulid(s: str) -> str:
            st = []
            for c in s:
                if c != '#':
                    st.append(c)
                elif st:
                    st.pop()
            return "".join(st)
        return bulid(s) == bulid(t)

3.快慢指针

来自题解(. - 力扣(LeetCode))。很妙!

class Solution:
    def backspaceCompare(self, s: str, t: str) -> bool:
        # 快慢指针
        # 优化速度和存储空间
        # 从后向前遍历
        i, j = len(s) - 1, len(t) - 1
        skipS, skipT = 0, 0
        while i >= 0 or j >= 0:
            # 外循环,判断对应位置是否相等
            while i >= 0:
                # 内循环,跳过特殊情况
                if s[i] == '#':
                    skipS += 1
                    i -= 1
                elif skipS > 0:
                    skipS -= 1
                    i -= 1
                else:
                    break
            while j >= 0:
                if t[j] == '#':
                    skipT += 1
                    j -= 1
                elif skipT > 0:
                    skipT -= 1
                    j -= 1
                else:
                    break
            # 判断
            if i >= 0 and j >= 0:
                if s[i] != t[j]:
                    return False
            elif i >= 0 or j >= 0:
                return False
            i -= 1
            j -= 1
        return True

四、378. 有序矩阵中第 K 小的元素

1.直接排序-堆排序

没有利用性质,时复最大。

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 直接排序-堆排序
        q = [x for row in matrix for x in row]
        heapq.heapify(q)
        for _ in range(k - 1):
            heapq.heappop(q)
        return q[0]

2024.5.(25,26号)续:《

2.归并排序

利用每一横排的有序性。

class Solution:
    def merge_sort(self, nums:List[List[int]]) -> List[int]:
        n = len(nums)
        if n == 0:
            return []
        if n == 1:
            return nums[0]
        mid = n // 2
        left = self.merge_sort(nums[:mid])
        right = self.merge_sort(nums[mid:])
        
        res = []
        i, j = 0, 0
        # 左右列表长度
        while i < len(left) and j < len(right):
            if right[j] < left[i]:
                res.append(right[j])
                j += 1
            else:
                res.append(left[i])
                i += 1
        # 将剩下的添加到末尾
        res += left[i:]
        res += right[j:]
        return res

    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 归并排序
        nums = self.merge_sort(matrix)
        return nums[k - 1]

3.归并排序-最小堆实现

来自官方题解(. - 力扣(LeetCode))。通过将坐标一起入堆,更好追踪后节点。

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 最小堆实现归并排序
        n = len(matrix)
        q = [(matrix[i][0], i, 0) for i in range(n)]
        # 将坐标一起存入,便于调用后面的元素

        heapq.heapify(q)    # 堆化
        
        for _ in range(k - 1):
            num, x, y = heapq.heappop(q)
            # 将后节点入堆
            if y != n - 1:
                heapq.heappush(q, (matrix[x][y + 1], x, y + 1))
        return q[0][0]

4.二分查找

来自官方题解(. - 力扣(LeetCode))。check函数是精髓,充分利用了该矩阵的性质,时复最小。

class Solution:
    def kthSmallest(self, matrix: List[List[int]], k: int) -> int:
        # 二分查找
        n = len(matrix)

        def check(mid):
            i, j = n - 1, 0     # 左下角起步
            cnt = 0
            while i >= 0 and j < n:
                if matrix[i][j] <= mid:
                    # 向右走并更新cnt
                    cnt += i + 1
                    j += 1
                else:
                    # 向上走
                    i -= 1
            return cnt >= k

        l, r = matrix[0][0], matrix[n - 1][n - 1]   # 注意这里是值
        while l <= r:
            mid = (l + r) // 2
            if check(mid):
                r = mid - 1
            else:
                l = mid + 1
        return l

》2024.5.(25,26号)续

五、23. 合并 K 个升序链表

1.归并排序-递归

# 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]]) -> Optional[ListNode]:
        # 归并排序-递归
        n = len(lists)
        if n == 0:
            return None
        if n == 1:
            # 边界条件
            return lists[0]

        left = self.mergeKLists(lists[:n // 2])     # 递归
        right = self.mergeKLists(lists[n // 2:])

        head = ListNode()   # 返回链表
        lose = ListNode()   # 指向链表头,方便返回
        lose.next = head
        while left and right:
            if left.val > right.val:
                head.next = right
                right = right.next
            else:
                head.next = left
                left = left.next
            # 挪动指针
            head = head.next
        # 剩下部分
        if left:
            head.next = left
        else:
            head.next = right
        # lose -> head -> 表
        return lose.next.next
            

2024.5.25续:《

2.最小堆

来自灵神题解(. - 力扣(LeetCode))。

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

# 入堆时无法直接比较节点大小
ListNode.__lt__ = lambda a, b: a.val < b.val
'''
__lt__ 是 Python 中的一个特殊方法(magic method),用于定义对象之间的“小于”(less than)比较运算。它的名字来自于 "less than" 的缩写。在 Python 中,可以通过实现 __lt__ 方法来自定义对象的 < 比较行为。
'''
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        # 最小堆
        cur = dummy = ListNode() # 哨兵节点,指向头节点的前一个节点,类似于lose
        h = [head for head in lists if head]    # 头节点入堆
        heapq.heapify(h)    # 堆化
        while h:
            node = heapq.heappop(h)
            if node.next:
                # 下一个节点入堆
                heapq.heappush(h, node.next)
            # 连接
            cur.next = node
            cur = cur.next
        return dummy.next

 》2024.5.25续

感谢你看到这里!一起加油吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值