parse a char vector to different strings - c++

I have a character vector like
std::vector<char> input({'{', 'a', 'b','}',\0', '{','c','d','}',\0','\0','\0'});
I want to parse this to have strings
string1="ab"
string2="cd"
How to achieve this as vector has trailing '\0' characters.
Tried something like below. but going into infinite loop
td::vector<char> input({ 'a', 'b','\0', 'c','\0'});
std::vector<std::string> list;
std::string s(input.begin(), input.end());
size_t pos = 0;
std::string token;
while ((pos = s.find('\0')) != std::string::npos) {
token = s.substr(0, pos);
s.erase(0, pos);
list.push_back(token);
}

Not 100% sure, but I doubt s.find('\0') should return the first occurrence of \0, which means that if string(assume a string) is abcd\0ef, .find() should return index 4. In this case, erasing 4 characters from position 0 means you are erasing abcd part of the string, while leaving \0 still there. This is most likely causing the infinite loop.
To make sure, print the pos value to check what index it is before erasing.
Also, note that this approach will be quite slow, since .erase() is O(n) where n=string.size(), thus .substr() is also slow, with time complexity of substring size.

Related

Get string of characters from a vector of strings where the resulting string is equivalent to the majority of the same chars in the nth pos in strings

I'm reading from a file a series of strings, one for each line.
The strings all have the same length.
File looks like this:
010110011101
111110010100
010000100110
010010001001
010100100011
[...]
Result : 010110000111
I'll need to compare each 1st char of every string to obtain one single string at the end.
If the majority of the nth char in the strings is 1, the result string in that index will be 1, otherwise it's going to be 0 and so on.
For reference, the example I provided should return the value shown in the code block, as the majority of the chars in the first index of all strings is 0, the second one is 1 and so on.
I'm pretty new to C++ as I'm trying to move from Web Development to Software Development.
Also, I tought about making this with vectors, but maybe there is a better way.
Thanks.
First off, you show the result of your example input should be 010110000111 but it should actually be 010110000101 instead, because the 11th column has more 0s than 1s in it.
That being said, what you are asking for is simple. Just put the strings into a std::vector, and then run a loop for each string index, running a second loop through the vector counting the number of 1s and 0s at the current string index, eg:
vector<string> vec;
// fill vec as needed...
string result(12, '\0');
for(size_t i = 0; i < 12; ++i) {
int digits[2]{};
for(const auto &str : vec) {
digits[str[i] - '0']++;
}
result[i] = (digits[1] > digits[0]) ? '1' : '0';
}
// use result as needed...
Online Demo

Check String For Consecutive Pairs C++

I'm looking to write a C++ console app that takes in lines of text from a .txt file, which I have done, now what I need to do is check each line for consecutive pairs of letters
"For example, the word “tooth” has one pair of double letters, and the word “committee” has two pairs of consecutive double letters."
Should I convert each line into a Cstring and loop through each character? I really don't know where to start with this.
I'm not looking for someone to write out the entire solution, I just need to know how to start this.
You could loop through the string from start to the second last char and compare 2 chars at a time. In C++17 you have std::string_view which is handy.
#include <string_view>
size_t pair_count(std::string_view s) {
size_t rv = 0; // the result
for(size_t idx = 0; idx < s.size() - 1; ++idx) {
// compare s[idx] and s[idx+1]
// if they are equal, increase rv by one
// and increase idx by one (if you want "aaa" to count as 1 and not 2)
}
return rv;
}

Reversing the positions of words in a string without changing order of special characters in O(1) space limit

