Breaking a given string into dictionary words - c++

Am trying to break a given string into dictionary words from a given dictionary and find all such possible sets.
Ex.: if given word is “programmerit”, then output shall be:
{{pro, gram, merit}, {program, merit}, {programmer, it}}
My below solution, works in exponential time. O(c^n); where is c is some constant I haven't evaluated and n is the size (characters) of given word.
I am trying to reduce the complexity or maybe bring it down to a lower exponent, but to no avail. Looking for any suggestions in this regard.
PS: this is not a homework or assignment problem, I am a working professional and trying this out of curiosity.
Here is my code:
bool isContained(string word, string s) {
for (int i = 0; i < s.length(); i++) {
if (i >= word.length())
return false;
if (word[i] != s[i])
return false;
}
return true;
}
void getParts(vector<string> dict, string word, stack<string> s, vector<vector<string> > &parts) {
if (word.length() == 0) {
if (s.size() > 0) {
vector<string> part;
stack<string> t = s;
while(!t.empty()) {
part.push_back(t.top());
t.pop();
}
parts.push_back(part);
}
} else {
int j = find_starting_ind(dict, word[0]);
int ct = j;
while (dict[ct][0] == word[0]) {
if (isContained(word, dict[ct])) {
s.push(dict[ct]);
string nword = word-dict[ct];
getParts(dict, nword, s, parts);
s.pop();
}
ct++;
}
}
}

Related

Palindrome program not returning correct answers

I am currently coding in C++ and am wanting only take notice of lowercase letters and numbers.
My problem is that when I enter a string containing integers and characters (such as a lowercase letter), does not return the correct answer for and ODD length (of the array) above the value of 3.
For instance, if I was to enter '1b1', it would return as a palindrome, otherwise if I were to write '1bbb1', it would return false.
Here is the code:
bool isPalindrome(string s){
int len = s.size();
int mid = len / 2;
int unsigned i;
stack<char> palindromeStack;
for (i = 0; i < mid; i++)
{
if(s[i] <= 47 && s[i] >= 58 ||
s[i] <= 96 && s[i] >= 123){
s.erase(i,1);
i--;
}
if (s[i] > 47 && s[i] < 58 ||
s[i] > 96 && s[i] < 123)
{
palindromeStack.push(s[i]);
}
if (len % 2 != 0)
{
i++;
}
}
while (s[i] != '\0')
{
char ele;
ele = palindromeStack.top();
palindromeStack.pop();
if (ele != s[i])
{
return false;
i++;
}
return true;
}}
I assume this has something to do with the IF statements in relation to the length of the array, but since I'm still quite new to programming, I am unable to find the solution.
Any help would be greatly appreciated! (this includes directing me to already answered questions that will solve my issue)
P.S. Code brackets were slightly modified to fit within the Stack Overflow Code Sample function.
Thanks
I have a much better code. Usage of any data structure template does not indicate that it is a good code. If your target is to check if a string is palindrome including alphanumeric characters please refer to the following code. I have shared the screenshots as an example :-
#include <iostream>
#include<string>
using namespace std;
string transform(string s)
{
string result = "";
for(char ch : s)
{
if(('a'<=ch && ch<='z') || ('0'<=ch && ch<='9') )
result += ch;
}
return result;
}
int main() {
string s="";
// reading the input from the std input
cin>>s;
s = transform(s);
bool isPalindrome = true;
for(int i = 0, j = s.size()-1; i<=j; i++,j--)
{
if(s[i]!=s[j])
{
isPalindrome = false;
break;
}
}
if(isPalindrome)
{
cout<<"Palindrome";
}
else
{
cout<<"Not Palindrome";
}
return 0;
}
The key point is it won't be a palindrome if the values are not same from both ends of the string. If any character is unequal it is proven that it is not a palindrome, hence we need not to go for other comparisons.
This has lesser lines of code and works in every scenario.
This code will bail out checking at first sign of a mismatch :
#include <cassert>
#include <string>
bool is_palindrome(const std::string& str)
{
for (int front = 0, back = static_cast<int>(str.length()) - 1; front < back; ++front, --back)
{
if (str[front] != str[back]) return false;
}
return true;
}
int main()
{
assert(is_palindrome(""));
assert(is_palindrome("1"));
assert(is_palindrome("121"));
assert(is_palindrome("abcdefedcba"));
assert(!is_palindrome("121abc"));
return 0;
}
Edit (now with iterator & reverse iterator):
bool is_palindrome(const std::string& str)
{
for (auto [front, back] = std::tuple{str.begin(), str.rbegin()}; front < back.base(); ++front, ++back)
{
if (*front != *back) return false;
}
return true;
}

