Is there way to reduce memory consumption in my c++ code? - c++

I am new in c++ and I am trying to solve educational exercise in quiz platform, but in this platform I should use no more than 64 MB of memory. My code use more than 130 MB.
#include <sstream>
#include <string>
#include <fstream>
#include <iterator>
#include <vector>
#include <map>
using namespace std;
template<class Container>
void splitString(const std::string &basicString, Container &cont, char delim = ' ') {
std::stringstream ss(basicString);
std::string token;
while (std::getline(ss, token, delim)) {
cont.push_back(token);
}
}
int main() {
int target = 0;
int count = 0;
std::map<int, int> set;
string line;
ifstream fileR("input.txt");
std::vector<string> c;
if (fileR.is_open()) {
while (getline(fileR, line)) {
if (count == 0) {
target = std::stoi(line);
count++;
continue;
}
splitString(line, c);
for (auto &d : c) {
int key = std::stoi(d);
if (set.count(key)) {
set[key] += 1;
} else {
set[key] = 1;
}
}
c.clear();
}
fileR.clear();
fileR.close();
}
ofstream fileW;
fileW.open("output.txt");
bool found = false;
for (const auto &p : set) {
int d = target - p.first;
if (set.count(d)) {
if (p.first != d || set[d] > 1) {
fileW << 1;
found = true;
break;
}
}
}
if (!found) {
fileW << 0;
}
fileW.close();
return 0;
}
What I can add, remove or change for keep within the coveted 64 MB? I tried free memory manually but no effects. I am not sure that is possible to write more effective algorithm.

Your vector (c) is declared outside the loop and is not cleared every time you call split string. This means every time you pass in a string to split, your vector contains stuff from the previous run. Is this intentional? If it is not, then move your vector into the loop, before you call split string, or clear it in your split string function. If it is intentional please provide more info about what your code is supposed to do.

Related

How to replace "pi" by "3.14"?

