Program taking too much time - c++

I'm trying to solve a coding problem, the problem is:
Take a string input
Take a number input 'n'
Repeat the string up to n indexes
Count the number of 'a' characters that occur in the repeated string
This problem was authored by tunyash on Hackerrank with title 'Repeated String'
My current solution is taking too much time to run
This is what I am currently doing:
Use a variable to iterate through the original string
Each time the variable exceeds the original string length, reset it to 0
Iterate n times
I've made a function to do the counting as follows:
long long repeatedString(std::string s, long long n) {
long long sIndex{ 0 }, length = s.size(), result{ 0 };
for (long long i = 0; i < n; i++)
{
if (sIndex > (length - 1))
sIndex = 0;
if (s[sIndex] == 'a')
result += 1;
sIndex += 1;
}
return result;
}
I've tried modifying and using binary search algorithm by first writing the whole string then searching but the writing part takes too much time and seems not very intuitive

This is a typical beginner programming exercise. The idea is that you shouldn't blindly overengineer the problem, when a simple mathematical formula is right around the corner. In this case you can simply count the number of a's in the original string and multiply it by n to get the desired result:
std::count(s.begin(), s.end(), 'a') * n
where s is your input string.
Edit: I misinterpreted the question. I assumed n was the number of repetitions of the whole string, whereas it actually was the number of characters to concatenate by modularly concatenating the strings characters up until n number of characters. In this case, simply divide before multiplying: n / s.length() and adjust for the n % s.length() characters remaining with addition. I will leave this as an exercise.

Related

Find total number of substrings with 1's greater than 0's, need optimization

Given and string we need to find out the total number of substrings in which 1's are greater than 0's.
I approached this problem using Dynamic programming but I was not able to come up with a solution, I am successful in writing a naive-logic but I was not able to optimize the code (i.e time limit is exceeding)
Any help in optimizing or suggestions for a new approach will be help full.
The time complexity of below code is O(n^3) Any solutions to reduce the time-complexity will be helpfull.
Thank in advance.
Code I used:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main(){
int tc =0; //total count
string st; //original string
getline(cin,st);
int lent = st.size(); //size of string
for(int i =0;i<lent;i++){ //loop to generate all possible substrings
int j = lent-1;
while(j>=i){
string st1(st.begin()+i,st.end()-j+i); // A substring
int c1 = count(st1.begin(),st1.end(),'1'); // count of 1's in substring
if(c1 > st1.size()-c1) tc++; // Condition to check if 1's are more
j--;
}
}
cout << tc; // Print total substrings
}
Note: A substring is a contiguous sequence of characters within a string.
For more information about substrings visit Wikipedia
Treat respectively '0' and '1' as integers 1 and -1. Then the string becomes an integer array. Calculate its prefix sum array s, i.e., s[0] = 0 and s[i] = a[0] + ... + a[i - 1]. Now every substring with number of '1's > number of '0's corresponds to a pair (i, j) such that i < j and s[i] > s[j]. You can then use the trick in find total number of (i,j) pairs in array such that i<j and a[i]>a[j]. The time complexity is O(n log n).
The problem is you're counting the same chars multiple times from the same start point. You can easily tally the 1's and 0's once from each start point: at the same time as you are traversing the substring. Start at length 0 substring instead of starting at the longest substring.
After this change you will have reduced from O(n^3) to O(n^2) without doing anything unusual or counterintuitive.
"is O(n^2) the most optimized solution" -- no but it's a good first step in improving your algorithm. It can be further optimized.

Big-O analysis of two algorithms