Find prefix within a string

I'm currently doing a leetcode question where I have to find a prefix within a sentence and return the word number within the sentence else return -1. I came up with a solution but it crashes with some strings and i dont know why. An example of this is the following:
Input: sentence = "i love eating burger", searchWord = "burg"
Output: 4 (I also get an output of 4)
Explanation: "burg" is prefix of "burger" which is the 4th word in the sentence.
but fails this example:
Input: sentence = "this problem is an easy problem", searchWord = "pro"
Output: 2 ( I get an output of 6)
Explanation: "pro" is prefix of "problem" which is the 2nd and the 6th word in the sentence, but we return 2 as it's the minimal index.
My cout for this one produced a very weird snippet:
problem is an easy problem
problem is an easy problem
problem is an easy problem
problem is an easy problem
probl
proble
problem
problem
problem i
problem is
it completely ignored the first couple substrings when i increments, this is the only time it happens tho.
int isPrefixOfWord(string sentence, string searchWord)
{
string sub;
int count = 1;
for (int i = 0; i < sentence.length(); i++)
{
if (sentence[i] == ' ')
count++;
for (int j = i; j < sentence.length(); j++)
{
sub = sentence.substr(i, j);
cout<<sub<<endl;
if (sub == searchWord)
{
return count;
}
}
}
return -1;
}
Any Ideas?
int isPrefixOfWord(string sentence, string searchWord)
{
string sub;
int count = 1;
for (int i = 0; i < sentence.length() - searchWord.length() - 1; i++)
{
if (sentence[i] == ' ')
count++;
sub = sentence.substr(i,searchWord.length());
if ( sub == searchWord && (sentence[i-1] == ' ' || i == 0))
{
return count;
}
}
return -1;
}
A very simple C++20 solution using starts_with:
#include <string>
#include <sstream>
#include <iostream>
int isPrefixOfWord(std::string sentence, std::string searchWord)
{
int count = 1;
std::istringstream strm(sentence);
std::string word;
while (strm >> word)
{
if ( word.starts_with(searchWord) )
return count;
++count;
}
return -1;
}
int main()
{
std::cout << isPrefixOfWord("i love eating burger", "burg") << "\n";
std::cout << isPrefixOfWord("this problem is an easy problem", "pro") << "\n";
std::cout << isPrefixOfWord("this problem is an easy problem", "lo");
}
Output:
4
2
-1
Currently, LeetCode and many other of the online coding sites do not support C++20, thus this code will not compile successfully on those online platforms.
Therefore, here is a live example using a C++20 compiler
We can just use std::basic_stringstream for solving this problem. This'll pass through:
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
// Most of headers are already included;
// Can be removed;
#include <cstdint>
#include <string>
#include <sstream>
static const struct Solution {
static const int isPrefixOfWord(
const std::string sentence,
const std::string_view search_word
) {
std::basic_stringstream stream_sentence(sentence);
std::size_t index = 1;
std::string word;
while (stream_sentence >> word) {
if (!word.find(search_word)) {
return index;
}
++index;
}
return -1;
}
};
The bug that effects the function output is that you aren't handling the increment of i within your inner for loop:
for (int i = 0; i < sentence.length(); i++)
{
if (sentence[i] == ' ')
count++;
for (int j = i; j < sentence.length(); j++)
{
sub = sentence.substr(i, j);
cout<<sub<<endl;
if (sub == searchWord)
{
return count;
}
}
}
Notice that once your inner-loop is complete that i always iterates by one. So your next search through a word will incorrectly start at its next character, which incorrectly searches for "sub-words" instead of only prefixes, and so creates false positives (and unnecessary work).
Also note that every time that you do:
(sub == searchWord)
That this checks all j characters, even though we're only interested in whether the new jth character is a match.
Another bug, which effects your performance and your couts is that you're not handling mismatches:
if (sub == searchWord)
...is never false, so the only way to exit the inner loop is to keep increments j till the end of the array, so sub ends up being large.
A way to fix your second bug is to replace your inner loop like so:
if (sentence.substr(i, i + searchWord.length()) == searchWord)
return count;
and finally, to fix all bugs:
int isPrefixOfWord (const string & sentence, const string & searchWord)
{
if (sentence.length() < searchWord.length())
return -1;
const size_t i_max = sentence.length() - searchWord.length();
for (size_t i = 0, count = 1; ; ++count)
{
// flush spaces:
while (sentence[i] == ' ')
{
if (i >= i_max)
return -1;
++i;
}
if (sentence.substr(i, searchWord.length()) == searchWord)
return count;
// flush word:
while (sentence[i] != ' ')
{
if (i >= i_max)
return -1;
++i;
}
}
return -1;
}
Note that substr provides a copy of the object (it's not just a wrapper around a string), so this takes linear time with respect to searchWord.length(), which is particularly bad the word within sentence is smaller.
We can improve the speed by replacing
if (sentence.substr(i, searchWord.length()) == searchWord)
return count;
...with
for (size_t j = 0; sentence[i] == searchWord[j]; )
{
++j;
if (j == searchWord.size())
return count;
++i;
}
Others have shown nice applications of the libraries that help solve the problem.
If you don't have access to those libraries for your assignment, or if you just want to learn how you could modularise a problem like this without loosing efficiency, then here's a way to do it in c++11 without any libraries (except string):
bool IsSpace (char c)
{
return c == ' ';
}
bool NotSpace (char c)
{
return c != ' ';
}
class PrefixFind
{
using CharChecker = bool (*)(char);
template <CharChecker Condition>
void FlushWhile ()
{
while ((m_index < sentence.size())
&& Condition(sentence[m_index]))
++m_index;
}
void FlushWhiteSpaces ()
{
FlushWhile<IsSpace>();
}
void FlushToNextWord ()
{
FlushWhile<NotSpace>();
FlushWhile<IsSpace>();
}
bool PrefixMatch ()
{
// SearchOngoing() must equal `true`
size_t j = 0;
while (sentence[m_index] == search_prefix[j])
{
++j;
if (j == search_prefix.size())
return true;
++m_index;
}
return false;
}
bool SearchOngoing () const
{
return m_index + search_prefix.size() <= sentence.size();
}
const std::string & sentence;
const std::string & search_prefix;
size_t m_index;
public:
PrefixFind (const std::string & s, const std::string & sw)
: sentence(s),
search_prefix(sw)
{}
int FirstMatchingWord ()
{
const int NO_MATCHES = -1;
if (!search_prefix.length())
return NO_MATCHES;
m_index = 0;
FlushWhiteSpaces();
for (int n = 1; SearchOngoing(); ++n)
{
if (PrefixMatch())
return n;
FlushToNextWord();
}
return NO_MATCHES;
}
};
In terms of speed: If we consider the length of sentence to be m, and the length of searchWord to be n, then original (buggy) code had O(n*m^2) time complexity. But with this improvement we get O(m).

Search a string for all occurrences of a substring in C++

Write a function countMatches that searches the substring in the given string and returns how many times the substring appears in the string.
I've been stuck on this awhile now (6+ hours) and would really appreciate any help I can get. I would really like to understand this better.
int countMatches(string str, string comp)
{
int small = comp.length();
int large = str.length();
int count = 0;
// If string is empty
if (small == 0 || large == 0) {
return -1;
}
// Increment i over string length
for (int i = 0; i < small; i++) {
// Output substring stored in string
for (int j = 0; j < large; j++) {
if (comp.substr(i, small) == str.substr(j, large)) {
count++;
}
}
}
cout << count << endl;
return count;
}
When I call this function from main, with countMatches("Hello", "Hello"); I get the output of 5. Which is completely wrong as it should return 1. I just want to know what I'm doing wrong here so I don't repeat the mistake and actually understand what I am doing.
I figured it out. I did not need a nested for loop because I was only comparing the secondary string to that of the string. It also removed the need to take the substring of the first string. SOOO... For those interested, it should have looked like this:
int countMatches(string str, string comp)
{
int small = comp.length();
int large = str.length();
int count = 0;
// If string is empty
if (small == 0 || large == 0) {
return -1;
}
// Increment i over string length
for (int i = 0; i < large; i++) {
// Output substring stored in string
if (comp == str.substr(i, small)) {
count++;
}
}
cout << count << endl;
return count;
}
The usual approach is to search in place:
std::string::size_type pos = 0;
int count = 0;
for (;;) {
pos = large.find(small, pos);
if (pos == std::string::npos)
break;
++count;
++pos;
}
That can be tweaked if you're not concerned about overlapping matches (i.e., looking for all occurrences of "ll" in the string "llll", the answer could be 3, which the above algorithm will give, or it could be 2, if you don't allow the next match to overlap the first. To do that, just change ++pos to pos += small.size() to resume the search after the entire preceding match.
The problem with your function is that you are checking that:
Hello is substring of Hello
ello is substring of ello
llo is substring of llo
...
of course this matches 5 times in this case.
What you really need is:
For each position i of str
check if the substring of str starting at i and of length = comp.size() is exactly comp.
The following code should do exactly that:
size_t countMatches(const string& str, const string& comp)
{
size_t count = 0;
for (int j = 0; j < str.size()-comp.size()+1; j++)
if (comp == str.substr(j, comp.size()))
count++;
return count;
}

Find if we can get palindrome

Given a string S.We need to tell if we can make it to palindrome by removing exactly one letter from it or not.
I have a O(N^2) approach by modifying Edit Distance method.Is their any better way ?
My Approach :
int ModifiedEditDistance(const string& a, const string& b, int k) {
int i, j, n = a.size();
int dp[MAX][MAX];
memset(dp, 0x3f, sizeof dp);
for (i = 0 ; i < n; i++)
dp[i][0] = dp[0][i] = i;
for (i = 1; i <= n; i++) {
int from = max(1, i-k), to = min(i+k, n);
for (j = from; j <= to; j++) {
if (a[i-1] == b[j-1]) // same character
dp[i][j] = dp[i-1][j-1];
// note that we don't allow letter substitutions
dp[i][j] = min(dp[i][j], 1 + dp[i][j-1]); // delete character j
dp[i][j] = min(dp[i][j], 1 + dp[i-1][j]); // insert character i
}
}
return dp[n][n];
}
How to improve space complexity as max size of string can go upto 10^5.
Please help.
Example : Let String be abc then answer is "NO" and if string is "abbcbba then answer is "YES"
The key observation is that if the first and last characters are the same then you needn't remove either of them; which is to say that xSTRINGx can be turned into a palindrome by removing a single letter if and only if STRING can (as long as STRING is at least one character long).
You want to define a method (excuse the Java syntax--I'm not a C++ coder):
boolean canMakePalindrome(String s, int startIndex, int endIndex, int toRemove);
which determines whether the part of the string from startIndex to endIndex-1 can be made into a palindrome by removing toRemove characters.
When you consider canMakePalindrome(s, i, j, r), then you can define it in terms of smaller problems like this:
If j-i is 1 then return true; if it's 0 then return true if and only if r is 0. The point here is that a 1-character string is a palindrome regardless of whether you remove a character; a 0-length string is a palindrome, but can't be made into one by removing a character (because there aren't any to remove).
If s[i] and s[j-1] are the same, then it's the same answer as canMakePalindrome(s, i+1, j-1, r).
If they're different, then either s[i] or s[j-1] needs removing. If toRemove is zero, then return false, because you haven't got any characters left to remove. If toRemove is 1, then return true if either canMakePalindrome(s, i+1, j, 0) or canMakePalindrome(s, i, j-1, 0). This is because you're now testing whether it's already a palindrome if you remove one of those two characters.
Now this can be coded up pretty easily, I think.
If you wanted to allow for removal of more than one character, you'd use the same idea, but using dynamic programming. With only one character to remove, dynamic programming will reduce the constant factor, but won't reduce the asymptotic time complexity (linear in the length of the string).
Psudocode (Something like this I havn't tested it at all).
It is based on detecting the conditions that you CAN remove a character, ie
There is exactly 1 wrong character
It is a palendrome (0 mismatch)
O(n) in time, O(1) in space.
bool foo(const std::string& s)
{
int i = 0;
int j = s.size()-1;
int mismatch_count = 0;
while (i < j)
{
if (s[i]==s[j])
{
i++; j--;
}
else
{
mismatch_count++;
if (mismatch_count > 1) break;
//override first preference if cannot find match for next character
if (s[i+1] == s[j] && ((i+2 >= j-1)||s[i+2]==s[j-1]))
{
i++;
}
else if (s[j-1]==s[i])
{
j--;
}
else
{
mismatch_count++; break;
}
}
}
//can only be a palendrome if you remove a character if there is exactly one mismatch
//or if a palendrome
return (mismatch_count == 1) || (mismatch_count == 0);
}
Here's a (slightly incomplete) solution which takes O(n) time and O(1) space.
// returns index to remove to make a palindrome; string::npos if not possible
size_t willYouBeMyPal(const string& str)
{
size_t toRemove = string::npos;
size_t len = str.length();
for (size_t c1 = 0, c2 = len - 1; c1 < c2; ++c1, --c2) {
if (str[c1] != str[c2]) {
if (toRemove != string::npos) {
return string::npos;
}
bool canRemove1 = str[c1 + 1] == str[c2];
bool canRemove2 = str[c1] == str[c2 - 1];
if (canRemove1 && canRemove2) {
abort(); // TODO: handle the case where both conditions are true
} else if (canRemove1) {
toRemove = c1++;
} else if (canRemove2) {
toRemove = c2--;
} else {
return string::npos;
}
}
}
// if str is a palindrome already, remove the middle char and it still is
if (toRemove == string::npos) {
toRemove = len / 2;
}
return toRemove;
}
Left as an exercise is what to do if you get this:
abxyxcxyba
The correct solution is:
ab_yxcxyba
But you might be led down a bad path:
abxyxcx_ba
So when you find the "next" character on both sides is a possible solution, you need to evaluate both possibilities.
I wrote a sample with O(n) complexity that works for the tests I threw at it. Not many though :D
The idea behind it is to ignore the first and last letters if they are the same, deleting one of them if they are not, and reasoning what happens when the string is small enough. The same result could be archived with a loop instead of the recursion, which would save some space (making it O(1)), but it's harder to understand and more error prone IMO.
bool palindrome_by_1(const string& word, int start, int end, bool removed = false) // Start includes, end excludes
{
if (end - start == 2){
if (!removed)
return true;
return word[start] == word[end - 1];
}
if (end - start == 1)
return true;
if (word[start] == word[end - 1])
return palindrome_by_1(word, start + 1, end - 1, removed);
// After this point we need to remove a letter
if (removed)
return false;
// When two letters don't match, try to eliminate one of them
return palindrome_by_1(word, start + 1, end, true) || palindrome_by_1(word, start, end - 1, true);
}
Checking if a single string is palindrome is O(n). You can implement a similar algorithm than moves two pointers, one from the start and another from the end. Move each pointer as long as the chars are the same, and on the first mismatch try to match which char you can skip, and keep moving both pointers as long as the rest chars are the same. Keep track of the first mismatch. This is O(n).
I hope my algorithm will pass without providing code.
If a word a1a2....an can be made a palindrome by removing ak, we can search for k as following:
If a1 != an, then the only possible k would be 1 or n. Just check if a1a2....an-1 or a2a3....an is a palindrome.
If a1 == an, next step is solving the same problem for a2....an-1. So we have a recursion here.
public static boolean pal(String s,int start,int end){
if(end-start==1||end==start)
return true;
if(s.charAt(start)==s.charAt(end))
return pal(s.substring(start+1, end),0,end-2);
else{
StringBuilder sb=new StringBuilder(s);
sb.deleteCharAt(start);
String x=new String(sb);
if(x.equals(sb.reverse().toString()))
return true;
StringBuilder sb2=new StringBuilder(s);
sb2.deleteCharAt(end);
String x2=new String(sb2);
if(x2.equals(sb2.reverse().toString()))
return true;
}
return false;
}
I tried the following,f and b are the indices at which characters do not match
int canwemakepal(char *str)//str input string
{
long int f,b,len,i,j;
int retval=0;
len=strlen(str);
f=0;b=len-1;
while(str[f]==str[b] && f<b)//continue matching till we dont get a mismatch
{
f++;b--;
}
if(f>=b)//if the index variable cross over each other, str is palindrome,answer is yes
{
retval=1;//true
}
else if(str[f+1]==str[b])//we get a mismatch,so check if removing character at str[f] will give us a palindrome
{
i=f+2;j=b-1;
while(str[i]==str[j] && i<j)
{
i++;j--;
}
if(i>=j)
retval=1;
else
retval=0;
}
else if(str[f]==str[b-1])//else check the same for str[b]
{
i=f+1;j=b-2;
while(str[i]==str[j] && i<j)
{
i++;j--;
}
if(i>=j)
retval=1;
else
retval=0;
}
else
retval=0;
return retval;
}
I created this solution,i tried with various input giving correct result,still not accepted as correct solution,Check it n let me know if m doing anything wrong!! Thanks in advance.
public static void main(String[] args)
{
Scanner s = new Scanner(System.in);
int t = s.nextInt();
String result[] = new String[t];
short i = 0;
while(i < t)
{
String str1 = s.next();
int length = str1.length();
String str2 = reverseString(str1);
if(str1.equals(str2))
{
result[i] = "Yes";
}
else
{
if(length == 2)
{
result[i] = "Yes";
}
else
{
int x = 0,y = length-1;
int counter = 0;
while(x<y)
{
if(str1.charAt(x) == str1.charAt(y))
{
x++;
y--;
}
else
{
counter ++;
if(str1.charAt(x) == str1.charAt(y-1))
{
y--;
}
else if(str1.charAt(x+1) == str1.charAt(y))
{
x++;
}
else
{
counter ++;
break;
}
}
}
if(counter >= 2)
{
result[i] = "No";
}
else
result[i]="Yes";
}
}
i++;
} // Loop over
for(int j=0; j<i;j++)
{
System.out.println(result[j]);
}
}
public static String reverseString(String original)
{
int length = original.length();
String reverse = "";
for ( int i = length - 1 ; i >= 0 ; i-- )
reverse = reverse + original.charAt(i);
return reverse;
}

Using vectors to solve the anagrams in C++

I have a function that takes in two vectors of strings and compares each element to see if they are anagrams of one another.
Vector #1: "bat", "add", "zyz", "aaa"
Vector #2: "tab", "dad", "xyx", "bbb"
Restrictions and other things to clarify: The function is supposed to loop through both vectors and compare the strings. I am only supposed to compare based on the index of each vector; meaning I only compare the strings which are in the first index, then the strings which are in the second index, and so on. It's safe to assume that the vectors passed in as parameters will always be the same size.
If the compared strings are anagrams, "Match" is printed on the screen. If they aren't, "No Match" is printed.
Output: Match Match No Match No Match
I'm getting ridiculously stuck on this problem, I know how to reverse strings but when it gets to this I'm getting a bit clueless.
I understand that I would need to iterate through each vector, and then compare. But how would I be able to compare each letter within the string? Also, I'm not allowed to include anything else like algorithm, sort, or set. I've tried digging through a lot of questions but most answers utilized this.
If there are any tips on how to solve this, that would be great. I'll be posting what I find shortly.
Here's what I got so far:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void anagrams(const vector<string>& vOne, const vector<string>& vTwo){
for(int i=0; i< vOne.size(); i++){
for(int j=0; j< vTwo.size(); j++){
if(vOne[i].size() != vTwo[j].size()){
cout << 0 << endl;
}
else {
cout << 1 << endl;
}
}
}
}
void quicksort(vector<int>& a, int low, int high){
if(low < high)
{
int mid = (low + high)/2;
int pivot = a[mid];
swap(a[high], a[mid]);
int i, j;
for(i=low, j=high-1; ;){
while(a[i]<pivot) ++i;
while(j>i && pivot < a[j]) --j;
if (i < j)
swap(a[i++], a[j--]);
else
break;
}
swap(a[i], a[high]);
}
quicksort(a, low, i - 1);
quicksort(a, i + 1, high);
}
Thanks in advance!
Though you are not able to use sort, you should still sort the the words you are checking against, to see if they are anagrams. You will just have to sort the char[] manually, which is unfortunate, yet a good exercise. I would make a predicate, a function that compares the 2 strings and return true or false, and use that to check if they are anagrams. Also, it seems as though you don't need to print out both words that actually match, if that is true, then you can sort the words in the vectors when you first read them in, then just run them through your predicate function.
// Predicate
bool isMatch(const string &lhs, const string &rhs)
{
...sort and return lhs == rhs;
}
If you write the function, as I have above, you are passing in the parameters by const reference, which then you can copy (not using strcpy() due to vulnerabilities) the parameters into char[] and sort the words. I would recommend writing your sort as its own function.
Another hint, remember that things are much faster, and stl uses smart ptrs to do sorting. Anyway, I hope this helps even a little bit, I didn't want to give you the answer.
A solution that is fairly quick as long as the strings only contain characters between a-z and A-Z would be
bool is_anagram( const string& s1, const string& s2 ) {
if( s1.size() != s2.size() ) {
return false;
}
size_t count[ 26 * 2 ] = { 0 };
for( size_t i = 0; i < s1.size(); i++ ) {
char c1 = s1[ i ];
char c2 = s2[ i ];
if( c1 >= 'a' ) {
count[ c1 - 'a' ]++;
}
else {
count[ c1 - 'A' + 26 ]++;
}
if( c2 >= 'a' ) {
count[ c2 - 'a' ]--;
}
else {
count[ c2 - 'A' + 26 ]--;
}
}
for( size_t i = 0; i < 26 * 2; i++ ) {
if( count[ i ] != 0 ) {
return false;
}
}
return true;
}
If you're willing to use C++11, here is some rather inefficient code for seeing if two strings are anagrams. I'll leave it up to you to loop through the list of words.
#include <iostream>
#include <vector>
using namespace std;
int count_occurrences(string& word, char search) {
int count = 0;
for (char s : word) {
if (s == search) {
count++;
}
}
return count;
}
bool compare_strings(string word1, string v2) {
if (word1.size() != v2.size())
{
return false;
}
for (char s: word1) //In case v1 contains letters that are not in v2
{
if (count_occurrences(word1, s) != count_occurrences(v2, s))
{
return false;
}
}
return true;
}
int main() {
string s1 = "bat";
string s2 = "atb";
bool result = compare_strings(s1, s2);
if (result)
{
cout << "Match" << endl;
}
else
{
cout << "No match" << endl;
}
}
This works by simply counting the number of times a given letter occurs in a string. A better way to do this would be to sort the characters in the string alphabetically, and then compare the sorted strings to see if they are equal. I'll leave it up to you to improve this.
Best wishes.
Another solution, since I'm sufficiently bored:
#include <iostream>
#include <vector>
#include <string>
int equiv_class(char c) {
if ((c>='A')&&(c<='Z')) return c-'A';
if ((c>='a')&&(c<='z')) return c-'a';
return 27;
}
bool is_anagram(const std::string& a, const std::string& b)
{
if (a.size()!=b.size()) return false;
int hist[26]={};
int nz=0; // Non-zero histogram sum tally
for (int i=0, e=a.size() ; i!=e ; ++i)
{
int aclass = equiv_class(a[i]);
int bclass = equiv_class(b[i]);
if (aclass<27) {
switch (++hist[aclass]) {
case 1: ++nz; break; // We were 0, now we're not--add
case 0: --nz; break; // We were't, now we are--subtract
// otherwise no change in nonzero count
}
}
if (bclass<27) {
switch (--hist[bclass]) {
case -1: ++nz; break; // We were 0, now we're not--add
case 0: --nz; break; // We weren't, now we are--subtract
// otherwise no change in nonzero count
}
}
}
return 0==nz;
}
int main()
{
std::vector<std::string> v1{"elvis","coagulate","intoxicate","a frontal lobotomy"};
std::vector<std::string> v2{"lives","catalogue","excitation","bottlein frontofme"};
for (int i=0, e=(v1.size()==v2.size()?v1.size():0); i!=e; ++i) {
if (is_anagram(v1[i],v2[i])) {
std::cout << " Match";
} else {
std::cout << " No Match";
}
}
}