How to replace all "pi" from a string by "3.14"? Example: INPUT = "xpix" ___ OUTPUT = "x3.14x" for a string, not character array.
This doesn't work:
#include<iostream>
using namespace std;
void replacePi(string str)
{
if(str.size() <=1)
return ;
replacePi(str.substr(1));
int l = str.length();
if(str[0]=='p' && str[1]=='i')
{
for(int i=l;i>1;i--)
str[i+2] = str[i];
str[0] = '3';
str[1] = '.';
str[2] = '1';
str[3] = '4';
}
}
int main()
{
string s;
cin>>s;
replacePi(s);
cout << s << endl;
}
There is a ready to use function in the C++ lib. It is called: std::regex_replace. You can read the documentation in the CPP Reference here.
Since it uses regexes it is very powerful. The disadvantage is that it may be a little bit too slow during runtime for some uses case. But for your example, this does not matter.
So, a common C++ solution would be:
#include <iostream>
#include <string>
#include <regex>
int main() {
// The test string
std::string input{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Use simply the replace function
std::string output = std::regex_replace(input, std::regex("Pi"), "3.14");
// Show the output
std::cout << output << "\n";
}
But my guess is that you are learning C++ and the teacher gave you a task and expects a solution without using elements from the std C++ library. So, a hands on solution.
This can be implemented best with a temporary string. You check character by character from the original string. If the characters do not belong to Pi, then copy them as is to new new string. Else, copy 3.14 to the new string.
At the end, overwrite the original string with the temp string.
Example:
#include <iostream>
#include <string>
using namespace std;
void replacePi(string& str) {
// Our temporay
string temp = "";
// Sanity check
if (str.length() > 1) {
// Iterate over all chararcters in the source string
for (size_t i = 0; i < str.length() - 1; ++i) {
// Check for Pi in source string
if (str[i] == 'P' and str[i + 1] == 'i') {
// Add replacement string to temp
temp += "3.14";
// We consumed two characters, P and i, so increase index one more time
++i;
}
else {
// Take over normal character
temp += str[i];
}
}
str = temp;
}
}
// Test code
int main() {
// The test string
std::string str{ "Pi is a magical number. Pi is used in many places. Go for Pi" };
// Do the replacement
replacePi(str);
// Show result
std::cout << str << '\n';
}
What you need is string::find and string::replace. Here is an example
size_t replace_all(std::string& str, std::string from, std::string to)
{
size_t count = 0;
std::string::size_type pos;
while((pos=str.find(from)) != str.npos)
{
str.replace(pos, from.length(), to);
count++;
}
return count;
}
void replacePi(std::string& str)
{
replace_all(str, "pi", "3.14");
}

Find sum of numbers in a string without loops in c++

I've found plenty of resources online how how to calculate the sum of numbers in an alphanumeric string, and I've got a working c++ code below.
#include <iostream>
using namespace std;
int findSum(string str)
{
string temp = "";
int sum = 0;
for (char ch: str)
{
if (isdigit(ch))
temp += ch;
else
{
sum += atoi(temp.c_str());
temp = "";
}
}
return sum + atoi(temp.c_str());
}
int main()
{
string str = "t35t5tr1ng";
cout << findSum(str);
return 0;
}
For the example above, "t35t5tr1ng" returns "41".
Now I'm trying to do the same thing, without using any loops.
On the top of my head, I'm thinking arrays, but even then I'm not sure how to parse the values in the array without a for loop of some kind.
Any suggestions or help would be appreciated!
You can use standard algorithms instead of writing loops. Even if it's just a for-loop under the hood, but it can make user code easier to understandby stating the intent.
int findSum(string str)
{
// replace all the non-digits with spaces
std::replace_if(str.begin(), str.end(),
[](unsigned char c) {
return !std::isdigit(c);
}, ' ');
// sum up space separated numbers
std::istringstream iss{str};
return std::accumulate(
std::istream_iterator<int>{iss},
std::istream_iterator<int>{}, 0);
}
Here's a demo.
Here is another solution using std::accumulate:
#include <numeric>
#include <iostream>
#include <string>
#include <cctype>
int findSum(std::string str)
{
int curVal = 0;
return std::accumulate(str.begin(), str.end(), 0, [&](int total, char ch)
{
// build up the number if it's a digit
if (std::isdigit(static_cast<int>(ch)))
curVal = 10 * curVal + (ch - '0');
else
{
// add the number and reset the built up number to 0
total += curVal;
curVal = 0;
}
return total;
});
}
int main()
{
std::string str = "t35t5tr1ng";
std::cout << findSum(str);
return 0;
}

Parsing a text file C++ from specific line to specific line

so, I`m new to c++. My task is parse text file that look like:
RE002%%
RE002%%
RE002%%
RE002%%
RE002%%
RE004%on%
$GPGGA,124749.80,5543.3227107,N,03739.1366738,E,1,08,1.11,147.9635,M,14.4298,M,,*5C
$GPGSV,3,1,10,27,13,078,43,05,31,307,48,16,24,042,43,02,10,267,43*7D
$GPGSV,3,2,10,26,03,031,36,07,75,215,51,09,57,121,53,30,40,234,50*76
$GPGSV,3,3,10,23,29,117,46,04,36,114,46*70
$GPGGA,124749.90,5543.3227105,N,03739.1366737,E,1,08,1.11,147.9664,M,14.4298,M,,*54
RE005%off%
And it continuous for few thousand lines.I need to find where it writes RE004%on% and start processing lines in this loop until it finds RE005%off% and do it over and over until it file ends. I was trying to do it with line.find, but I am pretty sure it is wrong way to solve this problem
#include <iostream>
#include <fstream>
#include <string>
#include <stdlib.h>
using namespace std;
int main() {
string line, dollar, star, Checksum;
float *t0 = NULL;
int tount = 0;
int k;
ifstream logs_("C:/Users/Olya/Desktop/LogGLO.txt");
ofstream tout("outLOGTime.txt");
ofstream pout("outLOGPot.txt");
if (logs_.is_open())
{
while(getline(logs_,line))
{
line.find("RE004%on%")
k = 0;
if
dollar = line.find_first_of('$');
star = line.find_first_of('*');
Checksum = line.substr(line, dollar, star - dollar);
for (size_t i = 0; i < Checksum.size(); i++)
{
}
if (line.substr(0,6) == "$GPGSV")
{
for (size_t i = 0, N = 7; i < line.size(); i++)
{
if (line[i] == ',') k++;
if(k == N)
{
pout << line.substr(i+1,2) << endl;
if ((N += 4) > 19) break;
}
}
}
logs_.close();
}
}
else
cout<<"File is not open"<<'\n';
tout.close();
pout.close();
return 0;
}
Unfortunately your description si very unclear. Also by reading your code, I can really not understand, what you intent to do. And you edited your text and changed description. Not so easy for me
But, I made an educated guess. . .
I read all data between your given delimiters, validate the checksum and split the lines into tokens. Finally I store all the lines-with-Tokens in a vector. Then I filter for a specific value and output a column.
Please stude and try to understand. It is not so complicated.
Thank you
#include <iostream>
#include <regex>
#include <vector>
#include <iterator>
#include <string>
#include <utility>
#include <algorithm>
#include <functional>
#include <numeric>
#include <fstream>
const std::regex re{ R"(\$(.*)\*[abcdefABCDEF\d]{2})" };
const std::regex delimiter{ "," };
using Tokens = std::vector<std::string>;
std::tuple<bool, Tokens> checkString(const std::string& str) {
// Return value of the function. Assume that string is not ok
std::tuple<bool, std::vector<std::string>> result(false, {});
// We want to find a string in the given format
std::smatch sm{};
if (std::regex_match(str, sm, re)) {
// OK, found. Validate checksum
if (std::string s = sm[1];std::stoul(str.substr(str.size() - 2), nullptr, 16) == std::accumulate(s.begin(), s.end(), 0U, std::bit_xor<unsigned char>())) {
// Tokenize string
Tokens tokens(std::sregex_token_iterator(str.begin(), str.end(), delimiter, -1), {});
// Build return value
result = std::make_tuple(true, std::move(tokens));
}
}
return result;
}
int main() {
std::vector<Tokens> csvData{};
// Open file and check if it is open
if (std::ifstream logs("r:\\LogGLO.txt"); logs) {
// Shall we process text lines or not
bool processingActive{ false };
// Read all lines of files
for (std::string line{}; std::getline(logs, line);) {
// Check, if we should start or stio processing of the lines
if (line.substr(0, 9) == std::string("RE004%on%")) processingActive = true;
if (line.substr(0, 10) == std::string("RE005%off%")) processingActive = false;
// Check and read csv data
if (processingActive) {
const auto [ok, data] = checkString(line);
if (ok) csvData.push_back(std::move(data));
}
}
}
// So, now we have read all csv data
// Show eight column of GPGSV data
for (const Tokens& t : csvData)
if (t[0] == "$GPGSV")
std::cout << t[7] << "\n";
return 0;
}

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.

How to read string from stdin until meet blank lines

Consider a simple program. It must take string from stdin and save to variable.
It is not stated how many lines of input will be taken, but program must terminate if meet newline.
For example:
stdin:
abc
abs
aksn
sjja
\n
I tried but it doesn't work. Here is my code:
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
// Constant
#define max 100000
struct chuoi
{
char word[10];
};
chuoi a[max];
void readStr()
{
int i=0;
while ( fgets(a[i].word, 10,stdin) != NULL)
{
if (a[i].word[0] == ' ') break;
a[i].word[strlen(a[i].word)-1] = '\0'; //replaced \n by \0
i++;
}
//length = i;
}
int main()
{
readStr();
return 0;
}
So, how to solve this problem?
One alternative here is to use std::getline to get each line. If the line is empty, or the input fails, then exit the loop.
void readStr()
{
std::string str;
while ( std::getline(std::cin, str) && str.length() )
{
// use the string...
}
}
Adding the std::getline and use of std::vector to your sample code, and keeping with the spirit of your original sample;
#include <string>
#include <iostream>
#include <vector>
const std::size_t Max = 100000;
struct chuoi
{
explicit chuoi(std::string const& str) : word(str)
{
}
std::string word;
};
void readStr(std::vector<chuoi>& a)
{
std::string str;
while ( std::getline(std::cin, str) && str.length() )
{
a.push_back(chuoi(str));
}
}
void writeStr(std::vector<chuoi> const& a)
{
for (auto i = a.begin(); i != a.end(); ++i) {
std::cout << i->word << std::endl;
}
}
int main()
{
std::vector<chuoi> a;
a.reserve(Max);
readStr(a);
writeStr(a);
return 0;
}
To solve you immediate problem, minimal changes in the code can be made as follows;
void readStr()
{
int i = 0;
while ( fgets(a[i].word, 10, stdin) != NULL)
{
a[i].word[strlen(a[i].word) - 1] = '\0'; // transform the end of line character to NULL
if (strlen(a[i].word) == 0) {
break;
}
i++;
}
}
If the standard input will always be used (stdin), the gets function can also be used;
while ( gets(a[i].word) != NULL)
{
if (strlen(a[i].word) == 0) {
break;
}
i++;
}
Notes;
fgets reads until the "enter" key on the stdin but includes the new line character
gets also reads until the return, but excludes the new line character
Both functions NULL terminate the input
Be careful of the form of gets it does not check for buffer overflow conditions
I would do something like this:
#include <string>
#include <iostream>
int main()
{
std::string line; // will contain each line of input
// Stop when line is empty or when terminal input has an error
while(std::getline(std::cin, line) && !line.empty())
{
// do stuff with line
}
}