C++ twoSum. Optimize memory usage - c++

I am solving a twoSum problem.
Steps:
Read an input file with a following template:
7
1 7 3 4 7 9
First line is the target number, second line is a number sequence.
Numbers can be in range 0 < N < 999999999
If the sum of two numbers from the number sequence equals the target number, I write "1" to the output file.
If there are no numbers the sum of which equals the target number then I write "0" to the output file.
I need to optimize memory usage in my code. How can I do that?
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <unordered_map>
#include <string>
#include <algorithm>
using namespace std;
int main() {
ifstream f1;
vector<int> nums;
string line;
string source;
//Open input file and read it to a string
f1.open("input.txt");
while (getline(f1, line, '\n')) {
source+=line + " ";
} f1.close();
//Parse the string into an int vector
stringstream parser(source);
int num;
while (parser >> num) { nums.push_back(num); }
//Clear used strings
line = "";
source = "";
//Get target number
int target = nums.at(0);
//Get number sequence
nums.erase(nums.begin());
bool flag = false;
//Check number sequence for two numbers sum of which equals the target number
unordered_map<int, int> mp;
for(int i=0;i<nums.size();i++){
if(mp.count(nums[i])==1){
flag = true;
break;}
mp[target-nums[i]]=i;
}
//Write the result into the output file
ofstream f2;
f2.open("output.txt");
f2 << flag;
f2.close();
}

There are a couple of things you can do to minimise memory usage here. First up, you don't need to read entire contents of the file into std::string. You can read directly into std::vector, or better still read the file contents into a single int variable and process the numbers as you go. Another thing: you do not need to use a std::unordered_map, because presence of the key is the only thing you are really interested in, so std::unordered_set is sufficient. Below a simple solution making use of that suggestions:
#include <fstream>
#include <unordered_set>
int main() {
std::ifstream input {"input.txt"};
int target;
input >> target;
int current_number;
bool found = false;
std::unordered_set<int> observed_numbers;
while (input >> current_number) {
if (observed_numbers.count(target - current_number) > 0) {
found = true;
break;
}
observed_numbers.insert(current_number);
}
std::ofstream output {"output.txt"};
output << found;
}

Related

how to make our own function like touch in c++

As soon as I add the below code this programs ends showing this error message:
Process returned -1073741819 (0xC0000005)
If I run those code separately then both of them work.
I used sstream and array too but combined they do not work properly.
#include <sstream>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
int main()
{
string input = "touch world.txt this.txt is.txt sentence.txt";
string word;
int length = 0;
for(int a = 0;a<input.length();a++){
if(input[a] == ' '){
length++;
}
}
string filesNameArr[length];
int number = 0;
// hello world this is sentence
for(auto x:input)
{
if(x==' ')
{
filesNameArr[number] = word;
word.erase();
number++;
}
else
word=word+x;
}
filesNameArr[number] = word;
number = 0;
//when i add the below code it generates error and stops
ofstream outFile[41];
stringstream sstm;
for (int i=0;i<41 ;i++)
{
sstm.str("");
sstm << "subnode" << i;
outFile[i].open(sstm.str().c_str());
}
return 0;
}
length is one less than the number of words in your string as you are only counting the number of spaces. This means your final filesNameArr[number] = word causes undefined behaviour and will probably corrupt the stack.
string filesNameArr[length]; uses a variable length array which is not valid c++. If you use a std::vector instead you can skip the initial counting of the words completely:
std::vector<std::string> filesNameArr;
for(auto x:input)
{
if(x==' ')
{
filesNameArr.push_back(word);
word.erase();
}
else
{
word+=x;
}
}
filesNameArr.push_back(word);
You can use std::stringstreams built in ability to read words from strings to make this even simpler:
std::stringstream sinput(input);
std::vector<std::string> filesNameArr;
std::string word;
while (sinput >> word)
{
filesNameArr.push_back(word);
}

how to add an element to an array in c++?

