Leetcode之word search

给定一个字符矩阵和一个单词, 确定该单词是否存在于该矩阵中。

  1. 当找到一个连续的字母序列,使得该序列组成的单词和给定的单词相同时,则单词存在于矩阵中。找不到则不存在。
  2. 在单词中相邻的两个字母,必须在矩阵中横向或纵向相邻。

比如,设

board =[
[“ABCE”],
[“SFCS”],
[“ADEE”]
]
word = “ABCCED”, -> returns true,
word = “SEE”, -> returns true,
word = “ABCB”, -> returns false.

题目的提示是采用回溯法。回溯给我的感觉和深度优先搜索非常像,但是有种细微的区别说不上来。。(还是研究不到家。。⊙﹏⊙b汗)

设两个栈s和visited,s用于保存即将探索的点,visited用于保存搜索路劲和搜索进度。
设起始搜索点为start,首先将start入栈s。

假设当前匹配的字符位置i。
搜索算法描述如下:

  1. 取出s栈顶元素p, (p.i,p.j) 是坐标,p.len是在p点已经匹配的单词长度。若栈为空,转7
  2. 若i和p.len相等,转3(深搜);若不相等,转6(回溯)。
  3. 若board[p.i][p.j]和word[i]相等,则i++,p.len++;若不相等,转1。
  4. 将p入栈visited,设置p点为已访问
  5. 将p的上下左右未访问过的点入栈s,四个点的len均设为p.len,转1。
  6. 将visited不断出栈,将出栈位置设为未访问,并使i=i-1,直到出栈元素的len和i相等或者栈为空为止。然后转3。
  7. 若i和单词长度相等,则返回true,否则返回false。

实现代码如下

struct point{
    int i;
    int j;
    int len;
    point(int __i, int __j, int __len):i(__i), j(__j), len(__len){}
};

class Solution {

public:
    int row;
    int col;
    void push(int i, int j, int len, stack<point>& s, vector<vector<int> >& visit_flag){
        if(i >= 0 && i < row && j>=0 && j< col && visit_flag[i][j] != 1){
            s.push(point(i, j, len));
        }
    }

    void push_point(const point& p, stack<point>& s, vector<vector<int> >& visit_flag){
        push(p.i, p.j-1, p.len, s, visit_flag);
        push(p.i-1, p.j, p.len, s, visit_flag);
        push(p.i, p.j+1, p.len, s, visit_flag);
        push(p.i+1, p.j, p.len, s, visit_flag);
    }
    bool search(vector<vector<char>>& board, string& word, point start){
        stack<point> s;
        stack<point> visited;
        vector<vector<int> > visit_flag(board.size(), vector<int>(board[0].size(), 0));
        point p = start;
        int len = word.size(), i = 0;
        s.push(p);
        while(!s.empty() && i < len){   
            p = s.top();s.pop();
            while(!visited.empty() && i != p.len){
                //backtracking
                point tmp = visited.top();
                visited.pop();
                visit_flag[tmp.i][tmp.j] = 0;
                cout<<"back"<<endl;
                print(visit_flag);
                i--;
            }
            //if match?
            if(board[p.i][p.j] == word[i]){
                i++;
                p.len++;
                push_point(p, s, visit_flag);
                visited.push(p);
                visit_flag[p.i][p.j] = 1;
                cout<<"move"<<endl;
                print(visit_flag);
            }
        }
        cout<<"try end!!!"<<endl;
        return i==len;
    }
    void print(vector<vector<int>>& board){
        for(int i = 0;i < row;i++){
            for(int j = 0;j < col;j++){
                cout<<board[i][j]<<" ";
            }
            cout<<endl;
        }
        cout<<endl;
    }
    bool exist(vector<vector<char>>& board, string word) {
        row = board.size();
        col = board[0].size();
        bool hasfind = false;
        for(int i = 0;i < row && !hasfind;i++){
            for(int j = 0;j < col && !hasfind;j++){
                if(board[i][j] == word[0]){
                    hasfind = search(board, word, point(i, j, 0));
                }
            }
        }
        return hasfind;
    }
};

感觉代码写的非常不优雅,可能采用递归会好一点。

加油!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值