My word search II solution is very slow (Leetcode 212) - c++

My solution is correct and passes all test cases, but my solution is very slow (faster than 7% of C++ solutions).
Question:
Given an m x n board of characters and a list of strings words, return all words on the board.
Each word must be constructed from letters of sequentially adjacent cells, where adjacent cells are horizontally or vertically neighboring. The same letter cell may not be used more than once in a word.
For example:
Input: board = [["o","a","a","n"],["e","t","a","e"],["i","h","k","r"],["i","f","l","v"]], words = ["oath","pea","eat","rain"]
Output: ["eat","oath"]
By the way, I don't have Leetcode premium and looked at the discussion. I see that other people are using recursion. I am using a stack, but this shouldn't really be a problem. Does anyone see any performance issues with my code? The complexity should be O(n^2*3^n)
class Solution {
public:
vector<string> findWords(vector<vector<char>>& board, vector<string>& words) {
vector<string> ret;
Trie* root = new Trie();
for (const auto &i:words) {
root->insert(i);
}
Trie* cnode = root;
int numRow = board.size();
int numCol = board[0].size();
vector<int> temp(numCol, 0);
vector<vector<int>> visited(numRow, temp);
for (int i = 0; i < numRow; ++i) {
for (int j = 0; j < numCol; ++j) {
stack<pair<int, int>> searcher;
searcher.push(make_pair(i,j));
while (!searcher.empty()) {
int row = searcher.top().first;
int col = searcher.top().second;
int cur = board[row][col] - 97;
if (visited[row][col]) {
cnode = cnode->parent;
visited[row][col] = 0;
searcher.pop();
} else if (cnode->child[cur] == nullptr) {
searcher.pop();
visited[row][col] = 0;
} else {
visited[row][col] = 1;
cnode = cnode->child[cur];
if (cnode->contain != "") {
ret.push_back(cnode->contain);
cnode->contain = "";
}
if (row + 1 < numRow && !visited[row + 1][col]) {
searcher.push(make_pair(row+1, col));
}
if (row - 1 >= 0 && !visited[row-1][col]) {
searcher.push(make_pair(row-1, col));
}
if (col + 1 < numCol && !visited[row][col+1]) {
searcher.push(make_pair(row, col+1));
}
if (col - 1 >= 0 && !visited[row][col-1]) {
searcher.push(make_pair(row, col-1));
}
}
}
}
}
return ret;
}
class Trie {
public:
vector<Trie*> child;
Trie* parent;
string contain;
Trie() {
child = vector<Trie*>(26, nullptr);
contain = "";
parent = nullptr;
}
void insert(string word) {
Trie* root = this;
for (int i = 0; i < word.size(); ++i) {
int loc = word[i] - 97;
if (root->child[loc] == nullptr) {
root->child[loc] = new Trie();
root->child[loc]->parent = root;
}
root = root->child[loc];
}
root->contain = word;
}
};
};

Related

leetcode problem 1255 Maximum Score Words Formed by Letters

