How do I find if two strings is isomorphic of not? - c++

#include <iostream>
#include <string>
#include <vector>
using namespace std;
bool is_isomorphic(string input1, string input2)
{
if(input1.length()!= input2.length())
return false;
vector<int> diff_arr(26, -40);//Initialise with some random value.
for(int i = 0 ; i < input1.length(); i++){
if(diff_arr[input1[i]-'a'] == -40)
diff_arr[input1[i]-'a'] = input1[i] - input2[i];
else{
if(diff_arr[input1[i]-'a'] != input1[i] - input2[i])
return false;
}
}
return true;
}
int main() {
cout<<is_isomorphic("abcd", "aabb");
return 0;
}
My logic is that if characaters could be replaced with exact same characters in the second string then the character-wise difference has to be the same throughout.
The logic is failing in the above case.

You also need to check if two characters from input1 do not map to same character in input2.
#include <iostream>
#include <string>
#include <map>
#include <set>
using namespace std;
bool is_isomorphic(string input1, string input2)
{
if(input1.length()!= input2.length())
return false;
set<char> usedLetters;
map<char, char> transformations;
for(int i = 0 ; i < input1.length(); i++) {
auto iter = transformations.find(input1[i]);
if (iter != transformations.end()) {
if (iter->second == input2[i]) continue;
else return false;
}
if (usedLetters.count(input2[i])) return false;
usedLetters.insert(input2[i]);
transformations[input1[i]] = input2[i];
}
return true;
}
int main() {
cout<<is_isomorphic("abcd", "aabb");
return 0;
}

You need 2 arrays, one to know which character of input2 correspond to a given character of input1, and a second to check if a character of input2 is not already affected to a character of input1.
#include <iostream>
#include <string>
using namespace std;
bool is_isomorphic(const string& input1, const string& input2)
{
if (input1.length() != input2.length()) {
return false;
}
char map[256]{};
bool used[256]{};
for (size_t i = 0; i < input1.length(); i++) {
unsigned char val1 = input1[i];
if (!map[val1]) {
unsigned char val2 = input2[i];
if (used[val2]) {
return false;
}
map[val1] = input2[i];
used[val2] = true;
} else
if (map[val1] != input2[i]) {
return false;
}
}
return true;
}
int main() {
cout << is_isomorphic("abcd", "aabb") << endl;
cout << is_isomorphic("abcdb", "zerte") << endl;
return 0;
}

Related

String function optimisation?

I'm new to C++ and i just wrote a function to tell me if certain characters in a string repeat or not:
bool repeats(string s)
{
int len = s.size(), c = 0;
for(int i = 0; i < len; i++){
for(int k = 0; k < len; k++){
if(i != k && s[i] == s[k]){
c++;
}
}
}
return c;
}
...but i can't help but think it's a bit congested for what it's supposed to do. Is there any way i could write such a function in less lines?
Is there any way i could write such a function in less lines?
With std, you might do:
bool repeats(const std::string& s)
{
return std::/*unordered_*/set<char>{s.begin(), s.end()}.size() != s.size();
}
#include <algorithm>
bool repeats(std::string s){
for (auto c : s){
if(std::count(s.begin(), s.end(), c) - 1)
return true;
}
return false;
}
Assuming you are not looking for repeated substrings :
#include <iostream>
#include <string>
#include <set>
std::set<char> ignore_characters{ ' ', '\n' };
bool has_repeated_characters(const std::string& input)
{
// std::set<char> is a collection of unique characters
std::set<char> seen_characters{};
// loop over all characters in the input string
for (const auto& c : input)
{
// skip characters to ignore, like spaces
if (ignore_characters.find(c) == ignore_characters.end())
{
// check if the set contains the character, in C++20 : seen_characters.contains(c)
// and maybe you need to do something with "std::tolower()" here too
if (seen_characters.find(c) != seen_characters.end())
{
return true;
}
// add the character to the set, we've now seen it
seen_characters.insert(c);
}
}
return false;
}
void show_has_repeated_characters(const std::string& input)
{
std::cout << "'" << input << "' ";
if (has_repeated_characters(input))
{
std::cout << "has repeated characters\n";
}
else
{
std::cout << "doesn't have repeated characters\n";
}
}
int main()
{
show_has_repeated_characters("Hello world");
show_has_repeated_characters("The fast boy");
return 0;
}
std::string str;
... fill your string here...
int counts[256]={0};
for(auto s:str)
counts[(unsigned char)s]++;
for(int i=0;i<256;i++)
if(counts[i]>1) return true;
return false;
6 lines instead of 9
O(n+256) instead of O(n^2)
This is your new compact function :
#include <iostream>
#include <algorithm>
using namespace std;
int occurrences(string s, char c) {
return count(s.begin(), s.end(), c); }
int main() {
//occurrences count how many times char is repetated.
//any number other than 0 is considered true.
occurrences("Hello World!",'x')?cout<<"repeats!":cout<<"no repeats!";
//It is equal write
//
// if(occurrences("Hello World!",'x'))
// cout<<"repeats!";
// else
// cout<<"no repeats!";
//So to count the occurrences
//
// int count = occurrences("Hello World!",'x');
}

