LeetCode 212. 单词搜索 II 字典树 回溯 C++

35 篇文章 0 订阅
6 篇文章 0 订阅

描述

给定一个二维网格 board 和一个字典中的单词列表 words,找出所有同时在二维网格和字典中出现的单词。

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

示例:

输入:
words = [“oath”,“pea”,“eat”,“rain”] and board =
[
[‘o’,‘a’,‘a’,‘n’],
[‘e’,‘t’,‘a’,‘e’],
[‘i’,‘h’,‘k’,‘r’],
[‘i’,‘f’,‘l’,‘v’]
]

输出: [“eat”,“oath”]
说明:
你可以假设所有输入都由小写字母 a-z 组成。

提示:

你需要优化回溯算法以通过更大数据量的测试。你能否早点停止回溯?
如果当前单词不存在于所有单词的前缀中,则可以立即停止回溯。什么样的数据结构可以有效地执行这样的操作?散列表是否可行?为什么? 前缀树如何?如果你想学习如何实现一个基本的前缀树,请先查看这个问题: 实现Trie(前缀树)。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/word-search-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析

提示了使用字典树
可以先将words里的词组成字典树,然后在board里依次找,只要board当前字母是在字典树root下面的分支里,就可以递归的去找
找的过程中,如果中途字典树走不下去了就返回,已经是存在的单词了就添加(但不返回,因为aaa是,aaab可能也是),在四个方向里找,找到可用的就继续递归向下

代码

class Solution {
public:
	struct Node {
		bool isflag = false;
		Node * next[27] = {};
	};
	set<string>res; //防止结果有重复,多次查到同一个词
	vector<string>ans;
	Node * root;
	vector<int>dirx{ 0,0,1,-1 };
	vector<int>diry{ 1,-1,0,0 };
	bool flag;
	//组织字典树
	void createtree(vector<string>&words) {
		root = new Node();
		
		for (auto w : words) {
			Node * p = root;
			for (int i = 0; i < w.length(); i++) {
				if (p->next[w[i] - 'a'] == NULL) {
					p->next[w[i] - 'a'] = new Node();
				}
				p = p->next[w[i] - 'a'];
			}
			p->isflag = true;
		}
	}
	void backtrack(vector<vector<char>>&board,vector<vector<bool>>visited, int row, int col, Node*roott, string cur) {
		cur += board[row][col];
		roott = roott->next[board[row][col] - 'a'];
		if (!roott)return; //找不下去了
		if (roott->isflag == true)
		{
			//ans.push_back(cur);
			res.insert(cur);
			flag = true;
			//return;
		}
		visited[row][col] = true;
		
		for (int i = 0; i < 4; i++) {
			//if (flag == true)
				//return;
			int nx = row + dirx[i];
			int ny = col + diry[i];
			if (nx < 0 || ny < 0 || nx >= board.size() || ny >= board[0].size())
				continue;
			if (visited[nx][ny] == false) {
				backtrack(board, visited, nx, ny, roott, cur);
				//visited[nx][ny] = false;
				//cur.pop_back();
			}
		}
		
	}
	vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
		
		if (board.size() == 0 || words.size() == 0)
			return ans;
		createtree(words);
		
		for (int i = 0; i < board.size(); i++) {
			for (int j = 0; j < board[i].size(); j++) {
				Node * p = root; //每次查看是否符合root下的子分支
				flag = false;
				if (p->next[board[i][j] - 'a']) {
					vector<vector<bool>>visited{ board.size(),vector<bool>(board[0].size(),false) };
					backtrack(board, visited, i, j, p, "");
				}
			}
		}
		set<string>::iterator it;
		for (it = res.begin(); it != res.end(); it++)
			ans.push_back(*it);
		return ans;
	}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值