check if string contains only unique chars using .at(int) - c++

Really basic question but I can't figure this out. My program checks if a string is unique by setting flags for each ASCII in an array to true if found in the string. It's not working(it compiles, but doesn't give correct answer), and I can't for the life of my figure out why.
The output I get is 0:
main.cpp
#include "main.hpp"
#include <iostream>
bool isUnique(std::string str) {
if(str.length() > 128)
return false;
bool theChars[128];
for(int i = 0; i < str.length(); i++) {
int loc = str.at(i);
if(theChars[loc])
return false;
else
theChars[loc] = true;
}
return true;
}
int main() {
std::string timmy = "abcdefghijklmnop";
std::cout << isUnique(timmy);
return 0;
}

You forgot to initialize the bool array:
bool theChars[128] = {};
The empty initializer means "use the default value" which is zero, aka false for bool.
P.S. Your code produces undefined behavior if you have any character outside [0, 127]. You could fix this by making theChars 256 long and casting the character to uint8_t before indexing. Or use std::array<char, 128> and theChars.at(loc) to throw an exception if out of bounds.

easier way is use set:
#include <iostream>
#include <set>
using namespace std;
bool isUnique(string str) {
set<char>st(str.begin(),str.end());
if(st.size()==str.size())
return true;
return false;
}
int main() {
string timmy = "abcdefghijklmnop";
cout << boolalpha<<isUnique(timmy)<<endl;
timmy = "aaaaabbbcdefghijklmnop";
cout << boolalpha<<isUnique(timmy)<<endl;
return 0;
}
p.s. if not use boolalpha, it will print 1 for true and 0 for false.

std::sort(str.begin(), str.end());
return std::adjacent_find(str.begin(), str.end()) == str.end();
This doesn't use any additional space, and works for any character encoding.

Related

I Want This Code To Prove If An Integer Is A Palindrome. How Do I do It?

I am sure this code isn't perfect, but I am new to programming and am trying to work out a challenge for checking if a number is a palindrome or not. I tried writing a bool-type function in the code to return 'true' if the number is a palindrome and 'false' otherwise.
Anyway, jumping to context, I want this code to print 'YES" every time the computer notices a sign of palindrome-ism. The code is compiling successfully, however, it does not output anything after 'What is the integer you wanna check palindromism for?:' even when inputting numbers like '12321', '111', '1234321' (palindromes).
Can anyone help me, and if possible, without changing much of the code tell me ways to achieve what I want to (to prove palindrome-ism)?
#include <cstring>
using namespace std;
bool isPalindrome(int x, string md) {
int y = md.length() + 1;
char abz[y];
for (int i=0; i < md.length()-1; ++i) {
if (abz[i] == (md.length()-1)-i){
cout << "YES";
}
}
return true;
}
int main(){
int x;
cout << "What is the integer you wanna check palindromism for?: ";
cin >> x;
string md = to_string(x);
isPalindrome(x, md);
return 0;
}
Thanks!
I'm not sure what you're trying to do in isPalindrome.
One way to check if a string of size len is palindrome is to compare its i-th and (len-i-1)-th characters for i ranging in [0, len / 2).
If they differ at any point the string is not palindrome.
Here's how you may do it:
bool isPalindrome(std::string const& md) {
if (md.empty()) // Empty strings are not palindrome
return false;
auto const len = md.size();
auto const halfLen = len / 2;
for (std::size_t i = 0; i != halfLen; ++i)
if (md[i] != md[len - i - 1])
return false;
return true;
}
Can anyone help me, and if possible, without changing much of the code tell
me ways to achieve what I want to (to prove palindrome-ism)?
Please check the comments I've added in the code:
// Include the correct headers
#include <iostream>
#include <string>
// Don't do this
//using namespace std;
// This just checks if the string is palindrome.
// It does not print anything.
bool isPalindrome(std::string const& md) {
if (md.empty())
return false;
auto const len = md.size();
auto const halfLen = len / 2;
for (std::size_t i = 0; i != halfLen; ++i)
if (md[i] != md[len - i - 1])
return false;
return true;
}
int main() {
// No need to parse the number and convert it to string again.
//int x;
std::string md;
std::cout << "What is the integer you wanna check palindromism for?: ";
// NOTE: you may input any string here: not just integers.
std::cin >> md;
std::cout << (isPalindrome(md) ? "YES" : "") << '\n';
// ^ print "YES" or nothing
return 0;
}
You may also implement isPalindrome with algorithms and iterators like so:
// You'll need these two headers
#include <algorithm>
#include <iterator>
template <typename BidIt>
bool isPalindrome(BidIt first, BidIt last) {
if (first == last)
return false;
auto const halfLength = std::distance(first, last);
auto const mid = std::next(first, halfLength);
auto const rFirst = std::make_reverse_iterator(last);
return std::equal(first, mid, rFirst);
}
bool isPalindrome(std::string const& str) {
return isPalindrome(std::cbegin(str), std::cend(str));
}
This is basically the same algorithm as above but you can reuse
template <typename BidIt>
bool isPalindrome(BidIt, BidIt);
with more containers than just std::string.

How to print strings in an array that start in yan and end in es c++

My asssignmet is:
Input three strings into an array of strings. First, use a function to find the length for the end comparisons, then again compare the last two characters separately.
Second, use a string function to take a sub-string of the first three characters for the beginning comparison all at once.
{
string stringarray[3] = {"yankee", "yes", "word"};
for (int x = 0; x < 3; x++)
string substringend1 = stringarray.substr(stringarray.length(stringarray[x]) - 2, stringarray.length(stringarray[x]));
string substringend2 = stringarray.substr(stringarray.length(stringarray[x]) - 1, stringarray.length(stringarray[x]));
string substringstart = stringarray.substr(0, 3);
if (substringend1 == "e" && substringend2 == "s" || substringstart == "yan") {
for (int y = 0; y < 3; y++)
cout << stringarray[y];
}
}
I know Im an idiot and this is a bad question format and whatever but I need help
C++20 makes this very easy:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main() {
std::vector<std::string> in{"yankee", "yes", "word"};
for(const auto& s : in)
{
if(s.starts_with("yan") || s.ends_with("es"))
std::cout << s << '\n';
}
return 0;
}
Live Example: https://godbolt.org/z/6Eq3nnKrf
The hardest part is finding C++20 support in your compiler. Later versions of gcc have it, latest versions of MSVC have it.
Without C++20, you need to find replacements for starts_with() and ends_with(). Starts with is easy and has a good answer here: How do I check if a C++ std::string starts with a certain string, and convert a substring to an int?
Using that answer we can write a pretty simple starts_with() function:
bool starts_with(const std::string& in, const std::string& prefix)
{
return in.rfind(prefix, 0) == 0;
}
We can use that as an example on how to create an ends_with() function too!
bool ends_with(const std::string& in, const std::string& prefix)
{
return in.rfind(prefix) == (in.size() - prefix.size());
}
Then our main code changes only slightly:
int main()
{
std::vector<std::string> in{"yankee", "yes", "word"};
for(const auto& s : in)
{
if(starts_with(s, "yan") || ends_with(s, "es"))
std::cout << s << '\n';
}
return 0;
}
You can use std::compare to compare the start of a string with yan or its end with es:
#include <iostream>
#include <string>
using namespace std;
bool startWithString(string a, string mod)
{
if (a.length() < mod.length()) {return false;}
return 0 == a.compare(0, mod.length(), mod);
}
bool endWithString(string a, string mod)
{
if (a.length() < mod.length()) {return false;}
return 0 == a.compare(a.length()-mod.length(), mod.length(), mod);
}
int main()
{
string str[4] = {"yankee", "yes", "word", "yankes"};
for (int i = 0; i < 4; i++)
{
string cur = str[i];
if (startWithString(cur, "yan") || endWithString(cur, "es")) {cout << cur << endl;}
}
}
Result :
yankee
yes
yankes
Using rfind() also yields similar result:
bool startWithString(string a, string mod)
{
return a.rfind(mod, 0) == 0;
}
bool endWithString(string a, string mod)
{
return a.rfind(mod) == (a.length() - mod.length());
}
As #Chad mentioned, C++20 also support starts_with() and ends_with(), which makes stuff easier.

Trying to find isogram in a string c++

I am trying to write a code that has two functions: one that determines whether the string is an isogram or not and another one to print the outcome (true or false) to the console (for the purpose of solving the task).
Some of the things are not working correctly though. And I wonder where I need to improve the code (probably all over...). I would appreciate any advice :)
#include <iostream>
#include<string>
#include<bits/stdc++.h>
#include<iomanip>
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length; i++)
{
if (str.at(i) == str.at(i+1))
{
return false;
break;
}
else
{
return true;
}
}
}
void print_result()
{
std::string str;
if (!find_Isogram (str))
{
std::cout << "false" << std::endl;
}
else
{
std::cout << "true" << std::endl;
}
}
int main()
{
find_Isogram ("gdtub");
print_result();
return 0;
};
````````````````````````````````````````````````````
There are some problems here:
1) You always check an empty string:
print_result will just check an empty string, but it's redundant anyway.
void print_result()
{
std::string str; // empty string
if (!find_Isogram (str)) // finding isogram on empty string
{
std::cout << "false" << std::endl;
}
...
}
It can be simplified with std::boolalpha that allows you to print a bool as "true" or "false" (instead of 1 or 0). main would become
int main()
{
std::cout << std::boolalpha << find_Isogram ("gdtub"); // prints true or false
};
2) Isogram check always ends after first character
Take a look at the condition in find_Isogram. It has a return-statement in the if and else, so you always return after checking the first character.
The idea to detect duplicate characters this way is correct (except for the off-by-one-error already mentioned by others). But you want to return true; only after checking all of the characters, e.g. outside the loop:
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end()); //sorted the string for the for loop (e.g. eHllo)
int length = str.length();
for (int i = 0; i < length - 1; i++)
{
if (str.at(i) == str.at(i+1))
{
return false; // whoops duplicate char, stop here
}
}
return true; // no duplicates found, it's an isogram
}
For some further C++-magic, you could simplify it even more with standard library functions :D
bool find_Isogram (std::string str)
{
std::sort(str.begin(), str.end());
return std::unique(str.begin(), str.end()) == str.end();
}
The condition where you check the consecutive characters for equality is wrong. It will yield true for strings like ABAB. You instead need to use a map with count of each character that has appeared.
Something like:
std::map<char, int> map_of_chars;
for(int i = 0; i < length; i++) {
map_of_chars[str.at(i)] = map_of_chars[str.at(i)] + 1;
}
If any value in the map is more than 1 return false;
Another implementation would be using the return value of std::unique():
std::sort(str.begin(), str.end());
auto intial_size = str.size();
std::unique(str.begin(), str.end());
if(str.size() == initial_size) {
/is an isogram
}
else {
//is not an isogram
}

