Why is my program unable to sort integer strings? - c++

I was trying to solve a very simple coding question:
Consider an array of numeric strings where each string is a positive
number with anywhere from 1 to 10^6 digits. Sort the array's elements in
non-decreasing, or ascending order of their integer values and print
each element of the sorted array on a new line.
The first line contains an integer n denoting the number of strings
Each of the n subsequent lines contain an INTEGER STRING.
My code is:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i; string s;
cin >> i;
int j = i;
string arr[i];
int cntr = 0;
while (i--){
cin >> s;
arr[cntr] = s;
cntr++;
}
sort(arr, arr+j);
for (auto c: arr)
cout << c << endl;
}
The input is
6
31415926535897932384626433832795
1
3
10
3
5
And my output turns out to be:
1
10
3
3
31415926535897932384626433832795
5
If I make an array and add integer strings to it manually, the above code works fine. Then why is it producing wrong result when it takes input from the website?
PS: Here's the link to the problem:https://www.hackerrank.com/challenges/big-sorting/problem

Firstly use a vector of strings instead of a variable size array of strings (which is not allowed in C++).
The STL sort function uses lexicographical search to sort strings by default. You need to pass your own comparison function in order to sort the integer strings numerically.
Assuming the integer strings don't have leading 0's;
sort(arr.begin(), arr.end(), [] (const string& s1, const string& s2) {
return s1.size() < s2.size() || (s1.size() == s2.size() && s1 < s2);
});

I will give you an alternative solution as C++ already have sorted containers.
Some hints:
Please do not use "using namespace std;"
C++ did not have variable length arrays! So it is much easier to use a container type! In the example, we use a std::multimap which can have elements sorted and allows duplicates.
#include <iostream>
#include <map>
// we want to use our own sorting algorithm for std::multimap
// this needs a functional object with operator() which do the compare
//
// works only for non negative numbers without leading '0's
struct compare
{
bool operator()( const std::string& s1, const std::string& s2 ) const
{
// if the string contains a number as text, we can asume that
// a number which has less characters is lesser
if ( s1.size() < s2.size() ) return true;
// if the size is bigger, the numerical value is bigger
if ( s1.size() > s2.size() ) return false;
// if both are equal length
// so we simply compare lexigraphical
// this works because a bigger diggit char always means a
// bigger numerical value
return s1 < s2;
}
};
int main()
{
// instead of later sort, we use a sorted container, multiset because we can use duplicates
std::multiset<std::string, compare> data;
// read data as in your code
int numberOfElementsToRead;
std::string tmpInput;
std::cin >> numberOfElementsToRead;
while (numberOfElementsToRead--)
{
std::cin >> tmpInput;
data.insert( tmpInput ); // insert automatically sorts
}
// print out the container
for ( auto& s: data )
{
std::cout << s << std::endl;
}
}

This won't work:
int i;
cin >> i;
string arr[i];
If you need to dynamically resize an array, use std::vector (or new/delete if you really must).
int i;
cin >> i;
std::vector<std::string> arr(i);
In terms of why the sorting fails, you are sorting the numbers alphabetically, which means anything with a '1' at the front will appear first. Sort based on the numeric value instead:
auto compareStringsNumerically = [](const std::string& a, const std::string& b) {
return std::stoi(a) < std::stoi(b); //< compare integer values
};
std::sort(arr, arr + j, compareStringsNumerically);

Related

Finding 3 or more duplicates in array

