I Am Able To Go Outside Array Bounds - c++

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;
}

Related

Matching exact position in an array

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.

In arrays, see if last four elements of 1st array match last 4 elements of 2nd array?

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;
}

Find the minimum number of moves to get a "Good" string

A string is called to be good if and only if "All the distinct characters in String are repeated the same number of times".
Now, Given a string of length n, what is the minimum number of changes we have to make in this string so that string becomes good.
Note : We are only allowed to use lowercase English letters, and we can change any letter to any other letter.
Example : Let String is yyxzzxxx
Then here answer is 2.
Explanation : One possible solution yyxyyxxx. We have changed 2 'z' to 2 'y'. Now both 'x' and 'y' are repeated 4 times.
My Approach :
Make a hash of occurrence of all 26 lowercase letters.
Also find number of distinct alphabets in string.
Sort this hash array and start checking if length of string is divisible by number of distinct characters.If yes then we got the answer.
Else reduce distinct characters by 1.
But its giving wrong answers for some results as their may be cases when removing some character that has not occur minimum times provide a good string in less moves.
So how to do this question.Please help.
Constraints : Length of string is up to 2000.
My Approach :
string s;
cin>>s;
int hash[26]={0};
int total=s.length();
for(int i=0;i<26;i++){
hash[s[i]-'a']++;
}
sort(hash,hash+total);
int ans=0;
for(int i=26;i>=1;i--){
int moves=0;
if(total%i==0){
int eachshouldhave=total/i;
int position=26;
for(int j=1;j<26;j++){
if(hash[j]>eachshouldhave && hash[j-1]<eachshouldhave){
position=j;
break;
}
}
int extrasymbols=0;
//THE ONES THAT ARE BELOW OBVIOUSLY NEED TO BE CHANGED TO SOME OTHER SYMBOL
for(int j=position;j<26;j++){
extrasymbols+=hash[j]-eachshouldhave;
}
//THE ONES ABOVE THIS POSITION NEED TO GET SOME SYMBOLS FROM OTHERS
for(int j=0;j<position;j++){
moves+=(eachshouldhave-hash[j]);
}
if(moves<ans)
ans=moves;
}
else
continue;
}
Following should fix your implementation:
std::size_t compute_change_needed(const std::string& s)
{
int count[26] = { 0 };
for(char c : s) {
// Assuming only valid char : a-z
count[c - 'a']++;
}
std::sort(std::begin(count), std::end(count), std::greater<int>{});
std::size_t ans = s.length();
for(std::size_t i = 1; i != 27; ++i) {
if(s.length() % i != 0) {
continue;
}
const int expected_count = s.length() / i;
std::size_t moves = 0;
for(std::size_t j = 0; j != i; j++) {
moves += std::abs(count[j] - expected_count);
}
ans = std::min(ans, moves);
}
return ans;
}

Finding common characters in two strings