During mock interview I come up with this question. Interviewer first ask this question without any space limitations. Then he continued with space-limited version. To be on the same page. In the question a string and container class consist of delimiters are given. This is up to you to decide suitable container class and the language of response. I think sample input and output would be enough to understand what really question is.
Input:
"Reverse#Strings Without%Changing-Delimiters"
Output:
"Delimiters#Changing Without%Strings-Reverse"
Note That: Position of "#", "%"," ","-" is not changed
I came up with the solution below:
string ChangeOrderWithoutSpecial(string s, unordered_set<char> delimiter)
{
stack<string> words; // since last words outs first
queue<char> limiter; // since first delimiter outs first
string response =""; //return value
int index=-1; // index of last delimiter visited
int len=s.length();
for (int i =0 ; i <len;i++)
{
if(delimiter.find(s[i]) != delimiter.end()) // i-th char is a delimiter character
{
string temp=s.substr(index+1,i-index-1);
words.push(temp);
char t =s.at(i);
limiter.push(t);
index=i;
}
// i realized that part after interview under assumption starting with word and no double delimiters ie, each word followed by one delimiter
if(index!=s.length()-1)
{
string temp=s.substr(index+1,s.length()-index-1);//until the end;
cout<<temp<<endl;
words.push(temp);
}
while(!limiter.empty())
{
response+=words.top()+limiter.front();
words.pop();
limiter.pop();
}
response+=words.top();
return response;
}
However I couldnt find a o(1) space solution ? Anyone know how ? I also could not figure out if there are multiple delimiters , that also be appricated. Thank you anyone spend time even reading.
Find the first word and the last word. Rotate the string by length(last_word)-length(first_word): this would put the middle part in the correct position. In the example, that'll produce
ersReverse#Strings Without%Changing-Delimit
Then rotate the first and last part of the string, skipping the middle, by length(first_word):
Delimiters#Strings Without%Changing-Reverse
Repeat this algorithm for the substring between the two outermost delimiters.
"Rotate by m" operation can be performed in O(1) space and O(n) time, where n is the length of the sequence being rotated.
Instead of rotating the string, it can be also solved by successive reversing the string.
Reverse the whole string. This is O(n) operation. In your case the string becomes sretimileD-gnignahC%tuohtiW sgnirtS#esreveR.
Find all words and reverse each of them. This is O(n) operation. String is now equal to Delimiters-Changing%Without Strings#Reverse.
Reverse delimiters. This is O(n) operation. You'll get wanted result: Delimiters#Changing Without%Strings-Reverse.
Each of these operations can be done in place, so the total memory complexity is O(1) and time complexity is O(n).
It is worth noting that with this approach each character will be visited 4 times (first reverse, finding words, reverse word, reverse delimiter), so (in general case) it should be faster than Igor Tandetnik's answer where characters in the middle of the string are visited many times. However, in special case where each word has the same length, Igor's solution will be faster because the first rotate operation won't exists.
Edit:
Reverse delimiters can be done in O(n) without extra memory in the similar way as the standard reverse. Just iterate through delimiters instead of whole set of characters:
Iterate forward until you reach delimiter;
Reverse iterate until you reach delimiter from the back;
Swap the current delimiters;
Continue procedure until your iterators meet.
Here is procedure in C++ which will do this job
void reverseDelimiters(string& s, unordered_set<char>& delimiters)
{
auto i = s.begin(); auto j = s.end() - 1; auto dend = delimiters.end();
while (i < j) {
while (i < j && delimiters.find(*i) == dend) i++;
while (i < j && delimiters.find(*j) == dend) j--;
if (i < j) swap(*i, *j), i++, j--;
}
}

Is String a Permutation of list of strings

A list of words is given and a bigger string given how can we find whether the string is a permutation of the smaller strings.
eg- s= badactorgoodacting dict[]={'actor','bad','act','good'] FALSE
eg- s= badactorgoodacting dict[]={'actor','bad','acting','good'] TRUE
The smaller words themselves don't need to be permuted. The question is whether we can find a ordering of the smaller strings such that if concatenated in that order it gives the larger string
One more constraint - some words from dict[] may also be left over unused
The following gives a complexity O(n2). Any other ways to do this.. so as to improve complexity or increase efficiency in general? Mostly in Java. Thanks in Advance!
bool strPermuteFrom(unordered_set<string> &dict, string &str, int pos)
{
if(pos >= str.size())
return true;
if(dict.size() == 0)
return false;
for(int j = pos; j < str.size(); j++){
string w = str.substr(pos, j - pos + 1);
if(dict.find(w) != dict.end()){
dict.erase(w);
int status = strPermuteFrom(dict, str, j+1);
dict.insert(w);
if(status){
if(pos > 0) str.insert(pos, " ");
return status;
}
}
}
return false;
}
bool strPermute(unordered_set<string> &dict, string &str)
{
return strPermuteFrom(dict, str, 0);
}
The code sample you give doesn't take much advantage of unordered_set (equivalent to Java HashSet's properties); each lookup is O(1), but it has to perform many lookups (for each possible prefix, for the entire length of the string). A std::set (Java TreeSet), being ordered, would allow you to find all possible prefixes at a given point in a single O(log n) lookup (followed by a scan from that point until you were no longer dealing with possible prefixes), rather than stringlength O(1) lookups at each recursive step.
So where this code is doing O(stringlength * dictsize^2) work, using a sorted set structure should reduce it to O(dictsize log dictsize) work. The string length doesn't matter as much, because you no longer lookup prefixes; you look up the remaining string once at each recursive step, and because it's ordered, a matching prefix will sort just before the whole string, no need to check individual substrings. Technically, backtracking would still be necessary (to handle a case where a word in the dict was a prefix of another word in the dict, e.g. act and acting), but aside from that case, you'd never need to backtrack; you'd only ever have a single hit for each recursive step, so you'd just be performing dictsize lookups, each costing log dictsize.

