Add a newline every set amount of letters in std::string - c++

I'm working with a few long strings inside a C++ program (up to 65535 letters).
What am looking for is a way to add a new line every set amount of letters with an function like this:
addNewLinesToString(std::string* string, u8 lettersBetween newline);
Which would work like this:
string test = "Testing1234567";
addNewLinesToString(&test, 7); //test == "Testing\n1234567\n"
I have yet to find such a function that only used the standard class library (C and/or C++)
If somebody has a simple solution for this would be great :)
Thanks.

You can use string::insert for this purpose.
addNewLinesToString(std::string& str, int sep)
{
for (int i = 0; i < str.size(); i += sep)
str.insert(i, "\n");
}
But this will be O(n^2) (as pointed by #stefan) , you can also
addNewLinesToString(std::string& str, int sep)
{
string ans;
int i = 0;
while (i < str.size())
{
if (i % sep == 0 && i)
ans.push_back('\n');
ans.push_back(str[i]);
i++;
}
return ans;
}
Which uses more memory but is O(n).
Take a look at examples: http://www.cplusplus.com/reference/string/string/insert/

std::string insert_newlines(const std::string &in, const size_t every_n)
{
std::string out;
out.reserve(in.size() + in.size() / every_n);
for(std::string::size_type i = 0; i < in.size(); i++) {
if (!(i % every_n) && i) {
out.push_back('\n');
}
out.push_back(in[i]);
}
return out;
}
This:
allocates memory exactly once.
doesn't make the mistake of using int where size_t or std::string::size_type is required, so you don't run into strange problems for large strings or embedded platforms.
runs in linear O(n) time.
has an functional interface (rather than modifying the string in-place), an algorithm that modifies the input string and runs in O(n) time would be much more complex.

Try this function:
void addNewLinesToString(std::string* s, int change){
if(change <= 0)
return;
for(int i = 0; i < s.size(); i += change){
s.insert(i, "\n");
i++;
}
}
Edit: I don't know why your post got voted down, I up voted.

Maybe not fastest, but working:
void addNewLinesToString (std::string* txt, int limit)
{
if(limit <= 0)
return;
limit++;
for (int i=1; i<=txt->size()/limit; i++)
txt->insert((i*limit)-1, "\n");
}

Related

Does this count as a valid bubble sorting function? If so, how could I improve it?

I'm a complete novice to sorting algorithms so right now I'm more or less just trying to pick up the basics. This is something I wrote in C++ to sort a string and return it's characters in alphabetical order. I'm fairly confident this counts as a bubble sort, but I'd like confirmation from the experts :). I'd also like to get your take on how it could be further improved?
bool inOrder(std::string s){
for(int i = 0; i < s.length(); i++){
int thisLetterNum = s[i];
int nextLetterNum = s[i + 1];
if(thisLetterNum > nextLetterNum){
return false;
}
}
return true;
}
std::string alphabetSoup(std::string str) {
std::string &result = str;
while(!inOrder(result)){
for(int i = 0; i < str.length(); i++){
int thisLetterNum = str[i];
int nextLetterNum = str[i + 1];
if(thisLetterNum > nextLetterNum){
result[i] = nextLetterNum;
result[i + 1] = thisLetterNum;
}
}
}
return result;
}
Thanks!
Yes, it's a form of bubble sorting.
I'd also like to get your take on how it could be further improved
You have undefined behavior when i = length() - 1 because you use str[i + 1] so fixing that is the first improvement I would suggest.
You could also make fewer iterations and skip inOrder(). You can keep track of if it's in order by noting if you made a swap or not instead.
Example:
std::string alphabetSoup(std::string str) {
bool swapped;
size_t ei = str.length();
do {
--ei; // you can decrease this each iteration since the last element will be in
// the correct place after each iteration
swapped = false;
for(size_t i = 0; i < ei; ++i) {
if(str[i + 1] < str[i]) {
std::swap(str[i], str[i + 1]);
swapped = true;
}
}
} while(swapped);
return str;
}
A third improvement. Decrement
str.length()
by 1 each pass. This changes the behavior from n^2 to quadratic ((n * n) + n) / 2. This, coupled with the previous suggestions, radically improves exchange sort [another name for bubble sort]. Unfortunately, it is still inferior to other sort methods, just way easy to code.

Can't understand why Dynamic Programming isn't working here

I am trying to solve the Word Ladder problem from leetcode. In a nutshell, it asks you to write code that transforms one word into another by replacing one letter at a time, such that each intermediate string is also a word.
I know anyone can solve it easily with BFS. But I think dynamic programming (dp) technique will also work here. So I am trying to solve it with dp. For every sample test cases, it works fine. But this code fails for large input (System judges). .
Still now I am not understanding why dp won't work here?
Can anyone please give me a small input where this fails? You know it is almost impossible to test this code debugging by this large input.
Thank in advance.
class Solution {
public:
vector<int> dp;
int n;
bool isOneDiff(string str1, string str2) {
if(str1.length() != str2.length()) return false;
int len = str1.length();
int cnt = 0;
for(int i = 0; i < len; i++) {
if(str1[i] != str2[i]) cnt++;
}
return cnt == 1;
}
int solve(string cur, int ind, const string endWord, vector<string> wordList) {
if(cur == endWord) return 1;
int &ret = dp[ind];
if(ret != -1) return ret;
ret = 100000000; // Infinity
for(int i = 0; i < n; i++) {
if(isOneDiff(cur, wordList[i])) {
ret = min(ret, 1 + solve(wordList[i], i, endWord, wordList));
}
}
return ret;
}
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
n = wordList.size();
dp.clear();
dp.resize(n+2, -1);
int res = solve(beginWord, n, endWord, wordList);
if(res >= 100000000) return 0; // if res is greater than or equal to infinity then I have to return 0
return res;
}
};
It looks like you are trying to memoize a DFS. DFS will run into trouble on cycles, and also means that you have to explore a possibly large search space before you consider very short solutions.
Incidentally I would not suggest using BFS for this problem. Instead I would suggest using A* search.

