How to make this recursive function extract uppercase letters from a string? - c++

So the function should return all the uppercase letters from the string but it returns only the first letter IF it's the capital letter. So I believe the i + 1 isn't working. And also, I have to use recursion for this code. I'm not allowed to use isupper(), or any other "shortcuts". So does anyone see what's going wrong in the code?
string Return_Caps(const string& s, int pos = 0){
string temp;
string a;
if(s[pos] < 'A' && s[pos] > 'Z'){ // if the position does not have any capital letters, return a
return a;
}
else{
if(s[pos] >= 'A' && s[pos] <= 'Z'){
temp = temp + s[pos];
Return_Caps(s, pos + 1);
}
}
return temp;
}

Related

Replace element of a string

I need to convert all uppercase letters to lowercase and vice-versa. If one of the elements of the string is not a valid letter of the alphabet, it must be replaced with “bug here!”. Using user-defined function
Input: evEry1
Output: EVeRY*bug here!*
I am already able to convert all uppercase letters to lowercase and vice-versa. I was also able to change nonalphanumeric elements to a single character but cannot replace it with the entire string "bug here!". I end up having error saying it cannot be converted
string flip (string w, int t){
string ch = "*bug here!*";
for (int j=0; j<w.length(); j++){
if (w[j] >= 'A' && w[j] <= 'Z')
w[j] = w[j] + 32;
else if (w[j] >= 'a' && w[j] <= 'z')
w[j] = w[j] - 32;
else
w[j] = ch;
}
return w;
}
A character is not a string and a string is not a character. So you can not replace characters with strings by using w[j] = ch;. Instead you should use the string replace method. Something like this
string flip (string w, int t){
string ch = "*bug here!*";
for (int j=0; j<w.length(); j++){
if (w[j] >= 'A' && w[j] <= 'Z'){
w[j] = w[j] + 32;
}
else if (w[j] >= 'a' && w[j] <= 'z') {
w[j] = w[j] - 32;
}
else {
w.replace(j, 1, ch); // replace the character
j += ch.length() - 1; // advance j so we don't process the replacement string
}
}
return w;
}
Note that after inserting the replacement string we have to increment j otherwise we'll start processing the replacement string.
This is untested code.
BTW given the confusion over strings vs characters, you really should change the name of the variable ch. How about str instead?
BTW I'm not seeing what the purpose of t is in the function above. It's not being used so it could be removed.
When you index the string you are looking at a single character, so
w[j] = w[j] - 32;
is ok.
When you want to insert a substring, you need to use std::string's insert function:
w.insert(j, ch);
This will allocate the extra space needed since you have a string not a single character. You then need to skip j ahead by ch.length() to move to the next original character.

Keeping Tally of Characters in Arrays

