【回溯】79. 单词搜索

79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:
在这里插入图片描述

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCCED”
输出:true

示例 2:
在这里插入图片描述

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “SEE”
输出:true

示例 3:
在这里插入图片描述

输入:board = [[“A”,“B”,“C”,“E”],[“S”,“F”,“C”,“S”],[“A”,“D”,“E”,“E”]], word = “ABCB”
输出:false

提示:

m == board.length
n = board[i].length
1 <= m, n <= 6
1 <= word.length <= 15
board 和 word 仅由大小写英文字母组成

进阶:

你可以使用搜索剪枝的技术来优化解决方案,使其在 board 更大的情况下可以更快解决问题?

思路:回溯法

在这里插入图片描述

class Solution {
public:

    bool exist(vector<vector<char>>& board, string word) {
        for(int i=0;i<board.size();i++){
            for(int j=0;j<board[0].size();j++){
                if(dfs(board,word,0,i,j))
                    return true;
            }
        }
        return false;
    }

    bool dfs(vector<vector<char>>& board, string& str,int u ,int x, int y){
        if(board[x][y]!=str[u]) return false;
        if(u==str.size()-1) return true;

        int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
        char t=board[x][y];
        board[x][y]='*';
        for(int i=0;i<4;i++){
            int a=x+dx[i],b=y+dy[i];
            if(a<0 ||a>=board.size()||b<0 ||b>=board[0].size()||board[a][b]=='*'){
                continue;
            }
            if(dfs(board,str,u+1,a,b)) return true;
        }
        board[x][y]=t;
        return false;
    }
};

在这里插入图片描述

### Java回溯算法示例代码解析 #### 1. 回溯算法基本原理 回溯算法是一种基于深度优先搜索的思想,通过递归的方式逐步尝试解决问题的方法。当遇到无法满足条件的情况时,会撤销当前的选择并返回上一层继续尝试其他可能性[^3]。 #### 2. 示例代码:求解全排列问题 以下是使用Java实现的一个经典回溯算法案例——求数组 `[1, 2, 3]` 的所有排列: ```java import java.util.ArrayList; import java.util.List; public class BacktrackingExample { public static List<List<Integer>> permute(int[] nums) { List<List<Integer>> result = new ArrayList<>(); backtrack(nums, new boolean[nums.length], new ArrayList<>(), result); return result; } private static void backtrack(int[] nums, boolean[] used, List<Integer> current, List<List<Integer>> result) { if (current.size() == nums.length) { // 当前路径长度等于数组长度,则找到一种排列 result.add(new ArrayList<>(current)); return; } for (int i = 0; i < nums.length; i++) { if (used[i]) continue; // 如果该元素已被使用,则跳过 used[i] = true; // 标记为已使用 current.add(nums[i]); // 将当前元素加入路径 backtrack(nums, used, current, result); // 继续递归处理下一个位置 current.remove(current.size() - 1); // 撤销选择 used[i] = false; // 取消标记 } } public static void main(String[] args) { int[] nums = {1, 2, 3}; List<List<Integer>> permutations = permute(nums); System.out.println(permutations); } } ``` 上述代码实现了对给定数组 `nums` 所有排列的计算过程。核心逻辑在于通过递归和状态重置完成每种可能情况的枚举[^4]。 #### 3. 时间复杂度分析 对于大小为 \(n\) 的输入集合,其时间复杂度通常为 \(O(n!)\),因为需要穷尽所有的排列组合。空间复杂度主要由递归调用栈决定,在最坏情况下为 \(O(n)\)[^1]。 #### 4. 图解说明 假设输入数组为 `[1, 2, 3]`,则执行流程如下所示: - 初始状态为空列表; - 第一次迭代选取第一个数作为起点(如选 `1`),进入下层递归; - 下次迭代再依次挑选剩余未使用的数字直到填满整个排列为止; - 完成一条分支后退回到上级节点重新选择另一候选值形成新的分支直至全部结束。 此过程可以用树形结构表示出来以便更直观理解每个阶段的状态变化以及剪枝操作的发生时机。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值