Why split string is done in many questions in hackerrank?

It is Chief Hopper Greedy algorithm question .Here it is
https://www.hackerrank.com/challenges/chief-hopper/problem
I want to ask why splitting of string is done even though we are not giving any string as input and after that they used stoi function to convert that in int ??
string arr_temp_temp;
getline(cin, arr_temp_temp);
vector<string> arr_temp = split_string(arr_temp_temp);
vector<int> arr(n);
for (int i = 0; i < n; i++) {
int arr_item = stoi(arr_temp[i]);
arr[i] = arr_item;
}
vector<string> split_string(string input_string) {
string::iterator new_end = unique(input_string.begin(), input_string.end(), [] (const char &x, const char &y) {
return x == y and x == ' ';
});
input_string.erase(new_end, input_string.end());
while (input_string[input_string.length() - 1] == ' ') {
input_string.pop_back();
}
vector<string> splits;
char delimiter = ' ';
size_t i = 0;
size_t pos = input_string.find(delimiter);
while (pos != string::npos) {
splits.push_back(input_string.substr(i, pos - i));
i = pos + 1;
pos = input_string.find(delimiter, i);
}
splits.push_back(input_string.substr(i, min(pos, input_string.length()) - i + 1));
return splits;
I don't know where did u find this approach but from my point of view author trying to save time on IO operations. I think that this approach is wrong. I don't know how fast is reading string with getline compared to reading each int value one by one in the loop:
for(int i = 0; i<n; i++) cin>> x;
But I'm quite sure that converting string to integer is more time-consuming. So it's normal in competive programming to use scanf/printf for the fast IO or
ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr);
if you wanna use cout/cin.
To sum up I think that code author tried to save time on IO operations.
UPD: Sorry I was in rush and didn't take into account the platform. It should be this platform feature to read input only line by line so they give a template for you to focus only on the problem.

looking for a faster way to help reduce/create a huge list of strings