I created two solutions for leetcode problem 17 in which it asks you to generate all possible text strings from a phone number combination, e.g. "3" results in ["d","e","f"].
My first solution uses a recursive algorithm to generate the strings and is given below:
class Solution {
public:
void fill_LUT(vector<string>& lut) {
lut.clear();
lut.push_back(" ");
lut.push_back("");
lut.push_back("abc");
lut.push_back("def");
lut.push_back("ghi");
lut.push_back("jkl");
lut.push_back("mno");
lut.push_back("pqrs");
lut.push_back("tuv");
lut.push_back("wxyz");
}
void generate_strings(int index, string& digits, vector<string>& lut, vector<string>& r, string& work) {
if(index >= digits.size()) {
r.push_back(work);
return;
}
char idx = digits[index] - '0';
for(char c : lut[idx]) {
work.push_back(c);
generate_strings(index+1, digits, lut, r, work);
work.pop_back();
}
}
vector<string> letterCombinations(string digits) {
vector<string> r;
vector<string> lut;
fill_LUT(lut);
if(digits.size() <= 0)
return r;
string work;
generate_strings(0, digits, lut, r, work);
return r;
}
};
I am a bit rusty with big-O, but it appears to me that the space complexity would be O(n) for the recursive call, i.e. its maximum depth, O(n) for the buffer string, and O(n*c^n) for the resulting strings. Would this sum together as O(n+n*c^n)?
For time complexity I am a bit confused. Each level of the recursion performs c pushes + pops + recursive calls multiplied by the number of operations by the next level, so it sounds like c^1 + c^2 + ... + c^n. In addition, there are c^n duplications of n length strings. How do I consolidate this into a nice big-O representation?
The second solution views the number of results as a mixed radix number and converts it to a string as you might perform an int to hex string conversion:
class Solution {
public:
void fill_LUT(vector<string>& lut) {
lut.clear();
lut.push_back(" ");
lut.push_back("");
lut.push_back("abc");
lut.push_back("def");
lut.push_back("ghi");
lut.push_back("jkl");
lut.push_back("mno");
lut.push_back("pqrs");
lut.push_back("tuv");
lut.push_back("wxyz");
}
vector<string> letterCombinations(string digits) {
vector<string> r;
vector<string> lut;
fill_LUT(lut);
if(digits.size() <= 0)
return r;
unsigned total = 1;
for(int i = 0; i < digits.size(); i++) {
digits[i] = digits[i]-'0';
auto m = lut[digits[i]].size();
if(m > 0) total *= m;
}
for(int i = 0; i < total; i++) {
int current = i;
r.push_back(string());
string& s = r.back();
for(char c : digits) {
int radix = lut[c].size();
if(radix != 0) {
s.push_back(lut[c][current % radix]);
current = current / radix;
}
}
}
return r;
}
};
In this case, I believe that the space complexity is O(n*c^n) similar to the first solution minus the buffer and recursion, and the time complexity must be O(n) for the first for loop and an additional O(n*c^n) to create a result string for each of the possible results. The final big-O for this is O(n+n*c^n). Is my thought process correct?
Edit: To add some clarification to the code, imagine an input string of "234". The first recursive solution will call generate_strings with the arguments (0, "234", lut, r, work). lut is a look up table that converts a number to its corresponding characters. r is the vector containing the resulting strings. work is a buffer where the work is performed.
The first recursive call will then see that the index 0 digit is 2 which corresponds with "abc", push a to work, and then call generate_strings with the arguments (1, "234", lut, r, work). Once the call returns it will then push b to work and rinse and repeat.
When index is equal to the size of digits then a unique string has been generated and the string is pushed onto r.
For the second solution, the input string is first converted from it's ascii representation to it's integer representation. For example "234" is converted to "\x02\x03\x04". Then the code uses those as indices to look up the number of corresponding characters in the lookup table and calculates the total number of strings that will be in the result. e.g. if the input string was "234", 2 corresponds with abc, which has 3 characters. 3 corresponds with def which has 3 characters. 4 corresponds with ghi which has 3 characters. The total number of possible strings is 3*3*3 = 27.
Then the code uses a counter to represent each of the possible strings. If i were 15 it would be evaluated by first finding 15 % 3 which is 0, corresponding with the first character for the first digit (a). Then divide 15 by 3 which is 5. 5 % 3 is 2 which corresponds with the third character for the second digit, which is f. Finally divide 5 by 3 and you get 1. 1 % 3 is 1 which corresponds with the second character for the third digit, h. Therefore the string that corresponds with the number 15 is afh. This is performed for each number and the resulting strings are stored in r.
Recursive algorithm:
Space: each level of recursion is O(1) and there are O(n) levels. Thus it is O(n) for the recursion. The space of result is O(c^n), where c = max(lut[i].length). Total space for the algorithm is O(c^n).
Time: Let T(n) be the cost for digit with length n. Then we have recursion formula : T(n) <= c T(n-1) + O(1). Solve this equation give T(n) = O(c^n).
Hashing algorithm:
Space: if you need the space to store all results, then it is still O(c^n).
Time: O(n+c^n) = O(c^n).
I like the Hashing algorithm because it is better if the question asks you to give a specific string result (suppose we order them by alphabet order). In that case, the space and time is only O(n).
This question reminds me to a similar question: generate all permutations of the set {1,2,3,...,n}. The hashing approach is better because by generating the permutation one by one and process it, we can save a lot of space.

