(Scala) Leetcode 200. 超出内存限制
Posted
技术标签:
【中文标题】(Scala) Leetcode 200. 超出内存限制【英文标题】:(Scala) Leetcode 200. Memory limit exceeded 【发布时间】:2020-08-22 21:53:04 【问题描述】:我正在使用 Scala 来解决此处记录的问题:https://leetcode.com/problems/number-of-islands/
给定一个由“1”(陆地)和“0”(水)组成的二维网格图,计算数量 的岛屿。岛屿四面环水,由 水平或垂直连接相邻土地。你可以假设 网格的四个边缘都被水包围。
示例 1:
输入: 网格 = [ ["1","1","1","1","0"], ["1","1","0","1","0"], ["1","1","0","0","0"], ["0","0","0","0","0"] ] 输出:1
示例 2:
输入: 网格 = [ ["1","1","0","0","0"], ["1","1","0","0","0"], ["0","0","1","0","0"], ["0","0","0","1","1"] ] 输出:3
我认为这是广度(或深度)优先搜索的简单应用。但是,我的程序在 Leetcode 产生了超出内存限制的错误。我还在笔记本电脑上运行了该程序。我的 Mac 报告它使用了超过 3 GB 的内存,即使我已经注释掉了 3 行测试用例。什么在我的代码中消耗了这么多内存?
// Memory OVERFLOW !!? Why ??
class Leet0200
def numIslands(grid: Array[Array[Char]]): Int =
var (y, x) = getPosition(grid)
var c = 0
val dirs = Array(
Array(1, 0),
Array(-1, 0),
Array(0, 1),
Array(0, -1)
)
while ((y, x) != (-1, -1))
c += 1
val queue = scala.collection.mutable.Queue[(Int, Int)]()
queue.enqueue((y,x))
while (queue.nonEmpty)
val me = queue.dequeue()
val (me_y, me_x) = me
grid(me_y)(me_x) = 'c'
for (d <- dirs)
val (ny, nx) = (me_y + d(0), me_x+d(1))
if (ny >= 0 && ny < grid.length
&& nx >= 0 && nx < grid(0).length
&& grid(ny)(nx) == '1')
queue.enqueue((ny, nx))
val newPos = getPosition(grid)
y = newPos._1
x = newPos._2
c
def getPosition(grid: Array[Array[Char]]): (Int, Int) =
for (y <- grid.indices)
for (x <- grid(0).indices)
if (grid(y)(x) == '1') return (y, x)
(-1, -1)
object Leet0200
def main(args: Array[String]): Unit =
val leet = new Leet0200()
println(
leet.numIslands(Array(
Array('1','1','1','1','1','0','1','1','1','1','1','1','1','1','1','0','1','0','1','1'),
Array('0','1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','1','0'),
Array('1','0','1','1','1','0','0','1','1','0','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','0','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','0','0','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','0','1','1','1','1','1','1','0','1','1','1','0','1','1','1','0','1','1','1'),
Array('0','1','1','1','1','1','1','1','1','1','1','1','0','1','1','0','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','0','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('0','1','1','1','1','1','1','1','0','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','0','1','1','1','1','1','1','1','0','1','1','1','1','1','1'),
Array('1','0','1','1','1','1','1','0','1','1','1','0','1','1','1','1','0','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','1','1','0'),
//Array('1','1','1','1','1','1','1','1','1','1','1','1','1','0','1','1','1','1','0','0'),
//Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
//Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1'),
Array('1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1','1')
)))
【问题讨论】:
诚实的反馈,LeetCode 不是学习 Scala 的好资源。他们所有的问题都打算使用非常命令式的算法来解决,这只会教你语言的基本语法。您不会了解使 Scala 成为现在这样的所有东西,例如 Option 丰富的集合框架,Either 和 Try,更喜欢不变性,强类型系统等 虽然我倾向于同意 Luis Miguel 关于 LeetCode 倾向于命令式代码的观点,但并非总是如此。我用 15 行纯 FP Scala 解决了这个问题。 @jwvh 看到这个解决方案实际上会很有趣,至少作为一个 Sctie :) @LuisMiguelMejíaSuárez; As you wish. 【参考方案1】:您的队列中会出现重复项,它们会滚雪球。将内容放入队列时,通过将队列更改为 Set 来检查它是否已经在其中。
例如,让我们检查一张地图:
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
最初,getPosition() 将返回 (0, 0)。
0, 0:您将放入队列:(0, 1) 和 (1, 0)。 0, 1:您将放入队列:(0, 2) 和 (1, 1)。队列现在有:(1, 0), (0, 2), (1, 1) 1, 0:您将放入队列:(2, 0) 和 (1, 1)。队列现在有:(0, 2), (1, 1), (2, 0), (1, 1)请注意,队列中现在有 2 x (1, 1)。因此 (1, 1) 将被处理两次,因此将 2 x 结果添加到队列中(即 2 x (2, 1) 和 2 x (1, 2))。这些结果将复制成 4 x (2, 2)。因此会产生滚雪球效应。
这将是消耗队列中内存的雪球效应。如果使用 Set,则不会出现滚雪球效果,因为不会再次添加相同的位置。
另一种解决方案是在添加到队列时使用您的标记,而不是在处理如下代码时使用:
val queue = scala.collection.mutable.Queue[(Int, Int)]()
queue.enqueue((y,x))
grid(y)(x) = 'c'; // <--- moved to
while (queue.nonEmpty)
val me = queue.dequeue()
val (me_y, me_x) = me
// grid(me_y)(me_x) = 'c' // <--- moved from
for (d <- dirs)
val (ny, nx) = (me_y + d(0), me_x+d(1))
if (ny >= 0 && ny < grid.length
&& nx >= 0 && nx < grid(0).length
&& grid(ny)(nx) == '1')
queue.enqueue((ny, nx))
grid(ny)(nx) = 'c'; // <--- moved to
因为你做了grid(ny)(nx) == '1'
检查,同一个位置不会被多次添加到队列中。
【讨论】:
以上是关于(Scala) Leetcode 200. 超出内存限制的主要内容,如果未能解决你的问题,请参考以下文章
使用 scala 和 android-plugin 的 Proguard:java.lang.StringIndexOutOfBoundsException:字符串索引超出范围:160
scala中计算的的一个小问题,超出Int.maxValue时不会报错