[Leetcode Weekly Contest]187

链接:LeetCode

[Leetcode]1436. 旅行终点站

给你一份旅游线路图,该线路图中的旅行线路用数组 paths 表示,其中(paths[i] = [cityAi, cityBi])表示该线路将会从 cityAi 直接前往 cityBi 。请你找出这次旅行的终点站,即没有任何可以通往其他城市的线路的城市。
题目数据保证线路图会形成一条不存在循环的线路,因此只会有一个旅行终点站。

实际上只要寻找出现在终点集合而不出现在起点集合的点即可。

class Solution:
    def destCity(self, paths: List[List[str]]) -> str:
        starts = [x[0] for x in paths]
        ends =  [x[1] for x in paths]
        return [x for x in ends if x not in starts][0]

[Leetcode]1437. 是否所有 1 都至少相隔 k 个元素

给你一个由若干 0 和 1 组成的数组 nums 以及整数 k。如果所有 1 都至少相隔 k 个元素,则返回 True ;否则,返回 False 。

对于每一个1,与其左右最近的1的间距大于等于k,则保证了所有的1的间距大于等于k。所以只要顺序去查找1,然后将两个1的间距进行判断即可。只要这个过程中有两个相邻的1间距小于k就不满足题意。需要计算两个相邻的1的间距,需要知道这两个1的索引是多少,所以使用双指针pre, next分别表示一前一后两个的索引。

class Solution:
    def kLengthApart(self, nums: List[int], k: int) -> bool:
        if not k:return True
        pre = -float('inf')
        for i in range(len(nums)):
            if nums[i] == 1:
                if i-pre <= k:
                    return False
                pre = i
        return True

[Leetcode]1438. 绝对差不超过限制的最长连续子数组

给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。
如果不存在满足条件的子数组,则返回 0 。

构造滑动窗口([l, r]), 使用双端队列或者堆维护滑动窗口内的最大值序列和最小值序列.
如果窗口内的最大值和者最小值间隔大于题目条件, 移动l,改变窗口内的最大值或者最小值
直到满足要求.不断统计窗口的长度即可。

class Solution:
    def longestSubarray(self, nums: List[int], limit: int) -> int:
        from collections import deque
        max_ = deque()
        min_ = deque()
        n = len(nums)
        l = 0
        res = 0
        for r, num in enumerate(nums):
            while max_ and num > max_[-1]:
                max_.pop()
            max_.append(num)
            while min_ and num < min_[-1]:
                min_.pop()
            min_.append(num)

            while max_[0] - min_[0] > limit:
                if nums[l] == max_[0]:
                    max_.popleft()
                if nums[l] == min_[0]:
                    min_.popleft()
                l += 1
            if max_[0] - min_[0] <= limit:
                res = max(res, r - l +1)
        
        return res

[Leetcode]1439. 有序矩阵中的第 k 个最小数组和

给你一个 m * n 的矩阵 mat,以及一个整数 k ,矩阵中的每一行都以非递减的顺序排列。
你可以从每一行中选出 1 个元素形成一个数组。返回所有可能数组中的第 k 个 最小 数组和。

最小堆。最小堆存储的是([curr_sum, pointers])二元组,pointers是指针数组,curr_sum是该pointers指向的元素的和。初始化pointers全为0,求出相应的curr_sum,并将其入堆。
重复下列步骤k次:

  • 从堆中pop出curr_sum和pointers。
  • 遍历pointers的每个索引,将该索引加一,求出新的和,如果没有出现过,push入堆。

(mat = [[1,10,10],[1,4,5],[2,3,6]]),k = 7为例,初始化pointers = (0, 0, 0),curr_sum = 4,哈希表seen加入(0, 0, 0)
从堆中pop出最小和,pointers = (0, 0, 0),curr_sum = 4。新生成([13, (1, 0, 0)],[7, (0, 1, 0)],[5, (0, 0, 1)]),在seen中做好标记,然后将三者入堆。重复该步骤k次。

import heapq

class Solution:
    def kthSmallest(self, mat, k: int) -> int:
        m, n = len(mat), len(mat[0])
        # 初始化指针
        pointers = [0] * m 
        # 初始化heap
        heap = []
        curr_sum = 0
        for i in range(m):
            curr_sum += mat[i][0]
        heapq.heappush(heap, [curr_sum, tuple(pointers)])
        # 初始化seen
        seen = set()
        seen.add(tuple(pointers))
        # 执行k次
        for _ in range(k):
            # 从堆中pop出curr_sum(最小数组和)和pointers(指针数组)
            curr_sum, pointers = heapq.heappop(heap)
            # 每个指针轮流后移一位,将new_sum(新的数组和)和new_pointers(新的指针数组)push入堆
            for i, j in enumerate(pointers):
                if j < n - 1:
                    new_pointers = list(pointers)
                    new_pointers[i] = j + 1
                    new_pointers = tuple(new_pointers)
                    if new_pointers not in seen:
                        new_sum = curr_sum + mat[i][j + 1]- mat[i][j]
                        heapq.heappush(heap, [new_sum, new_pointers])
                        seen.add(new_pointers)
        return curr_sum
        

参考:
leetcode

原文地址:https://www.cnblogs.com/hellojamest/p/12835023.html