---
# System prepended metadata

title: '**Leetcode筆記(Word Search)**'
tags: [graph, medium, microsoft, leetcode]

---

# **Leetcode筆記(Word Search)**


:::info
:information_source: 題目 : Word Search, 類型 : graph , 等級 : medium
日期 : 2023/03/02，2023/05/17，2023/07/11，2023/12/01，2024/04/04，2025/02/20
:::


### 嘗試

2023/05/17，判斷錯誤條件要放上面
```python
条件判断顺序错误：在 dfs 函数中，你应该首先检查边界条件，
然后再检查字符匹配和访问状态。
将边界条件判断放在了字符匹配判断之后，
这会导致出现越界或访问重复位置的情况。
錯誤 : if board[r][c] != word[i] or r < 0 or r >= m 
        or c < 0 or c >= n or (r, c) in visited

    

class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        m, n = len(board), len(board[0])
        dirs = [(1, 0), (-1, 0), (0, 1), (0, -1)]
        visited = set()

        def dfs(r, c, i):
            if i == len(word):
                return True
            # 條件不符
            if r < 0 or r >= m or c < 0 or c >= n or board[r][c] != word[i] or (r, c) in visited:
                return False
            
            visited.add((r, c))

            for dr, dc in dirs:
                nr, nc = r + dr, c + dc
                # 如果把r和c的範圍限制條件放在這裡
                # 會使得board = "a", word = "a"這種例子無法通過
                # 但如果放上面進到i == len(word)就會通過了
                if dfs(nr, nc, i + 1):
                    return True

            # 會跑到這邊就代表dfs沒有回傳True
            # 要回頭是其他條路
            visited.remove((r, c))
            return False


        for r in range(m):
            for c in range(n):
                if dfs(r, c, 0):
                    return True
        return False
```
2023/07/11
需要**在遞迴呼叫dfs()時，加上if dfs()，因為如果其中一個一層達成上面return True的條件，那後面在遞迴stack的 皆無條件return True**
最後**如果這條路徑走不通，那就需要remove((r, c))，如果有兩層以上的遞迴路徑，remove會使得退回上一層時，visited內裝的是正常的路徑**
```python
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        visited = set()

        def dfs(r, c, i, visited):
            if i == len(word):
                return True

            if r < 0 or c < 0 or r >= len(board) or c >= len(board[0]) or board[r][c] != word[i] or (r, c) in visited:
                return
            
            visited.add((r, c))

            for dr, dc in dirs:
                nr, nc = r + dr, c + dc
                # 如果其中一個一層達成上面return True的條件
                # 那後面在遞迴stack的 皆無條件return True
                if dfs(nr, nc, i + 1, visited): 
                    return True 

            visited.remove((r, c))

            return

        for r in range(len(board)):
            for c in range(len(board[0])):
                if dfs(r, c, 0, visited):
                    return True
        return False
```
2023/12/01
```python
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        n, m = len(board), len(board[0])
        visited = set()
        dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]

        def dfs(r, c, i):
            if i == len(word):
                return True
            if r < 0 or c < 0 or r >= n or c >= m or (r, c) in visited or board[r][c] != word[i]:
                return False
            
            visited.add((r, c))
            for dr, dc in dirs:
                nr, nc = r + dr, c + dc
                if dfs(nr, nc, i + 1):
                    return True
            
            visited.remove((r, c))
            return False

        for r in range(n):
            for c in range(m):
                if dfs(r, c, 0):
                    return True
        return False
```
2024/04/04
```python
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        m, n = len(board), len(board[0])
        visited = set()
        dirs = [(0, 1), (0, -1), (1, 0), (-1, 0)]

        def dfs(r, c, i):
            if i == len(word):
                return True
            if r < 0 or r >= m or c < 0 or c >= n or (r, c) in visited or board[r][c] != word[i]:
                return False
            
            visited.add((r, c))
            for dr, dc in dirs:
                nr, nc = r + dr, c + dc
                if dfs(nr, nc, i + 1):
                    return True
            
            visited.remove((r, c))
            return


        for r in range(m):
            for c in range(n):
                if dfs(r, c, 0):
                    return True
        
        return False
```
2025/02/20
```python
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        self.n, self.m = len(board), len(board[0])
        self.dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        self.visited = set()
        self.board, self.word = board, word

        for r in range(self.n):
            for c in range(self.m):
                if self.dfs(r, c, 0):
                    return True
        return False

    def dfs(self, r, c, i):
        if i == len(self.word):
            return True
        if r < 0 or r >= self.n or c < 0 or c >= self.m or self.board[r][c] != self.word[i] or (r, c) in self.visited:
            return
        
        self.visited.add((r, c))
        for dr, dc in self.dirs:
            nr, nc = r + dr, c + dc
            if self.dfs(nr, nc, i + 1):
                return True
        
        self.visited.remove((r, c))
        return
```

---
### **優化**

時間複雜度：
- 在最壞的情況下，我們需要遍歷整個二維字符矩陣，因此時間複雜度為 O(rows * cols)，其中 rows 是矩陣的行數，cols 是矩陣的列數。
- 在每個遍歷過程中，我們可能需要遞迴調用 `dfs` 函數，該函數的時間複雜度與單詞長度相關，即 O(word_length)。
- **總體時間複雜度為 O(rows * cols * word_length)**。

空間複雜度：
- **在最壞的情況下(當word等於整個matrix上面的所有數字)**，當遞迴深度達到最大值時，堆疊空間的最大需求是 O(rows * cols)。
- `visited` 集合用於記錄已訪問的位置，其大小取決於二維字符矩陣的大小，最大情況下是 O(rows * cols)。
- 總體空間複雜度為 O(rows * cols)。

```python
class Solution:
    def exist(self, board: List[List[str]], word: str) -> bool:
        row, col = len(board), len(board[0])
        path = set()

        def dfs(r, c, i): # i為word中第幾個
            if i == len(word):
                return True
            
            if (r < 0 or c < 0 or r >= row or c >= col or 
            word[i] != board[r][c] or # 字母對不上
            (r, c) in path): # 已找到過
                return False # 也可以只打return(也就是return None)
                # 跳回呼叫它的起點

            path.add((r, c)) # 開始找到第一個會經過這裡

            # 若有任一一個dfs()執行，則res會收到true
            res = (dfs(r + 1, c, i + 1) or dfs(r - 1, c, i + 1) or 
            dfs(r, c + 1, i + 1) or dfs(r, c - 1, i + 1))

            # 上面找到的那點鄰近都沒有下一個點 代表不是真正的正確點 
            path.remove((r, c)) 
            return res # True或False
            # 如果是False 則會回去下面 跑下一個迴圈
        
        for r in range(row):
            for c in range(col):
                if dfs(r, c, 0): # 從word中第一個字開始 # 也只找第一個字
                # 若此指令為true，也就是上面回傳true
                    return True
        return False
```
---


**:warning: 錯誤語法** 
:::warning
換行 : 在一行末尾加上‘\’
從程式碼中清楚的判斷這個輸出是bool還是list還是int等等
:::


**:thumbsup:學習** 
:::success
函數中若有return就會跳出該函數，不會執行下面的程式碼
若是return沒有給資料，也會跳回到呼叫該函式的區塊，回傳值的結果是 None

集合不會包含重複的資料
set.add(value)
set.remove(value)
檢查元素是否在集合 : r, c in set
:::

**思路**


**講解連結**
https://www.youtube.com/watch?v=pfiQ_PS1g8E
Provided by. NeetCode

###### tags: `graph` `medium` `leetcode`