how to save string in longest common subsequence recursive algorithm - c++

I'm trying to implement a naive approach of the longest common subsequence algorithm. I'm using a recursive approach, passing two strings into the function lcs. I successfully counted the number of characters in the longest subsequence.
My problem is printing the characters of the lcs. I thought I could do this by storing matched characters in a string called sub and passing it as a parameter. However, I'm stuck on how to save the string. I've always struggled with recursion, and would appreciate any tips on approaching this problem the right way.
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int lcs(string a, string b,string sub){
int aLen = a.length();
int bLen = b.length();
if (aLen==0 || bLen==0){
return 0;
}
if(a.at(aLen-1)==b.at(bLen-1)){
return 1+lcs(a.substr(0,aLen-1),b.substr(0,bLen-1),a.at(aLen-1)+sub); // add letter to subsequence
}
else {
return max(lcs(a.substr(0,aLen-1),b.substr(0,bLen),sub),lcs(a.substr(0,aLen),b.substr(0,bLen-1),sub));
}
}
int main(int argc, const char * argv[])
{
char sub[]="";
int charsInLCS = lcs("sdmc","msdc",sub); //i want to output "sdc"
cout << charsInLCS << endl;
return 0;
}

Be careful, your base case is wrong as you never check a[0] against b[0]. Also, passing string copies is very expensive, much faster to pass just the indexes and work with that. We need to keep track of what characters we matched when a[idxa] == b[idxb]. Here is a solution using vectors:
#include <iostream>
#include <string>
#include <queue>
#include <math.h>
#include <algorithm> // std::reverse
using namespace std;
string s1, s2;
int lcs(int idx1, int idx2, vector<char> &v){
if (idx1 == -1 || idx2 == -1){
return 0;
}
if (s1[idx1] == s2[idx2]) {
v.push_back(s1[idx1]); // record that we used this char
return 1 + lcs(idx1 - 1, idx2 - 1, v);
} else {
vector<char> v1, v2;
int p1 = lcs(idx1 - 1, idx2, v1);
int p2 = lcs(idx1, idx2 - 1, v2);
if (p1 > p2) { // we used the chars we already had in v + the ones in v1
v.insert(v.end(), v1.begin(), v1.end());
return p1;
} else { // we used the chars we already had in v + the ones in v2
v.insert(v.end(), v2.begin(), v2.end());
return p2;
}
}
}
int main(int argc, const char * argv[])
{
s1 = "sdmc";
s2 = "msdc";
vector<char> v; // chars we used
int sol = lcs(s1.length() - 1, s2.length() - 1, v); //i want to output "sdc"
cout << sol << " ";
reverse(v.begin(), v.end());
for (auto num : v) {
cout << num;
}
return 0;
}

Related

How to change each specific char to an int in C++

It might be a really dumb question, but I have tried to look it up, and have googled a bunch, but still can't figure out an easy way...
In C++, saying that using namespace std;:
int main()
{
ios_base::sync_with_stdio(0);
cin.tie(0);
String N;
cin >> N;
}
When user input is 123, N will be "123".
How do I cast '1' to int 1, and '2' to int 2, and '3' to int 3?
I cannot use %.
It would be awesome if I were to use an index approach in the string.
I would like to have a function that receives N and its index as parameters. For instance:
int func(string N, int curr_ind)
{
// change curr_ind of N to a single int
// for instance, "123" and 1, it would return 2.
}
#include <iostream>
#include <string>
int get_digit_from_string(const std::string&s, int idx) {
return static_cast<int>(s[idx] - '0');
}
int main() {
std::string num{"12345"};
for (std::size_t i = 0; i < num.length(); ++i) {
std::cout << get_digit_from_string(num, i) << '\n';
}
}
Just get the character at the index, subtract '0', and cast to int.
The subtraction is necessary, otherwise the character of a digit will be cast to the ASCII value of that character. The ASCII value of '0' is 48.
Output:
❯ ./a.out
1
2
3
4
5
Now, just for fun, let's say you need frequent access to these digits. Ideally, you'd just do the conversion all at once and have these ints available to you. Here's one way of doing that (requires C++20):
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
std::vector<int> get_digits_from_string(const std::string& s) {
std::vector<int> v;
std::ranges::transform(s, std::back_inserter(v),
[](auto c) { return static_cast<int>(c - '0'); });
return v;
}
int main() {
std::string num{"12345"};
std::vector<int> digits = get_digits_from_string(num);
for (auto i : digits) {
std::cout << i << '\n';
}
}
We use the string to create a std::vector where each element is an int of the individual characters. I can then access the vector and get whatever digit I need easily.
Another possibility:
#include <iostream>
#include <string>
int main()
{
std::string input;
std::cin >> input;
// allocate int array for every character in input
int* value = new int[input.size()];
for (int i = 0; i < input.size(); ++i)
{
std::string t(1, input[i]);
value[i] = atoi(t.c_str());
}
// print int array
for (int i = 0; i < input.size(); ++i)
{
std::cout << value[i] << std::endl;
}
delete[] value;
}
Output:
x64/Debug/H1.exe
123
1
2
3
Try this:
int func(string N, int curr_ind)
{
return static_cast<int>(N[curr_ind]-'0');
}
Since the ASCII representation of consecutive digits differs by one, all you need to do to convert a character (char c;) representing a digit to the corresponding integer is: c-'0'

