cpp vector sort runtime error - c++

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

Related

sorting of map stl in c++; error: not match for operator -

I am getting an error stating 'no match for operator-'. It is happening when I am using the sort() function.
#include <bits/stdc++.h>
using namespace std;
bool comp(pair<char, int> &a, pair<char, int> &b)
{
return a.first < b.first ? 1 : -1;
}
int main() {
// your code goes here
int t;
cin >> t;
while (t--)
{
string s;
cin >> s;
map<char, int> m;
for(int i = 0; i < s.size(); i++)
{
m[s[i]]++;
cout << (char)s[i];
}
cout << "hello";
sort(m.begin(), m.end(), comp);
}
return 0;
}
std::sort() wants random-access iterators, but std::map iterators are not random-access, so you can't call std::sort() on a std::map, as they don't implement operator-.
std::map is a sorted container, sorted on its keys. And since your keys are simple char, they are already comparable as-is.
The correct way to custom sort a std::map is to either:
provide a comparator directly in the map declaration, eg:
#include <bits/stdc++.h>
using namespace std;
struct comp {
bool operator()(const char &a, const char &b) const {
return a < b; // or whatever you want...
}
};
int main() {
// your code goes here
int t;
cin >> t;
while (t--) {
string s;
cin >> s;
map<char, int, comp> m;
for(int i = 0; i < s.size(); i++) {
m[s[i]]++;
cout << s[i];
}
cout << "hello";
}
return 0;
}
Provide an operator< for the key type. You can't overload operators for fundamental types, but you can for custom types:
#include <bits/stdc++.h>
using namespace std;
struct my_key {
char value;
my_key(char ch) : value(ch) {}
bool operator<(const char &rhs) const {
return value < rhs.value; // or whatever you want...
}
};
int main() {
// your code goes here
int t;
cin >> t;
while (t--) {
string s;
cin >> s;
map<my_key, int> m;
for(int i = 0; i < s.size(); i++) {
m[s[i]]++;
cout << s[i];
}
cout << "hello";
}
return 0;
}

What's the most efficient way to calculate frequency of each letter in a string C++?

I was asked to do a task to count for each letter in the string how many times it occurs in it. It's assumed that all characters are alphabetical lower-case English letters. Also I should output string letters in ascending order, along with the frequency of each. I've tried to do so using std::set like the code below:
#include <iostream>
#include <set>
#include <string>
int main() {
std::string s;
std::cin >> s;
int cnt[26] = {};
for (int i = 0; i < s.length(); i++) {
cnt[s[i] - 'a']++;
}
std::set <char> st;
for (int i = 0; i < s.length(); i++) {
st.insert(s[i]);
}
for (auto x : st) {
std::cout << x << " : " << cnt[x - 'a'] << std::endl;
}
return 0;
}
You can omit std::set and just write like so
int main() {
std::string s;
std::cin >> s;
int cnt[26] = {};
for (int i = 0; i < s.length(); i++) {
cnt[s[i] - 'a']++;
}
for (int i = 0; i < 26; ++i)
if (cnt[i] > 0)
std::cout << (char)('a' + i) << " : " << cnt[i] << std::endl;
return 0;
}
Instead saving in the std::set, we check the presence of a character in the cnt and to output if a symbol was.
This option takes less memory.
You could have used std::map, something like:
std::map<char, int> mymap;
for (auto &c: s){
mymap [c]++;
}
You can use map to store key -> no occurances, then move that pairs to vector and sort, the code below:
std::vector<std::pair<char, int>> getSortedChars(std::string const& input) {
std::map<char, int> m;
std::vector<std::pair<char, int>> vp;
for (char c : input) {
++m[c];
}
for (auto e : m) {
vp.emplace_back(std::move(e));
}
std::sort(vp.begin(), vp.end(), [=](std::pair<char, int>& l, std::pair<char, int>& r) {
return l.second < r.second;});
return vp;
}
The returned vector will have sorted pairs, then you can just print them.
#include<iostream>
#include<algorithm>
#include<string>
#include<vector>
using namespace std;
bool sortbysec(const pair<int,int> &a,const pair<int,int> &b)
{
return (a.second < b.second);
}
int main(){
int len,cntS[26]={0},nonZero=0;
string s;
vector< pair<char,int> >v;
cin>>s;
len=s.length();
for(int i=0;i<len;i++){
cntS[s[i]-'a']++;
}
for(int i=0;i<26;i++){
if(cntS[i]!=0){
nonZero++;
v.push_back(make_pair(char(i+'a'),cntS[i]));
}
}
// Using sort() function to sort by 2nd element
// of pair
sort(v.begin(), v.end(), sortbysec);
for(int i=0;i<v.size();i++){
cout<<v[i].first<<v[i].second<<" ";
}
return 0;
}

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.

