AI刷题记录(三) | 豆包MarsCode AI刷题

52 阅读4分钟

AI刷题记录(三) | 豆包MarsCode AI刷题

课程表

问题描述

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程  bi 。

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。

思路

bi -> ai的边,然后从每个没有入度的根节点搜索,使用vis记录当次搜索的状态,使用flag记录总的访问情况。当vis[u]==True,说明节点已经被访问过,说明遇到环了,答案返回falseflag[u]==True,则跳过。

代码
class Solution:
    def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
        e = [[] for _ in range(numCourses)]
        in_deg = [0] * numCourses
        vis = [0] * numCourses
        flag = [0] * numCourses
        for v, u in prerequisites:
            e[u].append(v)
            in_deg[v] += 1
        def dfs(u) -> bool:
            vis[u] += 1
            flag[u] += 1
            ret = True
            for v in e[u]:
                if vis[v] > 0:
                    ret = False
                    break
                if flag[v] > 0: continue
                res = dfs(v)
                if res == False:
                    ret = False
                    break
            vis[u] -= 1
            return ret
        for i in range(numCourses):
            if in_deg[i] > 0: continue
            res = dfs(i)
            if res == False: return False
        if sum(flag) != numCourses: return False
        return True

网络延迟时间

问题描述

有 n 个网络节点,标记为 1 到 n

给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1 。

思路

使用搜索或者最短路均可,需要考虑会重复经过一个节点的问题,使用dis数组表示从根到该节点的最短距离,若当前花费小于dis内的值,则直接退出即可,否则更新并继续深入搜索。

代码
class Solution:
    def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int:
        adj = [[] for _ in range(n)]
        dis = [int(1e9)] * n
        for t in times:
            u, v, w = t
            adj[u-1].append((v-1, w))
        
        def dfs(u, t):
            if dis[u] <= t: return
            dis[u] = t
            for v, w in adj[u]:
                dfs(v, t + w)
                
        dfs(k-1, 0)
        if sum((1 for x in dis if x < int(1e9) )) < n: return -1
        return max((x for x in dis if x < int(1e9) ))

最大矩形面积

问题描述

小S最近在分析一个数组 h1,h2,...,hNh_1,h_2,...,h_N,数组的每个元素代表某种高度。小S对这些高度感兴趣的是,当我们选取任意 kk 个相邻元素时,如何计算它们所能形成的最大矩形面积。

对于 kk 个相邻的元素,我们定义其矩形的最大面积为:

R(k)=k×min(h[i],h[i+1],...,h[i+k1])R(k)=k×min(h[i],h[i+1],...,h[i+k1])R(k)=k×min(h[i],h[i+1],...,h[i+k−1])R(k)=k×min(h[i],h[i+1],...,h[i+k−1])

即,R(k)R(k) 的值为这 kk 个相邻元素中的最小值乘以 kk。现在,小S希望你能帮他找出对于任意 kkR(k)R(k) 的最大值。

思路
  1. 暴力解法

    • 对于每个可能的 k(从 1 到 n),遍历数组,计算每个 k 个相邻元素的矩形面积,并记录最大值。
    • 时间复杂度为 O(n^2),对于较大的 n 可能不够高效。
  2. 优化思路

    • 使用单调栈来优化查找最小值的过程。
    • 单调栈可以帮助我们在 O(n) 时间内找到每个元素作为最小值时,能形成的最大矩形面积。
数据结构选择
  • 单调栈

    • 单调栈可以用来维护一个递增或递减的序列。
    • 我们可以利用单调栈来快速找到每个元素作为最小值时,能形成的最大矩形面积。
算法步骤
  1. 初始化

    • 创建一个单调栈,用于存储数组元素的索引。
    • 创建一个数组 left 和 right,分别记录每个元素作为最小值时,能向左和向右扩展的最大范围。
  2. 遍历数组

    • 从左到右遍历数组,维护单调栈。
    • 对于每个元素,计算其作为最小值时,能向左扩展的最大范围。
    • 从右到左遍历数组,计算其作为最小值时,能向右扩展的最大范围。
  3. 计算最大面积

    • 对于每个元素,计算其作为最小值时,能形成的最大矩形面积。
    • 记录并返回最大面积。
代码
def solution(n, array):
    # 初始化单调栈和左右扩展范围数组
    stack = []
    left = [0] * n
    right = [0] * n

    # 从左到右遍历数组,计算每个元素作为最小值时,能向左扩展的最大范围
    for i in range(n):
        while stack and array[stack[-1]] >= array[i]:
            stack.pop()
        left[i] = stack[-1] if stack else -1
        stack.append(i)

    stack = []

    # 从右到左遍历数组,计算每个元素作为最小值时,能向右扩展的最大范围
    for i in range(n-1, -1, -1):
        while stack and array[stack[-1]] >= array[i]:
            stack.pop()
        right[i] = stack[-1] if stack else n
        stack.append(i)

    return max(array[i] * (right[i] - left[i] - 1) for i in range(n))

if __name__ == "__main__":
    # Add your test cases here
    print(solution(5, [1, 2, 3, 4, 5]) == 9)