|
| 1 | +package com.leetcode.scala.monthly2020.july |
| 2 | + |
| 3 | +import scala.collection.mutable |
| 4 | + |
| 5 | +/* |
| 6 | +* You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 represents water. |
| 7 | +* Grid cells are connected horizontally/vertically (not diagonally). |
| 8 | +* The grid is completely surrounded by water, and there is exactly one island (i.e., one or more connected land cells). |
| 9 | +* The island doesn't have "lakes" (water inside that isn't connected to the water around the island). |
| 10 | +* One cell is a square with side length 1. The grid is rectangular, width and height don't exceed 100. |
| 11 | +* Determine the perimeter of the island. |
| 12 | +* |
| 13 | +* */ |
| 14 | + |
| 15 | +/* |
| 16 | +* Input: |
| 17 | + [[0,1,0,0], |
| 18 | + [1,1,1,0], |
| 19 | + [0,1,0,0], |
| 20 | + [1,1,0,0]] |
| 21 | +
|
| 22 | + Output: 16 |
| 23 | + Explanation: The perimeter is the 16 yellow stripes in the image below: |
| 24 | + * @Link: https://leetcode.com/explore/featured/card/july-leetcoding-challenge/544/week-1-july-1st-july-7th/3383/ |
| 25 | +* |
| 26 | +* */ |
| 27 | + |
| 28 | +/* |
| 29 | +* Approach: Breadth First Search (BFS) |
| 30 | +* 1. We have defined a case class to store the indexes as pair. |
| 31 | +* 2. getIslandStart will find the edge of the island will give the Pair - from which we have to start the BFS. |
| 32 | +* 3. getValue will return the value of the Pair. |
| 33 | +* 4. In Our function islandPerimeter: |
| 34 | + * a. First, we will check if the grid is empty. If empty we will return 0. |
| 35 | + * b. If grid non-empty we will use getIslandStart to get the Pair from which we need to start. |
| 36 | + * c. We will build Queue(To store the nodes to be visited) and HashSet(To store the visited nodes). |
| 37 | + * d. We will enqueue the queue with start Pair and we will add the start Pair to the HashSet. |
| 38 | + * e. We will dequeue the queue and we will check for the conditions if the node is at the edge of the grid we will add (1 * no_of_edges shared with the edge of the grid) to the perimeter based on the fact that how many edges are at the edge of the grid for that particular node. |
| 39 | + * f. We will check if the node share it's edges with any nodes in top, left, right or bottom. If the node shares it's edge with any of the adjacent node and the value of the adjacent node is 1 and the node is not visited then we will enqueue the adjacent node to the queue and we will add the adjacent node to the HashSet. |
| 40 | + * g. If the above condition doesn't match then the adjacent node should be 0. So, we will add 1 to the perimeter. |
| 41 | + * h. Finally, the queue will be empty and we will be return the perimeter value. |
| 42 | + * |
| 43 | +* */ |
| 44 | + |
| 45 | +case class Pair(x: Int, y: Int) |
| 46 | + |
| 47 | +object IslandPerimeter { |
| 48 | + |
| 49 | + def main(args: Array[String]): Unit = { |
| 50 | + val grid = Array(Array(0, 1, 0, 0), |
| 51 | + Array(1, 1, 1, 0), |
| 52 | + Array(0, 1, 0, 0), |
| 53 | + Array(1, 1, 0, 0)) |
| 54 | + |
| 55 | + val result = islandPerimeter(grid) |
| 56 | + |
| 57 | + println(s"Result: ${result}, ${result == 16}") |
| 58 | + |
| 59 | + val grid1 = Array(Array(1)) |
| 60 | + |
| 61 | + val result1 = islandPerimeter(grid1) |
| 62 | + |
| 63 | + println(s"Result: ${result1}, ${result1 == 4}") |
| 64 | + |
| 65 | + val grid2 = Array(Array(1, 1), Array(1, 1)) |
| 66 | + |
| 67 | + val result2 = islandPerimeter(grid2) |
| 68 | + |
| 69 | + println(s"Result: ${result2}, ${result2 == 8}") |
| 70 | + |
| 71 | + } |
| 72 | + |
| 73 | + def islandPerimeter(grid: Array[Array[Int]]): Int = { |
| 74 | + if (grid.isEmpty) return 0 |
| 75 | + val start = getIslandStart(grid) |
| 76 | + var visited: mutable.HashSet[Pair] = mutable.HashSet() |
| 77 | + var queue: mutable.Queue[Pair] = mutable.Queue[Pair]() |
| 78 | + queue.enqueue(start) |
| 79 | + visited.add(start) |
| 80 | + var perimeter = 0 |
| 81 | + while (queue.nonEmpty) { |
| 82 | + val currentPair = queue.dequeue() |
| 83 | + val i = currentPair.x |
| 84 | + var j = currentPair.y |
| 85 | + val left = Pair(i, j - 1) |
| 86 | + val right = Pair(i, j + 1) |
| 87 | + val top = Pair(i - 1, j) |
| 88 | + val down = Pair(i + 1, j) |
| 89 | + if (i == 0) perimeter += 1 |
| 90 | + if (j == 0) perimeter += 1 |
| 91 | + if (i == grid.length - 1) perimeter += 1 |
| 92 | + if (j == grid(i).length - 1) perimeter += 1 |
| 93 | + if (j > 0 && !visited.contains(left) && getValue(left, grid) == 1) { |
| 94 | + queue.enqueue(left) |
| 95 | + visited.add(left) |
| 96 | + } else if (j > 0 && !visited.contains(left) && getValue(left, grid) == 0) { |
| 97 | + perimeter += 1 |
| 98 | + } |
| 99 | + if (j < grid(i).length - 1 && !visited.contains(right)) { |
| 100 | + if (getValue(right, grid) == 1) { |
| 101 | + queue.enqueue(right) |
| 102 | + visited.add(right) |
| 103 | + } else { |
| 104 | + perimeter += 1 |
| 105 | + } |
| 106 | + } |
| 107 | + if (i > 0 && !visited.contains(top)) { |
| 108 | + if (getValue(top, grid) == 1) { |
| 109 | + queue.enqueue(top) |
| 110 | + visited.add(top) |
| 111 | + } else { |
| 112 | + perimeter += 1 |
| 113 | + } |
| 114 | + } |
| 115 | + if (i < grid.length - 1 && !visited.contains(down)) { |
| 116 | + if (getValue(down, grid) == 1) { |
| 117 | + queue.enqueue(down) |
| 118 | + visited.add(down) |
| 119 | + } else { |
| 120 | + perimeter += 1 |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + return perimeter |
| 125 | + } |
| 126 | + |
| 127 | + def getValue(pair: Pair, grid: Array[Array[Int]]): Int = { |
| 128 | + return grid(pair.x)(pair.y) |
| 129 | + } |
| 130 | + |
| 131 | + def getIslandStart(grid: Array[Array[Int]]): Pair = { |
| 132 | + var pair = Pair(0, 0) |
| 133 | + for (i <- grid.indices) { |
| 134 | + for (j <- grid(i).indices) { |
| 135 | + if (grid(i)(j) == 1) return Pair(i, j) |
| 136 | + } |
| 137 | + } |
| 138 | + return pair |
| 139 | + } |
| 140 | + |
| 141 | +} |
0 commit comments