How would I add an element to an array, assuming that I have enough space? My code looks something like this:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
ofstream out("hi.out");
ifstream in("hi.in");
string currentLine;
string values[135];/*Enough for worst case scenario*/
if (out.is_open && in.isopen()){
while (in >> currentLine){
/*Add currentLine to values*/
}
/*Do stuff with values and write to hi.out*/
}
out.close()
in.close()
return 0;
}
No need to write the loop yourself. With your array:
auto l = std::copy(std::istream_iterator<std::string>(in), {}, values);
l - values is the number of strings read.
Or even better, use a vector, so that you don't have to worry about the possibility of your "worst case scenario" not being the actual worst case scenario.
std::vector<std::string> values(std::istream_iterator<std::string>(in), {});
You could use an index counter variable:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main(){
ofstream out("hi.out");
ifstream in("hi.in");
string currentLine;
string values[135];/*Enough for worst case scenario*/
int index = 0;
if (out.is_open && in.isopen()){
while (in >> currentLine){
/*Add currentLine to values*/
values[index++] = currentLine;
}
/*Do stuff with values and write to hi.out*/
}
out.close()
in.close()
return 0;
}
The variable index, once the loop is complete, will contain the number of strings in your array.

Reading numbers from file to string to array

I am reading numbers from a file, say:
1 2 3 4 5
I want to read this data from a file into a string into an array for further processing. Here's what I've done:
float *ar = nullptr;
while (getline(inFile, line))
{
ar = new float[line.length()];
for (unsigned int i = 0; i < line.length(); i++)
{
stringstream ss(line);
ss >> ar[i];
}
}
unsigned int arsize = sizeof(ar) / sizeof(ar[0]);
delete ar;
Suffice it to say that it works insofar it only gets the first value from the file. How do I get the array to be input ALL the values? I debugged the program and I can confirm that line has all the necessary values; but the float array doesn't. Please help, thanks!
line.length() is the number of characters in the line, not the number of words/numbers/whatevers.
Use a vector, which can be easily resized, rather than trying to juggle pointers.
std::vector<float> ar;
std::stringstream ss(line);
float value;
while (ss >> value) { // or (inFile >> value) if you don't care about lines
ar.push_back(value);
}
The size is now available as ar.size(); your use of sizeof wouldn't work since ar is a pointer, not an array.
The easiest option is to use the standard library and its streams.
$ cat test.data
1.2 2.4 3 4 5
Given the file you can use the stream library like this:
#include <fstream>
#include <vector>
#include <iostream>
int main(int argc, char *argv[]) {
std::ifstream file("./test.data", std::ios::in);
std::vector<float> res(std::istream_iterator<float>(file),
(std::istream_iterator<float>()));
// and print it to the standard out
std::copy(std::begin(res), std::end(res),
std::ostream_iterator<float>(std::cout, "\n"));
return 0;
}
I ran into this problem earlier when I wanted to extract data line by line from a file to fill my sql database that I wanted to use.
There are many solutions to this specific problem such as:
The solution is using stringstream with a while statement to put data from file into the array with a while statement
//EDIT
While statement with getline
//This solution isn't very complex and is pretty easy to use.
New Improved simple solution:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main()
{
ifstream line;
line.open("__FILENAME__");
string s;
vector<string> lines;
while(getline(line, s))
{
lines.push_back(s);
}
for(int i = 0;i < lines.size();i++)
{
cout << lines[i] << " ";
}
return 0;
}
compiled code to check - http://ideone.com/kBX45a
What about atof?
std::string value = "1.5";
auto converted = atof ( value.c_str() );
Rather complete:
while ( std::getline ( string ) )
{
std::vector < std::string > splitted;
boost::split ( splitted, line, boost::is_any_of ( " " ) );
std::vector < double > values;
for ( auto const& str: splitted ) {
auto value = atof ( str.c_str() );
values.push_back ( value );
}
}

Wrong answer in c++

