String function optimisation? - c++

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');
}

Related

Iterate a string until int or char

I want to make to two vectors from a string.
from :
std::string input = "82aw55beA1/de50Ie109+500s";
to :
std::vector<int> numbers = {82,55,1,50,109,500};
std::vector<char> notNumbers = {'a','w','b','e','A','/','d','e','I','e','+','s'};
How do I do this in the most efficient time complexitie?
You can make one pass over the string. You need to know if you're currently parsing a digit or not, whether you're "in" a number, and the current number you're in.
It's a pretty straightforward process, but if you have questions, please ask.
#include <string>
#include <vector>
#include <iostream>
#include <cctype>
int main() {
std::string input = "82aw55beA1/de50Ie109+500s";
std::vector<int> numbers;
std::vector<char> notNumbers;
int currentNumber = 0;
bool inNumber = false;
for (auto ch : input) {
if (std::isdigit(ch)) {
if (!inNumber) {
currentNumber = 0;
inNumber = true;
}
currentNumber = currentNumber * 10 + (ch - '0');
}
else {
if (inNumber) {
numbers.push_back(currentNumber);
inNumber = false;
}
notNumbers.push_back(ch);
}
}
if (inNumber) {
numbers.push_back(currentNumber);
}
for (auto i : numbers) {
std::cout << i << std::endl;
}
for (auto ch : notNumbers) {
std::cout << ch << std::endl;
}
}

How to insert an integer with leading zeros into a std::string?