Given a list of words, a list of single letters (might be repeating), and score of every character.
Return the maximum score of any valid set of words formed by using the given letters (words[i] cannot be used two or more times).
It is not necessary to use all characters in letters and each letter can only be used once. Score of letters 'a', 'b', 'c', ... ,'z' is given by score[0], score[1], ... , score[25] respectively
My approach is
finding score of a word
then can that word be formed or not
and finally, get the result code is given below
class Solution {
public:
// score finder func
int scoreFinder(vector<int>& score , string s){
int ans = 0;
for(int i = 0; i < s.size(); i++){
char ch = s[i];
ans += score[ch -'a'];
}
return ans;
}
// word can be formed or not
bool canFormed(string s , unordered_map<char,int>& myMap){
for(int i = 0; i < s.size(); i++){
if(myMap.count(s[i]) <= 0){
return false;
break;
}else{
myMap[s[i]]--;
}
}
return true;
}
int maxScoreWords(vector<string>& words, vector<char>& letters, vector<int>& score){
// freq Count of letters
/* unordered_map<char,int> map;
for(int i = 0; i < letters.size(); i++){
map[letters[i]]++;
}*/
int result = 0; // final score is stored in it
int idx = 0;
while(idx < words.size()){
// creating new map every time so that check for all possible words combinations
unordered_map<char,int> myMap;
for(int j = 0; j < letters.size(); j++){
myMap[letters[j]] ++; //= map[letters[j]];
}
int tempResult = 0;
for(int i = idx; i < words.size(); i++){
string temp = words[i];
if(canFormed(temp , myMap)){
tempResult += scoreFinder(score , temp);
}
}
result = max(result , tempResult);
idx++;
}
return result;
}
};
Input:
words = ["dog","cat","dad","good"],
letters = ["a","a","c","d","d","d","g","o","o"],
score = [1,0,9,5,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0]
Output:
23
but I am getting the wrong output and I am unable to find the error in my code, my output is 33 for this testcase.
There is a minor bug in your code.
In the function canFormed you decrement the counter als in the case where it is 0 already. We could simply add an additional if-statement or rewrite the whole condition.
Please see one possible solution below:
// word can be formed or not
bool canFormed(string s, unordered_map<char, int>& myMap) {
for (int i = 0; i < s.size(); i++) {
if (myMap.count(s[i]) <= 0) {
return false;
}
else {
if (myMap[s[i]] > 0) {
myMap[s[i]]--;
}
else return false;
}
}
return true;
}
Then it should work.
Solved with backtracking in JAVA
public int maxScoreWords(String[] words, char[] letters, int[] score) {
int[] counts = new int[26];
for (char letter : letters) {
counts[letter - 'a']++;
}
return wordHelper(words, counts, score, 0);
}
static int wordHelper(String[] words, int[] counts, int[] score, int index) {
// base case
if (index > words.length - 1) {
return 0;
}
// recursive case - exclude
int excludedSum = wordHelper(words, counts, score, index + 1);
// recursive case - include
int includedSum = 0;
boolean recursionCall = true;
int wordScore = 0;
for (char c : words[index].toCharArray()) {
counts[c - 'a']--;
if (counts[c - 'a'] < 0) {
recursionCall = false;
}
wordScore += score[c - 'a'];
}
if (recursionCall) {
includedSum = wordScore + wordHelper(words, counts, score, index + 1);
}
for (char c : words[index].toCharArray()) {
counts[c - 'a']++;
}
return Math.max(excludedSum, includedSum);
}

What is the normal way to debug nested for loop?

I am writing code for Leetcode problem 38. Count and Say. It doesn't pass the cases, so I add some cout to debug. Please tell me is there a normal way to debug nested for loop, where should I add the cout expression. I don't want to know how to modify the code to pass the cases.
Here is my code:
class Solution {
public:
string countAndSay(int n) {
string cur("1");
while (--n) {
string tmp = cur;
string next;
for (int i = 0; i < tmp.size();) {
cout << "i:" << i << endl;
int count = 1;
for (int j = i + 1; j < tmp.size(); j++) {
if (tmp[j] != tmp[0]) {
break;
}
count++;
}
cout << "count:" << count << endl;
next += std::to_string(count) + tmp[0];
cout << "cur:" << cur << endl;
i += count;
}
cur = next;
cout << n << cur << endl;
}
return cur;
}
};
You're gonna have to use a debugger for that, and step by step go through your algorithm to find the bugs. It's hard to debug someone else's algorithm.
This'll pass through:
#include <string>
struct Solution {
static const std::string countAndSay(int n) {
if (not n) {
return "";
}
std::string res = "1";
while (--n) {
std::string curr = "";
for (int index = 0; index < res.size(); index++) {
int count = 1;
while ((index + 1 < res.size()) and (res[index] == res[index + 1])) {
count++;
index++;
}
curr += std::to_string(count) + res[index];
}
res = curr;
}
return res;
}
};
Java Solutions
class Solution {
public String countAndSay(int n) {
if (n == 1)
return "1";
String prev = countAndSay(n - 1);
StringBuilder str = new StringBuilder();
int i = 0;
while (i < prev.length()) {
char curr = prev.charAt(i);
int j = 0;
while (i + j < prev.length() && prev.charAt(i + j) == curr)
j++;
str.append(j);
str.append(curr);
i += j;
}
return str.toString();
}
}
Here is one of LeetCode's solutions using regex:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Solution {
public String countAndSay(int n) {
String currSeq = "1";
// Pattern to match the repetitive digits
String regexPattern = "(.)\\1*";
Pattern pattern = Pattern.compile(regexPattern);
for (int i = 1; i < n; ++i) {
Matcher m = pattern.matcher(currSeq);
StringBuffer nextSeq = new StringBuffer();
// each group contains identical and adjacent digits
while (m.find()) {
nextSeq.append(m.group().length() + String.valueOf(m.group().charAt(0)));
}
// prepare for the next iteration
currSeq = nextSeq.toString();
}
return currSeq;
}
}
and here's another LeetCode's solution also using Sliding Window:
class Solution {
public String countAndSay(int n) {
LinkedList<Integer> prevSeq = new LinkedList<Integer>();
prevSeq.add(1);
// Using -1 as the delimiter
prevSeq.add(-1);
List<Integer> finalSeq = this.nextSequence(n, prevSeq);
StringBuffer seqStr = new StringBuffer();
for (Integer digit : finalSeq) {
seqStr.append(String.valueOf(digit));
}
return seqStr.toString();
}
protected LinkedList<Integer> nextSequence(int n, LinkedList<Integer> prevSeq) {
if (n <= 1) {
// remove the delimiter before return
prevSeq.pollLast();
return prevSeq;
}
LinkedList<Integer> nextSeq = new LinkedList<Integer>();
Integer prevDigit = null;
Integer digitCnt = 0;
for (Integer digit : prevSeq) {
if (prevDigit == null) {
prevDigit = digit;
digitCnt += 1;
} else if (digit == prevDigit) {
// in the middle of the sub-sequence
digitCnt += 1;
} else {
// end of a sub-sequence
nextSeq.add(digitCnt);
nextSeq.add(prevDigit);
// reset for the next sub-sequence
prevDigit = digit;
digitCnt = 1;
}
}
// add the delimiter for the next recursion
nextSeq.add(-1);
return this.nextSequence(n - 1, nextSeq);
}
}
References
For additional details, you can see the Discussion Board. There are plenty of accepted solutions with a variety of languages and explanations, efficient algorithms, as well as asymptotic time/space complexity analysis1, 2 in there.

