Find Number of Possible Alphabet Strings from Number Array - c++

Given a string 12345 and a alphabet to number mapping like a =1, b =2.., y=25, z=26; write a code to find the number of possible alphabet strings from the given string.
E.x. string 12345 has possible alphabet strings as {lcde,awde, abcde} from the mappings {12-3-4-5, 1-23-4-5, 1-2-3-4-5}.
I have a general idea of how to do it. I imagine it would be recursive. Look at the first digit and add it's char mapping to the result and then recurse with the sub array (1, size - 1). Also look at the two first digits and see if they are <= 26. If so, add that to the result and recurse (2, size - 2). Do this until number array is empty.
I get stuck on the actual implementation though. Is there a smarter way to do this than recursion?

This is similar to Word Break Problem. You can use same approach to solve it .you can use memoization to reduce overall running time. If you see in your given example:
12-3-4-5, 1-23-4-5, 1-2-3-4-5
4 and 5 is getting repeated and you are calculating it again and again. You can store permutation of given index first time you calculated and use it later whenever you visit same index.
pseudo code:
recursive_function(string,index)
if you have already calculated values for this index in previous call
return value
recursive_function(string,index+1)
if possible
recursive_function(string,index+2)
store this value for future use.
Detail:
when you have recursive call for say index i ,when you are done with this call (basically returning from current recursion) you have already used/calculated/found all possible values (all permutation for sub-string starting at index i). you can store these values because if you will see there may be times when you will come again to index i from some other index sayj (j<i). so now this time you can return from this place itself instead of more recursive call for index i as you have already calculated values for index i and that will be same irrespective of j

Just finish this coding, idea is from #dream_machine
Basically, it's a backtracking algorithm, complexity is O(2n!),
Need keep tracking the left to know should put string to output.
Seems the algorithm is too slow, maybe need add some memo to speed it up.
void helper(int start, string &s, string &path, vector<string> &result, int);
vector<string>
getPossibleCombo(string &s) {
vector<string> result;
string path;
helper(0, s, path, result, s.size());
return result;
}
void helper(int start, string &s, string &path, vector<string> &result, int left) {
if (start == s.size() && left == 0) {
result.push_back(path);
return;
}
for (int i = start; i < s.size(); i++) {
path.push_back('a' + (s[i] - '0') - 1);
helper(i + 1, s, path, result, left - 1);
path.pop_back();
if (i < s.size() - 1 && s[i] > '0' && s[i] <= '2') { // can try two.
if (s[i] == '2' && s[i+1] > '6')
continue;
int c = (s[i] - '0') * 10 + s[i + 1] - '0';
path.push_back('a' + c - 1);
helper(i + 2, s, path, result, left - 2);
path.pop_back();
}
}
}
int main() {
string s("12345");
auto r = getPossibleCombo(s);
for (auto &s : r) {
cout << s << endl;
}
}
output is
bash-3.2$ g++ -std=c++11 -g test2.cpp && ./a.out
abcde
awde
lcde

Related

Write a recursive function to convert a given string into the number it represents

