what is the difference between these two loops? I was working on a few competitive programming challenges, everytime I was using the first loop variant I was failing and when i changed it to the second kind of loop it passes all the tests:
Loop variant 1:
for(int j=0; j<str1.length() ; j++) {
char ch = str1[j]
int diff = ch-'a';
arr1[diff]++;
}
Loop variant 2:
for(int i =0; i<str1.length() ;i++) {
arr1[str1[i]-'a']++;
}
I understand that this is a silly question but please be patient, I just want to be clear about why the first one is not working.
Example: Find the minimum number of character deletions required for two given strings to be anagrams
Input:
cde
abc
Output:
4
Incorrect Code
void minDeletions(string str1, string str2) {
if(str1 == str2){
cout << 0 << endl;
return;
}
int arr1[26] = {0};
int diff,diff1;
for(int i =0; i<str1.length() ;i++) {
char ch = str1[i];
diff = ch-'a';
arr1[diff]++;
}
int arr2[26] = {0};
for(int j=0; j<str2.length() ; j++) {
char ch = str2[j];
diff1 = ch-'a';
arr2[diff]++;
}
int count = 0;
for(int k=0; k<26 ; k++){
if(arr1[k]!=arr2[k]){
count += abs(arr1[k]-arr2[k]);
}
}
cout << count << endl;
}
int main() {
string str1,str2;
cin >> str1;
cin >> str2;
minDeletions(str1,str2);
return 0;
}
Example of test case that fails
Input:
fcrxzwscanmligyxyvym
jxwtrhvujlmrpdoqbisbwhmgpmeoke
Output:
30
Cant this be it? Compared to the second loop variant, that works fine, there is no explicit int diff here that is a source of confusion (see below):
int arr1[26] = {0};
int diff, diff1;
for(int i = 0; i < str1.length() ; i++){
char ch = str1[i];
diff = ch - 'a';
// ^^^^
arr1[diff]++;
// ^^^^
}
int arr2[26] = {0};
for(int j = 0; j < str2.length() ; j++){
char ch = str2[j];
diff1 = ch - 'a';
// ^^^^^
arr2[diff]++;
// ^^^^
}
P.S. Look closely, both loops use the same index! I.e. it's not updated in the second loop after it gets a value in the first loop.
Related
I don't know how to use the find() function to check if a string contains a substring, then the program should print out all Words, and "Contains" if Sentence contains at least one of them. Can anyone help me out? My usage of find() sets A always to true. Thanks for help
#include <iostream>
#include <string>
using namespace std;
string Words, Sentence, buf;
int i, n, j = 0;
string arr[20];
bool A;
int main() {
cout << "Words separated by slashes";
cin >> Words;
cout << "Sentence";
cin >> Sentence;
for (i = 0; i <= Words.length(); i++)
{
if (Words[i] != '/')
{
buf = buf + Words[i];
}
else
{
arr[n] = buf;
n = n + 1;
buf = "";
}
}
for (j = 0; j <= n; j++)
{
cout << arr[j] << "\n";
if (Sentence.find(arr[j]) != string::npos)
{
A = true;
}
}
if (A == true)
{
cout << "Contains.";
}
else
{
enter code herecout << "Does not contain.";
}
}
There are a few bugs and issues in this code I think, but the biggest is the for loops all go too far by one.
for (i = 0; i <= Words.length(); i++)
and
for (j = 0; j <= n; j++)
should be
for (i = 0; i < Words.length(); i++)
and
for (j = 0; j < n; j++)
The valid indexes for a string, vector or array are zero upto but not including the size of the string, vector or array.
This mistake causes the bug that you see. Suppose you have two words in arr, e.g. arr = { "stack", "overflow", "", "", ... } . Because you go around the for loop one too many times you end up searching for arr[2] which equals "". This search always succeeds because every string contains the empty string. And so you always set A to true.
It's my first question in stack overflow so if there is some mistakes sorry about that. I'm trying to fill a 2d char array and then access each letter. I complied my code, there is no error but when I try to run it doesn't work. Here it's my code.
#include<iostream>
#include<string>
#include<stdlib.h>
using namespace std;
int main() {
char ch[] = "Welcome text in a separate line.";
char strWords[5][7];
int counter = 0;
int a = 0;
for (int i = 0; i < sizeof(ch); i++) {
if (ch[i] == ' ') {
strWords[counter][a] = '\0';
counter++;
a = 0;
}
else
{
strWords[counter][a] += ch[i];
a++;
}
}
for (int i = 0; i <= 5; i++) {
for (int a = 0; a <= 7; a++) {
cout << strWords[i][a] << " ";
}
}
return 0;
}
A few things wrong with your code
int main() {
char ch[] = "Welcome text in a separate line.";
// char strWords[5][7]; <<<=== i would change to be larger that you need, just in case
char strWords[20][20];
int counter = 0;
int a = 0;
for (int i = 0; i < strlen(ch); i++) { // sizeof is wrong, you need strlen
if (ch[i] == ' ') {
strWords[counter][a] = '\0';
counter++;
a = 0;
}
else
{
//strWords[counter][a] += ch[i];
strWords[counter][a] = ch[i]; // you do not need to try to concatenate, you are already walking down the buffer with 'a'
a++;
}
}
for (int i = 0; i < counter; i++) { // use 'counter' as it has the number of lines
// since you 0 terminated the string you do not need to walk character by character
cout << strWords[i] << " ";
}
return 0;
}
You are also not detecting and terminating the last word (since there is no space after it). I will leave that to you. The code I show does not print the word 'line.'
You should really have tests to make sure you do not overflow the length or number of words.
Plus you should ideally use std::string and std::vector
Note - if, for experimentation, you do want to walk through char by char to output the strings you should look for the terminating '0' character and exit the inner loop
so I wrote this code to reverse one of the names based on the user option the idea is to use another function to reverse and to use pointers but after trying all I could think of my code return the same name not changed the best I could do was changing the first letter of the name to a weird sign.
#include <iostream>
using namespace std;
void reverse(char* A) {
int count = 0;
char temp[10];
for (int i = 0; A[i] != NULL; i++)
count++;
for (int i = 0; A[i] != NULL; i++) {
temp[count]=A[i];
count--;
}
for (int i = 0; A[i] != NULL; i++) {
A[i] = temp[i];
}
}
int main(){
int x= 0;
int index;
char Name_list[5][10];
cout << "please enter the names of the student " << endl;
for (int i = 0; i < 5; i++) {
cin >> Name_list[i];
for (int j = 0; Name_list[i][j] != NULL; j++) {
x++;
}
while (x > 10)
{
x = 0;
cout << "you have entered more then the allowed number of characters per name enter another name " << endl;
cin >> Name_list[i];
for (int j = 0; Name_list[i][j] != NULL; j++) {
x++;
}
}
x = 0;
}
for (int i = 0; i < 5; i++) {
cout << Name_list[i] << endl;
}
cout << "please enter the index of the name you want to reverse" << endl;
cin >> index;
while (index>4||index <0)
{
cout << "you entered incorrect index please enter a number from 0 to 4 " << endl;
}
reverse(Name_list[index]);
for (int i = 0; i < 5; i++) {
cout << Name_list[i] << endl;
}
system("pause");
}
For starters such a function should return a pointer to the result string. That is it should be declared like
char * reverse( char *s );
Note: do not use variable names consisting from upper case letters.
The type int can be not large enough to store length of a string. Instead use the type size_t.
char * reverse( char *s )
{
size_t count = 0;
//...
It is totally unclear why there is present an array with the number of elements equal to the magic number 10
char temp[10];
To reverse a string there is no need to declare an auxiliary array. Such an approach is principally wrong.
In this for loop
for (int i = 0; A[i] != NULL; i++)
there is compared an object of the type char with the pointer NULL. The compiler should issue a message for such a wrong comparison. It seems you mean
for (int i = 0; A[i] != '\0'; i++)
In any case the introduced variable i in this first for loop is redundant because you already has the variable count.
As you have the array temp with the fixed size equal to 10 then the both loops after the first loop can invoke undefined behavior even if the length of the source string is equal exactly to 10.
And the result string is not zero terminated.
The function can look the following way.
char * reverse( char *s )
{
size_t count = 0;
while ( s[count] ) ++count;
for ( size_t i = 0; i < count / 2; i++ )
{
char c = s[i];
s[i] = s[count - i - 1];
s[count - i - 1] = c;
}
return s;
}
Or using standard functions you could write the function reverse the following way
#include <utility>
#include <cstring>
//...
char * reverse( char *s )
{
for ( size_t i = 0, n = std::strlen( s ); i < n / 2; i++ )
{
std::swap( s[i], s[n-i-1] );
}
return s;
}
Pay attention to that there is the standard algorithm std::reverse. Using it you could reverse a string the following way
std::reverse( s, s + std::strlen( s ) );
for (int i = 0; A[i] != NULL; i++) {
temp[count]=A[i];
count--;
}
If i goes up from 0 to 5, count goes down from 6 to 1.
Ok, a few things.
If you want do some string manipulation, look into the stdlib. Unless you are doing this for class.
Your writing everything to the end of the temp. buffer
You need to add an extra character at the end of the strings for the null byte (I think this implementation may allow for a seg. fault)
I am trying to learn some of this beautiful language but I've got stuck on this. Problem is: Why does the last count shows only Witaj PJC not Witaj Cpp PJC? As you see function app has to append transformed 2nd word to 1st one.
Thanks for any help.
If you could give me any good tutorial about pointers I would appreciate that. Thanks!
#include <iostream>
#include <string.h>
using namespace std;
void app(char *str2, char *str1){
for(int i =0; i < strlen(str2); i++){
*(str2++);
}
for(int i =0; i < strlen(str1); i++){
*(str1++);
}
for(int i =0; i < strlen(str1); i++){
*(str2)=*(str1);
*(str2)++;
*(str1)--;
}
}
int main()
{
char *str1 = "ppC ";
char str2[20] = "Witaj";
cout << str2 << endl; // Witaj
app(str2, str1);
cout << str2 << endl; // Witaj Cpp shows WitCpp
app(str2, "CJP ");
cout << str2 << endl; // Witaj Cpp PJC shows WitPJ
return 0;
}
Your problem is this sort of loops:
for(int i =0; i < strlen(str2); i++){
*(str2++);
}
You can't move your pointer with str2++ and expect that strlen(str2) still returning the lenght of the original one.
For loop variables, in each iteration:
i str2 strlen(str2) condition
Iteration 1 0 Witaj 5 0 < 5 Ok
Iteration 2 1 itaj 4 1 < 4 Ok
Iteration 3 2 taj 3 2 < 3 Ok
Iteration 4 3 aj 2 3 < 2 Exit at 3rd character!!
Thus.. you only "move" your pointer 3 bytes.
Change your app function for that one:
void app(char *str2, char *str1){
int nstr2 = strlen(str2);
int nstr1 = strlen(str1);
for(int i =0; i < nstr2; i++){
*(str2++);
}
for(int i =0; i < nstr1; i++){
*(str1++);
}
for(int i =0; i < nstr1; i++){
*(str2++)=*(--str1);
}
}
Anyway... this program is only for academic porpouses or you are thinking use it professionally?
And for some functioning code for just string appending, i scribbled this...
Note that you should make a const call instead, and if you want to reverse one of the strings (a bit unclear from your question) it should be done prior to appending.
Example of string append (rather unsafely and rudimentary) using a new allocation:
char* app(char *str2, char *str1){
char* appendedstring = (char*)malloc(sizeof(char)*20);
char *temp = str1;
char *temp2 = str2;
int stringlen1 = strlen(str1);
int stringlen2 = strlen(str2);
//Copy string 1
for (int i = 0; i < stringlen2; i++){
appendedstring[i] = *temp2;
temp2++;
}
//Append string 2
for (int i = 0; i < stringlen1 + 1; i++){
appendedstring[stringlen2 + i] = *temp;
temp++;
}
return appendedstring;
}
int main()
{
int t;
char *str1 = "ppC ";
char str2[20] = "Witaj";
cout << str1 << endl;
cout << str2 << endl; // Witaj
char* newstr = app(str2, str1);
cout << newstr << endl; // Witaj Cpp shows WitCpp
char* newstr2 = app(str2, "CJP ");
cout << newstr2 << endl; // Witaj Cpp PJC shows WitPJ
return 0;
}
I have a task that is difficult for me to handle. The task is: Create recursive function that can be generate a string of length N (N <= 100), formed by the letters 'A', 'B' and 'C' and does not containing two identical adjacent substring. For example: enter for N = 6 and the program should generate such a string in which no one else to repeated substrings: ABACAB. Wrong strings are: AABACA - because 'A' is to 'A'; ABCBCA - as 'BC' is to 'BC' and ABCABC is also wrong because 'ABC' is to 'ABC'.
I made a version of the program but an iterative way, here is the code:
#include <iostream>
#include <ctime>
using namespace std;
const char letters[] = "ABC";
char generate_rand()
{
return letters[rand() % 3];
}
int check(char *s, int pos)
{
for (int i = 1; i <= (pos + 1)/2; i++)
{
int flag = 1;
for (int j = 0; j < i; j++)
if (s[pos-j] != s[pos-i-j])
{
flag = 0;
break;
}
if (flag)
return 1;
}
return 0;
}
int main()
{
char s[100];
int n;
cout << "enter n: ";
cin >> n;
srand(time(NULL));
for (int i = 0; i < n; i++)
{
do
{
s[i] = generate_rand();
} while (check(s, i));
cout << s[i] << " ";
}
cout << " ok" << endl;
system("pause");
return 0;
}
I think the entrance of the recursive function may need to be the number of characters in the string, which will seek to repeat with an adjacent string and each time increased by 1, but not more than half the length of the original string, but do not know how to do it.
So lets start with a simple recursive function which prints 10 letters but doesn't check anything:
void addLetter(char* buf, int max_length)
{
int len = strlen(buf);
buf[len] = generate_rand();
if (strlen(buf) < max_length)
addLetter(buf);
}
int main()
{
srand(time(NULL)); //I forgot srand!
int max_length = 10; //ask user to input max_length, like you had earlier
char buf[100];
memset(buf,0,sizeof(buf));
addLetter(buf, max_length);
printf("\n%s\n", buf);
return 0;
}
Now lets change the recursive function, get it to check just 1 letter:
void addLetter(char* buf, int max_length)
{
int len = strlen(buf);
buf[len] = generate_rand();
if (len > 0)
{
if (buf[len] == buf[len-1])
buf[len] = 0;
}
if (strlen(buf) < max_length)
addLetter(buf);
}
Next step, check 2 letters with previous ones etc. You should be able to take it from here.