I am coding for the problem in which we got to count the number of common characters in two strings. Main part of the count goes like this
for(i=0; i < strlen(s1); i++) {
for(j = 0; j < strlen(s2); j++) {
if(s1[i] == s2[j]) {
count++;
s2[j] = '*';
break;
}
}
}
This goes with an O(n^2) logic. However I could not think of a better solution than this. Can anyone help me in coding with an O(n) logic.
This is very simple. Take two int arrays freq1 and freq2. Initialize all its elements to 0. Then read your strings and store the frequencies of the characters to these arrays. After that compare the arrays freq1 and freq2 to find the common characters.
It can be done in O(n) time with constant space.
The pseudo code goes like this :
int map1[26], map2[26];
int common_chars = 0;
for c1 in string1:
map1[c1]++;
for c2 in string2:
map2[c2]++;
for i in 1 to 26:
common_chars += min(map1[i], map2[i]);
Your current code is O(n^3) because of the O(n) strlens and produces incorrect results, for example on "aa", "aa" (which your code will return 4).
This code counts letters in common (each letter being counted at most once) in O(n).
int common(const char *a, const char *b) {
int table[256] = {0};
int result = 0;
for (; *a; a++)table[*a]++;
for (; *b; b++)result += (table[*b]-- > 0);
return result;
}
Depending on how you define "letters in common", you may have different logic. Here's some testcases for the definition I'm using (which is size of the multiset intersection).
int main(int argc, char *argv[]) {
struct { const char *a, *b; int want; } cases[] = {
{"a", "a", 1},
{"a", "b", 0},
{"a", "aa", 1},
{"aa", "a", 1},
{"ccc", "cccc", 3},
{"aaa", "aaa", 3},
{"abc", "cba", 3},
{"aasa", "asad", 3},
};
int fail = 0;
for (int i = 0; i < sizeof(cases) / sizeof(*cases); i++) {
int got = common(cases[i].a, cases[i].b);
if (got != cases[i].want) {
fail = 1;
printf("common(%s, %s) = %d, want %d\n",
cases[i].a, cases[i].b, got, cases[i].want);
}
}
return fail;
}
You can do it with 2n:
int i,j, len1 = strlen(s1), len2 = strlen(s2);
unsigned char allChars[256] = { 0 };
int count = 0;
for( i=0; i<len1; i++ )
{
allChars[ (unsigned char) s1[i] ] = 1;
}
for( i=0; i<len2; i++ )
{
if( allChars[ (unsigned char) s1[i] ] == 1 )
{
allChars[ (unsigned char) s2[i] ] = 2;
}
}
for( i=0; i<256; i++ )
{
if( allChars[i] == 2 )
{
cout << allChars[i] << endl;
count++;
}
}
Following code traverses each sting only once. So the complexity is O(n). One of the assumptions is that the upper and lower cases are considered same.
#include<stdio.h>
int main() {
char a[] = "Hello world";
char b[] = "woowrd";
int x[26] = {0};
int i;
int index;
for (i = 0; a[i] != '\0'; i++) {
index = a[i] - 'a';
if (index > 26) {
//capital char
index = a[i] - 'A';
}
x[index]++;
}
for (i = 0; b[i] != '\0'; i++) {
index = b[i] - 'a';
if (index > 26) {
//capital char
index = b[i] - 'A';
}
if (x[index] > 0)
x[index] = -1;
}
printf("Common characters in '%s' and '%s' are ", a, b);
for (i = 0; i < 26; i++) {
if (x[i] < 0)
printf("%c", 'a'+i);
}
printf("\n");
}
int count(string a, string b)
{
int i,c[26]={0},c1[26]={};
for(i=0;i<a.length();i++)
{
if(97<=a[i]&&a[i]<=123)
c[a[i]-97]++;
}
for(i=0;i<b.length();i++)
{
if(97<=b[i]&&b[i]<=123)
c1[b[i]-97]++;
}
int s=0;
for(i=0;i<26;i++)
{
s=s+abs(c[i]+c1[i]-(c[i]-c1[i]));
}
return (s);
}
This is much easier and better solution
for (std::vector<char>::iterator i = s1.begin(); i != s1.end(); ++i)
{
if (std::find(s2.begin(), s2.end(), *i) != s2.end())
{
dest.push_back(*i);
}
}
taken from here
C implementation to run in O(n) time and constant space.
#define ALPHABETS_COUNT 26
int commonChars(char *s1, char *s2)
{
int c_count = 0, i;
int arr1[ALPHABETS_COUNT] = {0}, arr2[ALPHABETS_COUNT] = {0};
/* Compute the number of occurances of each character */
while (*s1) arr1[*s1++-'a'] += 1;
while (*s2) arr2[*s2++-'a'] += 1;
/* Increment count based on match found */
for(i=0; i<ALPHABETS_COUNT; i++) {
if(arr1[i] == arr2[i]) c_count += arr1[i];
else if(arr1[i]>arr2[i] && arr2[i] != 0) c_count += arr2[i];
else if(arr2[i]>arr1[i] && arr1[i] != 0) c_count += arr1[i];
}
return c_count;
}
First, your code does not run in O(n^2), it runs in O(nm), where n and m are the length of each string.
You can do it in O(n+m), but not better, since you have to go through each string, at least once, to see if a character is in both.
An example in C++, assuming:
ASCII characters
All characters included (letters, numbers, special, spaces, etc...)
Case sensitive
std::vector<char> strIntersect(std::string const&s1, std::string const&s2){
std::vector<bool> presents(256, false); //Assuming ASCII
std::vector<char> intersection;
for (auto c : s1) {
presents[c] = true;
}
for (auto c : s2) {
if (presents[c]){
intersection.push_back(c);
presents[c] = false;
}
}
return intersection;
}
int main() {
std::vector<char> result;
std::string s1 = "El perro de San Roque no tiene rabo, porque Ramon Rodriguez se lo ha cortado";
std::string s2 = "Saint Roque's dog has no tail, because Ramon Rodriguez chopped it off";
//Expected: "S a i n t R o q u e s d g h l , b c m r z p"
result = strIntersect(s1, s2);
for (auto c : result) {
std::cout << c << " ";
}
std::cout << std::endl;
return 0;
}
Their is a more better version in c++ :
C++ bitset and its application
A bitset is an array of bool but each Boolean value is not stored separately instead bitset optimizes the space such that each bool takes 1 bit space only, so space taken by bitset bs is less than that of bool bs[N] and vector bs(N). However, a limitation of bitset is, N must be known at compile time, i.e., a constant (this limitation is not there with vector and dynamic array)
As bitset stores the same information in compressed manner the operation on bitset are faster than that of array and vector. We can access each bit of bitset individually with help of array indexing operator [] that is bs[3] shows bit at index 3 of bitset bs just like a simple array. Remember bitset starts its indexing backward that is for 10110, 0 are at 0th and 3rd indices whereas 1 are at 1st 2nd and 4th indices.
We can construct a bitset using integer number as well as binary string via constructors which is shown in below code. The size of bitset is fixed at compile time that is, it can’t be changed at runtime.
For more information about bitset visit the site : https://www.geeksforgeeks.org/c-bitset-and-its-application
The code is as follows :
// considering the strings to be of lower case.
int main()
{
string s1,s2;
cin>>s1>>s2;
//Declaration for bitset type variables
bitset<26> b_s1,b_s2;
// setting the bits in b_s1 for the encountered characters of string s1
for(auto& i : s1)
{
if(!b_s1[i-'a'])
b_s1[i-'a'] = 1;
}
// setting the bits in b_s2 for the encountered characters of string s2
for(auto& i : s2)
{
if(!b_s2[i-'a'])
b_s2[i-'a'] = 1;
}
// counting the number of set bits by the "Logical AND" operation
// between b_s1 and b_s2
cout<<(b_s1&b_s2).count();
}
No need to initialize and keep an array of 26 elements (numbers for each letter in alphabet). Just fo the following:
Using HashMap store letter as a key and integer got the count as a value.
Create a Set of characters.
Iterate through each string characters, add to the Set from step 2. If add() method returned false, (means that same character already exists in the Set), then add the character to the map and increment the value.
These steps are written considering Java programming language.
Python Code:
>>>s1='abbc'
>>>s2='abde'
>>>p=list(set(s1).intersection(set(s2)))
>>print(p)
['a','b']
Hope this helps you, Happy Coding!
can be easily done using the concept of "catching" which is a sub-algorithm of hashing.

