I was able to create a function that searches and returns a number of matching characters in a word, but now I'm having trouble to create another function that searches if the two words matches exactly down to the position and returns the number of matches . The constraints is c-strings.
So if a word is tiny, and I entered tine, it should return 3.
The function I attached below is simply the one I was able to figure out
int countMatches(const char s1[], const char s2[])
{
char s1copy[MAXWORDLEN+1];
strcpy(s1copy, s1);
int nMatches = 0;
// For every character in s2
for (int k2 = 0; s2[k2] != '\0'; k2++)
{
// For every character in the copy of s1
for (int k1 = 0; s1copy[k1] != '\0'; k1++)
{
// If they match, blot it out of the copy of s1
// so it won't be matched again
if (s1copy[k1] == s2[k2])
{
nMatches++;
s1copy[k1] = '#';
break;
}
}
}
return nMatches;
}
int countMatches(const char s1[], const char s2[]) {
int i = 0;
while (s1[i] != '\0' && s2[i] != '\0' && s1[i] == s2[i])
i++;
return i;
}
If you need just to count the number of initial matching characters in two words then the function can look the following way
size_t countMatches( const char s1[], const char s2[] )
{
size_t nMatches = 0;
while ( s1[nMatches] && s1[nMatches] == s2[nMatches] ) ++nMatches;
return nMatches;
}
Take into account that it is better to use for the count the type size_t. It is the type of the return value of standard C function strlen. Operator sizeofalso yields a value of type size_t. And other C standard functions that accept integer values have parameters of type size_t.
Related
This is what I have right now (str is a dynamic, null-terminating char array):
bool String::operator<(const String& rhs) const {
if (str == rhs.str)
return false;
int i = 0;
while (str[i] != '\0' && rhs[i] != '\0') {
if (str[i] > rhs[i])
return false;
++i;
}
return true;
}
This passes most tests, but it fails on:
String s1("abc");
String s2("abcde");
assert(!(s2 < s1));
No matter how I alter the function it always seem to fail one test or another. How would YOU overload this operator? Basically I just need to compare two null-terminating char arrays and see which one is the lesser (without any libraries).
You can take advantage of null-terminated strings to simplify the basic algorithm to:
While the nth character of both strings are the same (incrementing n starting with 0):
If the nth character of both strings is '\0' the strings are obviously the same, otherwise:
Otherwise, compare the nth characters as unsigned values, to determine the result of the comparison.
If you change your loop to:
int i = 0;
while (true) {
char l = str[i];
char r = rhs.str[i++];
if( l < r ) return true;
if( l == 0 || l > r ) return false;
}
it should work. Note if you need to handle national alphabets properly, that usually has values > 127, you need to change l and r type to unsigned char
But easier solution would be:
return strcmp( str, rhs.str ) < 0;
How is it possible to see if the last four elements of an array match the last four elements of the second array?
For instance, I'm writing a password program. First, the user is asked their birth date. Then they are asked to input a password.
for the birth date array, the user enters '05/14/1984'
for the password array, the user enters 'coke_1984'
I'm trying to see if the last four of birth date are the same as the last four of the password, if all four match, then add 1 to score.
I'm completely stuck! The code I have now has an "invalid conversion from 'char' to 'const char*'"
for(i = len; i <= len; i--)
{
if(strcmp(birthdate, password[i]) == 0)
{
dateCMP = true;
}else{dateCMP = false;}
}
if(dateCMP = true)
{
score += 1;
cout << "Your date of birth should not be the last four characters";
}
Make your life easier and take advantage of the already provided STL facilities like std::string.
Below is a function that takes as entries 2 strings and returns true if their last 4 characters are equal and false otherwise:
bool
compare_last_4_characters(std::string const &str1, std::string const &str2) {
std::size_t sz1 = str1.size();
std::size_t sz2 = str2.size();
if(sz1 > 3 && sz2 > 3) {
return str1.substr(sz1 - 4, sz1) == str2.substr(sz2 - 4, sz2);
}
return false;
}
LIVE DEMO
If you can't use std::string below is a version that works without them:
bool
compare_last_4_characters(char const *str1, char const *str2) {
int sz1 = strlen(str1) - 4;
int sz2 = strlen(str2) - 4;
if(sz1 >= 0 && sz2 >= 0) return !strcmp(str1 + sz1, str2 + sz2);
return false;
}
LIVE DEMO
#include <iostream>
#include <utility>
#include <algorithm>
//size_t literal: see http://stackoverflow.com/questions/22346369/initialize-integer-literal-to-stdsize-t
constexpr std::size_t operator "" _z(unsigned long long n)
{
return n;
}
bool lastFourEquals(const char* str1, size_t strlen1, const char* str2, size_t strlen2)
{
//variant 1: do not allow shorter strings
//if(strlen1 < 4 || strlen2 < 4) return false;
//Variant 2: maximum of last for equals (e.g. "123"=="0123")
size_t maxLen =std::min(std::max(strlen1, strlen2), 4_z);
for (int i = 1; i <= maxLen; i++)
{
size_t pos1 = strlen1 - i;
size_t pos2 = strlen2 - i;
if (str1[pos1] != str2[pos2]) return false; //Found difference
}
return true;
}
int main()
{
const char* test1 = "05/14/1984";
const char* test2 = "coke_1984";
bool eq = lastFourEquals(test1, strlen(test1), test2, strlen(test2));
std::cout << (eq ? "true" : "false") << std::endl;
}
I figured it out by using another array. I just made an array called compare to store values of password if password[i] == birthdate[i]... then used an if to strcmp(compare, birthdate)...
for(i = len-4; i < len; i++)
{
if(birthdate[i] == password[i])
{
compare[i] = password[i];
}
}
if(strcmp(compare, birthdate))
{
score += 1;
}
Thanks for your attempts to help!
I think this works! I finally got it. It's a pain in the ass not being able to use the string library. Please let me know! You guys have been so much help. Don't worry about my other arguments in the function, I'm not using those quite yet.
//this function runs to see if the first letter of last name matched
//first letter of password, if the birthdate
int checkStrength(char password[SIZE], char lastName[SIZE], char
birthdate[SIZE], char carMake[SIZE], int favNum)
{
//array and variables for use through the checks
char compareDate[SIZE];
int weakness = 0;
int len = strlen(password) - 4;
int i;
int c = 0;
//this for loop compares arrays, if comparison is found, adds element to
//compareDate and then uses an if statement to strcmp compare and birthdate
//if compare and birthdate are then the same, add weakness
for(i = 0; i < len; i++)
{
if(birthdate[c] == password[len])
{
compareDate[c] = password[i];
c += 1;
}
}
if(strcmp(compareDate, birthdate) == 1)
{
weakness += 1;
cout << "Your birth year should not be the last four character of your
password.";
cout << compareDate;
}
//this checks to see if the car make array is used in order through password,
//if it is, add weakness
return weakness;
}
Given two strings, write a method to decide if one is an anagram/permutation of the other. This is my approach:
I wrote this function to check if 2 strings are anagrams (such as dog and god).
In ascii, a to z is 97 - 122.
Basically I have an array of bools that are all initially false. Everytime I encounter a char in string1, it marks it as true.
To check if its an anagram, I check if any chars of string2 are false (should be true if encountered in string1).
I'm not sure how but this works too: arr[num] = true; (shouldnt work because I dont take into account that ascii starts at 97 and thus goes out of bounds).
(Side note: is there a better approach than mine?)
EDIT: Thanks for all the responses! Will be carefully reading each one. By the way: not an assignment. This is a problem from a coding interview practice book
bool permutation(const string &str1, const string &str2)
{
// Cannot be anagrams if sizes are different
if (str1.size() != str2.size())
return false;
bool arr[25] = { false };
for (int i = 0; i < str1.size(); i++) // string 1
{
char ch = (char)tolower(str1[i]); // convert each char to lower
int num = ch; // get ascii
arr[num-97] = true;
}
for (int i = 0; i < str2.size(); i++) // string 2
{
char ch = (char)tolower(str2[i]); // convert char to lower
int num = ch; // get ascii
if (arr[num-97] == false)
return false;
}
return true;
}
There is nothing inherent in C++ arrays that prevents you from writing beyond the end of them. But, in doing so, you violate the contract you have with the compiler and it is therefore free to do what it wishes (undefined behaviour).
You can get bounds checking on "arrays" by using the vector class, if that's what you need.
As for a better approach, it's probably better if your array is big enough to cover every possible character (so you don't have to worry about bounds checking) and it shouldn't so much be a truth value as a count, so as to handle duplicate characters within the strings. If it's just a truth value, then here and her would be considered anagrams.
Even though you state it's not an assignment, you'll still learn more if you implement it yourself, so it's pseudo-code only from me. The basic idea would be:
def isAnagram (str1, str2):
# Different lengths means no anagram.
if len(str1) not equal to len(str2):
return false
# Initialise character counts to zero.
create array[0..255] (assumes 8-bit char)
for each index 0..255:
set count[index] to zero
# Add 1 for all characters in string 1.
for each char in string1:
increment array[char]
# Subtract 1 for all characters in string 2.
for each char in string2:
decrement array[char]
# Counts will be all zero for an anagram.
for each index 0..255:
if count[index] not equal to 0:
return false
return true
Working approach : with zero additional cost.
bool permutation(const std::string &str1, const std::string &str2)
{
// Cannot be anagrams if sizes are different
if (str1.size() != str2.size())
return false;
int arr[25] = {0 };
for (int i = 0; i < str1.size(); i++) // string 1
{
char ch = (char)tolower(str1[i]); // convert each char to lower
int num = ch; // get ascii
arr[num-97] = arr[num-97] + 1 ;
}
for (int i = 0; i < str2.size(); i++) // string 2
{
char ch = (char)tolower(str2[i]); // convert char to lower
int num = ch; // get ascii
arr[num-97] = arr[num-97] - 1 ;
}
for (int i =0; i< 25; i++) {
if (arr[i] != 0) {
return false;
}
}
return true;
}
Yes, C and C++ both doesn't carry out the index-out-of-bounds.
It is the duty of the programmer to make sure that the program logic doesn't cross the legitimate limits. It is the programmer who need to make checks for the violations.
Improved Code:
bool permutation(const string &str1, const string &str2)
{
// Cannot be anagrams if sizes are different
if (str1.size() != str2.size())
return false;
int arr[25] = { 0 }; //<-------- Changed
for (int i = 0; i < str1.size(); i++) // string 1
{
char ch = (char)tolower(str1[i]); // convert each char to lower
int num = ch; // get ascii
arr[num-97] += 1; //<-------- Changed
}
for (int i = 0; i < str2.size(); i++) // string 2
{
char ch = (char)tolower(str2[i]); // convert char to lower
int num = ch; // get ascii
arr[num-97] = arr[num-97] - 1 ; //<-------- Changed
}
for (int i =0; i< 25; i++) { //<-------- Changed
if (arr[i] != 0) { //<-------- Changed
return false; //<-------- Changed
}
}
return true;
}
I got a code. It supposes to give me an output for the number of count everytime it found "code", "cope", "coze", "cole", or "core". for example: countCode("aaacodebbb") it should be 1, but found 0.
int countCode(const string& inStr) {
int count = 0;
for (unsigned i = 0; i < inStr.length(); i++) {
if (inStr.substr(i,i+3) == "code" || inStr.substr(i,i+3) == "coze" || inStr.substr(i,i+3) == "cope" || inStr.substr(i,i+3) == "core" || inStr.substr(i,i+3) == "cole") {
count++;
}
}
return count;
}
string substr (size_t pos = 0, size_t len = npos) const;
That second argument is meant to be the length, not the final character position. You need to use inStr.substr(i,4) instead.
In addition, you know that a four-character string cannot occur when there's less than four characters remaining in the string, so you can make it more logical (and possibly mire efficient) with something like:
int countCode (const string& inStr) {
int count = 0;
size_t len = inStr.length();
if (len >= 4) {
for (size_t i = 0; i <= len - 4; i++) {
if (inStr.substr(i,4) == "code" || ... ) {
count++;
}
}
}
}
Also note the use of size_t which is the more natural type for handling sizes and positions in strings.
If you check e.g. this substr reference you will see that the second argument is the length of the sub-string, not the ending position.
The second parameter of substr() is the count, not the end position.
basic_string substr( size_type pos = 0,
size_type count = npos ) const;
Parameters
pos - position of the first character to include
count - length of the substring
^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^
That means, you should use
inStr.substr(i,4)
I somehow need to find the longest string in other string, so if string1 will be "Alibaba" and string2 will be "ba" , the longest string will be "baba". I have the lengths of strings, but what next ?
char* fun(char* a, char& b)
{
int length1=0;
int length2=0;
int longer;
int shorter;
char end='\0';
while(a[i] != tmp)
{
i++;
length1++;
}
int i=0;
while(b[i] != tmp)
{
i++;
length++;
}
if(dlug1 > dlug2){
longer = length1;
shorter = length2;
}
else{
longer = length2;
shorter = length1;
}
//logics here
}
int main()
{
char name1[] = "Alibaba";
char name2[] = "ba";
char &oname = *name2;
cout << fun(name1, oname) << endl;
system("PAUSE");
return 0;
}
Wow lots of bad answers to this question. Here's what your code should do:
Find the first instance of "ba" using the standard string searching functions.
In a loop look past this "ba" to see how many of the next N characters are also "ba".
If this sequence is longer than the previously recorded longest sequence, save its length and position.
Find the next instance of "ba" after the last one.
Here's the code (not tested):
string FindLongestRepeatedSubstring(string longString, string shortString)
{
// The number of repetitions in our longest string.
int maxRepetitions = 0;
int n = shortString.length(); // For brevity.
// Where we are currently looking.
int pos = 0;
while ((pos = longString.find(shortString, pos)) != string::npos)
{
// Ok we found the start of a repeated substring. See how many repetitions there are.
int repetitions = 1;
// This is a little bit complicated.
// First go past the "ba" we have already found (pos += n)
// Then see if there is still enough space in the string for there to be another "ba"
// Finally see if it *is* "ba"
for (pos += n; pos+n < longString.length() && longString.substr(pos, n) == shortString; pos += n)
++repetitions;
// See if this sequence is longer than our previous best.
if (repetitions > maxRepetitions)
maxRepetitions = repetitions;
}
// Construct the string to return. You really probably want to return its position, or maybe
// just maxRepetitions.
string ret;
while (maxRepetitions--)
ret += shortString;
return ret;
}
What you want should look like this pseudo-code:
i = j = count = max = 0
while (i < length1 && c = name1[i++]) do
if (j < length2 && name2[j] == c) then
j++
else
max = (count > max) ? count : max
count = 0
j = 0
end
if (j == length2) then
count++
j = 0
end
done
max = (count > max) ? count : max
for (i = 0 to max-1 do
print name2
done
The idea is here but I feel that there could be some cases in which this algorithm won't work (cases with complicated overlap that would require going back in name1). You may want to have a look at the Boyer-Moore algorithm and mix the two to have what you want.
The Algorithms Implementation Wikibook has an implementation of what you want in C++.
http://www.cplusplus.com/reference/string/string/find/
Maybe you made it on purpose, but you should use the std::string class and forget archaic things like char* string representation.
It will make you able to use lots of optimized methods, such as string research, etc.
why dont you use strstr function provided by C.
const char * strstr ( const char * str1, const char * str2 );
char * strstr ( char * str1, const char * str2 );
Locate substring
Returns a pointer to the first occurrence of str2 in str1,
or a null pointer if str2 is not part of str1.
The matching process does not include the terminating null-characters.
use the length's now and create a loop and play with the original string anf find the longest string inside.