I need write a program which checks if there are 3 or more matching numbers in an array. My code works fine until there is an array like "2 2 3 3 5 5 4 4 1 1", then it approves that there are 3 or more duplicates in the array which is not true. Maybe someone knows a simple solution which would help me? Or do I need to overwrite my code?
Here is my code:
#include <iostream>
using namespace std;
void funk(int n, int a[], int &kiek);
int main()
{
int n, a[101],kiek=0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
funk(n, a, kiek);
if (kiek > 2) {
cout << "TAIP";
}
else
cout << "NE";
}
void funk(int n, int a[], int &kiek)//funkcijos kūnas
{
int j;
for (int i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (a[i] == a[j])
kiek++;
cout << kiek;
}
}
}
This is the input:
10
2 2 3 3 5 5 4 4 1 1
This is the output I need to get:
NE
The problem that your code has is:
You are comparing any 2 numbers and never reset the counter. So if there is an 1 1, you are increasing the counter. If there is then an 2 2 you are also increasing the counter. And for the final 3 3 you also increase the same counter. Then it is 3. Although there are only 2 same values. This can never work. What you could do is
Read all values
Count the frequency of EACH different value
Check if the frequency of the values
If any of the counts is greater than 2, then show corresponding message
Show count of each value
I will show you the "more-modern" C++ approach and will use C++ algorithms for the below example solution.
First we will get the number of values to work with from the user. We will store the values in a std::vector. And, we use std::copy_n to copy the values from std::cin to our std::vector. For that we will use the std::istream_iterator that will iterate over the elements given by the user. So, we use a simple one-liner to read all values from the user.
Next is the frequency counting. For this we have a standard solution in C++. You will find it in dozens of places in the net. We will use a std::map. The key is the integer that we read into the vector and the value is the counter. With the std::map's index operator [] we add a value to the map, if it is not yet existing. With the ++ we simply do the counting, whether the value was already in the std::map or has just been added. Also this is a very simple one-liner.
Then, we check, if any of the counts is greater than 2. For this we will use the STL algorithm std::any:of with a very simple lambda. With that, we can create your desired result.
Last, but not least, we show all values and their count, if the count is greater than 2. This we do with an ultra simple range based for loop. We extract the values out of the counter-std::map using structered bindings.
Please see:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
int main() {
// Give instructions
std::cout << "How many values do you want do read? Please specify: ";
// Read the number of values to enter
size_t numberOfValues{ 0U }; std::cin >> numberOfValues;
// Read the given number of values from std::cin
std::vector <int> values(numberOfValues);
std::copy_n(std::istream_iterator<int>(std::cin), numberOfValues, values.begin());
// Count each value
std::map<int, size_t> counter{};
std::for_each(values.begin(), values.end(), [&counter](const int& i) { counter[i]++; });
// Check, if any count is bigger than 2
if (std::any_of(counter.begin(), counter.end(), [](const std::pair<int, size_t> & c) { return c.second > 2; }))
std::cout << "TAIP\n";
else
std::cout << "NE\n";
// Look, if there is any number with a count bigger than 2 and show the result
for (const auto& [value, count] : counter)
if (count > 2) std::cout << value << " --> " << count << "\n";
return 0;
}
I hope this gives you an idea on how this could be done . . .

Error with a vector when I did permutation