string repetition replaced by hyphen c++

I am a beginner at coding, and was trying this question that replaces all repetitions of a letter in a string with a hyphen: i.e ABCDAKEA will become ABCD-KE-.I used the switch loop and it works, but i want to make it shorter and maybe use recursion to make it more effective. Any ideas?
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char x[100];
int count[26]={0}; //initialised to zero
cout<<"Enter string: ";
cin>>x;
for(int i=0; i<strlen(x); i++)
{
switch(x[i])
{
case 'a':
{
if((count[0]++)>1)
x[i]='-';
}
case 'b':
{
if((count[1]++)>1)
x[i]='-';
}
case 'c':
{
if((count[2]++)>1)
x[i]='-';
}
//....and so on for all alphabets, ik not the cutest//
}
}
Iterate through the array skipping whitespace, and put characters you've never encountered before in std::set, if you find them again you put them in a duplicates std::set if you'd like to keep track of how many duplicates there are, otherwise change the value of the original string at that location to a hyphen.
#include <iostream>
#include <string>
#include <cctype>
#include <set>
int main() {
std::string s("Hello world");
std::set<char> characters;
std::set<char> duplicates;
for (std::string::size_type pos = 0; pos < s.size(); pos++) {
char c = s[pos];
// std::isspace() accepts an int, so cast c to an int
if (!std::isspace(static_cast<int>(c))) {
if (characters.count(c) == 0) {
characters.insert(c);
} else {
duplicates.insert(c);
s[pos] = '-';
}
}
}
return 0;
}
Naive (inefficient) but simple approach, requires at least C++11.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
std::string f(std::string s)
{
auto first{s.begin()};
const auto last{s.end()};
while (first != last)
{
auto next{first + 1};
if (std::isalpha(static_cast<unsigned char>(*first)))
std::replace(next, last, *first, '-');
first = next;
}
return s;
}
int main()
{
const std::string input{"ABCDBEFKAJHLB"};
std::cout << f(input) << '\n';
return 0;
}
First, notice English capital letters in ASCII table fall in this range 65-90. Casting a capital letter static_cast<int>('A') will yield an integer. If after casing the number is between 65-90, we know it is a capital letter. For small letters, the range is 97-122. Otherwise the character is not a letter basically.
Check create an array or a vector of bool and track the repetitive letters. Simple approach is
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string str("ABCDAKEAK");
vector<bool> vec(26,false);
for(int i(0); i < str.size(); ++i){
if( !vec[static_cast<int>(str[i]) - 65] ){
cout << str[i];
vec[static_cast<int>(str[i]) - 65] = true;
}else{
cout << "-";
}
}
cout << endl;
return 0;
}
Note: I assume the input solely letters and they are capital. The idea is centered around tracking via bool.
When you assume input charactor encode is UTF-8, you can refactor like below:
#include <iostream>
#include <string>
#include <optional>
#include <utility>
std::optional<std::size_t> char_to_index(char u8char){
if (u8'a' <= u8char && u8char <= u8'z'){
return u8char - u8'a';
}
else if (u8'A' <= u8char && u8char <= u8'A'){
return u8char - u8'A';
}
else {
return std::nullopt;
}
}
std::string repalce_mutiple_occurence(std::string u8input, char u8char)
{
bool already_found[26] = {};
for(char& c : u8input){
if (const auto index = char_to_index(c); index && std::exchange(already_found[*index], true)){
c = u8char;
}
}
return u8input;
}
int main(){
std::string input;
std::getline(std::cin, input);
std::cout << repalce_mutiple_occurence(input, u8'-');
}
https://wandbox.org/permlink/UnVJHWH9UwlgT7KB
note: On C++20, you should use char8_t instead of using char.