why does it give me bigger than 4 always?

I am trying to get the numbers bigger than 4 after I loop in every other number, but the problem is that it keeps giving me bigger than 4 even tho the number isn't bigger than 4. thank you!
#include <iostream>
#include <vector>
#include <string>
using namespace std;
bool isvalidcc(const string& s)
{
vector<char> v (s.begin(), s.end());
for(auto i=0 ; i<v.size();i+=2)
{
if (v.at(i)>'4')
{
cout<<v.at(i)<<"bigger than 4"<<endl;
}
else
{
cout<<v.at(i)<<"smaller than 4"<<endl;
}
}
return false;
}
int main()
{
vector<string> cardnumbers = {
"371449635398431"
};
int i;
vector<string>::iterator itr;
for (i = 1, itr = cardnumbers.begin(); itr != cardnumbers.end(); ++itr, i++) {
// cout << i << " "
// << *itr
((isvalidcc(*itr)));
}
return 0;
}
I figured it out
Because v.at(i) is a char instead of an int it converts it into ascii code.
this means u have to convert the char in to an int the right way.
if (v.at(i) - '0' >4)
the - '0' will convert it to an int the right way otherwise it will return the wrong values, u can check this by making a new int variable and cout <<
int n = v.at(i);
cout << n;

How to print frequency of each letter in a string in descending order c++?

#include <iostream>
#include <string>
using namespace std;
int main () {
int cnt[26] {};
char alpha[26];
string s = "abcdefffggghiii";
for (int i = 0; i < s.length(); i++) {
cnt[s[i] - 'a']++;
}
for (int i = 'a'; i <= 'z'; i++) {
alpha[i - 'a'] = i;
}
for (int i = 0; i < 26; i++) {
if (cnt[i]) {
cout << alpha[i] << " " << cnt[i] << endl;
}
}
return 0;
}
I wanted to print the frequencies of each letter in the string in descending order. I've thought to sort the cnt array and print from 25 to 0 but it will only print the frequencies with wrong letter. How can I fix it to print for example i 3 and so on in descending order?
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
// Create result container
auto x = vector<pair<char, int>>();
std::string s = "abcdefffggghiii";
for (auto& l : s) {
// Find the item that corresponds to letter
auto pLetter =
find_if(x.begin(), x.end(), [&l](pair<char, int> &arg) {
return arg.first == l;
});
if (pLetter != x.end())
pLetter->second++; // If item corresponding to letter is found, increment count
else {
x.push_back(make_pair(l, 1)); // Otherwise, create a new result entry
}
}
// Sort results by count in descending order
std::sort(x.begin(), x.end(),
[](auto &left, auto &right) { return left.second > right.second; });
for (auto i = x.begin(); i != x.end(); ++i)
std::cout << i->first << ':' << i->second << '\n';
}
Produces
f:3
g:3
i:3
a:1
b:1
c:1
d:1
e:1
h:1
You can run it here. This uses C++14 lambdas for the find_if and sort predicates. This solution is very similar to #Retired Ninja's, except that the result vector contains items only for those letters that have non-zero counts. This means that it is extendable to wstrings without the need for a large result vector.
Here's how I might do it. You just need to keep the letter and the count together.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
struct LetterFreq
{
char letter;
int freq;
};
int main()
{
std::vector<LetterFreq> cnt(26);
for (size_t i = 0; i < cnt.size(); ++i)
{
cnt[i].freq = 0;
cnt[i].letter = static_cast<char>(i) + 'a';
}
std::string s = "abcdefffggghiii";
for (auto& l : s)
{
cnt[l - 'a'].freq++;
}
std::sort(cnt.begin(), cnt.end(), [](const LetterFreq& lhs, const LetterFreq& rhs)
{
return lhs.freq > rhs.freq;
});
for (auto& item : cnt)
{
if (item.freq == 0)
{
break;
}
std::cout << item.letter << " : " << item.freq << "\n";
}
return 0;
}
This is simple if all you have it lowercase ASCII letters. For more complicated input you can use the same idea of the letter and count in a struct, but you'd either want to increase the size of the vector to 256 to keep track of all possibilities, or use something like an unordered map to only store used symbols and then copy them out into a container you can sort to display them. You could also use parallel arrays and while sorting swap the letter positions at the same time you're swapping the counts. There are many ways to handle this.
You could use pairs, but it looks like you're doing this with more basic types. In that case you might have to use nested loops. Keep finding the highest frequency character, print it, and then set its frequency to -1 to indicate that you've processed it already.