How to make sure that two strings only have certain alphabets in c++

Aim is to make sure that the user entered input for string 1 and string 2 contains only characters A,T,G or C in any order. If either string contains another other character then error should be displayed. Example:
Input contains error
Error in String #1: aacgttcOgMa
Error in String #2: ggataccaSat
This is my attempt at LCS.cpp file code:
#include "LCS.h"
#include <string>
using namespace std;
bool validate(string strX, string strY)
{
string x = strX;
string y = strY;
char searchItem = 'A';
char searchItem = 'C';
char searchItem = 'G';
char searchItem = 'T';
int numOfChar = 0;
int m = strX.length();
int n = strY.length();
for (int i = 0; i < m; i++)
{
if (x[i] == searchItem)
{
numOfChar++;
}
for (int i = 0; i < n; i++)
{
if (y[i] == searchItem)
{
numOfChar++;
}
}
}
This is my LCS.h file code:
#pragma once
#ifndef LCS_H
#define LCS_H
#include <string>
using namespace std;
bool validate(string strX, string strY);
#endif
And my driver file "Driver6.cpp" has this code:
#include "LCS.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string strX, strY;
cout << "String #1: ";
cin >> strX;
cout << "String #2: ";
cin >> strY;
//validate the input two strings
if (validate(strX, strY) == false)
{
return 0;
}
int m = strX.length();
int n = strY.length();
}
Didn't really want to do this but it seems like the best bet rather than going round the houses in the comments:
#include <string>
#include <iostream>
bool validate( const std::string & s ) {
for ( auto c : s ) {
if ( c != 'A' && c != 'T' && c != 'C' && c != 'G' ) {
return false;
}
}
return true;
}
int main() {
std::string s1 = "ATGCCCG";
std::string s2 = "ATGfooCCCG";
if ( validate( s1 ) ) {
std::cout << "s1 is valid\n";
}
else {
std::cout << "s1 is not valid\n";
}
if ( validate( s2 ) ) {
std::cout << "s2 is valid\n";
}
else {
std::cout << "s2 is not valid\n";
}
}
Another technique:
bool validate(const std::string& s)
{
const static std::string valid_letters("ATCGatcg");
for (auto c: s)
{
std::string::size_type position = valid_letters.find_first_of(c);
if (position == std::string::npos)
{
return false;
}
}
return true;
}
The above code searches a container of valid letters.

Remove only one element to make a string palindrome

I will be given string. I can remove only 1 element from it. After removing it if the new string becomes palindrome I have to print "Yes" otherwise "No".
For example, I am given a string "abdbca". Here I can remove 5th index 'c' and make it palindrome and i have to print "Yes". On the other hand if the string is something like "abcd" I can not make it palindrome by removing only one character. Hence I have to print "No".
I tried to do it but my code is not efficient enough. Can anybody please suggest me a efficient way to do it? I have to check strings of 10^5 length in less than 2.5 seconds.
the way I tried to do it is shown bellow :
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#define REP(i,n) for(int i=0;i<n;i++)
#define MAX 100010
using namespace std;
bool isPalindrome(char abc[]){
int len = strlen(abc), lem = len/2;
for(int i=0,n=len-1;i<=lem;i++,n--) if(abc[i]!=abc[n]) return false;
return true;
}
int main()
{
int tc;
char str[MAX];
scanf("%d",&tc);
while(tc--){
scanf("%s", str);
int length = strlen(str), len = length - 1, z = length % 2, res = 0, ans = 0, b=0,lem = length / 2;
for(int i = 0;i<length;i++){
int n=0, m=1;
for(int x = 0, y = len;x<i && y!=i;x++,y--){
n++;
if(str[x]!=str[y]){
m=0; ++res;
break;
}
}
if(i>lem) for(int x=n,y=len-n-1;x<y;x++,y--){
if(str[x]!=str[y]){
m=0; ++res;
break;
}
}
else for(int x=n+1,y=len-n;x<y;x++,y--){
if(str[x]!=str[y]){
m=0; ++res;
break;
}
}
if(m==1) {printf("YES\n");b++;break;}
}
//if(length <= res) printf("NO\n");
if(b==0) printf("NO\n");
}
return 0;
}
Since you you only need to remove one character, you can do so in linear time by modifying palindrome checking. The idea is that you compare characters from the beginning to characters from the end and stop at the first mismatch. If you remove one character from the mismatching pair and get a palindrome, then return true, otherwise return false. I implemented the idea in C++ below.
#include<iostream>
#include<string>
using namespace std;
bool palindromeExists(string s)
{
int i = 0;
int j = s.length()-1;
while(i < j)
{
if(s[i] != s[j]) //first mismatch
break;
i++;
j--;
}
int tempj = j-1; //remove s[j]
int tempi = i;
while(tempi < tempj)
{
if(s[tempi] != s[tempj])
break;
tempi++;
tempj--;
}
if(tempi >= tempj) //palindrome found?
return true;
tempi = i+1; //remove s[i]
tempj = j;
while(tempi < tempj)
{
if(s[tempi] != s[tempj])
return false;
tempi++;
tempj--;
}
return true;
}
int main()
{
string s = "abca";
if(palindromeExists(s))
cout << "YES" << endl;
else
cout << "NO" << endl;
return 0;
}
This should return true if the string is already a palindrome, or if it can be a palindrome after the removal of one character. I hope I didn't miss any corner cases.
You can refer complete program in c++ here. Input the string to get the index of character to be removed. String reversal is performed in palim() function. It returns -1 if string is already palindrome.
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
bool palim(string s)
{
string s2;
s2=string(s.rbegin(),s.rend());
if(s2==s)
{
return true;
}
else
{
return false;
}
}
int check(string s)
{
int x;
if(s.length()%2==0)
{
for(int i=0,j=s.length()-1;i<s.length()/2,j>=s.length()/2;i++,j--)
{
if(s[i]!=s[j])
{
string s1=s;
s1.erase(j,1);
if(palim(s1))
{
x=j;
break;
}
else
{
string s1=s;
s1.erase(i,1);
if(palim(s1))
{
x=i;
break;
}
}
}
}
}
else
{
for(int i=0,j=s.length()-1;i<s.length()/2,j>s.length()/2;i++,j--)
{
if(s[i]!=s[j])
{
string s1=s;
s1.erase(j,1);
if(palim(s1))
{
x=j;
break;
}
else
{
string s1=s;
s1.erase(i,1);
if(palim(s1))
{
x=i;
break;
}
}
}
}
}
return x;
}
int main()
{
string s;
cin>>s;
if(palim(s))
{
cout<<"-1"<<endl;
}
else
{
cout<<check(s)<<endl;
}
return 0;
}
Similar to turingcomplete, but with sub functions:
bool isPalindrome(std::string::const_iterator& start, std::string::const_iterator& end)
{
while (start < end) {
--end;
if (*start != *end) {
return false;
}
++start;
}
return true;
}
bool test(const std::string& s)
{
auto start = s.begin();
auto end = s.end();
if (isPalindrome(start, end)) {
// If we remove the middle character of a palindrome,
// We still have a palindrome.
return true;
}
// Now test if there is a palindrome
// if we skip the mismatch char from the start or from the end.
auto start2 = start;
auto end2 = end;
++start2;
--end;
return isPalindrome(start, end) || isPalindrome(start2, end2);
}
Live example