Unable to set breakpoints to see errors C++ ORDERED LIST

I am having a problem trying to use breakpoints in my code to see what is happening step by step. No matter where I put one in my code, it says it can't reach it (even though the code is running through all the functions I told it to), even if I set a conditional to true that definitely should be true (count == 3 for example).
I am setting up an ordered list that inserts movies as strings with certain details for a college project, it adds the movies in order, and then you should be able to delete a specific title. I have used an ordered list using numbers i got working to set this one up as to why I am getting errors, but I cant see what happening as it wont reach any breakpoints, even if i put one on the constructor before anything else is ran. Can anyone tell me why this is happening or what might be wrong with my code. My list remove() function is just removing the last element, instead of the one I have defined.
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
class OList
{
private:
string data[3];
int count; //First empty slot
public:
OList();
bool isEmpty();
bool isFull();
void Add(string newVal);
string Remove(string newVal);
bool LinearSearch(string searchVal);
void Display();
};
OList::OList()
{
count = 0;
}
bool OList::isEmpty()
{
if (count == 0)
{
return true;
}
else
{
return false;
}
}
bool OList::isFull()
{
if (count == 5)
{
return true;
}
else
{
return false;
}
}
void OList::Add(string movie)
{
data[count] = movie;
int i;
if (isFull())
return;
//Find the insertion point
for (i = 0; i < count; i++);
if (i == count)
data[i] = movie; //Copy in the new value
else
//Make a Space
for (int j = count - 1; j >= i; j--)
{
data[j + 1] = data[j];
}
data[i] = movie; //Copy in the new value
count++;
}
string OList::Remove(string movie)
{
int i = LinearSearch(movie);
string temp = movie;
if (isEmpty())
return false;
i++;
while (i < count - 1)
{
data[i] = data[i + 1];
i++;
}
count--;
return temp;
}
bool OList::LinearSearch(string searchVal)
{
for (int i = 0; (i < count) || (data[i] > searchVal); i++)
{
if (data[i] == searchVal)
return -1;
}
return false;
}
void OList::Display()
{
for (int i = 0; i < count; i++)
{
cout << data[i] << endl;
}
}
int main()
{
OList movies;
string movie;
movies.Add(movie = "Yeh Jawaani Hai Deewani | 1, 790, 000, 000 | Ayan Mukerji");
movies.Add(movie = "Dhoom 3 | 2,840,000,000 | Vijay Krishna Acharya");
movies.Add(movie = "Chennai Express | 2, 275, 000, 000 | Rohit Shetty");
movies.Display();
std::cout << "\n";
movies.Remove(movie = "Chennai Express | 2, 275, 000, 000 | Rohit Shetty");
movies.Display();
system("pause");
return 0;
}
Just looking at your Add function here, not going to go through whole program. Lets say count is 0
void OList::Add(string movie)
{
data[count] = movie; //data[0] = movie;
int i;
if (isFull())
return;
//Find the insertion point
for (i = 0; i < count; i++); //i = 0
if (i == count) //if i == 0, which we know it does
data[i] = movie; //data[0] = movie; AGAIN
else //never enter this...
//Make space
for (int j = count - 1; j >= i; j--)//never get here
{
data[j + 1] = data[j];//nope
}
data[i] = movie; //data[0] = movie; just to be sure
count++;
}
It might as well be
void OList::Add(string movie)
{
data[count] = movie;
if (isFull())
return;
count++;
}