Find the number of strings w of length n over the alphabet {a, b, c}

I'm trying to figure out how to calculate the number of all strings of length n such that any substring of length 4 of string w, all three letters a, b, c occur. For example, abbcaabca should be printed when n = 9, but aabbcabac should not be included.
I was trying to make a math formula like
3^N - 3 * 2^N + 3 or (3^(N-3))*N!
Can it work this way or do I have to generate them and count them? I'm working with large numbers like 100, and I don't think I can generate them to count them.
You should probably be able to work your way up and start with let's say all possible words of length 4 and then add just one letter and count the possible allowed resulting words. Then you can iteratively go up to high numbers without having to explore all 3^N possibilities.
const unsigned w = 4;
unsigned n = 10;
vector<string> before,current;
// obtain all possible permutations of the strings "aabc", "abbc" and "abcc"
string base = "aabc";
before.emplace_back(base);
while(std::next_permutation(base.begin(),base.end())) before.emplace_back(base);
base = "abbc";
before.emplace_back(base);
while(std::next_permutation(base.begin(),base.end())) before.emplace_back(base);
base = "abcc";
before.emplace_back(base);
while(std::next_permutation(base.begin(),base.end())) before.emplace_back(base);
// iteratively add single letters to the words in the collection and add if it is a valid word
size_t posa,posb,posc;
for (unsigned k=1;k<n-w;++k)
{
current.clear();
for (const auto& it : before)
{
posa = it.find("a",k);
posb = it.find("b",k);
posc = it.find("c",k);
if (posb!= string::npos && posc!= string::npos) current.emplace_back(it+"a");
if (posa!= string::npos && posc!= string::npos) current.emplace_back(it+"b");
if (posa!= string::npos && posb!= string::npos) current.emplace_back(it+"c");
}
before = current;
}
for (const auto& it : current) cout<<it<<endl;
cout<<current.size()<<" valid words of length "<<n<<endl;
Note that with this you will still however run into the exponential wall pretty quickly... In a more efficient implementation I would represent words as integers (NOT vectors of integers, but rather integers in a base 3 representation), but the exponential scaling would still be there. If you are just interested in the number, #Jeffrey's approach is surely better.
The trick is to break down the problem. Consider:
Would knowing how many such strings, of length 50, ending in each pair of letter, help ?
Number of 50-string, ending in AA times
Number of 50-string, starting with B or C
+
Number of 50-string, ending in AB times
Number of 50-string, starting with C
+
All other combinations gives you the number of 100-long strings.
Continue breaking it down, recursively.
Look up dynamic programming.
Also look up large number libraries.

C++: First non-repeating character, O(n) time using hash map