Trimming a vector of strings

I have an std::vector of std::strings containing data similar to this:
[0] = ""
[1] = "Abc"
[2] = "Def"
[3] = ""
[4] = "Ghi"
[5] = ""
[6] = ""
How can I get a vector containing the 4 strings from 1 to 4? (i.e. I want to trim all blank strings from the start and end of the vector):
[0] = "Abc"
[1] = "Def"
[2] = ""
[3] = "Ghi"
Currently, I am using a forward iterator to make my way up to "Abc" and a reverse iterator to make my way back to "Ghi", and then constructing a new vector using those iterators. This method works, but I want to know if there is an easier way to trim these elements.
P.S. I'm a C++ noob.
Edit
Also, I should mention that the vector may be composed entirely of blank strings, in which case a 0-sized vector would be the desired result.
How about this, with a predicate:
class StringNotEmpty
{
bool operator()(const std::string& s) { return !s.empty(); }
};
Now to trim:
vec.erase(std::find_if(vec.rbegin(), vec.rend(), StringNotEmpty()).base(), vec.end());
vec.erase(vec.begin(), std::find_if(vec.begin(), vec.end(), StringNotEmpty()));
There might be an off-by-one on the .base() call, but the general idea should work.
Your approach is reasonable. Another approach is to find the first string, and then copy all successive strings to the beginning (and following) elements in the vector, after which you trim the end of the vector.
Unless this is a critical piece of code that is slowing down your application, it matters more that it works than that you have the most efficient implementation possible.
What you've done is good. But if you want to shorten a single container "in place" rather than make a copy of a subrange, you can erase the other ranges from the vector.
// Probably similar to what you already have: Find iterators for the range to keep.
std::vector<std::string>::iterator start=strs.begin(), stop=strs.end();
start = strs.begin();
while (start != stop && start->empty()) ++start;
if (start == stop) {
// all strings were empty!
strs.clear();
} else {
while (start != --stop && stop->empty()) ;
++stop;
// std::vector<std::string>(start, stop) is the desired subrange
strs.erase(stop, strs.end());
strs.erase(strs.begin(), start);
}
But I agree with #Nathan: If you what you already have makes more sense to you than this, keep it, unless you know or strongly suspect that there will be an awful lot of strings involved.
typedef std::vector<std::strings> Strings;
Strings myStrings;
//... currently myStrings contains "","Abc","Def","","Ghi","",""
Strings::iterator itNewBegin = myStrings.begin();
Strings::iterator itNewEnd = myStrings.end();
std::advance(itNewBegin,1);
std::advance(itNewEnd,4);
String myTrimmedStrings(itNewBegin,itNewEnd);
//... currently myTrimmedStringscontains "Abc","Def","","Ghi"
By curiosity, I would like to see your code with the use of the reverse iterator.
I don't grasp the way you contruct new vector from two iterators that have different directions.
Iterators are definitely the way to go. They make the code much more readable and intuitive.
#include <algorithm>
typedef std::vector<std::string> strVec_t;
bool notEmpty(std::string s){
return !s.empty();
}
void trim(strVec_t& vec){
//get the first and last non-empty elements
strVec_t::const_iterator first = std::find_if(vec.begin(), vec.end(), notEmpty);
strVec_t::const_reverse_iterator last = std::find_if(vec.rbegin(), vec.rend(), notEmpty);
//if every element is an empty string, delete them all
if (first == vec.end()){
vec.clear();
//make a new vector from the first to the last non-empty elements
} else {
vec = strVec_t(first, last.base());
}
}