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

news2024/12/27 13:09:08

题目链接:https://leetcode.cn/problems/word-search-ii/
给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words, 返回所有二维网格上的单词 。

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

示例 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:
在这里插入图片描述

输入:board = [[“a”,“b”],[“c”,“d”]], words = [“abcb”]
输出:[]

提示:

m == board.length
n == board[i].length
1 <= m, n <= 12
board[i][j] 是一个小写英文字母
1 <= words.length <= 3 * 10^4
1 <= words[i].length <= 10
words[i] 由小写英文字母组成
words 中的所有字符串互不相同

解题思路:
因为棋盘不大,但是单词很多,所以不能一个一个枚举单词是否在棋盘中是否存在,这样要超时

可以先利用字典树,把所有的候选单词存入字典树,这样就只需要枚举每一个棋盘的位置做起点,利用DFS搜索以该路径出发,能够构造哪些单词。

注意搜索的时候,可以进行如下剪枝:当前位置的上下左右4个方向,并不是都可以作为候选落点,要根据字典树的提示,过滤到那些明显不会有候选词的路径。

最后,看起来我的算法问题应该不大,但是提交的时候超时了很多次,最后没有办法,把字典树当中有个本来通过递归来查询当前节点单词的方法改成了用缓存直接记答案。我不知道是不是我用了太多STL和开辟内存空间等操作。最后擦线过的,代码做个参考吧

#include<vector>
#include<string>
#include<set>
#include<map>
#include<queue>
#include<iostream>

using namespace std;

#define MAX_KEY 26
#define MAX_N 13

struct TrieNode{
    TrieNode* father;
    TrieNode* next[MAX_KEY];
    set<char> key_set;
    char data;
    string word;
    TrieNode()
    {
        this->data='\0';
        this->word="";
        this->father=NULL;
        for(int i=0;i<MAX_KEY;++i)
            this->next[i]=NULL;
    }
};

struct Point{
    int x;
    int y;
    TrieNode* node;
    Point(){};
    Point(int x,int y)
    {
        this->x=x;
        this->y=y;
        this->node=NULL;
    }
};

class Trie{
private:
    TrieNode* root;
public:
    TrieNode* get_root()
    {
        return root;
    }

    void init()
    {
        this->root=new TrieNode();
    }

    void insert_word(string word)
    {
        TrieNode* now_root=root;
        for(int i=0;i<word.size();++i)
        {
            char c=word[i];
            int ci=c-'a';
            if(now_root->key_set.find(c)!=now_root->key_set.end())
            {
                now_root=now_root->next[ci];
            }
            else
            {
                now_root->key_set.insert(c);
                now_root->next[ci]=new TrieNode();
                now_root->next[ci]->data=c;
                now_root->next[ci]->father=now_root;
                now_root->next[ci]->word=now_root->word+c;
                now_root=now_root->next[ci];
            }
        }
    }

    // 本来这里是用递归实现的,但是用了要超时
    string query_word(TrieNode* child)
    {
        return child->word;
    }
};

class Solution{
private:
    int n,m;
    vector<Point> start_pos;
    vector<vector<char>> board;
    vector<string> words;
    Trie trie;
    set<string> word_set;
    int dx[4]={1,-1,0,0};
    int dy[4]={0,0,1,-1};
    bool flag[MAX_N][MAX_N];

    void init(vector<vector<char>>& board, vector<string>& words)
    {
        this->m=board.size();
        this->n=board[0].size();
        this->trie.init();
        this->board=board;
        this->words=words;
        set<char> start_char;
        this->start_pos.clear();
        for(int i=0;i<words.size();++i)
        {
            this->trie.insert_word(words[i]);
            start_char.insert(words[i][0]);
            this->word_set.insert(words[i]);
        }
        for(int i=0;i<board.size();++i)
        {
            for(int j=0;j<board[i].size();++j)
            {
                if(start_char.find(board[i][j])!=start_char.end())
                {
                    Point pt(i,j);
                    this->start_pos.push_back(pt);
                }
            }
        }
    }

    void fill_start_point(Point& start_pos,vector<vector<char>>& board)
    {
        int x=start_pos.x;
        int y=start_pos.y;
        int c=board[x][y]-'a';
        start_pos.node=this->trie.get_root()->next[c];
    }