I am trying to permutate my numbers in the vector.
Below are my codes. This code is very simple. Firstly, the input size of a vector is determined by user-input. And then, all the numbers in the vector are permutated in order to find the maximum integer value and minimum integer value when I concatenated all the numbers into one string.
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
string retS(const vector<int>& v)
{
string s = "";
for (int e : v) {
s += to_string(e);
}
return s;
}
int main(void) {
int num = 0;
cin >> num;
vector<int> numbers;
for (int i = 0; i < num; ++i) {
int n;
cin >> n;
numbers.push_back(n);
}
sort(numbers.begin(), numbers.end());
unsigned long long maxVal = 0;
unsigned long long minVal = 987654321;
do {
string s = retS(numbers);
if (stoll(s) > maxVal) {
maxVal = stoi(s);
}
if (stoll(s) < minVal)
minVal = stoi(s);
} while (std::next_permutation(numbers.begin(), numbers.end()));
cout << maxVal+minVal << endl;
}
However, the problem is that the error occurred when I inputted two digit numbers. For example, I inputted 10 20 30 40 50 60 70 80 90 20 into my vectors, then my codes didn't work. I think it is because the range of integer variable because the concatenated string can be a size of 20(~up to 20) if I assume only one or two digit number can be accepted.
Therefore, I changed my integer variable into unsigned long long type from int, which is, i think, the longest range value for storing integer type, but, the program was aborted when I executed.
So, Can you help me to have this code work well?
As Zereges noted the problem here is that you are trying to store a number that exceeds the capacity of the biggest numeric variable type that C++ has built-in. You can solve this problem storing such long numbers as strings. This will solve the problem you have, but it will make your code a bit slower.
If you don't want to fight with strings more than necessary this could help you: https://mattmccutchen.net/bigint/ It's a library to work with big integers.
Hope this helps
Sorry, I have made a mistake in my post.
---The Begining of the Mistake---
Firstly, below statement perhaps may not function as you expect.
sort(numbers.begin(), numbers.end());
According to this, sort() sorts the elements in the range [first,last) into ascending order. In fact, there is the same problem for std::next_permutation().
There indeed is a difference between parentheses and square brackets. [ means >= while ) means <. According to your code, the last element would not be sorted.
---The End of the Mistake---
I have just discovered that end() does not return an iterator referring to the last element in the vector container, but the past-the-end element, which is the theoretical element that would follow the last element in the vector.
Moreover, I see you have declared two unsigned long long to hold the values.
unsigned long long maxVal = 0;
unsigned long long minVal = 987654321;
It seems that 987654321 is the upper limit of the value you would like to store. However, there are few potential problems in your code which may make the value's upper bound fails.
(1) The upper limit is not applied to maxVal.
if (stoll(s) > maxVal) { //may add a upper boundary for maxVal
maxVal = stoi(s);
}
(2) The functions of stoll() and stoi() returns a long long and an int respectively. In case, a number greater than the upper limit of long long and int is caught, the above 2 functions will throw std::out_of_range exception. This is a restriction in using the functions. It seems this was the run-time error you have encountered. In addition, though you have tried to declare unsigned long long to store the values, it does not release the restriction in using the 2 functions.
To fix it, you may try the suggestion from Carlos.
Below is a possible implementation of the suggestion from Carlos.
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
string retS(const vector<int>& v)
{
string s = "";
for (int i = 0; i < v.size(); i++) {
s += to_string(v.at(i));
}
return s;
}
//prone to error
bool str1GreaterThanStr2(const string str1, const string str2)
{
if (str1.size() != str2.size())
return (str1.size() > str2.size());
int cursor = 0;
while (cursor < str1.size())
{
if (str1.at(cursor) != str2.at(cursor))
return (str1.at(cursor) > str2.at(cursor));
cursor++;
}
return false; //if both string are the same
}
int main(void) {
int num;
vector<int> numbers;
cin >> num;
for (int i = 0; i < num; ++i) {
int n;
cin >> n;
numbers.push_back(n);
}
sort(numbers.begin(), numbers.end());
string maxStr = retS(numbers);
string minStr = retS(numbers);
while (std::next_permutation(numbers.begin(), numbers.end()))
{
string str = retS(numbers);
maxStr = str1GreaterThanStr2(str, maxStr) ? str : maxStr;
minStr = str1GreaterThanStr2(str, minStr) ? minStr : str;
}
cout << maxStr << endl;
cout << minStr << endl;
}
/*
test case tried:
10
10 20 30 40 50 60 70 80 90 20
*/
Hope this helps.

How to parse a user's input and store each individual character as a string