How to call a function within a function?

I am trying to determine if my code is a palindrome so I created a reverse function and then a palindrome function. I am trying to assign the reversed Character array into the new function but I can't seem to get it to compile.... any tips?
Here is my palindrome function
bool Palindrome(char Characters[], unsigned long length)
{
char tempstring[62];
tempstring[62] == reverse(Characters);
for(int i=0; i <= length; i++){
if(Characters[i] == tempstring[i])
return false;
else
return true;
}
}
Here is my reverse function
void reverse(char Characters[], unsigned long length)
{
char temp;
for(int i=0; i<length/2; i++){
temp = Characters[i];
Characters[i]=Characters[length-i-1];
Characters[length-i-1]=temp;
}
}
First things first, you have a typo; == is a compare equality, =. You ought to have written
tempstring[62] = reverse(Characters);
But this will still not work. For starters, reverse is a void function and so therefore it does not return a value.
The quickest fix will be to replace that line with
reverse(Characters, length);
(Note that I'm also passing the length parameter as required).
One final thing: if you have organised your file so that reverse appears after Palindrome, then you need to forward declare reverse using this statement:
void reverse(char Characters[], unsigned long length);
That fixes the compilation errors. I defer to you to check the runtime behaviour.
You are making this quite complicated.
Just find the end of the string (strlen). Read from both ends a character at a time and if they do not match then it is not a palindrome. If the indexes become the same or they cross then you are done. It is indeed a palindrome.
I.e
bool Palindrome(char *s) {
int left = 0, right = strlen(s) - 1;
while (left < right) {
if (s[left] != s[right] return false;
++left;
--right;
}
return true;
}
EDIT
Similar vain to construct the reverse
char *Reverse(char *s)
{
char *rev = new char[strlen(s) + 1];
int left = 0, right = strlen(s) - 1;
while (right > -1) {
rev[left] = s[right];
right--;
left++;
}
rev[left] = 0;
// Remember to use delete[]
return rev;
}
EDIT 2
Or
void Reverse(char[] s, int len) {
int left = 0; right = len;
while (right > -1) {
char t = s[left];
s[left] = s[right];
s[right] = t;
left++; right--;
}
}
Then make a copy of the string, reverse it and compare it.
Your error is the line tempstring[62] == reverse(Characters);. You don't need the double = sign. In the future, it would be helpful to post the error messages you get when compiling.
bool Palindrome(char Characters[], unsigned long length)
{
char tempstring[62];
tempstring[62] = reverse(Characters);
for(int i=0; i <= length; i++){
if(Characters[i] == tempstring[i])
return false;
else
return true;
}
}
Your error is here:
tempstring[62] == reverse(Characters);
You've wrote == means, a condition that returns true or false (for example: if (5 == 7) -> false)
But what you've actually wanted to do was tempstring[62] = reverse(Characters);
One = means equal (int a = 3)
Two == means to check a condition (for example if (a == b) (and thats why you dont write in ifs: if(a = 3) because it will assign a = 3 and allways get inside the if
First of all, your reverse function returns nothing, so attempting to assign its return value to anything is not going to work:
tempstring[62] == reverse(Characters); // won't work as it is attempting to compare a void
tempstring[62] = reverse(Characters); // won't work as it is attempting to assign a void
From a more fundamental level, testing for a palindrome is much less complex than you are making it:
bool Palindrome(char Characters[], unsigned long length)
{
bool result = true;
for(int i=0; i < length / 2; i++)
{
if (Characters[i] != Characters[length - i - 1])
{
result = false;
break;
}
}
return result;
}