    void deep_first_search(Point& pos,vector<string>& result)
    {
        string word=this->trie.query_word(pos.node);
        if(this->word_set.find(word)!=this->word_set.end())
        {
            result.push_back(word);
            this->word_set.erase(word);
        }
        for(int i=0;i<4;++i)
        {
            int nx=pos.x+dx[i];
            int ny=pos.y+dy[i];
            if(nx>=0 && nx<this->m && ny>=0 && ny<this->n && !flag[nx][ny])
            {
                char c=board[nx][ny];
                int ci=c-'a';
                if(pos.node->key_set.find(c)!=pos.node->key_set.end())
                {
                    flag[nx][ny]=true;
                    Point next_pos(nx,ny);
                    next_pos.node=pos.node->next[ci];
                    deep_first_search(next_pos,result);
                    flag[nx][ny]=false;
                }
            }
        }
    }
public:
    vector<string> findWords(vector<vector<char>>& board, vector<string>& words)
    {
        vector<string> result;
        this->init(board,words);
        for(int i=0;i<this->start_pos.size();++i)
        {
            if(this->word_set.empty())
                break;
            Point st=start_pos[i];
            memset(this->flag,0,sizeof(this->flag));
            this->flag[st.x][st.y]=true;
            this->fill_start_point(st,board);
            this->deep_first_search(st,result);
        }
        return result;
    }
};

