scala 刷LeetCode题——1462. 课程表 IV

目录

题目描述

思路分析

解决方案

1、拓扑排序

2、递归

两种算法的执行结果

代码总结

优越性比较


题目描述

        你总共需要上 numCourses 门课,课程编号依次为 0 到 numCourses-1 。你会得到一个数组 prerequisite ,其中 prerequisites[i] = [ai, bi] 表示如果你想选 bi 课程,你 必须 先选 ai 课程。

        有的课会有直接的先修课程,比如如果想上课程 1 ,你必须先上课程 0 ,那么会以 [0,1] 数对的形式给出先修课程数对。

        先决条件也可以是 间接 的。如果课程 a 是课程 b 的先决条件,课程 b 是课程 c 的先决条件,那么课程 a 就是课程 c 的先决条件。

        你也得到一个数组 queries ,其中 queries[j] = [uj, vj]。对于第 j 个查询,您应该回答课程 uj 是否是课程 vj 的先决条件。返回一个布尔数组 answer ,其中 answer[j] 是第 j 个查询的答案。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/course-schedule-iv

举例:

输入:numCourses = 2, prerequisites = [[1,0]], queries = [[0,1],[1,0]]
输出:[false,true]
解释:课程 0 不是课程 1 的先修课程,但课程 1 是课程 0 的先修课程。

思路分析

  1. 此题最容易想到的是拓扑排序,其思路如下:
    1. 创建一个map集合,key用于存储课程号,value用于存储该课程号下的所有去重先修课程
    2. 定义一个长度为numCourses的数组,用于存放每个课程号的入度
    3. 创建一个栈,用于存放入度为0的课程号
    4. 将栈中的课程号对应的先修课程号存入map的value中
    5. 在集合中找到queries(i)(0)的课程号对应的所有先修课程values,如果values中包含queries(i)(1),则返回TRUE,否则返回false
  2. 当然,也可以使用递归来实现,其思路如下:
    1. 我们的目的是要判断queries(i)(1)的先修课程是否是queries(i)(0),因此
    2. 创建一个一维数组array,以数组下标作为先修课程号,数组内容为去重的课程号
    3. 递归逻辑:将先修课程号a下所有课程号放入先修课程号b下去重的课程号中
    4. 递归退出:当b中的课程号不再包含a中的课程号,则递归结束

解决方案

1、拓扑排序

def checkIfPrerequisite03(numCourses: Int, prerequisites: Array[Array[Int]], queries: Array[Array[Int]]): List[Boolean] = {
    import scala.collection.mutable
    import scala.collection.mutable.ListBuffer

    val list: ListBuffer[Boolean] = mutable.ListBuffer[Boolean]()

    // 创建一个map集合,key作为课程号,value的值作为key的先修课程号
    val map: mutable.HashMap[Int, mutable.Set[Int]] = new mutable.HashMap[Int, mutable.Set[Int]]()

    // 定义一个长度为numCourses的数组,存放每个课程号的入度
    val array: Array[Int] = new Array[Int](numCourses)

    // 初始化map
    for (i <- 0 until(numCourses)){
      map.put(i, mutable.HashSet())
    }

    for (i <- prerequisites.indices){
      map(prerequisites(i)(0)).add(prerequisites(i)(1))
      // 统计每个课程号的入度
      array(prerequisites(i)(1)) += 1
    }

    // 创建一个栈,用于存放入度为0的课程号
    val stack: mutable.Stack[Int] = new mutable.Stack[Int]()
    for (i <- array.indices){
      if (array(i)== 0){
        stack.push(i)
      }
    }

    while (stack.nonEmpty){
      val tmp: Int = stack.pop()

      for (i <- map(tmp)){
        for (j <- 0 until(numCourses)){
          if (map(j).contains(tmp)){
            // 如果课程j的先修课程号中包含了入度为0的课程号,则将入度为0的先修课程号加入到课程j中
            map(j).add(i)
          }
        }

        // 将课程号tmp的入度减1,如果减1后为0,则将其课程号入栈
        array(i) -= 1
        if (array(i) == 0){
          stack.push(i)
        }
      }

    }


    queries.foreach(c => {
      if (map.contains(c(0)) && map(c(0)).contains(c(1))) {
        list.append(true)
      } else {
        list.append(false)
      }
    })

    list.toList
  }

2、递归

  def addMap(a: Int, b: Int, map: Array[mutable.Set[Int]]): Unit = {
    // 把a里面的元素放到b里面来,只要b里面全都有了a里面的元素即可
    for (i <- map(a)){
      if (! map(b).contains(i)){
        map(b).add(i)
        addMap(i,b,map)
      }
    }
  }


  def checkIfPrerequisite02(numCourses: Int, prerequisites: Array[Array[Int]], queries: Array[Array[Int]]): List[Boolean] = {
    import scala.collection.mutable
    import scala.collection.mutable.ListBuffer

    val map: Array[mutable.Set[Int]] = new Array[mutable.Set[Int]](numCourses)
    val list: ListBuffer[Boolean] = mutable.ListBuffer[Boolean]()


    // 初始化map

    for (n <- 0 until numCourses){
      map(n) = mutable.Set()
    }

    for (i <- prerequisites.indices){
      map(prerequisites(i)(1)).add(prerequisites(i)(0))
    }


    for (i <- 0 until(numCourses)) {
      for (j <- 0 until(numCourses)){
        if (map(j).contains(i)){
          // 如果j里面的元素有i,就把i里面的元素放到j里面来
          addMap(i,j,map)
        }
      }

    }

    for (i <- queries.indices){
      list.append(map(queries(i)(1)).contains(queries(i)(0)))
    }

    list.toList
  }

两种算法的执行结果

代码总结

  • 当定义另一个定长的map数组,数组内容没有默认值时,必须记得初始化,否则其元素是null。
    • val map: Array[mutable.Set[Int]] = new Array[mutable.Set[Int]](numCourses)
  • scala也提供了栈(Stack)的数据结构,
    • 栈主要两个操作: 入栈(push)和出栈(pop)。

优越性比较

在此我以LeetCode提交结果做简要的分析吧,

由图可以发现,

  • 同为递归算法,但java的执行用时和内存消耗是最小的,这也说明了scala语言虽然比java简洁,开发效率高,但由于scala底层调用了java,导致其执行效率明显不足。
  • 同为scala语言,递归算法确实比拓扑排序要略胜一筹。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值