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.
Related
I am writing a function which will check the closeness of 2 strings. What I mean by closeness is:
strings "bat" and "bot" are 1 character apart, so the function should return 1. strings "dog" and "bot" are 2 characters apart, so the function should return 2(the 'd' vs 'b' and the 'g' vs 't'). strings "very good boy john" and "very good bot john" are just 1 character apart.
The length of 2 strings will always be the same.
I was not getting the desired output .My code for the following was:
int main(){
string a = "dog";
string b = "bot";
int index = 0;
int tot = std::count_if(a.begin(), a.end(), [&](char ch){
if(ch != b[index]){return true;}
return false;
index+=1;
});
std::cout << tot; //expected 2 but not getting 2 :(
}
Any help?
Just needed to b[index++]
.Because the index+=1 is not getting executed.
A different algorithm does the work for you.
(untested)
int main(){
string a = "dog";
string b = "bot";
int tot = std::inner_product(a.begin(), a.end(), b.begin(), 0,
std::plus<>(), std::not_equal_to<>());
std::cout << tot;
}
Requires that a and b are equal length or a is shortest
#include <iostream>
using namespace std;
// Function to count the valid indices pairs
int pairs(string str1, int size1, string str2, int size2){
// f1 and f2 for frequencies of characters
// of string str1 and str2
int f1[26] = { 0 };
int f2[26] = { 0 };
// 'c' To count the valid pairs
int i, c = 0;
//updating the frequencies of str1 and st2
for (i = 0; i < size1; i++){
f1[str1[i] - 'a']++;
}
for (i = 0; i < size2; i++){
f2[str2[i] - 'a']++;
}
// Find the count of valid pairs
for (i = 0; i < 26; i++){
c += (min(f1[i], f2[i]));
}
return c;
}
// main function
int main(){
string str1 = "tutorialspoint", str2 = "codingground";
int size1 = str1.length(), size2 = str2.length();
cout<<”Total pairs with str1[i]=str2[j] are: ”;
cout << pairs(str1, size1, str2, size2);
return 0;
}
Reference : https://www.tutorialspoint.com/count-common-characters-in-two-strings-in-cplusplus
I'm practicing in programming and I generating all combinations in c++. I know how to generate all combination in
certain length
My result is something like that
A A A
A A B
A A C
A B A
A B B
A B C
A C A
A C B
A C C
B A A
.....
and my problem is, I don't know, how to generate all combinations with unknown length. For example I want word length = 5 and program will generate all combination in exactly length 5. How to do it?
A A A A A
A A A A B
A A A A C
A A A B A
.........
(Sorry for my english)
See the link Print all permutations with repetition of characters
The below recursive function in the page, can create last+1 length permutations.
/* The main function that recursively prints all repeated
permutations of the given string. It uses data[] to store all
permutations one by one */
void allLexicographicRecur (char *str, char* data, int last, int index)
{
int i, len = strlen(str);
// One by one fix all characters at the given index and recur for
// the/ subsequent indexes
for ( i=0; i<len; i++ )
{
// Fix the ith character at index and if this is not the last
// index then recursively call for higher indexes
data[index] = str[i] ;
// If this is the last index then print the string stored in
// data[]
if (index == last)
printf("%s\n", data);
else // Recur for higher indexes
allLexicographicRecur (str, data, last, index+1);
}
}
I think this can serve your purpose.
Call allLexicographicRecur with the required (length-1) value for the 'last' parameter.
This is actually nothing more than counting.
If you have the letters A, B, and C, you are counting in base 3.
A is 0, B is 1 and C is 2.
Quick and dirty:
#include <string>
#include <iostream>
int main()
{
for(int i = 0; i < 100; i++) {
const int base = 3;
const char zero_char = 'A';
const size_t length = 5;
std::string out;
for(int n = i; n > 0; ) {
int d = n%base;
out = static_cast<char>(zero_char + d) + out;
n /= base;
}
while(out.length() < length) out = zero_char + out;
std::cout << out << '\n';
}
}
see it live
The possible combinations are baselength, so if you want all combinations for A, B, C with 5 digits, change the limit of the first for loop to 35 ( = 243):
for(int i = 0; i < 243; i++)
You may use something like:
bool increase(const std::string& s, std::vector<std::size_t>& it)
{
for (std::size_t i = 0, size = it.size(); i != size; ++i) {
const std::size_t index = size - 1 - i;
++it[index];
if (it[index] >= s.size()) {
it[index] = 0;
} else {
return true;
}
}
return false;
}
void do_job(const std::string& s,
const std::vector<std::size_t>& it)
{
for (std::size_t i = 0; i != it.size(); ++i) {
std::cout << s[it[i]] << " ";
}
std::cout << std::endl;
}
void cartesian_product(const std::string& s, std::size_t n)
{
std::vector<std::size_t> it(n, 0u);
do {
do_job(s, it);
} while (increase(s, it));
}
Demo
I need to insert symbol '+' into string after its each five symbol.
st - the member of class String of type string
int i = 1;
int original_size = st.size;
int count = 0;
int j;
for (j = 0; j < st.size; j++)
{
if (i % 5)
count++;
}
while (st.size < original_size + count)
{
if (i % 5)
{
st.insert(i + 1, 1, '+');
st.size++;
}
i++;
}
return st;
I got an error in this part of code. I think it is connected with conditions of of the while-cycle. Can you help me please how to do this right?
If I've understood you correctly then you want to insert a '+' character every 5 chars in the original string. One way to do this would be to create a temporary string and then reassign the original string:
std::string st("A test string with some chars");
std::string temp;
for (int i = 1; i <= st.size(); ++i)
{
temp += st[i - 1];
if (i % 5 == 0)
{
temp += '+';
}
}
st = temp;
You'll notice I've started the loop at 1, this is to avoid the '+' being inserted on the first iteration (0%5==0).
#AlexB's answer shows how to generate a new string with the resulting text.
That said, if your problem is to perform in-place insertions your code should look similar to this:
std::string st{ "abcdefghijk" };
for(auto i = 4; i != st.size(); i += 5)
st.insert(i+1, 1, '+'); // insert 1 character = '+' at position i
assert(st == "abcde+fghij+k");
std::string InsertEveryNSymbols(const std::string & st, size_t n, char c)
{
const size_t size(st.size());
std::string result;
result.reserve(size + size / n);
for (size_t i(0); i != size; ++i)
{
result.push_back(st[i]);
if (i % n == n - 1)
result.push_back(c);
}
return result;
}
You don't need a loop to calculate the length of the resulting string. It's going to be simply size + size / 5. And doing multiple inserts makes it a quadratic-complexity algorithm when you can just as easily keep it linear.
Nothing no one else has done, but eliminates the string resizing and the modulus and takes advantage of a few new and fun language features.
std::string temp(st.length() + st.length()/5, '\0');
// preallocate string to eliminate need for resizing.
auto loc = temp.begin(); // iterator for temp string
size_t count = 0;
for (char ch: st) // iterate through source string
{
*loc++ = ch;
if (--count == 0) // decrement and test for zero much faster than
// modulus and test for zero
{
*loc++ = '+';
count = 5; // even with this assignment
}
}
st = temp;
I am trying to write a function that takes a string, and splits every X number of characters:
std::vector<std::string> DIFSplitStringByNumber(std::string s, int l)
{
const char *c = s.c_str();
char buffer[l];
std::vector<std::string> entries;
entries.reserve(int(s.length() / l) + 1);
int d = 0;
for(int i = 0; i < s.length() - 1;)
{
if(d != l)
{
buffer[d] = c[i];
d++;
i++;
}
else
{
entries.push_back(std::string(buffer, l));
//Clear array
memset(buffer, 0, l);
d = 0;
}
}
return entries;
}
For example, If I called DIFSplitStringByNumber("hello!", 2), I should get a vector containing:
[0] he
[1] ll
[2] o!
However, it only seems to get the first two results (the vector size is 2), and when I do something like DIFSplitStringByNumber("hello", 2), it crashes, presumably because its trying to access an array index that doesn't exist (it expects 6 characters, but there are only 5). Is there a simpler way to do this?
The heart of the algorithm really comes down to the following two lines.
for (size_t i = 0; i < s.size(); i += l)
res.push_back(s.substr(i, l));
Also, you should pass the string by const reference.
This will split a string into a vector. If there aren't an even number of splits, it will add the extra characters to the end.
std::vector<std::string> Split(const std::string& str, int splitLength)
{
int NumSubstrings = str.length() / splitLength;
std::vector<std::string> ret;
for (auto i = 0; i < NumSubstrings; i++)
{
ret.push_back(str.substr(i * splitLength, splitLength));
}
// If there are leftover characters, create a shorter item at the end.
if (str.length() % splitLength != 0)
{
ret.push_back(str.substr(splitLength * NumSubstrings));
}
return ret;
}
Using that std::string is a collection of char, a simple implementation could be :
std::vector<std::string> DIFSplitStringByNumber(const std::string & str, int len)
{
std::vector<std::string> entries;
for(std::string::const_iterator it(str.begin()); it != str.end();)
{
int nbChar = std::min(len,(int)std::distance(it,str.end()));
entries.push_back(std::string(it,it+nbChar));
it=it+nbChar;
};
return entries;
}
Live sample
Change the way that you are calculating the vector size:
int size = (s.length() - 1) / l + 1;
This is equivalent to the ceiling of the input string length divided by the input length.
BTW, the int(s.length() / l) casting is useless, since both operands are integers.
Finally, use this size inside the loop:
for (int i=0; i<size; i++)
To find the sub-sequences from a string of given length i have a recursive code (shown below) but it takes much time when the string length is big....
void F(int index, int length, string str)
{
if (length == 0) {
cout<<str<<endl;
//int l2=str.length();
//sum=0;
//for(int j=0;j<l2;j++)
//sum+=(str[j]-48);
//if(sum%9==0 && sum!=0)
//{c++;}
//sum=0;
} else {
for (int i = index; i < n; i++) {
string temp = str;
temp += S[i];
//sum+=(temp[i]-48);
F(i + 1, length - 1, temp);
}
}
}
Please help me with some idea of implementing non-recursive code or something else.
You mentioned your current code is too slow when the input string length is large. It would be helpful if you could provide a specific example along with your timing info so we know what you consider to be "too slow". You should also specify what you would consider to be an acceptable run time. Here's an example:
I'll start with an initial version that I believe is similar to your current algorithm. It generates all subsequences of length >= 2:
#include <iostream>
#include <string>
void subsequences(const std::string& prefix, const std::string& suffix)
{
if (prefix.length() >= 2)
std::cout << prefix << std::endl;
for (size_t i=0; i < suffix.length(); ++i)
subsequences(prefix + suffix[i], suffix.substr(i + 1));
}
int main(int argc, char* argv[])
{
subsequences("", "ABCD");
}
Running this program produces the following output:
AB
ABC
ABCD
ABD
AC
ACD
AD
BC
BCD
BD
CD
Now let's change the input string to something longer. I'll use a 26-character input string:
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
This generates 67,108,837 subsequences. I won't list them here :-). On my machine, the code shown above takes just over 78 seconds to run (excluding output to cout) with the 26-character input string.
When I look for ways to optimize the above code, one thing that jumps out is that it's creating two new string objects for each recursive call to subsequences(). What if we could preallocate space once upfront and then simply pass pointers? Version 2:
#include <stdio.h>
#include <malloc.h>
#include <string.h>
void subsequences(char* prefix, int prefixLength, const char* suffix)
{
if (prefixLength >= 2)
printf("%s\n", prefix);
for (size_t i=0; i < strlen(suffix); ++i) {
prefix[prefixLength] = suffix[i];
prefix[prefixLength + 1] = '\0';
subsequences(prefix, prefixLength + 1, suffix + i + 1);
}
}
int main(int argc, char* argv[])
{
const char *inputString = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *prefix = (char*) _malloca(strlen(inputString) + 1);
subsequences(prefix, 0, inputString);
}
This generates the same 67,108,837 subsequences, but execution time is now just over 2 seconds (again, excluding output via printf).
Your code might be slow because your string is large. For a sequence of n unique elements there are (n over k) subsequences of length k. That means for the sequence "ABCDEFGHIJKLMNOPQRSTUVWXYZ" there are 10.400.600 different subsequences of length 13. That number grows pretty fast.
Nevertheless, since you asked, here is a non-recursive function that takes a string str and a size n and prints all subsequences of length n of that string.
void print_subsequences(const std::string& str, size_t n)
{
if (n < 1 || str.size() < n)
{
return; // there are no subsequences of the given size
}
// start with the first n characters (indexes 0..n-1)
std::vector<size_t> indexes(n);
for (size_t i = 0; i < n; ++i)
{
indexes[i] = i;
}
while (true)
{
// build subsequence from indexes
std::string subsequence(n, ' ');
for (size_t i = 0; i < n; ++i)
{
subsequence[i] = str[indexes[i]];
}
// there you are
std::cout << subsequence << std::endl;
// the last subsequence starts with n-th last character
if (indexes[0] >= str.size() - n)
{
break;
}
// find rightmost incrementable index
size_t i = n;
while (i-- > 0)
{
if (indexes[i] < str.size() - n + i)
{
break;
}
}
// increment that index and set all following indexes
size_t value = indexes[i];
for (; i < n; ++i)
{
indexes[i] = ++value;
}
}
}