【LeetCode每日一题】——212. 单词搜索II

文章目录

  • 一【题目类别】
  • 二【题目难度】
  • 三【题目编号】
  • 四【题目描述】
  • 五【题目示例】
  • 六【题目提示】
  • 七【解题思路】
  • 八【时间频度】
  • 九【代码实现】
  • 十【提交结果】

一【题目类别】

  • 回溯法

二【题目难度】

  • 困难

三【题目编号】

  • 212.单词搜索II

四【题目描述】

  • 给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words,找出所有同时在二维网格和字典中出现的单词。
  • 单词必须按照字母顺序,通过 相邻的单元格 内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母在一个单词中不允许被重复使用。

五【题目示例】

  • 示例 1:
    【LeetCode每日一题】——212. 单词搜索II_第1张图片
    输入:board = [[“o”,“a”,“a”,“n”],[“e”,“t”,“a”,“e”],[“i”,“h”,“k”,“r”],[“i”,“f”,“l”,“v”]], words = [“oath”,“pea”,“eat”,“rain”]
    输出:[“eat”,“oath”]
  • 示例 2:
    【LeetCode每日一题】——212. 单词搜索II_第2张图片
    输入:board = [[“a”,“b”],[“c”,“d”]], words = [“abcb”]
    输出:[]

六【题目提示】

  • m = = b o a r d . l e n g t h m == board.length m==board.length
  • n = = b o a r d [ i ] . l e n g t h n == board[i].length n==board[i].length
  • 1 < = m , n < = 12 1 <= m, n <= 12 1<=m,n<=12
  • b o a r d [ i ] [ j ] 是 一 个 小 写 英 文 字 母 board[i][j] 是一个小写英文字母 board[i][j]
  • 1 < = w o r d s . l e n g t h < = 3 ∗ 1 0 4 1 <= words.length <= 3 * 10^4 1<=words.length<=3104
  • 1 < = w o r d s [ i ] . l e n g t h < = 10 1 <= words[i].length <= 10 1<=words[i].length<=10
  • w o r d s [ i ] 由 小 写 英 文 字 母 组 成 words[i] 由小写英文字母组成 words[i]
  • w o r d s 中 的 所 有 字 符 串 互 不 相 同 words 中的所有字符串互不相同 words

七【解题思路】

  • 和79.单词搜索一样,就是加了一个for循环遍历每一个word和一个List存放结果

八【时间频度】

  • 时间复杂度: O ( S ∗ M ∗ N ∗ 3 L ) O(S*M*N*3^L) O(SMN3L),其中 M 和 N 分别为行数和列数,L是单词的最大长度,S为二维网格中的单元格数

九【代码实现】

  1. Java语言版
package ToFlashBack;

import java.util.ArrayList;
import java.util.List;

public class p212_WordSearchII {

    // 用于存放坐标方向,分别运动方向是上,右,下,左
    private static int[][] dires = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    // 定义行数和列数
    private int row, col;
    // 定义是否找到的标志位
    private boolean hasFind;
    // 定义是否访问过的坐标的二维数组
    private boolean[][] visited;

    public static void main(String[] args) {
        p212_WordSearchII p_212_wordSearchII = new p212_WordSearchII();
        char[][] board = {
                {'o', 'a', 'a', 'n'},
                {'e', 't', 'a', 'e'},
                {'i', 'h', 'k', 'r'},
                {'i', 'f', 'l', 'v'}
        };
        String[] words = {"oath", "pea", "eat", "rain"};
        List<String> res = p_212_wordSearchII.findWords(board, words);
        System.out.println("res = " + res);
    }

    public List<String> findWords(char[][] board, String[] words) {
        List list = new ArrayList();
        for (int i = 0; i < words.length; i++) {
            String word = words[i];
            if (exist(board, word)) {
                list.add(word);
            }
        }
        return list;
    }

    /**
     * 判断主方法
     *
     * @param board 初始二维数组
     * @param word  准备查找的字符串
     * @return
     */
    public boolean exist(char[][] board, String word) {
        // 行数
        row = board.length;
        // 列数
        col = board[0].length;
        // 初始标志位为false,没有找到
        hasFind = false;
        // 如果行数和列数乘积小于整个字符串的长度直接返回false
        if (row * col < word.length()) {
            return false;
        }
        // 初始化是否访问的二维数组大小为board的大小
        visited = new boolean[row][col];
        // 把单词字符串转为对应的字符串一维数组
        char[] chars = word.toCharArray();
        // 双层for循环,遍历board的每一个单词
        for (int i = 0; i < row; i++) {
            for (int j = 0; j < col; j++) {
                // 如果当前board中的单词等于word中的单词,那么就开始进入下一个方法
                if (board[i][j] == chars[0]) {
                    backTrack(board, chars, 1, i, j);
                    // 如果已经判断出结果,则返回true
                    if (hasFind) {
                        return true;
                    }
                }
            }
        }
        // 如果进入for循环没有任何返回结果,就返回false
        return false;
    }

