1

Ref: https://leetcode.com/problems/word-search/submissions/

Brief problem statement: Given a matrix of characters and a string, does the string exist in this matrix. Please refer the above link for details.

Solution-1 Gives time-limit exceeded.

class Solution {
public:
    int n;
    int m;
    bool search(vector<vector<char>>& board, const char* w, int i, int j){
        
        if(i < 0 || i >= m || j < 0 || j >= n || *w != board[i][j] || board[i][j] == '\0') return false;
        if(*(w+1) == '\0') return true;

        char t = board[i][j];
        board[i][j] = '\0';
        vector<vector<int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
        for(auto d: dir){
            bool temp = search(board, w+1, i + d[0], j + d[1]);
            if(temp) return true;
        }
        board[i][j] = t;
        return false;
    }
    bool exist(vector<vector<char>>& board, string word) {
        m = board.size();
        n = board[0].size();
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(search(board, word.c_str(), i, j)) return true;
            }
        }
        return false;
    }
};

Solution-2 Works fine. In fact faster than ~93 % of C++ submissions

class Solution {
public:
    int n;
    int m;
    bool search(vector<vector<char>>& board, const char* w, int i, int j){
        
        if(i < 0 || i >= m || j < 0 || j >= n || *w != board[i][j] || board[i][j] == '\0') return false;
        if(*(w+1) == '\0') return true;

        char t = board[i][j];
        board[i][j] = '\0';
        if(search(board, w+1, i -1, j) || search(board, w+1, i+1, j) || search(board, w+1, i, j-1) || search(board, w+1, i, j+1)) return true;
        board[i][j] = t;
        return false;
    }
    bool exist(vector<vector<char>>& board, string word) {
        m = board.size();
        n = board[0].size();
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(search(board, word.c_str(), i, j)) return true;
            }
        }
        return false;
    }
};

The only difference between these two solutions is the way I call the search function recursively within the search function.

In the solution-1 it is:

vector<vector<int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
for(auto d: dir){
    bool temp = search(board, w+1, i + d[0], j + d[1]);
    if(temp) return true;
}

In solution-2 it is:

if(search(board, w+1, i -1, j) || search(board, w+1, i+1, j) || search(board, w+1, i, j-1) || search(board, w+1, i, j+1)) return true;

I think the second solution is like loop unrolling and while this partly explains why the second one is faster than the first one. Isn't it faster by only a constant factor. I mean asymptotically they are similar. I am just surprised that loop unrolling is causing my solution to go from TLE to faster than 93% solutions.

Basically, my question is, Is loop unrolling the only reason why the second solution is so fast, or am I missing something?

  • 4
    Creating a local vector (of vectors!) on the stack will do some memory allocations and generally take a little while. Especially recursively. Not sure if thats the only reason though. – Mike Vine Jun 06 '22 at 10:32
  • 1
    I don't suppose you tried making that vector of vectors `d` a static array of arrays, and enumerating by const-ref. – WhozCraig Jun 06 '22 at 10:47
  • Unfortunately, web sites with lists of random coding puzzles rarely offer any kind C++ learning material that explain the various tricks their coding puzzles are based on. They're just a list of coding puzzles, and in order to learn how to do them correctly, investment of time in a good C++ textbook is required. – Sam Varshavchik Jun 06 '22 at 11:02
  • 1
    I don't understand why my question has been closed. The message states it needs debugging details. By pointing out the difference between the two solutions, I have given sufficient debugging details. It is also very easy to reproduce the issue. You just have to copy paste the code above to LeetCode. In fact the first answer and comments to this question proves that. And I am satisfied by answer and the first comment, which are very helpful to solve / understand the issue. I could not find any thing wrong with my question. I kindly request to reopen the question. – Ramasamy Kandasamy Jun 07 '22 at 06:45

1 Answers1

1

I am not sure about the time complexity of auto type! But if you remove the 2D vector construction from the recursive function, and instead of auto use the normal index-based loop to access the vector then you would pass the timelimit.

class Solution {
public:
    int n;
    int m;
    vector<vector<int>> dir = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    bool search(vector<vector<char>>& board, const char* w, int i, int j){
        
        if(i < 0 || i >= m || j < 0 || j >= n || *w != board[i][j] || board[i][j] == '\0') return false;
        if(*(w+1) == '\0') return true;

        char t = board[i][j];
        board[i][j] = '\0';
        
        for(int r=0; r<4; r++){
            bool temp = search(board, w+1, i + dir[r][0], j + dir[r][1]);
            if(temp) return true;
        }
        board[i][j] = t;
        return false;
    }
    bool exist(vector<vector<char>>& board, string word) {
        m = board.size();
        n = board[0].size();
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(search(board, word.c_str(), i, j)) return true;
            }
        }
        return false;
    }
};
sowrov
  • 1,018
  • 10
  • 16