In a C++14 program, I am given a string like
std::string s = "MyFile####.mp4";
and an integer 0 to a few hundred. (It'll never be a thousand or more, but four digits just in case.) I want to replace the "####" with the integer value, with leading zeros as needed to match the number of '#' characters. What is the slick C++11/14 way to modify s or produce a new string like that?
Normally I would use char* strings and snprintf(), strchr() to find the "#", but figure I should get with modern times and use std::string more often, but know only the simplest uses of it.
What is the slick C++11/14 way to modify s or produce a new string like that?
I don't know if it's slick enough but I propose the use of std::transform(), a lambda function and reverse iterators.
Something like
#include <string>
#include <iostream>
#include <algorithm>
int main ()
{
std::string str { "MyFile####.mp4" };
int num { 742 };
std::transform(str.rbegin(), str.rend(), str.rbegin(),
[&](auto ch)
{
if ( '#' == ch )
{
ch = "0123456789"[num % 10]; // or '0' + num % 10;
num /= 10;
}
return ch;
} // end of lambda function passed in as a parameter
); // end of std::transform()
std::cout << str << std::endl; // print MyFile0742.mp4
}
I would use regex since you're using C++14:
#include <iostream>
#include <regex>
#include <string>
#include <iterator>
int main()
{
std::string text = "Myfile####.mp4";
std::regex re("####");
int num = 252;
//convert int to string and add appropriate number of 0's
std::string nu = std::to_string(num);
while(nu.length() < 4) {
nu = "0" + nu;
}
//let regex_replace do it's work
std::regex_replace(std::ostreambuf_iterator<char>(std::cout),
text.begin(), text.end(), re, nu);
std::cout << std::endl;
return 0;
}
WHy not use std::stringstream and than convert it to string.
std::string inputNumber (std::string s, int n) {
std::stringstream sstream;
bool numberIsSet = false;
for (int i = 0; i < s; ++i) {
if (s[i] == '#' && numberIsSet == true)
continue;
else if (s[i] == '#' && numberIsSet == false) {
sstream << setfill('0') << setw(5) << n;
numberIsSet = true;
} else
sstream << s[i];
}
return sstream.str();
}
I would probably use something like this
#include <iostream>
using namespace std;
int main()
{
int SomeNumber = 42;
std:string num = std::to_string(SomeNumber);
string padding = "";
while(padding.length()+num.length()<4){
padding += "0";
}
string result = "MyFile"+padding+num+".mp4";
cout << result << endl;
return 0;
}
Mine got out of control while I was playing with it, heh.
Pass it patterns on its command line, like:
./cpp-string-fill file########.jpg '####' test###this### and#this
#include <string>
#include <iostream>
#include <sstream>
std::string fill_pattern(std::string p, int num) {
size_t start_i, end_i;
for(
start_i = p.find_first_of('#'), end_i = start_i;
end_i < p.length() && p[end_i] == '#';
++end_i
) {
// Nothing special here.
}
if(end_i <= p.length()) {
std::ostringstream os;
os << num;
const std::string &ns = os.str();
size_t n_i = ns.length();
while(end_i > start_i && n_i > 0) {
end_i--;
n_i--;
p[end_i] = ns[n_i];
}
while(end_i > start_i) {
end_i--;
p[end_i] = '0';
}
}
return p;
}
int main(int argc, char *argv[]) {
if(argc<2) {
exit(1);
}
for(int i = 1; i < argc; i++) {
std::cout << fill_pattern(argv[i], 1283) << std::endl;
}
return 0;
}
I would probably do something like this:
using namespace std;
#include <iostream>
#include <string>
int main()
{
int SomeNumber = 42;
string num = std::to_string(SomeNumber);
string guide = "myfile####.mp3";
int start = static_cast<int>(guide.find_first_of("#"));
int end = static_cast<int>(guide.find_last_of("#"));
int used = 1;
int place = end;
char padding = '0';
while(place >= start){
if(used>num.length()){
guide.begin()[place]=padding;
}else{
guide.begin()[place]=num[num.length()-used];
}
place--;
used++;
}
cout << guide << endl;
return 0;
}

Palindrome class help in C++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
Hi i am trying to write a palindrome class but am getting the wrong results.
I need to create a Palindrome class and return whether the phrase is a Palindrome.
Here is my code.
Palindrome.h:
#ifndef PALINDROME_H
#define PALINDROME_H
#include <iostream>
#include<cstring>
using namespace std;
class Palindrome{
private:
char str[1024];
char s1[1024];
char s2[1024];
int a;
int b;
public:
Palindrome(char s2[1024], int a, int b)
{
s2[1024] = { 0 };
a = 0;
b = 0;
}
void removeNonLetters(char str[]);
void lowerCase(char s1[]);
bool isPalindrome(char s2[], int a, int b);
}; // End of class definition
#endif
Palindrome.cpp:
#include "Palindrome.h"
void Palindrome::removeNonLetters(char str[])
{
char s1[1024] = { 0 };
int j = 0;
int l1 = strlen(str);
for (int i = 0; i < l1; i++)
{
if (str[i] <= '9' && str[i] >= '0')
{
s1[j++] = str[i];
}
else if ((str[i] >= 'A' && str[i] <= 'Z')
|| (str[i]) >= 'a' && str[i] <= 'z')
{
s1[j++] = str[i];
}
}
cout << s1 << endl;
}
void Palindrome::lowerCase(char s1[])
{
char s2[1024] = { 0 };
int l2 = strlen(s1);
int g = 0;
for (int i = 0; i < l2; i++)
{
if (s1[i] >= 'a' && s1[i] <= 'z')
{
s2[g++] = s1[i];
}
else if (s1[i] >= 'A' && s1[i] <= 'Z')
{
s2[g++] = s1[i] + 32;
}
}
cout << s2 << endl;
}
bool Palindrome::isPalindrome(char s2[], int a, int b)
{
if (a >= b)
return true;
cout << "Yes" << endl;
if (s2[a] != s2[b])
return false;
else
return isPalindrome(s2, a + 1, b - 1);
cout << "No" << endl;
}
Main.cpp:
#include "Palindrome.h"
int main()
{
char str[1024] = { 0 };
char s1[1024] = { 0 };
char s2[1024] = { 0 };
cout << "input a string:" << endl;
cin.getline(str, sizeof(str));
Palindrome removeNonLetters(char str[]);
Palindrome lowerCase(char s1[]);
int length = strlen(s2);
Palindrome isPalindrome(s2, 0, length - 1);
return 0;
}
You teacher may not like this, but this is how we do it in the real world.
First things first, reach for the standard library:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
A function to strip non-alpha characters from a string:
std::string strip(std::string s)
{
s.erase(std::remove_if(std::begin(s),
std::end(s),
[](auto c) { return !std::isalpha(c); }),
std::end(s));
return s;
}
A function to transform a string to lower case:
std::string to_lower(std::string s)
{
std::transform(std::begin(s),
std::end(s),
std::begin(s),
[](auto c) { return std::tolower(c); });
return s;
}
A function to check that a string is the same in reverse as it is forwards:
bool is_palindrome(const std::string& s)
{
return std::equal(std::begin(s), std::end(s),
std::rbegin(s), std::rend(s));
}
Putting it all together in a test:
int main()
{
auto word = std::string("a!b B <>A");
if (is_palindrome(to_lower(strip(word)))) {
std::cout << "palindrome" << std::endl;
}
else {
std::cout << "not palindrome" << std::endl;
}
return 0;
}
Complete listing:
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
std::string strip(std::string s)
{
s.erase(std::remove_if(std::begin(s),
std::end(s),
[](auto c) { return !std::isalpha(c); }),
std::end(s));
return s;
}
std::string to_lower(std::string s)
{
std::transform(std::begin(s),
std::end(s),
std::begin(s),
[](auto c) { return std::tolower(c); });
return s;
}
bool is_palindrome(const std::string& s)
{
return std::equal(std::begin(s), std::end(s),
std::rbegin(s), std::rend(s));
}
int main()
{
auto word = std::string("a!b B <>A");
if (is_palindrome(to_lower(strip(word)))) {
std::cout << "palindrome" << std::endl;
}
else {
std::cout << "not palindrome" << std::endl;
}
return 0;
}
There are many things wrong with your code. I hope these pointers help:
You should be using std library.
Why does the constructor for the class take any parameters? Nothign uses them
Why are there any member variables? Nothing uses them.
Why are the functions in a class at all? They're just functions - they should be in a functions library or similar.
The functions just write to cout so are useless.
Your main function doesn't even seem to call the functions correctly.
I tried this:
char str[1024] = { 0 };
cout << "input a string:" << endl;
cin.getline(str, sizeof(str));
int length = strlen(str);
Palindrome a(str,0, length);
a.removeNonLetters(str);
a.lowerCase(str);
a.isPalindrome(str, 0, length - 1);
cin.getline(str, sizeof(str));
return 0;
I don't get the exception but get the following output:
input a string:
EVIL rats on no star **** live
EVILratsonnostarlive
evilratsonnostarlive
Yes
However this works too:
input a string
hello
hello
hello
Yes
So the first two functions seem to work (if removing spaces was also intentional) but the third does not.

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

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;
}