    /**
     * 查找的核心方法:使用递归+回溯
     *
     * @param board    初始的二维数组
     * @param word     待查找的字符数组
     * @param curIndex 判断的索引值,每次都+1
     * @param x        横坐标,每次都是newX
     * @param y        纵坐标,每次都是newY
     */
    private void backTrack(char[][] board, char[] word, int curIndex, int x, int y) {
        // 如果标志位为true,直接返回,这个也是递归的结束条件
        if (hasFind) {
            return;
        }
        // 如果临时索引值和单词数组长度相等,说明已经找到了最后一个单词,则将标志位置为true,返回
        if (curIndex == word.length) {
            hasFind = true;
            return;
        }
        // 因为传进来的x和y就是当前坐标值,说明已经走过了
        visited[x][y] = true;
        // 使用增强for循环遍历方向数组
        for (int[] dire : dires) {
            // 更新坐标位置,并按照上->右->下->左的方向,依次开始递归
            int newX = x + dire[0];
            int newY = y + dire[1];
            // 如果满足,更新后的坐标在二维数组中,并且没有访问过,并且更新后的坐标值和字符数组的下一个单词相等,则进入递归,如果不满足条件,则依次使用下面的方向继续进行递归
            if (isIn(newX, newY) && !visited[newX][newY] && board[newX][newY] == word[curIndex]) {
                backTrack(board, word, curIndex + 1, newX, newY); // 这里curIndex+1,意味着更新索引值,下面就判断字符数组的下一个单词
            }
        }
        // 将判断是否访问过的二维数组恢复
        visited[x][y] = false;
    }

    /**
     * 判断当前坐标是否在二维数组中
     *
     * @param x 横坐标
     * @param y 纵坐标
     * @return
     */
    private boolean isIn(int x, int y) {
        return x >= 0 && x < row && y >= 0 && y < col;
    }


}
  1. C语言版
#include
#include
#include
#include

bool p212_WordSearchII_backTrack(char** board, int boardSize, int boardColSize, char* word, int wordIndex, bool** visited, int x, int y)
{
	/*剪枝操作:边界值或者当前位置已经访问过或者当前字符和待匹配字符不相等直接返回false*/
	if (x < 0 || x >= boardSize || y < 0 || y >= boardColSize || visited[x][y] || board[x][y] != word[wordIndex])
	{
		return false;
	}
	/*递归跳出条件:这步必须放在剪枝操作的后面,必须先判断当前字符和待匹配字符相等,如果相等且将待匹配字符串都已经匹配过了,递归跳出,返回true*/
	if (wordIndex + 1 == strlen(word))
	{
		return true;
	}
	/*将当前位置的字符置为已访问*/
	visited[x][y] = 1;
	/*分别向右上下左四个方向继续匹配*/
	if (p212_WordSearchII_backTrack(board, boardSize, boardColSize, word, wordIndex + 1, visited, x + 1, y))
	{
		return true;
	}
	else if (p212_WordSearchII_backTrack(board, boardSize, boardColSize, word, wordIndex + 1, visited, x, y + 1))
	{
		return true;
	}
	else if (p212_WordSearchII_backTrack(board, boardSize, boardColSize, word, wordIndex + 1, visited, x - 1, y))
	{
		return true;
	}
	else if (p212_WordSearchII_backTrack(board, boardSize, boardColSize, word, wordIndex + 1, visited, x, y - 1))
	{
		return true;
	}
	/*回溯操作:如果右上下左四个方向均没有匹配成功返回到上一个状态,并且返回false,说明当前路径不通,也就是没有找到*/
	else
	{
		visited[x][y] = 0;
		return false;
	}
}

bool p212_WordSearchII_exist(char** board, int boardSize, int boardColSize, char* word, int wordIndex, bool** visited)
{
	/*遍历每一个位置作为起点*/
	for (int x = 0; x < boardSize; x++)
	{
		for (int y = 0; y < boardColSize; y++)
		{
			/*如果在表格中找到待查找单词就返回true,让主函数加入这个单词*/
			if (p212_WordSearchII_backTrack(board, boardSize, boardColSize, word, wordIndex, visited, x, y))
			{
				return true;
			}
		}
	}
	/*如果在表格中没有找到待查找单词就返回true,让主函数不要加入这个单词*/
	return false;
}

char ** findWords(char** board, int boardSize, int* boardColSize, char ** words, int wordsSize, int* returnSize)
{
	/*结果数组,用于存放找到的单词*/
	char** res = (char**)malloc(sizeof(char*) * 1000);
	/*结果数组指针*/
	int resIndex = 0;
	/*设置访问二维数组,防止二次遍历*/
	int** visited = (int**)malloc(sizeof(int*)*boardSize);
	/*遍历每一个待查找单词*/
	for (int i = 0; i < wordsSize; i++)
	{
		/*对每一个待查找单词都设置一个新的访问二维数组,防止二次遍历*/
		for (int j = 0; j < boardSize; j++)
		{
			visited[j] = (int*)calloc(boardColSize[0], sizeof(int));
		}
		/*如果在表格中找到待查找单词就加入到结果数组中*/
		if (p212_WordSearchII_exist(board, boardSize, boardColSize[0], words[i], 0, visited))
		{
			res[resIndex++] = words[i];
		}
	}
	/*设置返回的结果数组的大小*/
	*returnSize = resIndex;
	/*返回结果*/
	return res;
}

/*主函数省略*/

十【提交结果】

  1. Java语言版
    【LeetCode每日一题】——212. 单词搜索II_第3张图片

  2. C语言版
    【LeetCode每日一题】——212. 单词搜索II_第4张图片

你可能感兴趣的:(LeetCode,leetcode,数据结构,算法,回溯法,深度优先搜索)