How can I pass a substring by reference? - c++

I call recursively a function passing as argument a substring which always starts from the beginning of the current string up to a position. If I was using C, I could pass the pointer to the first position of the string and then the necessary length. Nevertheless, I would like to achieve the same result using the class string. Is it possible? If I use const, is the compiler smart enough to make the optimization on its own? Even better, is there a way to check on my own whether the compiler actually makes a copy of the argument or passes a reference?
My question was motivated after having written the following code which passes the tests on problem Alphacode on poj, once someone uses atoi instead of atof.
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#include <string>
using namespace std;
map<string, int> cache;
bool valid_character_number(string a) {
return 0 < stoi(a.substr(a.size() - 2, 2)) && stoi(a.substr(a.size() - 2, 2)) <= 26;
}
bool zero_last_digit(string a) {
return a[a.size() - 1] == '0';
}
bool zero_before_last_digit(string a) {
return a[a.size() - 2] == '0';
}
int decodings(string a) {
if (a.size() == 0)
return 1;
if (a.size() == 1) {
if (zero_last_digit(a))
return 0;
else
return 1;
}
if (cache.find(a) != cache.end())
return cache[a];
if (zero_last_digit(a) && valid_character_number(a))
return cache[a] = decodings(a.substr(0, a.size() - 2));
else if (valid_character_number(a) && !zero_before_last_digit(a))
return cache[a] = decodings(a.substr(0, a.size() - 1)) + decodings(a.substr(0, a.size() - 2));
else
return cache[a] = decodings(a.substr(0, a.size() - 1));
}
int main() {
string input;
while (true) {
cin >> input;
if (input.size() == 1 && stoi(input) == 0)
return 0;
cout << decodings(input) << endl;
}
return 0;
}

You cannot use std::string for this purpose, but you can easily make a class of your own that holds a pair of iterators (begin and end) into another string, or a C-style char* and size. With C++11 (since you tagged it), you should even be able to make a User Defined Literal syntax for creating strings of your new type.

You can use your own wrapper class like this one:
struct RefString
{
RefString(const std::string & s, int i, int l) : s(s), i(i), l(l) {}
const char & operator [] (int x) const {
return s[i+x];
}
size_t length() const {
return l;
}
bool operator < (const RefString & s2) const {
return s.compare(i, l, s2.s, s2.i, s2.l) < 0;
}
private:
const std::string & s;
int i;
int l;
};
std::ostream & operator << (std::ostream &stream, const RefString & ms) {
for (int i = 0; i < ms.length(); i++)
stream << ms[i];
return stream;
}
And use it like this, for example for creating set of unique substrings:
std::string s = "hello";
std::set<RefString> st;
for (int i = 0; i < s.length(); i++)
for (int j = i; j < s.length(); j++)
st.insert(RefString(s, i, j-i+1));

Related

Convert integer to binary string with variable size