I'm trying to write a function to get the first non-repeating character of a string. I haven't found a satisfactory answer on how to do this in O(n) time for all cases. My current solution is:
char getFirstNonRepeated(char * str) {
if (strlen(str) > 0) {
int visitedArray[256] = {}; // Where 256 is the size of the alphabet
for (int i = 0; i < strlen(str); i++) {
visitedArray[str[i]] += 1;
}
for (int j = 0; j < 256; j++) {
if (visitedArray[j] == 1) return j;
}
}
return '\0'; // Either strlen == 0 or all characters are repeated
}
However, as long as n < 256, this algorithm runs in O(n^2) time in the worst case. I've read that using a hash table instead of an array to store the number of times each character is visited could get the algorithm to run consistently in O(n) time, because insertions, deletions, and searches on hash tables run in O(1) time. I haven't found a question that explains how to do this properly. I don't have very much experience using hash maps in C++ so any help would be appreciated.
Why are you repeating those calls to strlen() in every loop? That is linear with the length of the string, so your first loop effectively becomes O(n^2) for no good reason at all. Just calculate the length once and store it, or use str[i] as the end condition.
You should also be aware that if your compiler uses signed characters, any character value above 127 will be considered negative (and used as a negative, i.e. out of bounds, array offset). You can avoid this by explicitly casting your character values to be unsigned char.

How can I remove the leading zeroes from an integer generated by a loop and store it as an array?

I have a for loop generating integers.
For instance:
for (int i=300; i>200; i--)
{(somefunction)*i=n;
cout<<n;
}
This produces an output on the screen like this:
f=00000000000100023;
I want to store the 100023 part of this number (i.e just ignore all the zeros before the non zero numbers start but then keeping the zeros which follow) as an array.
Like this:
array[0]=1;
array[1]=0;
array[2]=0;
array[3]=0;
array[4]=2;
array[5]=3;
How would I go about achieving this?
This is a mish-mash of answers, because they are all there, I just don't think you're seeing the solution.
First off, if they are integers Bill's answer along with the other answers are great, save some of them skip out on the "store in array" part. Also, as pointed out in a comment on your question, this part is a duplicate.
But with your new code, the solution I had in mind was John's solution. You just need to figure out how to ignore leading zero's, which is easy:
std::vector<int> digits;
bool inNumber = false;
for (int i=300; i>200; i--)
{
int value = (somefunction) * i;
if (value != 0)
{
inNumber = true; // its not zero, so we have entered the number
}
if (inNumber)
{
// this code cannot execute until we hit the first non-zero number
digits.push_back(value);
}
}
Basically, just don't start pushing until you've reached the actual number.
In light of the edited question, my original answer (below) isn't the best. If you absolutely have to have the output in an array instead of a vector, you can start with GMan's answer then transfer the resulting bytes to an array. You could do the same with JohnFx's answer once you find the first non-zero digit in his result.
I'm assuming f is of type int, in which case it doesn't store the leading zeroes.
int f = 100023;
To start you need to find the required length of the array. You can do that by taking the log (base 10) of f. You can import the cmath library to use the log10 function.
int length = log10(f);
int array[length];
length should now be 6.
Next you can strip each digit from f and store it in the array using a loop and the modulus (%) operator.
for(int i=length-1; i >= 0; --i)
{
array[i] = f % 10;
f = f / 10;
}
Each time through the loop, the modulus takes the last digit by returning the remainder from division by 10. The next line divides f by 10 to get ready for the next iteration of the loop.
The straightforward way would be
std::vector<int> vec;
while(MyInt > 0)
{
vec.push_back(MyInt%10);
MyInt /= 10;
}
which stores the decimals in reverse order (vector used to simplify my code).
Hang on a second. If you wrote the code generating the integers, why bother parsing it back into an array?
Why not just jam the integers into an array in your loop?
int array[100];
for (int i=300; i>200; i--)
{
array[i]= (somefunction)*i;
}
Since the leading zeros are not kept because it represents the same number
See: convert an integer number into an array