C++ combine two files output

I am new to C/C++ .I have 2 text files and need to combine two files contents
I executed like this g++ merge.cc -o merge and created two text files with content like this:
file1 : 1 3 5 7
file2 : 2 4 6 8
then excuted this command : ./merge 10 t1.txt t2.txt
Out came : 1 2 3 4 5 6 7 81 2 3 4 5 6 7 8
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
void combine(char s[], char t[], char result[]);
int main(int argc, char* argv[])
{
const int MAX = 20;
char inBuffer1[MAX];
char inBuffer2[MAX];
char outBuffer[MAX*2];
int max = atoi(argv[1]);
ifstream file1(argv[2]);
ifstream file2(argv[3]);
file1.getline(inBuffer1,max);
file2.getline(inBuffer2,max);
combine (inBuffer1, inBuffer2, outBuffer);
cout << outBuffer << endl;
}
void combine(char s[], char t[], char result[])
{
int i, j, k;
for (i = j = k = 0; s[i] && t[j]; k++)
{
if (s[i] <= t[j])
result[k] = s[i++];
else
result[k] = t[j++];
cout << result[k];
}
//tidy up
for (; s[i]; )
{
result[k] = s[i++];
cout << result[k++];
}
for (; t[j]; )
{
result[k] = t[j++];
cout << result[k++];
}
result[k] = 0;
}
Could you please anyone explain about this. I thave to sort files and reserve output using -c, -r commands
Thanks in advance
The c++ standard library has std::merge to do exactly what you seem to want here. Basically open the files, then do the merge from a couple of istream_iterators to an ostream_iterator.
Try the following C-program example (without combine function):
#include <stdio.h>
#include <stdlib.h>
// compare function to sort int values
int comparator(const void *p, const void *q)
{
int l = *(int*)p;
int r = *(int*)q;
return (l - r);
}
int main(int argc, char* argv[])
{
const int MAX = 20;
int buffer[MAX*2];
int cnt = 0; // numbers in buffer
// check arguments
if( argc < 3)
{
printf("Provide correct arguments: one number and two files with numbers\n");
return 1;
}
// reading from 2 files in series
FILE * f;
for(int i = 2; i <= 3; i++)
{
f = fopen(argv[i], "r");
if( f == NULL )
{
printf("File %s cannot be read!\n", argv[2]);
break;
}
while( !feof(f) && cnt < MAX*2 ) // while file is not finished and array is not full
{
if( fscanf(f, "%d", &buffer[cnt]) ) // read data
cnt++; // and if reading is successful count
}
fclose(f);
}
// sort the resulting array (instead of combine function)
qsort(buffer, cnt , sizeof(int), comparator);
// printing results
for( int i = 0; i < cnt; i++)
{
printf("%d ", buffer[i]);
}
}
This example is for cases when initial files can consist not ordered values, so all values from both files are read to memory and then sorted by standard function from stdlib.h (to use that qsort we need function comparator, read more in the references).
But for case when both input files are already arranged (sorted) program can be simpler, but you need open both files and compare values while reading to output the smallest value from two "current", and you do not need buffer array for that case (it is just a tip, try to write a program yourself).
EDIT:
It is C++ example with merge and sort from <algorithm>:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <functional>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
int data; // buffer to read one value from file
ifstream file1(argv[1]);
ifstream file2(argv[2]);
vector<int> v1, v2; // vectors to store data
// reading initial data to vectors
while( !file1.eof() )
{
file1 >> data;
v1.push_back(data);
}
file1.close();
while( !file2.eof() )
{
file2 >> data;
v2.push_back(data);
}
file2.close();
// sorting (essential if files are not sorted)
sort(v1.begin(), v1.end(), less <int>());
sort(v2.begin(), v2.end(), less <int>());
// marging
vector<int> res(v1.size() + v2.size()); // vector to store result
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), res.begin(), less <int>());
// printing result
for(vector<int>::iterator i = res.begin(); i != res.end(); i++)
{
cout << *i << " ";
}
}
NOTE: In this example you do not need to ask user about size of data sequence, so argv[1] is name of the first file, and argv[2] is name of the second one (add appropriate check by yourself).
The following C++ example shows usage of istream_iterator and ostream_iterator with merge method:
#include <iostream>
#include <fstream>
#include <algorithm>
#include <iterator>
using namespace std;
int main(int argc, char* argv[])
{
// open input files
ifstream file1(argv[1]);
ifstream file2(argv[2]);
// link input streams with files
istream_iterator<int> it1(file1);
istream_iterator<int> it2(file2);
istream_iterator<int> eos; // end-of-stream iterator
// link output stream to standard output
ostream_iterator<int> oit (cout," "); // " " = usage of space as separator
// marging to output stream
merge(it1, eos, it2, eos, oit);
file1.close();
file2.close();
return 0;
}