int main()
{
    Solution solve;
    vector<vector<char>> board={{'o','a','a','n'},{'e','t','a','e'},{'i','h','k','r'},{'i','f','l','v'}};
    vector<string> words={"oath","pea","eat","rain","hklf", "hf","oaaneateihkrvlfi"};
    vector<string> result=solve.findWords(board,words);
    for(int i=0;i<result.size();++i)
        cout<<result[i]<<endl;
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/195842.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

VC+VB开发CAD重生记:CADEditorX 15.X Crack

CADEditorX是一个 ActiveX 组件&#xff0c;用于在任何支持 ActiveX 和 COM 技术的开发环境&#xff08;例如 C#、Visual C、Delphi、VB、JavaScript 等&#xff09;中向网页或正在开发的应用程序添加 CAD 功能。它可以查看、编辑、转换、打印和测量DWG、DXF、SVG、HPGL、PDF、…

python设计模式-构建器(Builder)设计模式,原型设计模式

构建器(Builder)设计模式构建器(Builder)模式是一种独特的设计模式&#xff0c;它有助于使用简单对象构建复杂对象并使用算法。 这种设计模式属于创建型模式。 在这种设计模式中&#xff0c;构建器类逐步构建最终对象。 该构建器独立于其他对象。构建器(Builder)模式的优点它提…

Anolis Os linux U盘 安装

Anolis OS系统8.4安装|U盘安装Anolis OS(龙蜥)8.4系统_白云一键重装系统 (baiyunxitong.com)https://www.baiyunxitong.com/jiaocheng/7092.html#:~:textAnolis%20OS%E7%B3%BB%E7%BB%9F8.4%E5%AE%89%E8%A3%85%E6%AD%A5%E9%AA%A4%EF%BC%9A%20%28%E5%88%B6%E4%BD%9CU%E7%9B%98%E5…

深度解读 python 实现 dbscan算法

DBScan (密度基于空间聚类) 是一种聚类算法&#xff0c;它通过找到图像中的密度峰值来对数据进行聚类。 文章目录DBScan 算法解释说明DBScan 算法的应用场景Python 实现的 DBScan 算法Python 实现 dbscan 高级算法再演示一种 python 实现 dbscan 算法的代码总结DBScan 算法解释…

共享模型之内存(二)

1.有序性 1>.JVM会在不影响正确性的前提下调整语句的执行顺序,思考下面一段代码: static int i; static int j; // 在某个线程内执行如下赋值操作 i ...; j ...;可以看到,至于是先执行i还是先执行j,对最终的结果不会产生影响.所以,上面代码真正执行时,既可以是: i ..…

mysql:日志,redo,undo,为什么使用日志?

mysql日志 mysql事务的隔离性是通过锁来实现的 而原子性&#xff0c;一致性&#xff0c;持久性就是通过日志来实现的。 REDO LOG 称为 重做日志 &#xff0c;提供再写入操作&#xff0c;恢复提交事务修改的页操作&#xff0c;用来保证事务的持 久性。 UNDO LOG 称为 回滚日志 …

凑个小热闹:python采集《狂飙》评论

前言 昨晚&#xff0c;2023年首部爆款剧集《狂飙》迎来大结局&#xff0c;一度冲上热搜第一 “是非面前稍不留神&#xff0c;就会步入万丈深渊&#xff0c;唯有坚守信仰&#xff0c;才能守得初心” 面对这么多广大网友的讨论&#xff0c;我也来凑上一个热闹 用python采集一下…

Mybatis框架(三)深入Mybatis之Mybatis注解开发与分页的实现

本文是本人专栏【Java开发后端系列框架】里的文章&#xff0c;文章根据各框架官网与网上资料加上本人工作经验&#xff0c;进行修改总结发布在这个专栏&#xff0c;主要目的是用于自我提升&#xff0c;不用于获取利益。如果系列文章能到帮到您本人将感到荣幸&#xff0c;如果有…

docker学习(四):DockerFile微服务实战及docker端口映射

文章目录前言1.Dockerfile介绍2.微服务实战案例3.docker端口映射3.1查看docker网络模式命令3.2docker网络模式前言 大家好&#xff0c;这是我学习docker系列的笔记文章&#xff0c;目标是掌握docker,为后续学习K8s做准备。本文记录了springBoot微服务项目通过DockerFile生成镜…

基于Android的租车app

需求信息&#xff1a; 1.用户中心 进行登陆注销、修改信息、修改密码、上传用户信息:身份证、驾驶证等&#xff0c;并提供基本的验证真伪功能。2.租车交易 用户可以查看可以根据条件查看可以租用的汽车车辆信,息。完成租用车辆功能&#xff0c;(包括登记汽车使用的位置范围) 车…

基于数字孪生的智慧电网3D可视化运维系统

十四五规划提出&#xff1a;“加快推动数字产业化&#xff0c;培育壮大人工智能、大数据、区块链、云计算、网络安全等新兴数字产业”&#xff0c;这是深化电网领域以新能源为主体的国家新型电力系统战略。建设背景在2020年的联合国气候峰会上&#xff0c;我国正式提出了“3060…

听说,这届飞桨社区的框架贡献者真的很“卷”

飞桨平台的快速发展&#xff0c;与开源开放密不可分。飞桨框架建设并非只靠百度工程师&#xff0c;也离不开热爱飞桨、热爱开源的开发者们&#xff0c;他们用自己的方式参与飞桨框架建设&#xff0c;与飞桨共同成长。 为了鼓励更多的开发者参与到飞桨社区的开源建设中&#xff…

前端利器——炫酷的CodePen

前言众所周知&#xff0c;前端是一个很容易将自己的劳动成果呈现出来的一个职位&#xff0c;无论是写1行代码还是写100行代码&#xff0c;都可以通过页面来进行呈现&#xff0c;在工作中的劳作成果也是可以一眼就呈现给客户、用户的。比如一些精美的页面&#xff0c;炫酷的特效…

C++智能指针auto_ptr、unique_ptr、shared_ptr、weak_prt详解

目录 一.为什么要使用智能指针 二.auto_ptr 三.unique_ptr 四.shared_ptr 五.weak_ptr 智能指针均定义在头文件<memory>中&#xff1a; #include<memory> 同时每种智能指针都是以类模板的方式实现 一.为什么要使用智能指针 C的内存管理中&#xff0c;每当…

如何使用ArcGIS拼接栅格

1、概述数据的来源是多种多样的&#xff0c;特别是从网上下载的各种数据往往是分块的数据&#xff0c;在使用的时候需要进行数据的拼接&#xff0c;这里为大家介绍一下ArcGIS进行栅格拼接的方法&#xff0c;希望能对你有所帮助。2、直接拼接在ArcToolbox中点击“数据管理工具\栅…

某书x-s和web_session

开工发现某书web更新了,目前笔记信息接口: /api/sns/web/v1/feed 请求时headers中需要x-s、x-t,cookie中需要有web_session。 文章目录 web_sessionX-SJS代码Python代码web_session web_session和当前环境绑定,重新注册后浏览器中的ID也会更新。 其主要依赖的参数是webI…

WebDAV之葫芦儿·派盘 +Polaris Office

Polaris Office 支持WebDAV方式连接葫芦儿派盘。 推荐一款可以实现在Windows桌面PC,Mac,Android设备和iOS设备上同步的移动办公软件,还支持通过WebDAV添加葫芦儿派盘。 Polaris Office是一款功能全面的办公自动化套件,软件集成了

vue 动态组件component

这篇文章主要介绍了 vue 动态组件component &#xff0c;vue提供了一个内置的<component>,专门用来实现动态组件的渲染&#xff0c;这个标签就相当于一个占位符&#xff0c;需要使用is属性指定绑定的组件&#xff0c;想了解更多详细内容的小伙伴请参考下面文章的具体内容…

ChatGPT小白免费使用教程

本教程介绍chargpt使用教程 :不需要翻墙,不需要注册,也不需要缴纳费用 通过本教程您将会使用chargpt写代码 搜索问题写论文 。 我展示了两个问题 问题一 :用python写一个学生信息管理系统 问题二:用python进行中文分词

【iMessage苹果相册推】CSR邮箱必须与证书分属的AppID相同。 若是您可以在步伐中吸取令牌,则此步伐是成功的。

推荐内容IMESSGAE相关 作者✈️IMEAX推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容3.日历推 *** …