C++ Check if whole string is uppercase

I am trying to check if the whole word is upper case, if this is true it should return true, else return false.
My current code is:
#include "UpperCaseFilter.h"
#include "ReadFilteredWords.h"
#include "ReadWords.h"
#include <locale>
bool UpperCaseFilter::filter(string word) {
if(!word.empty()) {
for(int i = 0; i < word.length(); i++) {
if(isupper(word[i])) {
return true;
}
else {
return false;
}
}
}
}
The problem with this code is, if i have for example HeLLO, it will return true because my last character is true. How would I only return true if the whole string is true. I did it using a counter method but it is not the most efficient.
I also tried using the all_of method but I think I dont have the correct compiler version because it says all_of isn't defined (Even with correct imports).
I'm not sure what other approaches there are to this.
Alternatively utilize the std::all_of function in combination with std::isupper in predicate:
#include <iostream>
#include <string>
#include <algorithm>
int main() {
std::string s = "HELLo";
if (std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); })) {
std::cout << "Is uppercase." << '\n';
} else {
std::cout << "Is not uppercase." << '\n';
}
}
Used as part of a function:
bool isUpper(const std::string& s) {
return std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); });
}
bool is_all_upper(const std::string& word)
{
for(auto& c: word)
if(!std::isupper(static_cast<unsigned char>(c)))
return false;
return true;
}
I assume that, if the string is empty, it can be considered all-uppercase.
You shouldn't have two return conditions inside your loop. Rather, you can use the loop to find problems and, if there are no problems, you'll escape the loop and can tell the user that everything was alright at the end.
In the comments you say "i believe it doesn't need to return anything if the string is empty"; however, a function with a return type, such as this one always returns something. If you don't specify a return value it will give you one, whether you like it or not. Therefore, you must decide what the output should be for every conceivable input. Accordingly, I've added an if statement that emphasizes the special condition of an empty string.
#include "UpperCaseFilter.h"
#include "ReadFilteredWords.h"
#include "ReadWords.h"
#include <locale>
bool UpperCaseFilter::filter(const string &word) {
if(word.empty()) //You'll need to do the right thing here
return true;
//Even if the right thing to do were to return true, so that
//the check above would be redundant, you'd want to leave a
//comment here pointing out that you've handled the special case
for(size_t i = 0; i < word.length(); i++)
if(!isupper(static_cast<unsigned char>(word[i])))
return false;
return true;
}
Note that your previous function signature was:
bool UpperCaseFilter::filter(string word) {
I've changed this to:
bool UpperCaseFilter::filter(const string &word) {
The const guarantees that the function will not alter word and the & symbol passes the string to the function without copying it. This makes the function faster and saves memory.
#include "UpperCaseFilter.h"
#include "ReadFilteredWords.h"
#include "ReadWords.h"
#include <locale>
bool UpperCaseFilter::filter(string word)
{
int k=0;
if(!word.empty())
{
for(int i = 0; i < word.length(); i++)
{
if(isupper(word[i]))
k++;
}
}
if(k==word.length())
return true;
else
return false; //this will return false even when word length is 0
}
its more simple now provided if you have done other things right this would run.
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
string str;
cin >> str;
bool flag = false;
int i = 0;
while(str[i])
{
if(isupper(str[i]))
{
flag = true;
}
if(!(isupper(str[i])))
{
flag = false;
break;
}
i++;
}
if(flag == false)
cout << "false" << endl;
else
cout << "true" << endl;
}
#include <iostream>
#include <string>
#include <boost/algorithm/string.hpp>
bool IsAllUpperString(string str)
{
if(boost::to_upper_copy(str)== str) return true;
return false;
}