Algorithm to generate all permutation by selecting some or all charaters

I need to generate all permutation of a string with selecting some of the elements. Like if my string is "abc" output would be { a,b,c,ab,ba,ac,ca,bc,cb,abc,acb,bac,bca,cab,cba }.
I thought a basic algorithm in which I generate all possible combination of "abc" which are {a,b,c,ab,ac,bc,abc} and then permute all of them.
So is there any efficient permutation algorithm by which I can generate all possible permutation with varying size.
The code I wrote for this is :
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <map>
using namespace std;
int permuteCount = 1;
int compare (const void * a, const void * b)
{
return ( *(char*)a - *(char*)b);
}
void permute(char *str, int start, int end)
{
// cout<<"before sort : "<<str;
// cout<<"after sort : "<<str;
do
{
cout<<permuteCount<<")"<<str<<endl;
permuteCount++;
}while( next_permutation(str+start,str+end) );
}
void generateAllCombinations( char* str)
{
int n, k, i, j, c;
n = strlen(str);
map<string,int> combinationMap;
for( k =1; k<=n; k++)
{
char tempStr[20];
int index =0;
for (i=0; i<(1<<n); i++) {
index =0;
for (j=0,c=0; j<32; j++) if (i & (1<<j)) c++;
if (c == k) {
for (j=0;j<32; j++)
if (i & (1<<j))
tempStr[ index++] = str[j];
tempStr[index] = '\0';
qsort (tempStr, index, sizeof(char), compare);
if( combinationMap.find(tempStr) == combinationMap.end() )
{
// cout<<"comb : "<<tempStr<<endl;
//cout<<"unique comb : \n";
combinationMap[tempStr] = 1;
permute(tempStr,0,k);
} /*
else
{
cout<<"duplicated comb : "<<tempStr<<endl;
}*/
}
}
}
}
int main () {
char str[20];
cin>>str;
generateAllCombinations(str);
cin>>str;
}
I need to use a hash for avoiding same combination, so please let me know how can I make this algorithm better.
Thanks,
GG
#include <algorithm>
#include <iostream>
#include <string>
int main() {
using namespace std;
string s = "abc";
do {
cout << s << '\n';
} while (next_permutation(s.begin(), s.end()));
return 0;
}
Next_permutation uses a constant size, but you can add a loop to deal with varying size. Or just store in a set to eliminate the extra dupes for you:
#include <set>
int main() {
using namespace std;
string s = "abc";
set<string> results;
do {
for (int n = 1; n <= s.size(); ++n) {
results.insert(s.substr(0, n));
}
} while (next_permutation(s.begin(), s.end()));
for (set<string>::const_iterator x = results.begin(); x != results.end(); ++x) {
cout << *x << '\n';
}
return 0;
}
I don't think you can write much faster program than you have already. The main problem is the output size: it has order of n!*2^n (number of subsets * average number of permutations for one subset), which is already > 10^9 for a string of 10 different characters.
Since STL's next_permutation adds very limited complexity for such small strings, your program's time complexity is already nearly O(output size).
But you can make your program a bit simpler. In particular, for( k =1; k<=n; k++) loop seems unnecessary: you already calculate size of subset in variable c inside. So, just have int k = c instead of if (c == k). (You'll also need to consider case of empty subset: i == 0)
edit
Actually, there's only 9864100 outputs for n == 10 (not ~ 10^9). Still, my point remains the same: your program already wastes only "O(next_permutation)" time for each output, which is very, very little.