Huffman coding c++

So I am working on Huffman coding for a project. However, my code just doesn't work. When i ran it on visual studio, it didn't give me an error. What I was trying to do is to read a file and put all of them into a string. And get the frequency for each character in that string. But I think when the file got a little bit large, it seems like my code is running in a infinite loop. Can anyone explain anything to me? By the way, I had a sorted function that I used to sort a vector of node* by their frequency.
ifstream infile;
infile.open(filename);
string q;
string line;
while (getline(infile, line))
{
q += line;
}
char y;
int count = 0;
int check = 0;
for (int i = 0; i < q.size(); i++) //if the string gets big, it seems to become an infinite loop in here
{
y = q[i];
for (int x = i - 1; x > 0; x--) //make sure not counting the same char
{
if (y == q[x])
{
check++;
}
}
if (check == 0)
{
for (int i = 0; i < q.size(); i++)
{
if (q[i] == y)
{
count++;
}
}
node*x = new node;
x->char1 = y; //my node have char
x->freq = count; //my node has frequency
list1.push_back(x);
}
count = 0;
check = 0;
}
sort(list1.begin(), list1.end(), sorter); //sort them from small to big
while (list1.size() > 1)
{
node*left = list1[0];
node*right = list1[1];
list1.erase(list1.begin(), list1.begin() + 2);
double sum = left->freq + right->freq;
node* x = new node;
x->freq = sum;
x->left = left;
x->right = right;
list1.push_back(x);
sort(list1.begin(), list1.end(), sorter);
}
list1.clear();
return true;
The following is my sort function
static struct {
bool operator()(NodeInterface* a, NodeInterface* b) {
if (a->getFrequency() == b->getFrequency()) {//if the frequencies are even,
if (b->getCharacter() == '\0') return false;
if (a->getCharacter() != '\0') {
return (int)a->getCharacter() < (int)b->getCharacter();
}
return false;
}
return a->getFrequency() < b->getFrequency();
}
} sorter;
I see two major problems.
You have a for loop inside a for loop both initializing and using int i
Change the variable name of the inner loop.
for (int i = 0; i < q.size(); i++) //if the string gets big, it seems to become an infinite loop in here
.
.
if (check == 0)
{
for (int i = 0; i < q.size(); i++) //Change this to int j for example
{
.
.
And the Sorter struct. I would rewrite it as this.
static struct {
bool operator()(NodeInterface* a, NodeInterface* b) {
if (a->getFrequency() == b->getFrequency()) {//if the frequencies are even,
if (b->getCharacter() == '\0') return false;
if (a->getCharacter() == '\0') return true;
return (int)a->getCharacter() < (int)b->getCharacter();
}
return a->getFrequency() < b->getFrequency();
}
} sorter;
A few suggestions for your for loop:
for (int i = 0; i < q.size(); i++) //if the string gets big, it seems to become an infinite loop in here
{
y = q[i];
//You can avoid this entire loop by using a structure like map
for (int x = i - 1; x > 0; x--) //make sure not counting the same char
{
if (y == q[x])
{
check++;
//break; //if you use a loop, break it once you find the character.
}
}
if (check == 0)
{
for (int j = 0; j < q.size(); j++)//Renamed variable + you can start this loop from j = i as you know there is no occurrence of y before that.
{
if (q[i] == y)
{
count++;
}
}
node*x = new node;
x->char1 = y; //my node have char
x->freq = count; //my node has frequency
list1.push_back(x);
}
count = 0;
check = 0;
}

Bubble Sort Ragged Table in C

I was trying to sort a ragged table using bubble sort. The algorithm I have only sorts the first row, but leaves the rest of the rows unsorted. I think the problem is the fact that the "last" variable is not properly initialized.
void bubbleSort (int **table)
{
// Local Declarations
int temp;
int current;
int walker;
int column;
int row=0;
int numCol = 0;
int last = *table[numCol];
// Statements
while (table[row] != NULL) {
for (column = 2; column <= *table[row]; column++) {
for (current = 2; current < last; current++) {
bool swapsOccured = false;
for (walker = last; walker > current; walker--) {
if (table[row][walker] > table[row][walker - 1]) {
swapsOccured = true;
temp = table[row][walker];
table[row][walker] = table[row][walker - 1];
table[row][walker - 1] = temp;
} // if
} // for walker
if (!swapsOccured)
return;
} // for current
}
row++;
} // while
return;
}