Largest Palindrome 3 digits C++

I cannot figure out why this code isn't working. It doesn't even seem to be going through my for loops and nested loops. I'm very new to programing. I have been trying to answer Euler questions for practice. Sorry if my code is awful.
#include <iostream>
#include <string>
using namespace std;
bool isPalindrome(int x) {
string str = to_string(x);
for(string::reverse_iterator rit=str.rbegin(); rit!=str.rend(); ++rit) {
string pal = to_string(*rit);
if(pal == str) {
return true;
}else {
return false;
}
}
}
int main() {
int max[] = {0, 0};
for(int i=999; i>99; i--) {
for( int j =999; j>99; j--) {
int pal = i*j;
if(isPalindrome(pal) == true) {
max[1] = pal;
if(max[1] > max[0]){
max[0] = pal;
}
}
}
}
cout << max[0];
}
I think you need to return true in isPalindrome after comparing complete string. ie return true; should be outside for loop
And for checking largest 3 digit palindrome why are you passing int pal = i*j; ie for first iteration 999*999. Check this
bool isPalindrome(int x) {
string str = to_string(x);
string pal = str;
std::reverse(pal.begin(),pal.end());
if(pal == str) {
return true;
}else {
return false;
}
}

How to check if parts of a single-string input are int or char?

I have to take a string i/p of length 15. First two letters should be alphabets, next 13 digits. Eg: AB1234567891234. How can I check if the first two are only alphabets and others are only digits?
#include <regex>
const std::regex e("^[a-zA-Z][a-zA-Z][0-9]{13}$");
std::string str = "ab1234567890123";
if (std::regex_match (s,e))
std::cout << "string object matched\n";
#include <cctype>
bool is_correct(std::string const& s) {
if (s.size() != 15) return false;
if (!std::isalpha(string[0]) || !std::isalpha(string[1]))
return false;
for (std::size_t i = 2; i < 13; ++i) {
if (!std::isdigit(string[i])) return false;
}
return true;
}
You can use the functions defined in the <cctype> header file like isalpha() and isdigit().
#include<iostream>
#include<string>
int main(int argc, char *argv[])
{
std::string n_s = "AB1234567896785";
bool res = true;
std::cout<<"Size of String "<<n_s.size()<<n_s.length()<<std::endl;
int i = 0, th = 2;
while(i < n_s.length())
{
if(i < th)
{
if(!isalpha(n_s[i]))
{
res = false;
break;
}
}
else
{
if(!isdigit(n_s[i]))
{
res = false;
break;
}
}
i++;
}
if(res)
{
std::cout<<"Valid String "<<std::endl;
}
else
{
std::cout<<"InValid Strinf "<<std::endl;
}
return 0;
}