Okay so I'm working a calculator program that takes in a user input(ex. "(3+(4+12))"), and I need to parse the user's input and store it in an array of strings but I am having trouble doing so. My code currently is this
void parseInput(string input) {
vector <string> input_vector;
for(int i = 0; i < input.size(); ++i) {
if(isdigit(input.at(i)) == 0 && isdigit(input.at(i + 1)) == 0) {
++i;
input_vector.push_back((input.at(i) + input.at(i+1)));
}
else {
input_vector.push_back(input.at(i));
}
}
for(int i = 0; i < input_vector.size(); ++i) {
cout << endl << input_vector[i];
}
}
I know my problem is coming from trying to add a char to an vector of strings, but how would I get each char in the string and keep it as a string to store into my vector. Or is there a better way to parse this out??
edit
Okay so what I am having the most trouble with is the problems that come from the 12 splitting up into two separate chars "1 * 2" How would I go about so that it represents 12 and doesn't split it up???
Here is a solution (using c++11):
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main() {
std::string const input = "(3+(4+12))";
std::vector<std::string> chars(input.length());
// Maps each character of `input` to `std::string`
// with that character and saves the results in
// corresponding position in `chars` vector:
std::transform(input.cbegin(), input.cend(), chars.begin(),
[](char c) {
// One of the ways to cast `char` to `std::string`:
return std::string(1, c);
});
// To be sure it works properly, it prints
// generated strings:
for (size_t i = 0; i < chars.size(); ++i) {
std::cout << chars[i];
}
std::cout << std::endl;
}
The answer is u need to split the string into tokens, i have given an example which will add 4 to 12, to make it 16, but think that the string does'nt have any brackets, suppose if the user entered 4+12 and u need to add it you can do the following:
char string[10], nstr[10];
int p=0, a=0, b=0, op=0;
cin>>string; // input string
While (string[i]!='+' || string[i]!='-')
{
nstr[p]=string[i]; // copy the contents of string to nstr.
p++;
i++;
}// loop exits if the string[i] reaches to the operator (+/-*).
nstr[p]='\0';
a=atoi(nstr);// convert the string to integer.
op=i;// this will hold the position of array of the operator in the string.
i++;
p=0;
while (string[i]!='\0')
{
nstr[p]=string[i];// this will copy the contents of the string after the operator.
i++;
p++;
}
nstr[p]='\0';
b=atoi(nstr);
if (string[op]=='+')// check what the user want to do. Add/subtract/divide etc.
c=a+b;
else if (string[op]=='-')
c=a-b;
This program is not tested but will work, if not then use the logic in your program, like i did in my program, this will not take 1 and 2 sepratly, instead it will take 4 and 12, you can type more charaters but is limited to long, i used int here to get the return value of atoi(), hope this helps u...

checking whether an element at a certain position exists (is set) in a STL vector

I'm writing an algorithm which takes random strings as input. I need to output the maximum length encountered and also how many words have that particular length. YES, I know I can use a different approach but I was thinking to store each string in a v[it's length] and if there are multiple strings with the same length then I would increment u[same length], then just output those values. How can I check whether v[length] is already set?
Sorry for possible bad English.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef unsigned short us;
typedef vector<string> vstr;
typedef vector<us> vus;
int main()
{
string str;
vstr v;
vus u(50, 1);
us len;
while (cin >> str && str != "0")
{
len = str.length();
//if there is an element set at v[len] then ++u[len] otherwise v[len] = str;
}
//bunch of other code
return 0;
}
YES, I know I can use a different approach
Honestly, I really believe you'd be better off following a different approach then.
You don't need a vector of lengths at all, nor a map, and neither you need a vector of strings unless you want to display those strings as well (here, I will assume you do need it). Finally, you don't even need to know the maximum length of those strings:
#include <iostream>
#include <vector>
#include <string>
int main()
{
std::vector<std::string> words;
std::string::size_type maxLength = 0;
std::string str;
while (std::cin >> str)
{
auto len = str.length();
if (len == maxLength)
{
words.push_back(str);
}
else if (len > maxLength)
{
maxLength = len;
words.clear();
words.push_back(str);
}
}
std::cout << "Max length: " << maxLength << std::endl;
std::cout << "# of words with max length: " << words.size() << std::endl;
std::cout << "Words with max length: " << std::endl;
for (auto const& s : words) { std::cout << s << std::endl; }
return 0;
}
This won't work unless you know the maximum length of any possible string beforehand. Let's call this maximum X. Then you can construct a vector of X ints, initialized to 0, and just increment the one you need using the subscript operator.
std::vector<int> counts(X, 0); // X ints, initialized to 0
for (const string str : v) {
int length = str.size();
try {
counts.at(length)++;
} catch (const std::out_of_range& oor) {
// Your professor lied to you!
}
}
The way I would approach this problem would be to use a map. Then you can just do the following:
std::map<int, int> counts;
for (const string str : v) {
int length = str.size();
++counts[length];
}
counts[length] will create the element at [length] if it doesn't exist already, and will increment it if it already exists.
A std::vector v has a length given by v.size(), and all elements in the range [0,v.size()) exist.
So an element exists at v[n] if v.size() > n
You can test for it either by checking the vector's length, or accessing the element with v.at(n) instead of v[n] because the at() function will throw an exception if the element doesn't exist (that is, if the length is not at least n)
The fact a std::vector contains an element at every index up to its length means it is not an efficient representation of a sparse array To represent a sparse array with one of the standard containers it is better to use std::map because it doesn't require elements to have contiguous keys.

