DFS即Depth First Search,是一種用於遍歷或搜索樹或圖的算法。 沿着樹的深度遍歷樹的節點,儘可能深的搜索樹的分支。其過程簡要來說是對每一個可能的分支路徑深入到不能再深入爲止,而且每個節點只能訪問一次。
##DFS模塊基本步驟
DFS(dep,...)
{
if (找到解 or 走不下去了)
{
...
return
}
枚舉下一種可能出現的情況,DFS(dep+1,...)
}
例題
地上有一個m行和n列的方格。一個機器人從座標0,0的格子開始移動,每一次只能向左,右,上,下四個方向移動一格,但是不能進入行座標和列座標的數位之和大於k的格子。 例如,當k爲18時,機器人能夠進入方格(35,37),因爲3+5+3+7 = 18。但是,它不能進入方格(35,38),因爲3+5+3+8 = 19。請問該機器人能夠達到多少個格子?
思路:利用回溯法遍歷所有元素,記錄滿足條件的路徑,爲了簡單起見,我們可以只從兩個方向尋找,向右與向下。需要注意的是邊界條件。
class Solution3:
def movingCount(self, threshold, rows, cols):
# 計算每一位之和
def getsum(num):
sum = 0
while num>0:
sum += num%10
num = num//10
return sum
path = []
def back(start):
if start in path or getsum(start[0]) + getsum(start[1])> threshold:
return None
if start[0]>=rows or start[1]>=cols:
return None
path.append(start) # 從0,0開始向右向下遍歷,減少走回頭路的次數
print(path)
back([start[0]+1,start[1]])
back([start[0],start[1]+1])
"""
if start[0]>=rows or start[1]>=cols or start[0]<0 or start[1]<0:
return None
path.append(start) # 從0,0開始向右向下遍歷,減少走回頭路的次數
back([start[0]+1,start[1]])
back([start[0]-1,start[1]])
back([start[0],start[1]-1])
back([start[0],start[1]+1])
"""
back([0,0])
return len(path)
print(Solution3().movingCount(4,3,5))
方法二
與方法一種保存每一條符合條件的路徑不同,該方法是通過構建一個同等大小的矩陣,記錄走過的路徑,然後在四個方向深度搜索。
class Solution2:
def __init__(self):
self.count = 0
def movingCount(self, threshold, rows, cols):
# write code here
arr = [[1 for i in range(cols)] for j in range(rows)]
self.findway(arr, 0, 0, threshold)
return self.count
def findway(self, arr, i, j, k):
if i < 0 or j < 0 or i >= len(arr) or j >= len(arr[0]):
return
tmpi = list(map(int, list(str(i)))) # 將一個整型數字轉化字符串類型,然後在列表化,最後在轉化爲整型。 12——[1,2]
tmpj = list(map(int, list(str(j))))
if sum(tmpi) + sum(tmpj) > k or arr[i][j] != 1:
return
arr[i][j] = 0 #記錄走過的路徑
self.count += 1
self.findway(arr, i + 1, j, k)
self.findway(arr, i - 1, j, k)
self.findway(arr, i, j + 1, k)
self.findway(arr, i, j - 1, k)
方法三
1、從(0,0)開始走,每成功走一步標記當前位置爲true,然後從當前位置往四個方向探索,
返回1 + 4 個方向的探索值之和。
2、探索時,判斷當前節點是否可達的標準爲:
1)當前節點在矩陣內;
2)當前節點未被訪問過;
3)當前節點滿足limit限制。
class Solution:
def movingCount(self, threshold, rows, cols):
# write code here
if not threshold or not rows or not cols:
return 0
# 定義每格標誌位: 0代表沒走過; 1代表走過
visited = [0]*(rows * cols)
for row in range(rows):
for col in range(cols):
return self.movingCountCore(threshold, rows, cols, row, col, visited)
# 數字數位求和函數
def digitSum(self, dig):
re = 0
while dig:
re = re + dig % 10
dig = dig // 10
return re
# 遞歸回溯判斷每步是否可行,並返回計數和累加
def movingCountCore(self, threshold, rows, cols, row, col, visited):
count = 0
if 0 <= row < rows and 0 <= col < cols\
and self.digitSum(row) + self.digitSum(col) <= threshold and visited[row * cols + col] == 0:
visited[row * cols + col] = 1
print("visited:",visited)
# 在遞歸中,依次遍歷每個元素的上下左右四個元素,如果滿足條件,則繼續遞歸,遞歸過的每一個元素都進行標記
count = 1 + self.movingCountCore(threshold, rows, cols, row - 1, col, visited) \
+ self.movingCountCore(threshold, rows, cols, row + 1, col, visited) \
+ self.movingCountCore(threshold, rows, cols, row, col - 1, visited) \
+ self.movingCountCore(threshold, rows, cols, row, col + 1, visited)
print("count:",count)
return count
# print(Solution().movingCount(10,7,7))
總結
類似的求路徑都可以用這種無腦深度優先搜索法去解決,即回溯的思想,需要注意的是遞歸的終止條件。