In this code, I want to convert the string into integer by using recursive function but it is giving output in negetive.
#include <iostream>
using namespace std;
int convert1(string s) {
if (s.length() == 1) {
int i = s[0] - '0';
return i;
}
int so = convert1(s.substr(0, s.length() - 1));
int num = s[s.length()] - '0';
int ans = so * 10 + num;
return (int)ans;
}
int main()
{
string s;
cin >> s;
cout << convert1(s) << endl;
}
If you try printing s[s.length()] each time you call convert1, you'll see that it's printing 0. And then you're subtracting the value of '0' (48) from that.
Let's say we try to convert "12".
The length is not 1, so we call convert1 on "1".
That is of length 1, so we return 1.
So, if so is 1, and s[s.length()] is 0, then num is -48 and so * 10 + num evaluates to 1 * 10 - 48 which is -38.
For a two digit number input, you will always see the first digit times 10, minus 48. For a three digit number, you'll see (the first digit * ten minus 48) times 10 minus 48. This pattern continues on. If the first digit is large enough, it times 10 minus 48 creates a positive number. If that's large enough, positive numbers continue to propagate through the recursion. If they ever get smaller than 48, then once the result is negative, it will just get larger as a negative number the more recursive calls are made.
As opposed to the way you have done things, you can employ an accumulator parameter in convert1.
int convert1(string s, int acc=0) {
if (s.length() == 1) {
return acc * 10 + (s[0] - '0');
}
return convert1(s.substr(1, s.length() - 1),
acc * 10 + (s[0] - '0'));
}
Each time the function is recursively called, we update the accumulator by multiplying it by ten and adding the value of the first digit, and update the string by taking the "tail" of the string.
Or better, but a little bit further from your original, we return the accumulator when the string is empty.
int convert1(string s, int acc=0) {
if (s.empty()) return acc;
return convert1(s.substr(1, s.length() - 1),
acc * 10 + (s[0] - '0'));
}
The benefit of this tail recursion is that this function (if properly optimized by a decent compiler) can run in constant stack space. Though it's academic in this case as the int type will overflow before a stack overflow.
The normal way
int main()
{
string s;
cin >> s;
cout << strtol(s.c_str(), nullptr, 10) << endl;
}
Recursive for some reason
int convert_string(const char* string, int length){
if (length == 0) {
return 0;
}
int output = string[0] - '0';
output *= pow(10, length - 1);
output += convert_string(&string[1], --length);
return output;
}
int main()
{
std::string s;
std::cin >> s;
std::cout << convert_string(s.c_str(), s.length()) << std::endl;
}
When you compute the last digit
int num = s[s.length()] - '0';
you have an out-of-bounds access to the string. Changing that to
int num = s[s.length() - 1] - '0';
and your code works. Inefficiently.
You create a new substring in every recursion. There are 2 ways to improve on that:
make a helper function that makes a copy of the string and then calls the recursive function. The recursive function takes a std::string & s and then can use s.pop_back(). As a side benefit the helper function can easily deal with strings starting with '-'. You should have this helper anyway.
change the argument to std::string_view then it's just a reference into the string and substring will just shrink that reference. The string is never copied. That's actually the only change, just change std::string to std::string_view and done.
I think the std::string_view is the way to go but requires c++17. Combine that with the helper for dealing with '-'.
The next thing is s[s.length() - 1], which can be written as s.back(). Safes a bit of typing and no risk of an off-by-one error.
Then your condition for terminating the recursion is overly complex. You can write
if (s.empty()) return 0;
instead at the cost of an extra recursion call. On the other hand this allows parsing "". Not sure which way is faster, the simpler test might balance the extra recursive call. I like it because it doesn't repeat the digit conversion code and is less to type.
Next, if you are using std::string_view, then the s.substr(0, s.length() - 1) expression can be changed to using s.remove_suffix(1);.
All combined this gives you:
int convert1(std::string_view s) {
if (s.empty()) return 0;
int num = s.back() - '0';
s.remove_suffix(1);
int so = convert1(s)
int ans = so * 10 + num;
return ans;
}
One more thing to consider but it's a complete rewrite of your algorithm:
Your recursion isn't tail recursive. This uses up stack space proportional to the length of the string. While for parsing an "int" this shouldn't be a problem it will be a problem for larger problems. Or if someone just enters a really big number "14654645656348756...65464".
To solve this you have to turn your algorithm around. Instead of chopping digits of at the end take them from the front like you would doing this iteratively:
int iterative_convert(const std::string &s) {
int acc = 0;
for (const auto c : s) acc = acc * 10 + (c - '0');
return acc;
}
To make this recursive you have to pass the intermediate result as accumulator down the recursion. So it becomes this:
int convert1(std::string_view s, int acc = 0) {
if (s.empty()) return acc;
acc = 10 * acc + (s.front() - '0');
return convert1(s.substr(1), acc);
}
Not sure how you came up with the back to front algorithm but front to back results in better code.
Note: Short of needing c++17, or if you prefer, you can also use std::string::const_iterator (requires passing s.cend() as extra argument) or good old const char *p = s.c_str();

Why calculate the remainders here?