I'm working on a Caesar Cipher program for an assignment and I have the general understanding planned out, but my function for determining the decipher key is unnecessarily long and messy.
while(inFile().peek != EOF){
inFile.get(character);
if (character = 'a'|| 'A')
{ aCount++; }
else if (character = 'b' || 'B')
{ bCount++; }
so on and so on.
What way, if it's possible, can I turn this into an array?
You can use the following code:
int count [26] = {0};
while(inFile().peek != EOF){
inFile.get(character);
if (int (character) >=65 || int (character) <=90)
{ count [(int (character)) - 65] ++; }
else if (int (character) >=97 || int (character) <=122)
{ count [(int (character)) - 97] ++; }
}
P.S. This is checking for the ASCII value of each character and then increment its respective element in the array of all characters, having 0 index for A/a and 1 for B/b and so on.
Hope this helps...
P.S. - There was an error in your code, = is an assignment operator and == is a conditional operator and you do not assign value in if statement, you check for condition... So always use == to check for equality...
You can use an array in the following manner
int letterCount['z'] = {0}; //z is the highest letter in the uppercase/lowercase alphabet
while(inFile().peek != EOF){
inFile.get(character);
if (character > 'A' && character < 'z')
letterCount[character]++;
}
You can also use a hashmap like this
#include <unordered_map>
std::unordered_map<char,int> charMap;
while(inFile().peek != EOF){
inFile.get(character);
if (charMap.find(character) == charMap.end())
charMap[character] = 1;
else
charMap[character] = charMap[character] + 1;
}
In case you do not know, a hashmap functions as an array, where the index can be any class you like, as long as it implements a hash function.

C++ how to determine if char is first char in a word

It seems like this should be simple but I can't seem to figure it out. I am trying to write a function that will return true if the character at position pos is the first character of a word. A word it this case is defined as any string of alphanumeric characters.
Here is my latest attempt:
bool wordBeginsAt (const std::string& message, int pos)
{
string temp;
int x;
for (x=pos;isAlphanumeric(message[x]==true);x++)
{
temp[x] = message[x];
}
if (temp[pos]!=0)
{
return false;
}
else
return true;
}
bool isAlphanumeric (char c)
{
return (c >= 'A' && c <= 'Z')
|| (c >= 'a' && c <= 'z')
|| (c >= '0' && c <= '9');
}
By your definition, a character is the first character in a word if it is alphanumeric and either it's the first character in the string or the character before it is not alphanumeric.
Well, isAlphanumeric(message[x]==true) should have been isAlphanumeric(message[x])==true. But your code has other severe issues such as writing out of bounds of temp and the loop logic is all wrong, so I think it is best to start over.
What you need to do is:
Check if the character is alphanumeric
Check that either the previous character isn't, or there is no previous character
No loops or variables are required. The second condition would occur when pos == 0 ; you don't want to check the previous character if you are actually looking at the first character.

C++ manipulating numbers in ASCII to stay only in range of letters

#include <iostream>
using namespace std;
Int main() {
cout<<"Give me a letter" <<endl;
char letter;
cin>>letter;
cout<<letter;
(Int)letter;
letter+=2;
cout<<(char)letter;
(Int)letter;
letter-=25;
cout<<(char)letter;
return 0;
}
How would I manipulate the numbers in a way so that the numbers will always output a letter.
ie: if the letter z was chosen and adding 2 is a symbol how would I manipulate it in a way so that it will always stay between the numbers for capital numbers and uncapitalized numbers. Thanks. Please try to keep answers at a beginner level please I am new to this.
if(letter > 'z') {
//do stuff
}
if(letter < 'a' && letter > 'Z') {
//do stuff
}
if(letter < 'A') {
//do stuff
}
It just depends on how you want to handle the character when it goes into one of the three ranges on the ASCII chart in which the characters are not letters.
As a side note, you don't have to cast a char to an int to do math with it.
char myChar = 'a' + 2;
cout << myChar;
This will print: c
c has an ASCII value of 2 more than a.
The surest method is to use a table for each category, and do
your arithmetic on its index, modulo the size of the table.
Thus, for just lower case letters, you might do something like:
char
transcode( char original )
{
char results = original;
static std::string const lower( "abcdefghijklmnopqrstuvwxyz" );
auto pos = std::find( lower.begin(), lower.end(), results );
if ( pos != lower.end() ) {
int index = pos - lower.begin();
index = (index + 2) % lower.size();
results = lower[ index ];
}
return results;
}
This solution is general, and will work regardless of the sets
of letters you want to deal with. For digits (and for upper and
lower case, if you aren't too worried about portability), you
can take advantage of the fact that the code points are
contiguous, and do something like:
char
transcode( char original )
{
char results = original;
if ( results >= '0' && results <= '9' ) {
char tmp = results - '0'
tmp = (tmp + 2) % 10;
results = tmp + '0';
}
return results;
}
An alternative implementation would be to use something like:
results = results + 2;
if ( results > '9' ) {
results -= 10;
}
in the if above. These two solutions are mathematically
equivalent.
This is only guaranteed to work for digits, but will generally
work for upper or lower case if you limit yourself to the
original ASCII character set. (Be aware that most systems today
support extended character sets.)
You can test directly against ASCII chars by using 'x' notation. Further, you can test things together using && ("and" respectively"):
if ('a' <= letter && letter <= 'z') {
// Letter is between 'a' and 'z'
} else if ('A' <= letter && letter <= 'Z')) {
// Letter is between 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}
Or you can use the standard library function std::isalpha which handles this for you:
if (std::isalpha(letter)) {
// Letter is between 'a' and 'z' or 'A' and 'Z'
} else {
// Error! Letter is not between 'a' and 'z' or 'A' and 'Z'
}

How to convert a recursive solution to bottom up or top down solution?

I am solving this problem-
Given a string consisting of a,b and c's, we can take any two adjacent
distinct characters and replace it with the third character. For
example, if 'a' and 'c' are adjacent, they can replaced with 'b'. What
is the smallest string which can result by applying this operation
repeatedly?
Now I have written the following recursive solution (far from efficient), but want to convert it to either top-down or bottom-up solution.
Problem: I am not able to come up with a tabular structure for memoization. Even though I have to output only the length of resulting string, how can I solve it without actually solving the problem. The strings are getting reduced, so how do I store them?
Any hint for DP solution or Memoization would be great!
EDIT Many people have come up with top-down memoization solution, please try bottom-up as well.
#include <iostream>
#include <string>
using namespace std;
string reduce(string s)
{
if (s.length() <= 1)
return s;
int k;
char c = s[0];
string min = s;
for (k = 1; k < s.length() && c; ++k)
if (s[k] != c)
c = 0;
if (c)
return s;
if (s.length() == 2){
if (s[0] != 'a' && s[1] != 'a')
s[0] = 'a';
else if (s[0] != 'b' && s[1] != 'b')
s[0] = 'b';
else if (s[0] != 'c' && s[1] != 'c')
s[0] = 'c';
s.resize(1);
return s;
}
for (k = 1; k < s.length(); ++k){
string s1 = reduce(s.substr(0, k));
string s2 = reduce(s.substr(k));
if (s1.length() + s2.length() < min.length())
min = s1 + s2;
if (!s1.empty() && !s2.empty() && s1.back() != s2.front()){
if (s1.back() != 'a' && s2.front() != 'a')
s1.back() = 'a';
else if (s1.back() != 'b' && s2.front() != 'b')
s1.back() = 'b';
else if (s1.back() != 'c' && s2.front() != 'c')
s1.back() = 'c';
s1 = reduce(s1 + s2.substr(1));
if (s1.length() < min.length())
min = s1;
}
}
return min;
}
int main()
{
string input;
cin >> input;
cout << reduce(input) << endl;
return 0;
}
I'm a bit too lazy to think the problem through, but I'll give you an approach to memoization that often enough works.
Instead of recursing directly, introduce mutual recursion.
std::string reduce(std::string const &s)
{
// ...
string s1 = reduce_memo(s.substr(0, k));
string s2 = reduce_memo(s.substr(k));
// ...
}
where reduce_memo maintains a hash table, i.e. an unordered_map, mapping subproblems to their solutions.
// static is incredibly ugly, but I'll use it here for simplicity
static std::unordered_map<std::string, std::string> memo;
std::string reduce_memo(std::string const &s)
{
try {
return memo.at(s);
} except (std::out_of_range const &) {
std::string r = reduce(s);
memo[s] = r;
return r;
}
}
When programming in C++98, use std::map instead of unordered_map.
This doesn't solve the problem, but I noticed:
if (s.length() == 2){
if (s[0] != 'a' && s[1] != 'a')
s[0] = 'a';
else if (s[0] != 'b' && s[1] != 'b')
s[0] = 'b';
else if (s[0] != 'c' && s[1] != 'c')
s[0] = 'c';
s.resize(1);
return s;
}
doesn't work according to the problem statement:
we can take any two adjacent distinct characters and replace it with the third character.
Consider the string s = "bb". Neither s[0] nor s[1] are equal to 'a', which means the condition s[0] != 'a' && s[1] != 'a' will evaluate to true for the string "bb". This goes for any string of consecutive characters of the same value, e.g. "bb", "cc".
Perhaps in the condition you can take the difference of the two consecutive characters, and check if they're non-zero.
You can memoize your solution by storing the result of reduce(s) in a map<string,string>.
string reduce(string s, map<string,string>& memo) {
if (memo.count(s)) {
return memo[s];
}
// The rest of your code follows...
memo[s] = min;
}
Whatever i have understood from the problem the solutions should be
length of the input - if all input characters are same like
aaaaa - 5
bbb - 3
and 1 in every other case.
Correct me if I miss some part of the problem.
The absolute minimum is 1. However, the specifics of the string and replacement rules may yield between 1 and n, where n is the length of the string.
For the specific example, then the smallest possible is n/2, as you take 2 characters and replace them with 1 (which cannot be further replaced) so even if you had "acacacacacacacac", the best possible case, you would still only achieve the factor of 2 reduction.
I solved a similar problem in competitive programming workshop,
and indeed your proposed solution weren't fast enough.
My solution was creating such vector:
string s;
cin >> s;
int length = s.length();
vector<vector<int> > v(length, vector<int>(length)); // 2d array of size length*length.
where v[i][j] will be the minimal length the substring from i to j of s can get to.
Later all you have to do is fill this table in increasing size.
Hope that helped.
"a...a" (“a" * n) == > n
"b...b" (“b" * n) == > n
"c...c" (“c" * n) == > n
any other ==> 1 or 2 with my greedy algorithm.
If we get 2 in this greedy algorithm, I can't prove it is the smallest result for the input string.
Greedy algorithm
while the last two is the same character { // the number of the same characters
find the last replaceable pair // at the tail will decrease until
reduce them // it become 1
}
while find the first replaceable pair
reduce them