程式碼隨想錄day52 || 圖論搜尋 島嶼數量,島嶼的最大面積

周公瑾55發表於2024-09-05

圖遍歷

dfs 深度優先搜尋

image

bfs 廣度優先搜尋

image

200 島嶼數量(dfs)

var dirPath = [][]int{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} // 上, 右, 下, 左
var visited [][]bool
func numIslands(grid [][]byte) int {
	// dfs 深度優先遍歷,對於每一個節點,按照上下左右四個固定順序遍歷,然後到下一個節點遞迴,實現一條路走到黑

	// 重新初始化,避免多個測試樣例導致出現全域性變數汙染情況
	visited = make([][]bool, len(grid))
	for idx, _ := range visited {
		visited[idx] = make([]bool, len(grid[0]))
	}
	var res int
	for i:=0; i<len(grid); i++ {
		for j:=0; j<len(grid[0]); j++ {
			if grid[i][j] != '0' && !visited[i][j] {  // 是陸地並且沒被遍歷過
				dfs(grid, i, j)
			}else{
				continue
			}
			if visited[i][j] { // 是陸地,並且被標記了,這裡的標記會遍歷整個四周陸地,並且為周邊陸地打上標記,所以不會出現同一陸地多個地塊都被計數
				res += 1
			}
		}
	}

	return res
}
func dfs(grid [][]byte, x, y int) {
	// 遇到之前節點或者水,返回
	if grid[x][y] == '0' || visited[x][y] == true {
		visited[x][y] = true  // 最佳化,不是陸地也標記遍歷過,防止出現多次對水進行重複遍歷
		return
	}

	visited[x][y] = true  // 本節點是陸地並且標記為已經遍歷過
	// 按照四個方向遍歷到下一個節點,然後遞迴,實現一條路走到黑之後回溯,由於不需要路徑,所以回溯過程視為隱藏
	for _, v := range dirPath {
		next_x, next_y := x+v[0], y+v[1] // 要遍歷的下一個節點
		if next_x < 0 || next_x >= len(grid) || next_y < 0 || next_y >= len(grid[0]) {  // 避免出現節點越界情況
			continue
		}
		// 加入
		dfs(grid, next_x, next_y)
		// 回溯
	}
	return
}

島嶼數量(bsf)

var dirPath = [][]int{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} // 上, 右, 下, 左
var visited [][]bool
var queue *list.List
func numIslands(grid [][]byte) int {
	// 重新初始化,避免多個測試樣例導致出現全域性變數汙染情況
	queue = list.New()
	visited = make([][]bool, len(grid))
	for idx, _ := range visited {
		visited[idx] = make([]bool, len(grid[0]))
	}

	var res int
	for i:=0; i<len(grid); i++ {
		for j:=0; j<len(grid[0]); j++ {
			if grid[i][j] != '0' && !visited[i][j] {  // 是陸地並且沒被遍歷過
				queue.PushBack([2]int{i, j})
				visited[i][j] = true
				bfs(grid)
			}else{
				continue
			}
			if visited[i][j] { // 本質上多餘這一步判斷,方便理解放進去了
				// 是陸地,並且被標記了,這裡的標記會遍歷整個四周陸地,並且為周邊陸地打上標記,所以不會出現同一陸地多個地塊都被計數
				res += 1
			}
		}
	}
	return res
}
func bfs(grid [][]byte) {
	for queue.Len() > 0 { // 一個島嶼的完成遍歷過程就是整個佇列完全為空
		node := queue.Remove(queue.Front()).([2]int) // 去除隊首,斷言為長度為2陣列
		for _, v := range dirPath {  // 遍歷四個節點標記入隊
			next_x, next_y := node[0] + v[0], node[1] + v[1]
			if next_x < 0 || next_x >= len(grid) || next_y < 0 || next_y >= len(grid[0]) {  // 避免越界
				continue
			}
			if visited[next_x][next_y] { // 節點被使用過,過
				continue
			}

			// 先標記再入隊,可以避免很多重複遍歷,例如如果節點是0,不標記已經遍歷過,那麼bfs中也要遍歷多次,主函式兩層for迴圈也要遍歷多次,容易超時
			visited[next_x][next_y] = true
			if grid[next_x][next_y] == '1'{
				queue.PushBack([2]int{next_x, next_y})
			}
		}
	}
}

島嶼最大面積(dfs)

var dirPath = [4][2]int{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} // 上右下左
var visited [][]bool
var area int
func maxAreaOfIsland(grid [][]int) int {

	visited = make([][]bool, len(grid))
	for idx, _ := range visited {
		visited[idx] = make([]bool, len(grid[0]))
	}

	var maxArea int
	for i:=0; i<len(grid); i++ {
		for j:=0; j<len(grid[0]); j++{
			if !visited[i][j] && grid[i][j] == 1{
				area = 1
				dfs(grid, i, j)
				maxArea = max(area, maxArea)
			}
		}
	}

	return maxArea
}

func dfs(grid [][]int, x, y int) {
	if visited[x][y] || grid[x][y] == 0 { // 如果是水,標記返回,或者如果是標記過,也直接返回
		visited[x][y] = true
		return
	}
	visited[x][y] = true // 此時是陸地,標記
	for _, dir := range dirPath {
		next_x, next_y := dir[0] + x, dir[1] + y
		if next_x < 0 || next_x >= len(grid) || next_y < 0 || next_y >= len(grid[0]) {
			continue
		}
		if grid[next_x][next_y] == 1 && !visited[next_x][next_y]{
			area++
			dfs(grid, next_x, next_y)
		}
	}
}


島嶼最大面積(bfs)

var dirPath = [4][2]int{{0, -1}, {1, 0}, {0, 1}, {-1, 0}} // 上右下左
var visited [][]bool
var queue *list.List
func maxAreaOfIsland(grid [][]int) int {

	visited = make([][]bool, len(grid))
	for idx, _ := range visited {
		visited[idx] = make([]bool, len(grid[0]))
	}
	queue = list.New()

	var maxArea int
	for i:=0; i<len(grid); i++ {
		for j:=0; j<len(grid[0]); j++{
			if !visited[i][j] && grid[i][j] == 1{
				visited[i][j] = true
				queue.PushBack([2]int{i, j})
				area := bfs(grid)
				maxArea = max(area, maxArea)
			}
		}
	}

	return maxArea
}

func bfs(grid [][]int) int {
	var area int = 1
	for queue.Len() >0 {
		node := queue.Remove(queue.Front()).([2]int)
		for _, dir := range dirPath{
			next_x, next_y := node[0] + dir[0], node[1] + dir[1]
			if next_x < 0 || next_x >= len(grid) || next_y < 0 || next_y >= len(grid[0]) { // 越界
				continue
			}
			if grid[next_x][next_y] == 1 && !visited[next_x][next_y] {
				area++
				queue.PushBack([2]int{next_x, next_y})
			}
			visited[next_x][next_y] = true
		}
	}
	return area
}

相關文章