Suppose I want to get every combination of 1's and 0's with length n. For example, if n = 3, then I want
000
001
010
011
100
101
110
111
My initial thought was to use something like:
#include <iostream>
#include <bitset>
#include <cmath>
int main() {
int n = 3;
for (int i = 0; i < pow(2, n); i++)
std::cout << std::bitset<n>(i).to_string() << '\n';
}
but this does not work since std::bitset takes a const, whereas I need n to be variable (for example if I am in a loop).
How can I do this?
A straightforward way: Extract each bits using bitwise shift operation.
#include <iostream>
int main() {
int n = 3;
for (int i = 0; i < (1 << n); i++) {
for (int j = n - 1; j >= 0; j--) {
std::cout << ((i >> j) & 1);
}
std::cout << '\n';
}
return 0;
}
Note that this method will work only if n is small enough not to cause an integer overflow (1 << n doesn't exceed INT_MAX).
To generate larger sequence, you can use recursion:
#include <iostream>
#include <string>
void printBits(int leftBits, const std::string& currentBits) {
if (leftBits <= 0) {
std::cout << currentBits << '\n';
} else {
printBits(leftBits - 1, currentBits + "0");
printBits(leftBits - 1, currentBits + "1");
}
}
int main() {
int n = 3;
printBits(n, "");
return 0;
}
C++20 format to the rescue:
int main()
{
int p;
while (std::cin >> p) {
std::cout << std::format("--------\n2^{}\n", p);
auto n = 1 << p;
for (int i = 0; i < n; i++) {
std::cout << std::format("{:0{}b}\n", i, p);
}
}
}
https://godbolt.org/z/5so59GGMq
Sadly for now only MSVC supports it.
It is also possible to declare and use an Integer class with a parametrable number of bits (static variable) like below ? Use is simple :
#include "Integer.hpp"
int main (int argc, char* argn []) {
Integer::set_nbit (3);
Integer i (0);
do {
i.write (std::cout); std::cout << std::endl;
++i;
}
while (!i.is_max ());
if (i.is_max ()) {i.write (std::cout); std::cout << std::endl;}
return 0;
}
The results are those expected :
000
001
010
011
100
101
110
111
And the Integer class is not that complex now (to be completed with other operation than pre-incrementation, operator =, ==...) : using Little Endian Convention internally, and Big Endian convention for outputs (Integer class can be easily extended to an undetermined number of bits Integer)
#include <iostream>
#include <vector>
#include <algorithm>
class Integer {
static int nbit_;
static int nmax_;
public :
static void set_nbit (int s) {nbit_ = s; auto q (1); auto nb (0); while ((nb +1) < nbit_) {q <<= 1;++nb; nmax_ += q;} }
Integer (int i = 0) : val_ (nbit_, 0) {
int q (1);
int siz (0);
while (q <= i) { ++siz; q<<=1;}
if (!siz) return;
if (q > 1) q >> 1;
auto rit (val_.rbegin ());
auto rest (i);
while (rest > 1) {
*rit++ = rest%q ?true:false;
rest -= q;
q >>= 1;
}
if (q) *rit++ = true;
}
Integer (const Integer& i) : val_ (i.val_) {
}
void operator ++ () {
auto carry ((int) 1);
std::find_if (val_.begin (), val_.end (), [&carry] (std::_Bit_iterator::reference b) {
if (!carry) return true;
if (b) {
b = false;
//carry continues to be 1
}
else {
b = true; carry = 0;
}
return false;
});
if (carry) exit (1);
}
operator std::string () const {
std::string str (val_.size (), '0');
auto i (str.begin ());
auto b0 ('0'), b1 ('1');
std::for_each (val_.rbegin (), val_.rend (), [&i, &b0, &b1] (const auto& b) {*i++ = b ?b1:b0;});
return str;
}
void write (std::ostream& os) const{
os << operator std::string ();
}
bool is_max () const {
auto i (val_.begin ());
i = std::find_if (val_.begin (), val_.end (), [] (const auto& b) {return !b;});
if (i == val_.end ()) return true;
return false;
}
//operators == (string), < (int), < (Integer), =, == TO be written
private :
std::vector<bool> val_;
};
int Integer::nmax_ (0);
int Integer::nbit_ (0);

How can i search a pattern in a string and return an iterator?

i want to find a pattern inside a string.using brute-force algorithm
int match(string p, string t) {
size_t n = t.size(), i = 0;
size_t m = p.size(), j = 0;
while (i < n && j < m) {
if (p[j] == t[i]) {
j++; i++;
}
else {
i -= j - 1;
j = 0;
}
}
return i - j;
}
but i am wondering how it worked in std::find_if.If there is a string "abab"and i will find "ab" Should i write my code like thisstring::iterator it=find_if(s.begin(),s.end(),match)? but it does not work,How should i write my code and tell me why?
The title says you want to return an iterator. Iterators can be const or not. Declare two overloads and let the compiler sort it out.
std::string::iterator
match( std::string &p, const std::string& t) {
return (p.begin() + p.find(t));
}
std::string::const_iterator
match( const std::string &p, const std::string& t) {
return (p.begin() + p.find(t));
}

Solving String Factoring

I'm trying to solve a question from kattis as shown here regarding string factorisation. I've tried adjusting my code for quite abit but it still seems theoretically correct. Not sure why it still fails for some of the test cases.
#include <stdio.h>
#include <iostream>
#include <string>
#include <map>
#include <algorithm>
using namespace std;
string shortener (string input) {
map<string, int> freq;
int flag = 0;
for (int i = (input.length())/2; i >= 1 && !flag; i--) {
for (int d = 0; d + i + i <= input.length(); d++) {
if (input.substr(d, i) == input.substr(d + i, i)) {
freq[input.substr(d,i)]++;
flag = 1; // stop at this size
}
}
}
int largest = 0;
if (freq.empty()) return input;
//string largest;
auto x = max_element(freq.begin(), freq.end(),
[](const pair<string, int>& p1, const pair<string, int>& p2) {
return p1.second < p2.second; });
if (x->first == input) return input;
int a = input.find(x->first);
for (int i = 0; i < x->second ; i++) {
input.replace(a, x->first.length(), "");
a = input.find(x->first);
}
if (a != -1) {
if (!input.substr(0, a).empty())
input.replace(0, a, shortener(input.substr(0, a)));
if (!input.substr(a + x->first.length()-1, input.length()-1).empty())
input.replace(a + x->first.length()-1, input.length()-1, shortener(input.substr(a + x->first.length()-1, input.length()-1)));
//cout << input.substr(a + x->first.length()-1, input.length()-1) << endl;
input.replace(a, x->first.length(), shortener(x->first));
}
return input;
}
int main () {
string input;
cin >> input;
cout << shortener(input).length() << endl;
}
I know my code may not be the most efficient, but I'm hoping to find out what kind of test case might potentially break my code.

cpp vector sort runtime error

#include <stdio.h>
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
using namespace std;
int max(int a, int b) {
return a < b ? b : a;
}
bool comp(const string &l, const string &r) {
for (int i = 0; i < max(l.length(), r.length()); i++) {
if (i >= l.length()) return false;
if (i >= r.length()) return true;
if (l[i] < r[i]) return l[i] < r[i];
}
return true;
}
int main(void) {
int N; scanf("%d", &N);
vector<string> v;
for (int i = 0; i < N; i++) {
string s; cin >> s;
v.push_back(s);
}
sort(v.begin(), v.end(), comp);
for (const string& s : v) {
cout << s;
}
cout << endl;
}
In Educational Codeforces Round 9 held on yesterday, I couldn't solve the problem http://codeforces.com/contest/632/problem/C using sort with user-defined function.
I used stl vector containing string and it seems to work on some test cases, but it occurs runtime-error on following testcase.
100
abccaacaacacabbbcbbabcccccacabbaccbcacabcbbbaca
bbbaccbbccbbbcacaabbcccaabcbbcbbbacaacabc
cccabccaaabcaccabccbcccbbaacaaccbb
cccabccaaabcaccabccbcccbbaacaaccbbcb
cccabccaaabcaccabccbcccbbaacaaccbb
cccabccaaabcaccabccbcccbbaacaaccbbbcca
abbbcbbbbbbcccccbcbbb
bbbaccbbccbbbcacaabbcccaabcbbcbbbacaacabcb
abbcacbcabacccbcbabaabcaabcabacbbbbbca
cccabccaaabcaccabccbcccbbaacaaccbbcaa
cbcbbaccacbcababbccaacabacbcabbaccbcbcbcabbc
acbbbbbbbcabbcbcaccccbcbaacccaccabcbaac
bacccabacbbaaa
I can't view the full test input due to codeforces' policy. How do I defeat this situation?
Your comp() predicate doesn't handle the case where l[i] > r[i]. So it returns 1 when comparing "foo" and "boo", and also returns 1 when comparing "boo" and "foo". Therefore, it fails to implement a strict weak ordering (i.e., fails to behave like <=) , and the results of passing it to std::sort() are undefined.
Try to use standard comparison method (not your own bool comp(const string &l, const string &r)), e.g.:
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
#include <functional>
using namespace std;
int main(void) {
int N;
cin >> N;
vector<string> v;
for (int i = 0; i < N; i++) {
string s;
cin >> s;
v.push_back(s);
}
std::sort (v.begin(), v.end(), std::greater<string>());
// or std::less<string>()
for (const string& s : v) {
cout << s << endl;
}
cout << endl;
}
Or change your function to simple one, like:
bool comp(const string &l, const string &r) {
return l < r;
}
Update:
But if you really want to use your own comp function, you should understand that reason why exception invalid operator < occurs because your comparison function (comp) returns true when both relevant fields are equal (this not correct behavior for "less than" required for sort).
And at the end, small tip (it is hardly a solution) - try this for your code:
bool comp(const string &l, const string &r) {
for (int i = 0; i < max(l.length(), r.length()); i++) {
if (i >= l.length()) return false;
if (i >= r.length()) return true;
if (l[i] != r[i]) return l[i] < r[i];
}
return true;
}

own implementation of std::string::find (brute-force search)

I am trying to find the occurrence of string T in string P and return the position of T in P.
This is what I have tried, but it is incorrect:
int bruteForce(string T, string P) {
int n, m;
for (int i = 0; i <= n-m; i++) {
int j = 0;
while (j < m && T[i+j] == P[j]) {
if (j == m) {
return i;
}
return 0;
}
}
}
What am I doing wrong? What am I missing?
In this part:
int n,m;
for (int i=0;i<= n-m;i++) {
you are using uninitialized local variable which results in undefined behavior. Also try to name your variables with something more meaningful than alphabet letters, I think what you actually meant was:
int bruteForce(std::string needle, std::string haystack) {
int needleLen = needle.length(),
haystackLen = haystack.length();
for (int i = 0; i <= needleLen - haystackLen; i++) {
int j = 0;
while (j < haystackLen && needle[i+j] == haystack[j]) {
if(j == haystackLen) {
return i;
}
return 0;
}
}
// return 0; <--
}
also note that in your function doesn't return any value in case when none of needle[i+j] equals haystack[j] (for every i). What about the situation when needle is "ab" and haystack is "aab" ~> while comparing needle[1] with haystack[1], your function would return 0 (it should be placed after for loop)
Another reasonable change would be changing passing by value to passing by reference to avoid copies being created. And since your function doesn't change these strings, its prototype should be:
int bruteForce(const std::string& needle, const std::string& haystack)
And in case you didn't want to intentionally create own implementation of std::string::find but yet for some reason you still need it to return 0 on failure (did you think about usage of your function when needle is equal to haystack?) it could look like this:
std::size_t bruteForce(const std::string& needle, const std::string& haystack) {
std::size_t pos = haystack.find(needle);
if (pos != std::string::npos)
return pos;
return 0;
}
...but if this is the case, you wouldn't call it bruteForce, would you? :)
I tried not to alter your code too much. My changes were:
Changed function parameters to const reference to avoid wasteful copies.
The variables n and m weren't initialized.
The inner while loop had problems. It didn't increment j and the test for success makes more sense outside the loop.
The return value for failure can't be 0 as that may be a valid position.
Modified code (briefly tested and seems to work):
int bruteforce(const std::string &T, const std::string &P)
{
int n = T.length();
int m = P.length();
for (int i = 0; i <= n-m; ++i) {
int j = 0;
while (j < m && T[i+j] == P[j]) {
++j;
}
if (j == m) { // match found
return i;
}
}
return -1;
}