I am trying to solve a question on LeetCode.com:
An encoded string S is given. To find and write the decoded string to a tape, the encoded string is read one character at a time and the following steps are taken:
If the character read is a letter, that letter is written onto the tape.
If the character read is a digit (say d), the entire current tape is repeatedly written d-1 more times in total.
Now for some encoded string S, and an index K, find and return the K-th letter (1 indexed) in the decoded string.
The most upvoted solution goes like this:
string decodeAtIndex(string S, int K) {
long N = 0, i;
for (i = 0; N < K; ++i)
N = isdigit(S[i]) ? N * (S[i] - '0') : N + 1;
while (i--)
if (isdigit(S[i]))
N /= S[i] - '0', K %= N; // what's the intuition for this
else if (K % N-- == 0) // and this?
return string(1, S[i]);
return "lee215";
}
While I carried out a dry-run over the code using pen-and-paper, I am not sure I fully understand the intuition behind the commented lines.
How does this work?

Runtime of KMP algorithm and LPS table construction

I recently came across the KMP algorithm, and I have spent a lot of time trying to understand why it works. While I do understand the basic functionality now, I simply fail to understand the runtime computations.
I have taken the below code from the geeksForGeeks site: https://www.geeksforgeeks.org/kmp-algorithm-for-pattern-searching/
This site claims that if the text size is O(n) and pattern size is O(m), then KMP computes a match in max O(n) time. It also states that the LPS array can be computed in O(m) time.
// C++ program for implementation of KMP pattern searching
// algorithm
#include <bits/stdc++.h>
void computeLPSArray(char* pat, int M, int* lps);
// Prints occurrences of txt[] in pat[]
void KMPSearch(char* pat, char* txt)
{
int M = strlen(pat);
int N = strlen(txt);
// create lps[] that will hold the longest prefix suffix
// values for pattern
int lps[M];
// Preprocess the pattern (calculate lps[] array)
computeLPSArray(pat, M, lps);
int i = 0; // index for txt[]
int j = 0; // index for pat[]
while (i < N) {
if (pat[j] == txt[i]) {
j++;
i++;
}
if (j == M) {
printf("Found pattern at index %d ", i - j);
j = lps[j - 1];
}
// mismatch after j matches
else if (i < N && pat[j] != txt[i]) {
// Do not match lps[0..lps[j-1]] characters,
// they will match anyway
if (j != 0)
j = lps[j - 1];
else
i = i + 1;
}
}
}
// Fills lps[] for given patttern pat[0..M-1]
void computeLPSArray(char* pat, int M, int* lps)
{
// length of the previous longest prefix suffix
int len = 0;
lps[0] = 0; // lps[0] is always 0
// the loop calculates lps[i] for i = 1 to M-1
int i = 1;
while (i < M) {
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
else // (pat[i] != pat[len])
{
// This is tricky. Consider the example.
// AAACAAAA and i = 7. The idea is similar
// to search step.
if (len != 0) {
len = lps[len - 1];
// Also, note that we do not increment
// i here
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}
// Driver program to test above function
int main()
{
char txt[] = "ABABDABACDABABCABAB";
char pat[] = "ABABCABAB";
KMPSearch(pat, txt);
return 0;
}
I am really confused why that is the case.
For LPS computation, consider: aaaaacaaac
In this case, when we try to compute LPS for the first c, we would keep going back until we hit LPS[0], which is 0 and stop. So, essentially, we would travel back atleast the length of the pattern until that point. If this happens multiple times, how will time complexity be O(m)?
I have similar confusion on runtime of KMP to be O(n).
I have read other threads in stack overflow before posting, and also various other sites on the topic. I am still very confused. I would really appreciate if someone can help me understand the best and worse case scenarios for these algorithms and how their runtime is computed using some examples. Again, please don't suggest I google this, I have done it, spent a whole week trying to gain any insight, and failed.
One way to establish an upper bound on the runtime for construction of the LPS array is to consider a pathological case - how can we maximize the number of times we have to execute len = lps[len - 1]? Consider the following string, ignoring spaces: x1 x2 x1x3 x1x2x1x4 x1x2x1x3x1x2x1x5 ...
The second term needs to be compared to the first term as if it ended in 1 instead of 2, it would match the first term. Similarly the third term needs to be compared to the first two terms as if it ended in 1 or 2 instead of 3, it would match those partial terms. And so forth.
In the example string, it is clear that only every 1/2^n characters can match n times, so the total runtime will be m+m/2+m/4+..=2m=O(m), the length of the pattern string. I suspect it's impossible to construct a string with worse runtime than the example string and this can probably be formally proven.

Finding substring inside string with any order of characters of substring in C/C++

Suppose I have a string "abcdpqrs",
now "dcb" can be counted as a substring of above string as the characters are together.
Also "pdq" is a part of above string. But "bcpq" is not. I hope you got what I want.
Is there any efficient way to do this.
All I can think is taking help of hash to do this. But it is taking long time even in O(n) program as backtracking is required in many cases. Any help will be appreciated.
Here is an O(n * alphabet size) solution:
Let's maintain an array count[a] = how many times the character a was in the current window [pos; pos + lenght of substring - 1]. It can be recomputed in O(1) time when the window is moved by 1 to the right(count[s[pos]]--, count[s[pos + substring lenght]]++, pos++). Now all we need is to check for each pos that count array is the same as count array for the substring(it can be computed only once).
It can actually be improved to O(n + alphabet size):
Instead of comparing count arrays in a naive way, we can maintain the number diff = number of characters that do not have the same count value as in a substring for the current window. The key observation is that diff changes in obvious way we apply count[c]-- or count[c]++ (it either gets incremented, decremented or stays the same depending on only count[c] value). Two count arrays are the same if and only if diff is zero for current pos.
Lets say you have the string "axcdlef" and wants to search "opde":
bool compare (string s1, string s2)
{
// sort both here
// return if they are equal when sorted;
}
you would need to call this function for this example with the following substrings of size 4(same as length as "opde"):
"axcd"
"xcdl"
"cdle"
"dlef"
bool exist = false;
for (/*every split that has the same size as the search */)
exist = exist || compare(currentsplit, search);
You can use a regex (i.e boost or Qt) for this. Alternately you an use this simple approach. You know the length k of the string s to be searched in string str. So take each k consecutive characters from str and check if any of these characters is present in s.
Starting point ( a naive implementation to make further optimizations):
#include <iostream>
/* pos position where to extract probable string from str
* s string set with possible repetitions being searched in str
* str original string
*/
bool find_in_string( int pos, std::string s, std::string str)
{
std::string str_s = str.substr( pos, s.length());
int s_pos = 0;
while( !s.empty())
{
std::size_t found = str_s.find( s[0]);
if ( found!=std::string::npos)
{
s.erase( 0, 1);
str_s.erase( found, 1);
} else return 0;
}
return 1;
}
bool find_in_string( std::string s, std::string str)
{
bool found = false;
int pos = 0;
while( !found && pos < str.length() - s.length() + 1)
{
found = find_in_string( pos++, s, str);
}
return found;
}
Usage:
int main() {
std::string s1 = "abcdpqrs";
std::string s2 = "adcbpqrs";
std::string searched = "dcb";
std::string searched2 = "pdq";
std::string searched3 = "bcpq";
std::cout << find_in_string( searched, s1);
std::cout << find_in_string( searched, s2);
std::cout << find_in_string( searched2, s1);
std::cout << find_in_string( searched3, s1);
return 0;
}
prints: 1110
http://ideone.com/WrSMeV
To use an array for this you are going to need some extra code to map where each character goes in there... Unless you know you are only using 'a' - 'z' or something similar that you can simply subtract from 'a' to get the position.
bool compare(string s1, string s2)
{
int v1[SIZE_OF_ALFABECT];
int v2[SIZE_OF_ALFABECT];
int count = 0;
map<char, int> mymap;
// here is just pseudocode
foreach letter in s1:
if map doesnt contain this letter already:
mymap[letter] = count++;
// repeat the same foreach in s2
/* You can break and return false here if you try to add new char into map,
that means that the second string has a different character already... */
// count will now have the number of distinct chars that you have in both strs
// you will need to check only 'count' positions in the vectors
for(int i = 0; i < count; i++)
v1[i] = v2[i] = 0;
//another pseudocode
foreach letter in s1:
v1[mymap[leter]]++;
foreach letter in s1:
v2[mymap[leter]]++;
for(int i = 0; i < count; i++)
if(v1[i] != v2[i])
return false;
return true;
}
Here is a O(m) best case, O(m!) worst case solution - m being the length of your search string:
Use a suffix-trie, e.g. a Ukkonnen Trie (there are some floating around, but I have no link at hand at the moment), and search for any permutation of the substring. Note that any lookup needs just O(1) for each chararacter of the string to search, regardless of the size of n.
However, while the size of n does not matter, this becomes inpractical for large m.
If however n is small enough anf one is willing to sacrifice lookup performance for index size, the suffix trie can store a string that contains all permutations of the original string.
Then the lookup will always be O(m).
I'd suggest to go with the accepted answer for the general case. However, here you have a suggestion that can perform (much) better for small substrings and large string.

Determining the individual letters of Fibonacci strings?

The Fibonacci strings are defined as follows:
The first Fibonacci string is "a"
The second Fibonacci string is "bc"
The (n + 2)nd Fibonacci string is the concatenation of the two previous Fibonacci strings.
For example, the first few Fibonacci strings are
a
bc
abc
bcabc
abcbcabc
The goal is, given a row and an offset, to determine what character is at that offset. More formally:
Input: Two integers separated by a space - K and P(0 < K ≤ 109), ( < P ≤ 109), where K is the line number of the Fibonacci string and P is the position number in a row.
Output: The desired character for the relevant test: "a", "b" or "c". If P is greater than the kth row (K ≤ 109), it is necessary to derive «No solution»
Example:
input: 18 58
output: a
I wrote this code to solve the problem:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
int k, p;
string s1 = "a";
string s2 = "bc";
vector < int >fib_numb;
fib_numb.push_back(1);
fib_numb.push_back(2);
cin >> k >> p;
k -= 1;
p -= 1;
while (fib_numb.back() < p) {
fib_numb.push_back(fib_numb[fib_numb.size() - 1] + fib_numb[fib_numb.size() - 2]);
}
if (fib_numb[k] <= p) {
cout << "No solution";
return 0;
}
if ((k - fib_numb.size()) % 2 == 1)
k = fib_numb.size() + 1;
else
k = fib_numb.size();
while (k > 1) {
if (fib_numb[k - 2] > p)
k -= 2;
else {
p -= fib_numb[k - 2];
k -= 1;
}
}
if (k == 1)
cout << s2[p];
else
cout << s1[0];
return 0;
}
Is it correct? How would you have done?
You can solve this problem without explicitly computing any of the strings, and this is probably the best way to solve the problem. After all, if you're asked to compute the 50th Fibonacci string, you're almost certain to run out of memory; F(50) is 12,586,269,025, so you'd need over 12Gb of memory just to hold it!
The intuition behind the solution is that because each line of the Fibonacci strings are composed of the characters of the previous lines, you can convert an (row, offset) pair into a different (row', offset') pair where the new row is always for a smaller Fibonacci string than the one you started with. If you repeat this enough times, eventually you will arrive back at the Fibonacci strings for either row 0 or row 1, in which case the answer can immediately be read off.
In order to make this algorithm work, we need to establish a few facts. First, let's define the Fibonacci series to be zero-indexed; that is, the sequence is
F(0) = 0
F(1) = 1
F(n+2) = F(n) + F(n + 1)
Given this, we know that the nth row (one-indexed) of the Fibonacci strings has a total of F(n + 1) characters in it. You can see this quickly by induction:
Row 1 has length 1 = F(2) = F(1 + 1)
Row 2 has length 2 = F(3) = F(2 + 1).
For some row n + 2, the length of that row is given by Size(n) + Size(n + 1) = F(n + 1) + F(n + 2) = F(n + 3) = F((n + 2) + 1)
Using this knowledge, let's suppose that we want to find the seventh character of the seventh row of the Fibonacci strings. We know that row seven is composed of the concatenation of rows five and six, so the string looks like this:
R(7) = R(5) R(6)
Row five has F(5 + 1) = F(6) = 8 characters in it, which means that the first eight characters of row seven come from R(5). Since we want the seventh character out of this row, and since 7 ≤ 8, we know that we now need to look at the seventh character of row 5 to get this value. Well, row 5 looks like the concatenation of rows 3 and 4:
R(5) = R(3) R(4)
We want to find the seventh character of this row. Now, R(3) has F(4) = 3 characters in it, which means that if we are looking for the seventh character of R(5), it's going to be in the R(4) part, not the R(3) part. Since we're looking for the seventh character of this row, it means that we're looking for the the 7 - F(4) = 7 - 3 = 4th character of R(4), so now we look there. Again, R(4) is defined as
R(4) = R(2) R(3)
R(2) has F(3) = 2 characters in it, so we don't want to look in it to find the fourth character of the row; that's going to be contained in R(3). The fourth character of the line must be the second character of R(3). Let's look there. R(3) is defined as
R(3) = R(1) R(2)
R(1) has one character in it, so the second character of this line must be the first character of R(1), so we look there. We know, however, that
R(2) = bc
So the first character of this string is b, which is our answer. Let's see if this is right. The first seven rows of the Fibonacci strings are
1 a
2 bc
3 abc
4 bcabc
5 abcbcabc
6 bcabcabcbcabc
7 abcbcabcbcabcabcbcabc
Sure enough, if you look at the seventh character of the seventh string, you'll see that it is indeed a b. Looks like this works!
More formally, the recurrence relation we are interested in looks like this:
char NthChar(int row, int index) {
if (row == 1) return 'a';
if (row == 2 && index == 1) return 'b';
if (row == 2 && index == 2) return 'c';
if (index < Fibonacci(row - 1)) return NthChar(row - 2, index);
return NthChar(row - 1, index - Fibonacci(row - 1));
}
Now, of course, there's a problem with the implementation as written here. Because the row index can range up to 109, we can't possibly compute Fibonacci(row) in all cases; the one billionth Fibonacci number is far too large to represent!
Fortunately, we can get around this. If you look at a table of Fibonacci numbers, you'll find that F(45) = 1,134,903,170, which is greater than 109 (and no smaller Fibonacci number is greater than this). Moreover, since we know that the index we care about must also be no greater than one billion, if we're in row 46 or greater, we will always take the branch where we look in the first half of the Fibonacci string. This means that we can rewrite the code as
char NthChar(int row, int index) {
if (row == 1) return 'a';
if (row == 2 && index == 1) return 'b';
if (row == 2 && index == 2) return 'c';
/* Avoid integer overflow! */
if (row >= 46) return NthChar(row - 2, index);
if (index < Fibonacci(row - 1)) return NthChar(row - 2, index);
return NthChar(row - 1, index - Fibonacci(row - 1));
}
At this point we're getting very close to a solution. There are still a few problems to address. First, the above code will almost certainly blow out the stack unless the compiler is good enough to use tail recursion to eliminate all the stack frames. While some compilers (gcc, for example) can detect this, it's probably not a good idea to rely on it, and so we probably should rewrite this recursive function iteratively. Here's one possible implementation:
char NthChar(int row, int index) {
while (true) {
if (row == 1) return 'a';
if (row == 2 && index == 1) return 'b';
if (row == 2 && index == 2) return 'c';
/* Avoid integer overflow! */
if (row >= 46 || index < Fibonacci(row - 1)) {
row -= 2;
} else {
index -= Fibonacci(row - 1);
row --;
}
}
}
But of course we can still do much better than this. In particular, if you're given a row number that's staggeringly huge (say, one billion), it's really silly to keep looping over and over again subtracting two from the row until it becomes less than 46. It makes a lot more sense to just determine what value it's ultimately going to become after we do all the subtraction. But we can do this quite easily. If we have an even row that's at least 46, we'll end up subtracting out 2 until it becomes 44. If we have an odd row that's at least 46, we'll end up subtracting out 2 until it becomes 45. Consequently, we can rewrite the above code to explicitly handle this case:
char NthChar(int row, int index) {
/* Preprocess the row to make it a small value. */
if (row >= 46) {
if (row % 2 == 0)
row = 45;
else
row = 44;
}
while (true) {
if (row == 1) return 'a';
if (row == 2 && index == 1) return 'b';
if (row == 2 && index == 2) return 'c';
if (index < Fibonacci(row - 1)) {
row -= 2;
} else {
index -= Fibonacci(row - 1);
row --;
}
}
}
There's one last thing to handle, which is what happens if there isn't a solution to the problem because the character is out of range. But we can easily fix this up:
string NthChar(int row, int index) {
/* Preprocess the row to make it a small value. */
if (row >= 46) {
if (row % 2 == 0)
row = 45;
else
row = 44;
}
while (true) {
if (row == 1 && index == 1) return "a"
if (row == 2 && index == 1) return "b";
if (row == 2 && index == 2) return "c";
/* Bounds-checking. */
if (row == 1) return "no solution";
if (row == 2) return "no solution";
if (index < Fibonacci(row - 1)) {
row -= 2;
} else {
index -= Fibonacci(row - 1);
row --;
}
}
}
And we've got a working solution.
One further optimization you might do is precomputing all of the Fibonacci numbers that you'll need and storing them in a giant array. You only need Fibonacci values for F(2) through F(44), so you could do something like this:
const int kFibonacciNumbers[45] = {
0, 1, 1, 2, 3, 5,
8, 13, 21, 34, 55, 89,
144, 233, 377, 610,
987, 1597, 2584, 4181,
6765, 10946, 17711, 28657,
46368, 75025, 121393, 196418,
317811, 514229, 832040,
1346269, 2178309, 3524578,
5702887, 9227465, 14930352,
24157817, 39088169, 63245986,
102334155, 165580141, 267914296,
433494437, 701408733
};
With this precomputed array, the final version of the code would look like this:
string NthChar(int row, int index) {
/* Preprocess the row to make it a small value. */
if (row >= 46) {
if (row % 2 == 0)
row = 45;
else
row = 44;
}
while (true) {
if (row == 1 && index == 1) return "a"
if (row == 2 && index == 1) return "b";
if (row == 2 && index == 2) return "c";
/* Bounds-checking. */
if (row == 1) return "no solution";
if (row == 2) return "no solution";
if (index < kFibonacciNumbers[row - 1]) {
row -= 2;
} else {
index -= kFibonacciNumbers[row - 1];
row --;
}
}
}
I have not yet tested this; to paraphrase Don Knuth, I've merely proved it correct. :-) But I hope this helps answer your question. I really loved this problem!
I guess your general idea should be OK, but I don't see how your code is going to deal with larger values of K, because the numbers will get enormous quickly, and even with large integer libraries it might take virtually forever to compute fibonacci(10^9) exactly.
Fortunately, you are only asked about the first 10^9 characters. The string will reach that many characters already on the 44th line (f(44) = 1134903170).
And if I'm not mistaken, from there on the first 10^9 characters will be simply alternating between the prefixes of line 44 and 45, and therefore in pseudocode:
def solution(K, P):
if K > 45:
if K % 2 == 0:
return solution(44, P)
else:
return solution(45, P)
#solution for smaller values of K here
I found this. I did not do a pre-check (get the size of the k-th fibo string to test p againt it) because if the check is successful you'll have to compute it anyway. Of course as soon as k becomes big, you may have an overflow issue (the length of the fibo string is an exponential function of the index n...).
#include <iostream>
#include <string>
using namespace std;
string fibo(unsigned int n)
{
if (n == 0)
return "a";
else if (n == 1)
return "bc";
else
return fibo(n - 2) + fibo(n - 1);
}
int main()
{
unsigned int k, p;
cin >> k >> p;
--k;
--p;
string fiboK = fibo(k);
if (p > fiboK.size())
cout << "No solution" << endl;
else
cout << fiboK[p] << endl;
return 0;
}
EDIT: ok, I now see your point, i.e. checking in which part of the k-th string p resides (i.e. in string k - 2 or k - 1, and updating p if needed). Of course this is the good way to do it, since as I was saying above my naive solution will explode quite too quickly.
Your way looks correct to me from an algorithm point of view (saves memory and complexity).
I would have computed the K-th Fibonacci String, and then retrieve the P-th character of it. Something like that:
#include <iostream>
#include <string>
#include <vector>
std::string FibonacciString(unsigned int k)
{
std::vector<char> buffer;
buffer.push_back('a');
buffer.push_back('b');
buffer.push_back('c');
unsigned int curr = 1;
unsigned int next = 2;
while (k --)
{
buffer.insert(
buffer.end(),
buffer.begin(),
buffer.end());
buffer.erase(
buffer.begin(),
buffer.begin() + curr);
unsigned int prev = curr;
curr = next;
next = prev + next;
}
return std::string(
buffer.begin(),
buffer.begin() + curr);
}
int main(int argc, char** argv)
{
unsigned int k, p;
std::cin >> k >> p;
-- p;
-- k;
std::string fiboK = FibonacciString(k);
if (p > fiboK.size())
std::cout << "No solution";
else
std::cout << fiboK[p];
std::cout << std::endl;
return 0;
}
It does use more memory than your version since it needs to store both the N-th and the (N+1)-th Fibonacci string at every instant. However, since it is really close to the definition, it does work for every value.
Your algorithm seems to have some issue when k is large while p is small. The test fib_num[k] < p will dereference an item outside of the range of the array with k = 30 and p = 1, won't it ?
I made another example where each corresponding number of Fibonnaci series corresponds to the letter in the alfabet. So for 1 is a, for 2 is b, for 3 is c, for 5 is e... etc:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string a = "abcdefghijklmnopqrstuvwxyz"; //the alphabet
string a1 = a.substr(0,0); string a2 = a.substr(1,1); string nexT = a.substr(0,0);
nexT = a1 + a2;
while(nexT.length() <= a.length())
{
//cout << nexT.length() << ", "; //show me the Fibonacci numbers
cout << a.substr(nexT.length()-1,1) << ", "; //show me the Fibonacci letters
a1 = a2;
a2 = nexT;
nexT = a1 + a2;
}
return 0;
}
Output: a, b, c, e, h, m, u,
Quote from Wikipedia, Fibonacci_word:
The nth digit of the word is 2+[nφ]-[(n+1)φ] where φ is the golden ratio ...
(The only characters used in the Wikipedia page are 1 and 0.)
But note that the strings in the Wikipedia page, and in Knuth s Fundamental Algorithms, are built up in the opposite order of the above shown strings; there it becomes clear when the strings are listed, with ever repeating leading part, that there is only one infinitely long Fibonacci string. It is less clear when generated in the above used order, for the ever repeating part is the string s trailing part, but it is no less true. Therefore the term "the word" in the quotation, and, except for the question "is n too great for this row?", the row is not important.
Unhappily, though, it is too hard to apply this formula to the poster s problem, because in this formula the original strings are of the same length, and poster began with "a" and "bc".
This J(ava)Script script generates the Fibonacci string over the characters the poster chose, but in the opposite order. (It contains the Microsoft object WScript used for fetching command-line argument and outputting to the standard output.)
var u, v /*Fibonacci numbers*/, g, i, k, R;
v = 2;
u = 1;
k = 0;
g = +WScript.arguments.item(0); /*command-line argument for desired length of string*/
/*Two consecutiv Fibonacci numbers, with the greater no less than the
Fibonacci string s length*/
while (v < g)
{ v += u;
u = v - u;
k = 1 - k;
}
i = u - k;
while (g-- > 0)
{ /*In this operation, i += u with i -= v when i >= v (carry),
since the Fibonacci numbers are relativly prime, i takes on
every value from 0 up to v. Furthermore, there are u carries,
and, therefore, u instances of character 'cb', and v-u instances
of 'a' (no-carry). The characters are spread as evenly as can be.*/
if ((i += u) < v)
{ R = 'a'; // WScript.StdOut.write('a'); /* no-carry */
} else
{ i -= v; /* carry */
R = 'cb'; // WScript.StdOut.write('cb')
}
}
/*result is in R*/ // WScript.StdOut.writeLine()
I suggest it because actually outputting the string is not required. One can simply stop at the desired length, and show the last thing about to be outputted. (The code for output is commented out with '//'). Of course, using this to find the character at position n has cost proportional to n. The formula at the top costs much less.