How to generate lexicographical strings of a given length?

How to generate lexicographical strings of a given length?
I am looking for an algorithm to generate strings (lexicographic order) of length N, in lexicographical order. For example given a length 1, the strings generated are: "a","b","c","d","e","f",g,h,i,j,k...,z.
For length 2, the strings generated should be: "aa","ab","ac","ad",...,"ba","bb",...,"zz".
How could we do this?
Here is what I have done:
void permute(string a, int i, int n, int length)
{
int j;
if (i == length){
string cand = a.substr(0,length);
cout<<cand<<endl;
}
else
{
for (j = i; j <= n; j++)
{
swap((a[i]), (a[j]));
permute(a, i+1,n,length);
swap((a[i]), (a[j]));
}
}
}
While calling "permute(a,0,a.size(),1)" where the string a looks like this:
aaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbccccccccccccccccccccddddddddddddddddddddeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffgggggggggggggggggggghhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiijjjjjjjjjjjjjjjjjjjjkkkkkkkkkkkkkkkkkkkkllllllllllllllllllllmmmmmmmmmmmmmmmmmmmmnnnnnnnnnnnnnnnnnnnnooooooooooooooooooooppppppppppppppppppppqqqqqqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrrrrrrssssssssssssssssssssttttttttttttttttttttuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvwwwwwwwwwwwwwwwwwwwwxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyzzzzzzzzzzzzzzzzzzzz
Generates the correct output but it's repeating the lexicographic strings. If I reduce it to just alphabets I believe strings like "aa", "aaaa" will be missed. So how could we get around this,Any ideas?
I would do a recursive call into a function that simply loops through the alphabet, and call it for each letter placement.
Preliminary testing shows this may work:
#include <iostream>
#include <sstream>
#include <string>
void addLetters(std::string base, int tgt_depth)
{
if (base.length() == tgt_depth) {
std::cout << base << std::endl;
return;
}
for (char letter = 'a'; letter <= 'z'; ++letter) {
std::stringstream ss;
ss << letter;
addLetters(base + ss.str(), tgt_depth);
}
}
int main(int argc, char* argv)
{
// first argument is your "base" -- start with nothing
// second argument is the depth to which to recurse, i.e. how many letters
addLetters("", 2);
}
Assuming you want to see which string is in place M in the lexicographical order of these strings, represent this number in base 26 and than map 0 to a, 1 to b and so on. You will have to add zeros(or a-s) to the left until the string reaches the needed length. Now to solve your problem simply iterate through the integers(up to the number of string of length N which is 26N) and apply the conversion I suggest.
for(i='a';i<='z';i++)
{
recur(new String(i));
}
void recur(String s)
{
if(s.length()==dig)
{
add s to array
return
}
for(i='a';i<='z';i++)
recur(s+i);
}
Although this code is not feasable enough to generate more than 5 digits because there are 26^dig possibilities.And I dont know c++ so i have written the algorithm . But i feel there is nothing in it that a coder i a language cant convert