Given 2 strings, design a function that can check whether they are rotations to each other without making any changes on them ? The return value is boolean.
e.g ABCD, ABDC, they are not rotations. return false
ABCD, CDAB or DABC are rotations. return true.
My solution:
shift one of them to right or left one position and then compare them at each iteration.
If they are not equal at all iterations, return false. Otherwise, return true.
It is O(n). Are there other more efficient solutions ?
What if the contents of them cannot be changed ?
thanks
Concatenate the given string with the given string.
Search for the target string in the concatenated string.
Example:
Given = CDAB
After step 1, Concatenated = CDABCDAB
After step 2, Success CDABCDAB
^^^^
Rather than shifting one of them, it might be more efficient to use two index variables. Start one at 0 each time and the other at each of the possible positions (0 to N-1) and increment it mod N.
If you can't modify the strings, just take the first character of string1 and compare it to each character of string2. When you get a match, compare the second char of string1 to the next char of string2, and so on.
Pseudocode:
len = strlen(string1);
len2 = strlen(string2);
if( len != len2 )
printf("Nope.");
for( int i2=0; i2 < len; i2++ ) {
for( int i1=0; i1<len; i1++ ) {
if( string1[i1] != string2[(i2+i1)%len] )
break;
}
if( i1 == len ) {
print("Yup.");
break;
}
}
A simple one would be:
(s1+s1).find(s2) != string::npos && s1.size() == s2.size();
#include <iostream>
#include <cstring>
#include<string>
using namespace std;
void CompareString(string, string, int);
int ComputeStringLength(string str);
int main()
{
string str = ""; string str1 = ""; int len = 0, len1 = 0;
cout << "\nenter string ";
cin >> str;
cout << "\nenter string 2 to compare:- ";
cin >> str1;
len = ComputeStringLength(str);
len1 = ComputeStringLength(str1);
if (len == len1)
CompareString(str, str1, len);
else
cout << "rotation not possible";
getchar();
return 0;
}
int ComputeStringLength(string str)
{
int len = 0;
for (int i = 0; str[i] != '\0'; i++)
{
len++;
}
return len;
}
void CompareString(string str, string str1, int n)
{
int index = 0, flag = 0, curr_index = 0, count1 = 0, flagj = 0;
for (int i = 0; i<n; i++)
{
for (int j = flagj; j<n; j++)
{
if (str[i] == str1[j])
{
index = j;
flagj =j;
count1++;
flag++;
if (flag == 1)
{
curr_index = index;
}
break;
}
}
}
int temp = count1;
if (count1 != n)
{
if (curr_index>=0)
{
int k = 0;
for (int i = n - 1; i>n - curr_index - 1; i--)
{
if (str[i] == str1[k])
{
temp++;
k++;
}
}
}
if (temp == n)
{
cout << "\n\nstring is same after rotation";
}
else
{
cout << "\n\nstring is not same after rotation";
}
}
else
{
cout << "\n\nstring is same after rotation";
}
}
https://dsconceptuals.blogspot.in/2016/10/a-program-to-check-if-strings-are.html
Related
I cant get the char search to work. The substring function is working but the char search won't provide the right location of the char it is looking for
#include<iostream>
#include <string>
using namespace std;
int charsearch(string searchInto, char ch, int start = 0)
{
int x = 0;
long n = searchInto.length();
for (int i = 1; i < n; i++)
{
cout << ch;
if (searchInto[i] == ch)
{
i = x;
}
else
i++;
}
cout<< x;
return x;
}
int substr(string src, string tosearch, int start = 0)
{
string searchInto = src;
long n = searchInto.size();
long m = tosearch.size();
int ans = -1;
for (int i = start; i < n; ++i)
{
int p = i;
int q = 0;
bool escape = false;
while (p < n && q < m) {
if (searchInto[p] == tosearch[q]) {
if (tosearch[q] == '/' && !escape) {
++q;
} else {
++p; ++q;
}
escape = false;
} else if (!escape && tosearch[q] == '*') {
++q;
while (q < m && p < n && searchInto[p] != tosearch[q]) ++p;
escape = false;
} else if (!escape && tosearch[q] == '?') {
++p; ++q;
escape = false;
} else if (tosearch[q] == '/' && !escape) {
escape = true;
++q;
} else break;
}
if (q == m) {
return i;
}
if (q == m - 1 && tosearch[q] == '*') {
if (q > 0 && tosearch[q - 1] == '/') continue;
else return i;
}
}
return ans;
}
int main()
{
string searchInto, tosearch;
cout<< "Enter string:";
getline(cin, searchInto);
cout << "Looking for :";
getline(cin, tosearch);
if (tosearch.length() < 2)
{
char ch = tosearch.at(0);
cout << "Found at: " <<charsearch(searchInto, ch) << endl;
cout << "Used Char" << endl;
}
else
cout << "Found at: " <<substr(searchInto, tosearch) << endl;
return 0;
}
To find a character in a string, you have two interfaces.
std::string::find will return the position of a character you find:
auto pos = yourStr.find('h');
char myChar = yourStr[pos];
If the character does not exist, then std::string::npos will be returned as the std::size_t returned for position.
stl algorithm std::find, in header algorithm returns an iterator:
auto it = std::find(yourStr.begin(), yourStr.end(), 'h');
char myChar = *it;
If the character does not exist, then it == yourStr.end().
There are some silly mistakes in your CharSearch method. First of all, You have to break the loop when you got your target character. And most importantly you are not assigning x when you are finding the target. Furthermore, there is extra increment of value i inside the loop. I have modified the function. Please check it below
int charsearch(string searchInto, char ch, int start = 0) {
int x = -1;
long n = searchInto.length();
for (int i = start; i < n; i++)
{
cout << ch;
if (searchInto[i] == ch)
{
x = i; // previously written as i = x which is wrong
break; // loop should break when you find the target
}
}
cout<< x;
return x;
}
Please note that,you can either also use find method of string or std::find of algorithm to search in string.
You need to make changes as per this code
int charsearch(string searchInto, char ch, int start = 0)
{
int x = -1; // : change, if return -1, means not found
long n = searchInto.length();
for (int i = start; i < n; i++) // : change
{
cout << ch;
if (searchInto[i] == ch)
{
x = i; // : change
break; // : change
}
}
cout<< x;
return x;
}
Note : This function will return 1st match.
Hello I'm kind of new to coding and I am writing a code that deletes any duplicate characters on a string. Let's say the input string was ABBA, then the output should be "empty" since all of the duplicates were deleted. Another example would be if the input string was KKCCD, then the output should be "D" as the code would remove the K and C duplicates. The problem with my code is that when I type KKCCD, it returns KCD and it doesnt delete the duplicates entirely. Also if I we're to type "AA" the result comes back as "A" instead of "Empty". Any help in fixing my code will be much apreciated. Thanks.
include
#include <string.h>
using namespace std;
string deduplicate(string input){
int i;
int x;
int len= input.length();
string outputStr;
string strEmpty = "Empty";
if (input.length() == 1)
{return input;}
for(i = 0; i<len;i++){
for(x = i+1; x<len; x++){
if(input[i] == input[x]){
input.erase(x,1);
x--;}
}
len = input.length();
}
return outputStr = input;
if (input.length() == 0)
{return strEmpty;}
return outputStr = input;
}
int main()
{
string input;
cout << "Enter a string: " << endl;
cin >> input;
cout << deduplicate(input);
return 0;
}
Change your duplicate function to this
string deduplicate(string input){
int i;
int x;
int len= input.length();
string outputStr;
string strEmpty = "Empty";
if (input.length() == 1)
{return input;}
for(i = 0; i<len;i++){
for(x = i+1; x<input.length(); x++){ // This line
if(input[i] == input[x]){
input.erase(x,1);
input.erase(i,1); // and this line
x--;
}
}
len = input.length();
}
return outputStr = input;
if (input.length() == 0)
{return strEmpty;}
return outputStr = input;
}
You did delete the duplicate character but not original, so the second erase statement does it.
You are deleting the duplicate you find, but you never delete the original character. The most efficient way to achieve your goal is to use STL algorithms. You might want to check out this link: Remove all duplicate characters from a string (STL)
Generally speaking I do not think if that is a good idea to delete characters from a string you are iterating. It would be much better and cleaner to construct your output instead:
#include <string>
#include <iostream>
using namespace std;
string deduplicate(string input) {
string outputStr;
if (input.length() == 1) {
return input;
}
for ( int i = 0; i < input.length(); i++ ) {
// try to find character at the rest of the string
if ( input.find( input[i], i+1 ) == string::npos ) {
// try to find character in the front
if ( ( i > 0 ) && ( input.rfind( input[i], i-1 ) == string::npos ) ) {
outputStr += input[i];
}
}
}
return outputStr;
}
int main()
{
string input;
cout << "Enter a string: " << endl;
cin >> input;
cout << deduplicate(input) << endl;
return 0;
}
Here is a "brute force" implementation.
string deduplicate(string str)
{
size_t l = str.length();
bool bFound = false;
char character = 0;
for (int i = 0; i < l; i++)
{
character = str[i];
while (true)
{
size_t next = str.rfind(character);
if (next != std::string::npos)
{
if (bFound || (!bFound && next != i))
{
str.erase(next, 1);
bFound = true;
l--;
}
}
if (next == i)
{
if (bFound == true)
{
i--;
}
bFound = false;
break;
}
}
}
return str;
}
long time lurker, first time poster. I have been working on this problem for the last six hours hours.
Problem:
Implement the following functions. Each function deals with null terminated C-Style strings. You can assume that any char array passed into the functions will contain null terminated data. Place all of the functions in a single file and then create a main() function that tests the functions thoroughly.
Note: You may not use any c-string functions other than strlen().
I am having trouble with the fourth function.
The desired behavior is: This function returns the index in string s where the substring can first be found. For example if s is "Skyscraper" and substring is "ysc" the function would return 2. It should return -1 if the substring does not appear in the string.
prototype:
int findSubstring(char *str, char substring[])
Here's my two starts for function definitions, I'm not really sure if either is going in the right direction, I'm having a lot of trouble keeping the loop iterations in my head, any help would be TREMENDOUSLY appreciated.
int findSubstring(char *str, char substring[]){
int subS = -1, index1 = 0, index2 = 0;
int length1 = (strlen(str) - 1);
int length2 = (strlen(substring) - 1);
if(length1 > length2){
for(int i = 0; i <= length2; i++){
for(int j = 0; j <= length1; j++){
if(*(substring + i) == *(str + j) && *(substring +i) != '\0' ){
i++;
if(index1 == 0){
index1 = i;
}
}
if( *(substring + i) == '\0'){
subS = i + 2;
}
}
}
}
if (length1 < length2){
cout << "Invalid, substring exceeds size of string!" << endl;
}
return subS;
}
int findSubstring(char *str, char substring[]){
int index = -1;
int lengthStr = (strlen(str) - 1);
int lengthSub = (strlen(substring) - 1);
if (lengthStr < lengthSub){
cout << "Invalid input, substring exceeds size of string!" << endl;
}
if( lengthSub == 0){
cout << "";
}
if (lengthStr > lengthSub){
for(int i = 0; i <= lengthSub; i++){
for(int j = 0; j <= lengthStr; j++){
}
return index;
}
//You can replace my str.size() and subString.size() by the size of each c-string.
int stringPointerOperation( string str, string subString )
{
int pos=0;
bool notFound;
for(int i = 0; i < str.size() ; i++)
{
notFound= false;
if(str[i] == subString[0])
{
pos=i;
for(int k = 0 ; k < subString.size() && k < str.size() ; k++,i++)
{
if(subString[k] != str[i] )
{
notFound=true;
break;
}
}
}
}
if(notFound)
return -1;
else
return pos;
}
You are using the wrong strategy for finding a sub-string in a string. The outer for loop needs to iterate over the main string and the inner for loop needs to iterate over the sub-string.
Say you are looking for "de" in "abcdef". The strategy that I find easier to understand and implement is:
Can I find "de" starting from 0 of "abcdef". No, I can't.
Can I find "de" starting from 1 of "abcdef". No, I can't.
Can I find "de" starting from 2 of "abcdef". No, I can't.
Can I find "de" starting from 3 of "abcdef". Yes, I can. Return 3.
Here's a version that works for me.
int findSubstring(char *str, char substring[]){
int i;
int j;
int length1 = strlen(str);
int length2 = strlen(substring);
if(length1 < length2){
std::cout << "Invalid, substring exceeds size of string!" << std::endl;
return -1;
}
for(i = 0; i < length1; i++){
for(j = 0; j < length2; j++){
// The index to use access the element of str
// needs to be offset by i.
if( str[i+j] != substring[j] )
{
break;
}
}
if ( j == length2 )
{
return i;
}
}
return -1;
}
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.
This was the interview question:
How to convert Dogs like cats to cats like Dogs ?
My code shows: cats like cats. Where am I making the mistakes?
#include <iostream>
using namespace std;
int main()
{
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++)
{
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--)
{
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--)
{
str[words] = reverse[m];
words++;
}
}
}
cout << str;
return 0;
}
I know you can do this using pointers, stack, vectors... but interviewer was not interested in that!
This is a fixed version of your sample code:
Your principal problem is that every time you found and ' ' or '\0' you copy the bytes of the reverse string from the beginning to that point. Example in loop 5 you copy from index 0-5 (stac) from reverse to str in reverse order, but in in loop 10 you copy from index 0-10 (stac ekil) from reverse to str in reverse order, until here you have already the printed result string ('cats like cats'), and the same in loop 15 all of this incrementing the index of str, in the last loop you are written pass the end of the valid memory of str (and because of that not printed as output).
You need to keep track when end the last word reversed to reverse only the actual word, and not the string from the beginning to the actual index.
You don't want to count the special character (' ' and '\0') in the reversing of the words, you would end with cats like\0dogs
Modified sample code provided:
#include <iostream>
using namespace std;
int main() {
char sentence[] = ("dogs like cats");
cout << sentence << endl;
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
char reverse[len];
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
cout << reverse << endl;
int words = 0;
char str[len];
// change here added last_l to track the end of the last word reversed, moved
// the check of the end condition to the end of loop body for handling the \0
// case
for (int l = 0, last_l = 0; ; l++) {
if (reverse[l] == ' ' || reverse[l] == '\0')
{
for (int m = l - 1; m >= last_l; m--) { // change here, using last_t to
str[words] = reverse[m]; // only reverse the last word
words++; // without the split character
}
last_l = l + 1; // update the end of the last
// word reversed
str[words] = reverse[l]; // copy the split character
words++;
}
if (reverse[l] == '\0') // break the loop
break;
}
cout << str << endl;
return 0;
}
Some code, written with the restriction of using the most simple features of the language.
#include <iostream>
// reverse any block of text.
void reverse(char* left, char* right) {
while (left < right) {
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main() {
char sentence[] = "dogs like cats";
std::cout << sentence << std::endl;
// The same length calculation as sample code.
int len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
std::cout << len << std::endl;
// reverse all the text (ex: 'stac ekil sgod')
reverse(sentence, sentence + len - 1);
// reverse word by word.
char* end = sentence;
char* begin = sentence;
while (end < sentence + len) {
if (*end != ' ')
end++;
if (end == sentence + len || *end == ' ') {
reverse(begin, end - 1);
begin = end + 1;
end = begin;
}
}
std::cout << sentence << std::endl;
return 0;
}
Dissecting your algorithm in pieces. First, you find the length of the string, not including the null char terminator. This is correct, though could be simplified.
size_t len = 0;
for (int i = 0; sentence[i] != '\0'; i++) {
len++;
}
cout << len << endl;
This could easily be written simply as:
size_t len = 0;
while (sentence[len])
++len;
Next, you reverse the entire string, but the first defect surfaces. The VLA (variable length array) you declare here, (which you don't need and shouldn't use, as it is a C++ extension and non-standard) does not account for, nor set, a terminating null-char.
char reverse[len]; // !! should be len+1
int k = 0;
for (int j = len - 1; j >= 0; j--) {
reverse[k] = sentence[j];
k++;
}
// !! Should have reverse[k] = 0; here.
cout << reverse << endl; // !! Undefined-behavior. no terminator.
This temporary buffer string is not needed at all. There is no reason you can't do this entire operation in-place. Once we calculate len correctly, you simply do something like the following to reverse the entire sequence, which retains the null char terminator in proper position:
// reverse entire sequence
int i = 0, j = len;
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
Next we move to where you try to reverse each internal word. Again, just as before, the buffer length is not correct. It should be len+1. Worse (hard to imagine), you never remember where you left off when finding the end point of a word. That location should be the next point you start checking for, and skipping, whitespace. Without retaining that you copy from current point all the way back to the beginning of the string. which essentially blasts cats over dogs.
int words = 0;
char str[len]; // !! should be len+1
for (int l = 0; reverse[l] != '\0'; l++)
{
if (reverse[l] == ' ' || reverse[l] == '\0') // not sure about this part
{
for (int m = l; m >= 0; m--) {
str[words] = reverse[m];
words++;
}
}
}
cout << str; //!! Undefined behavior. non-terminated string.
Once again, this can be done in-place without difficulty at all. One such algorithm looks like this (and notice the loop that reverses the actual word is not-coincidentally the same algorithm as reversing our entire buffer):
// walk again, reversing each word.
i = 0;
while (sentence[i])
{
// skip ws; root 'i' at beginning of word
while (sentence[i] == ' ') // or use std::isspace(sentence[i])
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (sentence[j] && sentence[j] != ' ') // or use !std::isspace(sentence[j])
++j;
// remember the last position
size_t last = j;
// same reversal algorithm we had before
while (i < j--)
{
char c = sentence[i];
sentence[i++] = sentence[j];
sentence[j] = c;
}
// start at the termination point where we last stopped
i = last;
}
Putting It All Together
Though considerably simpler to use pointers than all these index variables, the following will do what you're attempting, in place.
#include <iostream>
int main()
{
char s[] = "dogs like cats";
std::cout << s << '\n';
size_t len = 0, i, j;
while (s[len])
++len;
// reverse entire sequence
i = 0, j = len;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// walk again, reversing each word.
i = 0;
while (s[i])
{
// skip ws; root 'i' at beginning of word
while (s[i] == ' ') // or use std::isspace
++i;
// skip until ws or eos; root 'j' at one-past end of word
j = i;
while (s[j] && s[j] != ' ') // or use !std::isspace
++j;
// remember the last position
size_t last = j;
while (i < j--)
{
char c = s[i]; // or use std::swap
s[i++] = s[j];
s[j] = c;
}
// start at last-left posiion
i = last;
}
std::cout << s << '\n';
return 0;
}
Output
dogs like cats
cats like dogs
My advise would be to break up the original string into an array of words, reverse that array. Then add those words to your reversed sentence with a space in between.
Since they asked for no libraries, I assumed no std::string, no vectors, nothing at all and so I wrote it in C.. the only thing used is printf. Everything else is from scratch :l
The idea is that you reverse the array first. Then split the array by space and reverse each word.
Example: http://ideone.com/io6Bh9
Code:
#include <stdio.h>
int strlen(const char* s)
{
int l = 0;
while (*s++) ++l;
return l;
}
void reverse(char* str)
{
int i = 0, j = strlen(str) - 1;
for(; i < j; ++i, --j)
{
str[i] ^= str[j];
str[j] ^= str[i];
str[i] ^= str[j];
}
}
void nulltok(char* str, char tok, int* parts)
{
int i = 0, len = strlen(str);
*parts = 1;
for (; i < len; ++i)
{
if (str[i] == tok)
{
str[i] = '\0';
++(*parts);
}
}
}
char* reverse_sentence(char* str)
{
char* tmp = str;
reverse(str);
int i = 0, parts = 0, len = strlen(str);
nulltok(str, 0x20, &parts);
while(parts--)
{
reverse(str);
str += strlen(str) + 1;
}
for(; i < len; ++i)
if (tmp[i] == '\0')
tmp[i] = 0x20;
return tmp;
}
int main(void)
{
char str[] = "dogs like cats";
printf("%s", reverse_sentence(str));
return 0;
}
My solution
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
string str;
cout<<"enter the sentence"<<endl;
getline(cin,str);
char* pch;
pch = strtok((char*)str.c_str()," ");
string rev = "";
while(NULL != pch)
{
rev.insert(0,pch);
rev.insert(0," ");
pch = strtok(NULL," ");
}
cout<<"the reversed string is :"<<rev<<endl;
return 0;
}