Finding repeated points in 2D plane

I am trying to find repeated points from a given 10 points, where each points has x and y values. I have written the below code but can not get correct results. The output should be {3,5},{4,2},{2,4},{7,8}
#include <iostream>
#include<stdlib.h>
using namespace std;
struct point
{
int x;
int y;
};
void distinctPoints(point arr[], int size)
{
cout<<"Repeated Points"<<endl;
cout<<"x, y"<<endl;
for(int i = 0; i< size; i++)
for(int j = i+1; j< size; j++)
{
if ((arr[i].x==arr[j].x) && (arr[i].y==arr[j].y))
{
cout<<arr[j].x <<", "<<arr[j].y<<endl;
break;
}
}
}
int main()
{ int size=10;
point points[size]={{3,5},{4,2},{2,4},{3,5},{7,8},{7,8},{4,2},{7,8},{3,5},{2,4}};
distinctPoints(points, size);
return 0;
}
Your approach (once corrected, as VHS's answer did) could be fine for a small number of points, but, with a bigger set of data, an O(N2) algorithm could be too inefficient.
You can take advantage of the average costant time that takes inserting an element in a std::unordered_set, even if you are required to write a comparison function and an hash function for your class.
The algorithm presented below uses two unordered_set's:
uniques ends up storing all the elements that are present in the source container, without repetitions.
repeated stores a unique instance of only the elements that are present multiple times.
An element is copied to the output only if it's already present in uniques, but not in repeated.
#include <iostream>
#include <vector>
#include <unordered_set>
#include <algorithm>
#include <iterator>
struct point
{
int x, y;
bool operator== (point const& b) const
{
return x == b.x && y == b.y;
}
};
namespace std {
template<> struct hash<point>
{
std::size_t operator() (point const& p) const
{
return (std::hash<int>{}(p.x) << 1) ^ std::hash<int>{}(p.y);
}
};
}
std::ostream& operator<< (std::ostream& os, point const& pt)
{
return os << '(' << pt.x << ", " << pt.y << ')';
}
template<class InputIt, class OutputIt>
OutputIt copy_repeated_values(InputIt first, InputIt last, OutputIt dest)
{
using value_type = typename InputIt::value_type;
std::unordered_set<value_type> uniques, repeated;
return std::copy_if(
first, last, dest, [&] (value_type const& value) {
return
not uniques.insert(value).second &&
repeated.insert(value).second;
}
);
}
int main()
{
std::vector<point> points {
{3,5}, {4,2}, {2,4}, {3,5}, {7,8}, {7,8}, {4,2}, {7,8}, {3,5}, {2,4}
};
copy_repeated_values(
std::begin(points), std::end(points),
std::ostream_iterator<point>(std::cout, " ")
);
std::cout << '\n';
}
The output is:
(3, 5) (7, 8) (4, 2) (2, 4)
I have tweaked your distinctPoints method so that it doesn't print the duplicates multiple times even if the dups appear more than twice. See the following edits:
void distinctPoints(point arr[], int size)
{
point dups[size];
cout<<"Distinct Points"<<endl;
cout<<"x, y"<<endl;
for(int i = 0; i < size; i++)
for(int j = 0; j < size; j++) {
if ((arr[i].x==arr[j].x) && (arr[i].y==arr[j].y)) {
if(j < i) {
break;
}
else if( j == i) {
continue;
}
else {
cout<<arr[i].x <<", "<<arr[i].y<<endl;
break;
}
}
}
}
This should do what you are trying to achieve, I am making use of set and maps in c++ which takes care of unique entries.
The map keeps track of already visited points.
#include <iostream>
#include<stdlib.h>
#include <set>
#include <map>
using namespace std;
struct point
{
int x;
int y;
};
map<pair<int, int>, int> mapCountOfPoints;
set<pair<int, int> > disPoints;
void distinctPoints(point arr[], int size)
{
for(int i=0; i<size; i++) {
pair<int, int> temp = make_pair(arr[i].x, arr[i].y);
if(mapCountOfPoints.find(temp) != mapCountOfPoints.end()) {
disPoints.insert(temp);
} else {
mapCountOfPoints[temp] = 1;
}
}
// Now we will iterate over the set to get the distinct set of points
for(set<pair<int, int>>::iterator it=disPoints.begin(); it!=disPoints.end(); it++) {
cout<<it->first<<" "<<it->second<<endl;
}
}
int main()
{ int size=10;
point points[size]={{3,5},{4,2},{2,4},{3,5},{7,8},{7,8},{4,2},{7,8},{3,5},{2,4}};
distinctPoints(points, size);
return 0;
}
Hope this helps!

How can I pass a substring by reference?

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