I tried to write an algorithm to guess correctly in the game "Masterminds",
it works the average number of guesses is 6, but it takes a lot of time to calculate the best guess.
I used the idea of Knuth the algorithm works as follows:
Create the set S of 1296 possible codes (1111, 1112 ... 6665, 6666).
Start with initial guess 1122 (Knuth gives examples showing that other first guesses such as 1123, 1234 do not win in five tries on
every code).
Play the guess to get a response of colored and white pegs.
If the response is four colored pegs, the game is won, the algorithm terminates.
Otherwise, remove from S any code that would not give the same response if the current guess were the code.
In my code step 2 is to take random number.
I used vector<string> for this.
AllPoss is the vector full of strings, I guess is the last guess that was used. answer is the count of bulls and cows looks like "x,y" (where x and y are numbers)
void bullpgia::SmartGuesser::remove(string guess, string answer)
{
for (auto i= AllPoss.begin();i != AllPoss.end();i++){
string token = *i;
if (calculateBullAndPgia(token, guess) != answer)
AllPoss.erase(i--);
}
}
this is the part it take a lot of time to calculate is there any way of improvement?
to creating the list i used :
void bullpgia::SmartGuesser::All() {
/**
* creates a pool of all the possibilities strings
* we then delete the ones we dont need
* #param length is the length of the word we need to guess
*/
for(int i=0;i<pow(10,length);i++){
stringstream ss;
ss << setw(length) << setfill('0') << i;
string s = ss.str();
AllPoss.push_back(s);
}
}
the function calculateBullAndPgia(string , string) is:
string calculateBullAndPgia(const string &choice, const string &guess) {
string temp = choice;
string temp2 = guess;
unsigned int bull = 0;
unsigned int pgia = 0;
for (int i = 0; i < temp.length(); i++) {
if (temp[i] == temp2[i]) {
bull++;
temp[i] = 'a';
temp2[i] = 'z';
}
}
for (int i = 0; i < temp.length(); i++) {
for (int j = 0; j < temp2.length(); j++) {
if (i != j && temp[i] == temp2[j]) {
pgia++;
temp[i] = 'a';
temp2[j] = 'z';
}
}
}
return to_string(bull) + "," + to_string(pgia);
}
Erasing a single element in the middle of a vector is O(n). My guess is that you wind up doing it O(n) times per call to SmartGuesser::remove. Then you loop over that so you probably have a O(n^3) algorithm. You instead could use std::remove_if, which is O(n), to move all the to-be-erased elements to the end of the vector where they can be cheaply erased.:
AllPoss.erase(std::remove_if(AllPos.begin(), AllPos.end(), [&](const std::string& token, const std::string& guess) { return calculateBullAndPgia(token, guess) != answer; }), AllPos.end());

Getting Word Frequency From Vector In c++

I have googled this question and couldn't find an answer that worked with my code so i wrote this to get the frequency of the words the only issue is that i am getting the wrong number of occurrences of words apart form one that i think is a fluke. Also i am checking to see if a word has already been entered into the vector so i don't count the same word twice.
fileSize = textFile.size();
vector<wordFrequency> words (fileSize);
int index = 0;
for(int i = 0; i <= fileSize - 1; i++)
{
for(int j = 0; j < fileSize - 1; j++)
{
if(string::npos != textFile[i].find(textFile[j]) && words[i].Word != textFile[j])
{
words[j].Word = textFile[i];
words[j].Times = index++;
}
}
index = 0;
}
Any help would be appreciated.
Consider using a std::map<std::string,int> instead. The map class will handle ensuring that you don't have any duplicates.
Using an associative container:
typedef std::unordered_map<std::string, unsigned> WordFrequencies;
WordFrequencies count(std::vector<std::string> const& words) {
WordFrequencies wf;
for (std::string const& word: words) {
wf[word] += 1;
}
return wf;
}
It is hard to get simpler...
Note: you can replace unordered_map with map if you want the worlds sorted alphabetically, and you can write custom comparisons operations to treat them case-insensitively.
try this code instead if you do not want to use a map container..
struct wordFreq{
string word;
int count;
wordFreq(string str, int c):word(str),count(c){}
};
vector<wordFreq> words;
int ffind(vector<wordFreq>::iterator i, vector<wordFreq>::iterator j, string s)
{
for(;i<j;i++){
if((*i).word == s)
return 1;
}
return 0;
}
Code for finding the no of occurrences in a textfile vector is then:
for(int i=0; i< textfile.size();i++){
if(ffind(words.begin(),words.end(),textfile[i])) // Check whether word already checked for, if so move to the next one, i.e. avoid repetitions
continue;
words.push_back(wordFreq(textfile[i],1)); // Add the word to vector as it was not checked before and set its count to 1
for(int j = i+1;j<textfile.size();j++){ // find possible duplicates of textfile[i]
if(file[j] == (*(words.end()-1)).word)
(*(words.end()-1)).count++;
}
}