You are given a DNA sequence, and few enzymes. Suppose, a DNA sequence goes like this : ATGCTGCTATGCATGCAGTGACT, and you are given enzymes which can remove AT and GC sequences. Thereby, you need to remove all occurrences of AT from the DNA first and then reform the DNA and apply the next enzyme to remove all occurrences of GC. The output of the problem would be the string you get at last reforming the pieces which are not removed by these enzymes.
Input
The first line of input consists of an integer n that denotes the number of enzymes. The first line has the DNA sequence. The next T lines has the input B1, B2, B3... Bn.
Output
For given input DNA sequence, output a single line containing the final reformed DNA that is formed by repeatedly removing all the occurrences of B1, B2, B3... Bn from A.
In case the DNA is completely consumed print 0 to indicate that there is no DNA left.
Constraints
1 <= n <= 10
Example 1:
Input:
2
ATACGCATGACGATGCATGCAGCAT
ATA
GC
Output:
CATGACGATATAAT
Example 2:
Input:
3
ATGCATGCATCGACTCAGCATCAGCATCGACTA
TG
GC
AT
Output:
ACACCGACTCACACGACTA
My code:
I tried solving it using string in c++, I am getting :
terminate called after throwing an instance of 'std::out_of_range'
what():basic_string::erase()
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <math.h>
#include <vector>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <queue>
#include <stack>
#include <assert.h>
#include <limits.h>
using namespace std;
int main() {
string str, str1;
int n;
scanf("%d", &n);
cin >> str;
while (n--) {
cin >> str1;
int len = str1.length();int len1=str.length();
for (int i = 0; i < len1; i++) {
int found = str.find(str1);
str.erase(found, found + len);
}
}
cout << str;
return 0;
}
Three main problems:
Number one, out of range exception on string::erase.
Fixed by testing that find actually returned a value:
if (found!=std::string::npos)
Number two, searching correctly.
Fixed by keeping track of found (it's also a size_t not an int) and searching from the next location:
found = str.find(str1,found);
Number three, using string::erase properly.
Fixed by using length of substring to erase, not length + position:
str.erase(found,len);
I still haven't added any input validation to your code. You should really think about doing that yourself.
Final code:
(ideone)
#include <string>
#include <iostream>
int main()
{
std::string str;
std::string str1;
int n;
std::cin>>n;
std::cin>>str;
while(n--)
{
std::cin>>str1;
int len = str1.length();
size_t found = 0;
for(unsigned int i=0;i<str.length();i++)
{
found = str.find(str1,found);
if (found!=std::string::npos)
{
str.erase(found,len);
}
else
{
break;
}
}
}
std::cout<<(str.length()?str:"0");
return 0;
}
idone output for each example input (I've added your example outputs in between the /* */ marks):
Success time: 0 memory: 3476 signal:0
CATGACGATATAAT
/*CATGACGATATAAT*/
Success time: 0 memory: 3476 signal:0
ACACCGACTCACACGACTA
/*ACACCGACTCACACGACTA*/

How to move file pointer back by one integer?

Say I have a file containing integers in the form
1 57 97 100 27 86 ...
Say that I have a input file stream fin and I try to read the integers from the file.
ifstream fin("test.txt");
int val;
fin>>val;
Now I am doing this action in a while loop where at one period of time, I want to move my file pointer exactly one integer back. That is if my file pointer is about to read the integer 27 when I do fin>>val, I want to move the file pointer such that it can read the integer 100 when I do fin>>val. I know we can use fin.seekg() but I have used it only to move the file pointers by characters, not by integers.
Probably this is a naive question. But can someone please help me out?
You can use tellg after each read to save the pointer to be used later on with a seekg.
You could also take the implementation of << and modify it with a function that also returns the number of characters you have advanced each time. Where to find the source code of operator<< is not something where I could easily help you with.
In your case it is not an integer, but a text representing a number. Because of this you will have to move backward character by character until you find a non-digit one (!isdigit(c)).
As one of the commenters below pointed out, you may also pay attention to a the 'minus' sign in case your numbers can be negative.
first argument is the file name, second argument is the numbers index, program displays the number at the index and then displays the previous number (counting from zero)
#include <iostream>
#include <fstream>
#include <vector>
#include <cstdlib>
int main(int argc, char *argv[]){
if(argc != 3){
std::cout<<"argument error!\n";
return 1;
}
std::ifstream read;
read.open(argv[1],std::ios::app);
if( read.is_open() ){
std::vector<int> numbers;
int temp;
while(read >> temp){
numbers.push_back(temp);
}
std::cout<<"1) "<<numbers[atoi(argv[2])]<<"\n2) "<<numbers[atoi(argv[2]-1)]<<std::endl;
read.close();
}else {
std::cout<<"file open error!\n";
return 2;
}
return 0;
}
Try the following:
#include <iostream>
#include <fstream>
#include <locale>
int main()
{
std::ifstream fin("test.txt");
int val;
bool back = false;
for (int i = 0; fin >> val;)
{
if (!back && val == 27)
{
while (i++ < 2)
while (!std::isspace(fin.unget().rdbuf()->sgetc()));
back = true;
}
}
}
You could take a look at istream::unget()
#include <fstream>
#include <iostream>
int main()
{
ifstrem file("fileName.txt");
char var=file.get()://now this will move file pointer one time forward
/* Seekg(n,position) accept two arguments.The number of bits and position
from where to move the file pointer
if value of n is negative then file pointer will move back.
*/
file.seekg(-1,ios::cur);//to move the file back by one bit from current position
retur
n 0;
}