Time optimize C++ function to find number of decoding possibilities - c++

This is an interview practice problem from CodeFights. I have a solution that's working except for the fact that it takes too long to run for very large inputs.
Problem Description (from the link above)
A top secret message containing uppercase letters from 'A' to 'Z' has been encoded as numbers using the following mapping:
'A' -> 1
'B' -> 2
...
'Z' -> 26
You are an FBI agent and you need to determine the total number of ways that the message can be decoded.
Since the answer could be very large, take it modulo 10^9 + 7.
Example
For message = "123", the output should be
mapDecoding(message) = 3.
"123" can be decoded as "ABC" (1 2 3), "LC" (12 3) or "AW" (1 23), so the total number of ways is 3.
Input/Output
[time limit] 500ms (cpp)
[input] string message
A string containing only digits.
Guaranteed constraints:
0 ≤ message.length ≤ 105.
[output] integer
The total number of ways to decode the given message.
My Solution so far
We have to implement the solution in a function int mapDecoding(std::string message), so my entire solution is as follows:
/*0*/ void countValidPaths(int stIx, int endIx, std::string message, long *numPaths)
/*1*/ {
/*2*/ //check out-of-bounds error
/*3*/ if (endIx >= message.length())
/*4*/ return;
/*5*/
/*6*/ int subNum = 0, curCharNum;
/*7*/ //convert substr to int
/*8*/ for (int i = stIx; i <= endIx; ++i)
/*9*/ {
/*10*/ curCharNum = message[i] - '0';
/*11*/ subNum = subNum * 10 + curCharNum;
/*12*/ }
/*13*/
/*14*/ //check for leading 0 in two-digit number, which would not be valid
/*15*/ if (endIx > stIx && subNum < 10)
/*16*/ return;
/*17*/
/*18*/ //if number is valid
/*19*/ if (subNum <= 26 && subNum >= 1)
/*20*/ {
/*21*/ //we've reached the end of the string with success, therefore return a 1
/*22*/ if (endIx == (message.length() - 1) )
/*23*/ ++(*numPaths);
/*24*/ //branch out into the next 1- and 2-digit combos
/*25*/ else if (endIx == stIx)
/*26*/ {
/*27*/ countValidPaths(stIx, endIx + 1, message, numPaths);
/*28*/ countValidPaths(stIx + 1, endIx + 1, message, numPaths);
/*29*/ }
/*30*/ //proceed to the next digit
/*31*/ else
/*32*/ countValidPaths(endIx + 1, endIx + 1, message, numPaths);
/*33*/ }
/*34*/ }
/*35*/
/*36*/ int mapDecoding(std::string message)
/*37*/ {
/*38*/ if (message == "")
/*39*/ return 1;
/*40*/ long numPaths = 0;
/*41*/ int modByThis = static_cast<int>(std::pow(10.0, 9.0) + 7);
/*42*/ countValidPaths(0, 0, message, &numPaths);
/*43*/ return static_cast<int> (numPaths % modByThis);
/*44*/ }
The Issue
I have passed 11/12 of CodeFight's initial test cases, e.g. mapDecoding("123") = 3 and mapDecoding("11115112112") = 104. However, the last test case has message = "1221112111122221211221221212212212111221222212122221222112122212121212221212122221211112212212211211", and my program takes too long to execute:
Expected_output: 782204094
My_program_output: <empty due to timeout>
I wrote countValidPaths() as a recursive function, and its recursive calls are on lines 27, 28 and 32. I can see how such a large input would cause the code to take so long, but I'm racking my brain trying to figure out what more efficient solutions would cover all possible combinations.
Thus the million dollar question: what suggestions do you have to optimize my current program so that it runs in far less time?

A couple of suggestions.
First this problem can probably be formulated as a Dynamic Programming problem. It has that smell to me. You are computing the same thing over and over again.
The second is the insight that long contiguous sequences of "1"s and "2"s are a Fibonacci sequence in terms of the number of possibilities. Any other value terminates the sequence. So you can split the strings into runs of of ones and twos terminated by any other number. You will need special logic for a termination of zero since it does not also correspond to a character. So split the strings count, the length of each segment, look up the fibonacci number (which can be pre-computed) and multiply the values. So your example "11115112112" yields "11115" and "112112" and f(5) = 8 and f(6) = 13, 8*13 = 104.
Your long string is a sequence of 1's and 2's that is 100 digits long. The following Java (Sorry, my C++ is rusty) program correctly computes its value by this method
public class FibPaths {
private static final int MAX_LEN = 105;
private static final BigInteger MOD_CONST = new BigInteger("1000000007");
private static BigInteger[] fibNum = new BigInteger[MAX_LEN];
private static void computeFibNums() {
fibNum[0] = new BigInteger("1");
fibNum[1] = new BigInteger("1");
for (int i = 2; i < MAX_LEN; i++) {
fibNum[i] = fibNum[i-2].add(fibNum[i-1]);
}
}
public static void main(String[] argv) {
String x = "1221112111122221211221221212212212111221222212122221222112122212121212221212122221211112212212211211";
computeFibNums();
BigInteger val = fibNum[x.length()].mod(MOD_CONST);
System.out.println("N=" + x.length() + " , val = " + val);
}
}

Related

Error with two credit card numbers. Identifies the number as the wrong credit card type

These are my current errors, I think I did something wrong with the maths but everything I tried didn't work.
Ps: Sorry if my question's formatting is bad, first time using stackflow.
:) credit.c exists
:) credit.c compiles
:) identifies 378282246310005 as AMEX
:) identifies 371449635398431 as AMEX
:) identifies 5555555555554444 as MASTERCARD
:) identifies 5105105105105100 as MASTERCARD
:) identifies 4111111111111111 as VISA
:) identifies 4012888888881881 as VISA
:) identifies 4222222222222 as VISA
:) identifies 1234567890 as INVALID
:) identifies 369421438430814 as INVALID
:) identifies 4062901840 as INVALID
:) identifies 5673598276138003 as INVALID
:( identifies 4111111111111113 as INVALID
expected "INVALID\n", not "VISA\n"
:( identifies 4222222222223 as INVALID
expected "INVALID\n", not "VISA\n"
#include <cs50.h>
#include <math.h>
// Prompt user for credit card number
int main(void)
{
long credit_card, credit_number;
do
{
credit_card = get_long("Enter credit card number: ");
}
while (credit_card < 0);
credit_number = credit_card;
// Calculate total number of digits
int count = (credit_number == 0) ? 1 : (log10(credit_number) + 1);
int summation = 0;
while (credit_number == 0)
{
int x = credit_number % 10; summation += x;
int y = 2 * ((credit_number / 10) % 10);
int r = (y % 10) + floor((y / 10) % 10); summation += r; credit_number /= 100;
}
string card;
// Identify which card type you get after inputing your credit card number
int test = cc / pow(10, count - 2);
if ((count == 13 || count == 16) && test / 10 == 4)
{
card = "VISA";
}
else if (count == 16 && test >= 51 && test <= 55)
{
card = "MASTERCARD";
}
else if (count == 15 && (test == 34 || test == 37))
{
card = "AMEX";
}
else
{
card = "INVALID";
}
// Final verification
if (sum % 10 == 0)
{
printf("%s\n", card);
}
else
{
printf("INVALID\n");
}
}```
Your algorithm is maybe not fully correct. I would therefore propose a different approach. You can look at each single digit in a loop. And, you can also do the whole checksum calculation in one step.
I will show you how to do and explain the algorithm behind it.
BTW. Chosing the right algorithm is always the key for success.
So, first we need to think on how we can extract digits from a number. This can be done in a loop by repeating the follwoing steps:
Perform a modulo 10 division to get a digit
Do a integer division by 10
Repeat
Let us look at the example 1234.
Step 1 will get the 4 -- (1234 % 10 = 4)
Step 2 will convert original number into 123 -- (1234 / 10 = 123)
Step 1 will get the 3 -- (123 % 10 = 3)
Step 2 will convert the previous number into 12 -- (123 / 10 = 12)
Step 1 will get the 2 -- (12 % 10 = 2)
Step 2 will convert the previous number into 1 -- (12 / 10 = 1)
Step 1 will get the 1 -- (1 % 10 = 1)
Step 2 will convert the previous number into 0 -- (1 / 10 = 0)
Then the loop stops. Additionally we can observe that the loop stops, when the resulting divided becomes 0. And, we see addtionally that the number of loop executions is equal to the number of digits in the number. But this is somehow obvious.
OK, then let us look, what we learned so far
while (creditCardNumber > 0) {
unsigned int digit = creditCardNumber % 10;
creditCardNumber /= 10;
++countOfDigits;
}
This will get all digits and count them.
Good. Lets go to next step.
For later validation and comparison purpose we need to get the most significant digit (the first digit) and the second most significant digit (the second digit) of the number.
For this, we define 2 variables which will hold the number. We simply assign the current evaluated digit (and override it in each loop execution) to the "mostSignificantDigit". At the end of the loop, we will have it in our desired variable.
For the "secondMostSignificantDigit" we will simple copy the "old" or "previous" value of the "mostSignificantDigit", before assigning a new value to "mostSignificantDigit". With that, we will always have both values available.
The loop looks now like this:
while (creditCardNumber > 0) {
const unsigned int digit = creditCardNumber % 10;
secondMostSignificantDigit = mostSignificantDigit;
mostSignificantDigit = digit;
creditCardNumber /= 10;
++countOfDigits;
}
OK, now we come to the maybe more complex part. The cheksum. The calculation method is.
Start with the least significant (the last) digit
Do not multiply the digit, which is equivalent with multiplying it with 1, and add it to the checksum
Goto the next digit. Multiply it by 2. If the result is greater than 10, then get again the single digits and add both digits to the checksum
Repeat
So, the secret is, to analyze the somehow cryptic specification, given here. If we start with the last digit, we do not multiply it, the next digit will be multiplied, the next not and so on and so on.
To "not multiply" is the same as multiplying by 1. This means: In the loop we need to multiply alternating with 1 or with 2.
How to get alternating numbers in a loop? The algorithm for that is fairly simple. If you need alternating numbers, lets say, x,y,x,y,x,y,x..., Then, build the sum of x and y and perform the subtratcion "value = sum - value". Example:
We need alternating values 1 and 2. The sum is 3. To get the next value, we subtract the current value from the sum.
initial value = 1
sum = 3
current value = initial value = 1
next value = 3 - 1 = 2. Current value = 2
next value = 3 - 2 = 1. Current value = 1
next value = 3 - 1 = 2. Current value = 2
next value = 3 - 2 = 1. Current value = 1
next value = 3 - 1 = 2. Current value = 2
next value = 3 - 2 = 1. Current value = 1
. . .
Good, now we understand, how to make alternating values.
Next, If we multiply a digit with 2, then the maximum result maybe a 2 digit value. We get the single digits with a modulo and an integer division by 10.
And, now important, it does not matter, if we multiply or not, because, if we do not multiply, then the upper digit will always be 0. And this will not contribute to the sum.
With all that, we can always do a multiplication and always split the result into 2 digits (many of them having the upper digit 0).
The result will be:
checkSum += (digit * multiplier) % 10 + (digit * multiplier) / 10;
multiplier = 3 - multiplier;
An astonishingly simple formula.
Next, if we know C or C++ we also know that a multiplication with 2 can be done very efficiently with a bit shift left. And, additionally, a "no-multiplication" can be done with a bit shift 0. That is extremely efficient and faster than multiplication.
x * 1 is identical with x << 0
x * 2 is identical with x << 1
For the final result we will use this mechanism, alternate the multiplier between 0 and 1 and do shifts.
This will give us a very effective checksum calculation.
At the end of the program, we will use all gathered values and compare them to the specification.
Thsi will lead to:
int main() {
// Get the credit card number. Unfortunately I do not know CS50. I use the C++ standard iostream lib.
// Please replace the following 4 lines with your CS50 equivalent
unsigned long long creditCardNumber;
std::cout << "Enter credit card number: ";
std::cin >> creditCardNumber;
std::cout << "\n\n";
// We need to count the number of digits for validation
unsigned int countOfDigits = 0;
// Here we will calculate the checksum
unsigned int checkSum = 0;
// We need to multiply digits with 1 or with 2
unsigned int multiplier = 0;
// For validation purposes we need the most significant 2 digits
unsigned int mostSignificantDigit = 0;
unsigned int secondMostSignificantDigit = 0;
// Now we get all digits from the credit card number in a loop
while (creditCardNumber > 0) {
// Get the least significant digits (for 1234 it will be 4)
const unsigned int digit = creditCardNumber % 10;
// Now we have one digit more. In the end we will have the number of all digits
++countOfDigits;
// Simply remember the most significant digits
secondMostSignificantDigit = mostSignificantDigit;
mostSignificantDigit = digit;
// Calculate the checksum
checkSum += (digit << multiplier) % 10 + (digit << multiplier) / 10;
// Multiplier for next loop
multiplier = 1 - multiplier;
creditCardNumber /= 10;
}
// Get the least significant digit of the checksum
checkSum %= 10;
// Validate all calculated values and show the result
if ((0 == checkSum) && // Checksum must be correct AND
(15 == countOfDigits) && // Count of digits must be correct AND
((3 == mostSignificantDigit) && // Most significant digits must be correct
((4 == secondMostSignificantDigit) || (7 == secondMostSignificantDigit)))) {
std::cout << "AMEX\n";
}
else if ((0 == checkSum) && // Checksum must be correct AND
(16 == countOfDigits) && // Count of digits must be correct AND
((5 == mostSignificantDigit) && // Most significant digits must be correct
((secondMostSignificantDigit > 0) && (secondMostSignificantDigit < 6)))) {
std::cout << "MASTERCARD\n";
}
else if ((0 == checkSum) && // Checksum must be correct AND
((16 == countOfDigits) || (13 == countOfDigits)) && // Count of digits must be correct AND
((4 == mostSignificantDigit))) { // Most significant digit must be correct
std::cout << "VISA\n";
}
else {
std::cout << "INVALID\n";
}
return 0;
}
What we learn with this example, is integer division and modulo division and the smart usage of the identity element for binary operations.
In case of questions, please ask
Just to be complete, I will show you a C++ solution, based on a std::string and using modern C++ elements and algorithms.
For example, the whole checksum calculation will be done with one statement. The whole program does not contain any loop.
#include <iostream>
#include <string>
#include <regex>
#include <numeric>
int main() {
// ---------------------------------------------------------------------------------------------------
// Get user input
// Inform user, what to do. Enter a credit card number. We are a little tolerant with the input format
std::cout << "\nPlease enter a credit card number:\t";
// Get the number, in any format from the user
std::string creditCardNumber{};
std::getline(std::cin, creditCardNumber);
// Remove the noise, meaning, all non digits from the credit card number
creditCardNumber = std::regex_replace(creditCardNumber, std::regex(R"(\D)"), "");
// ---------------------------------------------------------------------------------------------------
// Calculate checksum
unsigned int checksum = std::accumulate(creditCardNumber.rbegin(), creditCardNumber.rend(), 0U,
[multiplier = 1U](const unsigned int sum, const char digit) mutable -> unsigned int {
multiplier = 1 - multiplier; unsigned int value = digit - '0';
return sum + ((value << multiplier) % 10) + ((value << multiplier) / 10); });
// We are only interested in the lowest digit
checksum %= 10;
// ---------------------------------------------------------------------------------------------------
// Validation and output
if ((0 == checksum) && // Checksum must be correct AND
(15 == creditCardNumber.length()) && // Count of digits must be correct AND
(('3' == creditCardNumber[0]) && // Most significant digits must be correct
(('4' == creditCardNumber[1]) || ('7' == creditCardNumber[1])))) {
std::cout << "AMEX\n";
}
else if ((0 == checksum) && // Checksum must be correct AND
(16 == creditCardNumber.length()) && // Count of digits must be correct AND
(('5' == creditCardNumber[0]) && // Most significant digits must be correct
((creditCardNumber[1] > '0') && (creditCardNumber[1] < '6')))) {
std::cout << "MASTERCARD\n";
}
else if ((0 == checksum) && // Checksum must be correct AND
((16 == creditCardNumber.length()) || (13 == creditCardNumber.length())) && // Count of digits must be correct AND
(('4' == creditCardNumber[0]))) { // Most significant digit must be correct
std::cout << "VISA\n";
}
else {
std::cout << "INVALID\n";
}
return 0;

Given a huge integer number as a string, check if its a power of 2

The number is huge (cannot fit in the bounds of unsigned long long int in C++). How do we check?
There is a solution given here but it doesn't make much sense.
The solution here tries to repeatedly divide the large number (represented as a string) by 2 but I'm not sure I understand how the result is reached step by step.
Can someone please explain this or propose a better solution?
We cannot use any external libraries.
This is the sample code:
int isPowerOf2(char* str)
{
int len_str = strlen(str);
// sum stores the intermediate dividend while
// dividing.
int num = 0;
// if the input is "1" then return 0
// because 2^k = 1 where k >= 1 and here k = 0
if (len_str == 1 && str[len_str - 1] == '1')
return 0;
// Divide the number until it gets reduced to 1
// if we are successfully able to reduce the number
// to 1 it means input string is power of two if in
// between an odd number appears at the end it means
// string is not divisible by two hence not a power
// of 2.
while (len_str != 1 || str[len_str - 1] != '1') {
// if the last digit is odd then string is not
// divisible by 2 hence not a power of two
// return 0.
if ((str[len_str - 1] - '0') % 2 == 1)
return 0;
// divide the whole string by 2. i is used to
// track index in current number. j is used to
// track index for next iteration.
for (int i = 0, j = 0; i < len_str; i++) {
num = num * 10 + str[i] - '0';
// if num < 2 then we have to take another digit
// to the right of A[i] to make it bigger than
// A[i]. E. g. 214 / 2 --> 107
if (num < 2) {
// if it's not the first index. E.g 214
// then we have to include 0.
if (i != 0)
str[j++] = '0';
// for eg. "124" we will not write 064
// so if it is the first index just ignore
continue;
}
str[j++] = (int)(num / 2) + '0';
num = (num) - (num / 2) * 2;
}
str[j] = '\0';
// After every division by 2 the
// length of string is changed.
len_str = j;
}
// if the string reaches to 1 then the str is
// a power of 2.
return 1;
}
I'm trying to understand the process in the while loop. I know there are comments but they arent really helping me glean through the logic.
Let's start by figuring out how to halve a "string-number". We'll start with 128 as an example. You can halve each digit in turn (starting from the left), keeping in mind that an odd number affects the digit on the right(a). So, for the 1 in 128, you halve that to get zero but, because it was odd, five should be kept in storage to be added to the digit on its right (once halved):
128
v
028
Then halve the 2 as follows (adding back in that stored 5):
028
v
018
v
068
Because that wasn't odd, we don't store a 5 for the next digit so we halve the 8 as follows:
068
v
064
You can also make things easier then by stripping off any leading zeros. From that, you can see that it correctly halves 128 to get 64.
To see if a number is a power of two, you simply keep halving it until you reach exactly 1. But, if at any point you end up with an odd number (something ending with a digit from {1, 3, 5, 7, 9}, provided it's not the single-digit 1), it is not a power of two.
By way of example, the following Python 3 code illustrates the concept:
import re, sys
# Halve a numeric string. The addition of five is done by
# Choosing the digit from a specific set (lower or upper
# digits).
def half(s):
halfS = '' # Construct half value.
charSet = '01234' # Initially lower.
for digit in s: # Digits left to right.
if digit in '13579': # Select upper for next if odd.
nextCharSet = '56789'
else:
nextCharSet = '01234' # Otherwise lower set.
halfS += charSet[int(digit) // 2] # Append half value.
charSet = nextCharSet # And prep for next digit.
while halfS[0] == '0': # Remove leading zeros.
halfS = halfS[1:]
return halfS
# Checks for validity.
if len(sys.argv) != 2:
print('Needs a single argument')
sys.exit(1)
num = sys.argv[1]
if not re.match('[1-9][0-9]*', num):
print('Argument must be all digits')
sys.exit(1)
print(num)
while num != '1':
if num[-1:] in '13579':
print('Reached odd number, therefore cannot be power of two')
sys.exit(0)
num = half(num)
print(num)
print('Reached 1, was therefore power of two')
Running that with various (numeric) arguments will show you the process, such as with:
pax$ python ispower2.py 65534
65534
32767
Reached odd number, therefore cannot be power of two
pax$ python ispower2.py 65536
65536
32768
16384
8192
4096
2048
1024
512
256
128
64
32
16
8
4
2
1
Reached 1, was therefore power of two
(a) Take, for example, the number 34. Half of the 3 is 1.5 so the 1 can be used to affect that specific digit position but the "half" left over can simply be used by bumping up the digit on the right by five after halving it. So the 4 halves to a 2 then has five added to make 7. And half of 34 is indeed 17.
This solution does work only for numbers which are not too large i.e. fits in the range of unsigned long long int.
Simpler C++ solution using bitmanipulation for small numbers :-
int power(string s) {
// convert number to unsigned long long int
// datatype can be changed to long int, int as per the requirement
// we can also use inbuilt function like stol() or stoll() for this
unsigned long long int len = s.length();
unsigned long long int num = s[0]-'0';
for(unsigned long long int i = 1; i<len; i++)
num = (num*10)+(s[i]-'0');
if(num == 1)
return 0;
//The powers of 2 have only one set bit in their Binary representation
//If we subtract 1 from a power of 2 what we get is 1s till the last unset bit and if we apply Bitwise AND operator we should get only zeros
if((num & (num-1)) == 0)
return 1;
return 0;
}
A bit better solution that I could code in Java, which doesn't use any fancy object like BigInteger. This approach is same as simple way of performing division. Only look out for remainder after each division. Also trim out the leading zeroes from the quotient which becomes new dividend for next iteration.
class DivisionResult{
String quotient;
int remainder;
public DivisionResult(String q, int rem){
this.quotient = q;
this.remainder = rem;
}
}
public int power(String A) {
if (A.equals("0") || A.equals("1")) return 0;
while (!A.equals("1")){
DivisionResult dr = divideByTwo(A);
if (dr.remainder == 1) return 0;
A = dr.quotient;
}
return 1;
}
public DivisionResult divideByTwo(String num){
StringBuilder sb = new StringBuilder();
int carry = 0;
for (int i = 0;i < num.length(); i++){
int divisibleNum = carry*10 + (num.charAt(i) - '0');
carry = divisibleNum%2;
sb.append(divisibleNum/2);
}
return new DivisionResult(sb.toString().replaceAll("^0+(?!$)", ""), carry);
}

count consecutive 1's in binary

I am writing code in Hackerrank. And recently the problem said, convert decimal to base 2 and then count the max consecutive 1's in the binary number. And first I come with following solution. It works fine. But I do not understand the counting part of it, even though I wrote it.
The code is
int main(){
int n,ind=0, count=0, mmax=0;
char bin[100];
cin >> n;
while(n){
if(n%2==0) {
bin[ind]='0';
n = n / 2;
ind = ind + 1;
}
else if(n%2==1) {
bin[ind]='1';
n = n / 2;
ind = ind + 1;
}
}
for(int i=0; i<=(ind-1); i++){
if(bin[i] == '1' && bin[i+1] == '1'){
count++;
if(mmax < count)
mmax = count;
}
else
count=0;
}
cout << mmax + 1 << endl;
return 0;
}
In the above code, I guess that variable mmax will give me the max consecutive number of 1's but it gives me value that has (max consecutive - 1), So I just wrote like that and submitted the code. But I am curious about. why it is working that way. I am little bit of confused the way that code works like this.
Thanks
Lets say you have this binary sequence:
11110
Your code will compare starting from the first and second:
|11|110 1 && 1 -> max = 1
1|11|10 1 && 1 -> max = 2
11|11|0 1 && 1 -> max = 3
111|10| 1 && 0 -> max = 3
you can see, that although there are 4 1's you only do 3 comparisons, so your max will always be -1 of the actual max. You can fix this by adding mmax += 1 after your for loop.
Just a little bit of trace using small example will show why.
First, lets say there is only 1 '1' in your array.
Since you require both the current position and your next position to be '1', you will always get 0 for this case.
Let's say I have "11111". At the first '1', since next position is also '1', you increment count once. This repeats until 4th '1' and you increment your count 4 times in total so far. When you reach 5th '1', your next position is not '1', thus your count stops at 4.
In general, your method is like counting gaps between fingers, given 5 fingers, you get 4 gaps.
Side note: your code will fail for the case when there is no '1' in your array.

How to store output of very large Fibonacci number?

I am making a program for nth Fibonacci number. I made the following program using recursion and memoization.
The main problem is that the value of n can go up to 10000 which means that the Fibonacci number of 10000 would be more than 2000 digit long.
With a little bit of googling, I found that i could use arrays and store every digit of the solution in an element of the array but I am still not able to figure out how to implement this approach with my program.
#include<iostream>
using namespace std;
long long int memo[101000];
long long int n;
long long int fib(long long int n)
{
if(n==1 || n==2)
return 1;
if(memo[n]!=0)
return memo[n];
return memo[n] = fib(n-1) + fib(n-2);
}
int main()
{
cin>>n;
long long int ans = fib(n);
cout<<ans;
}
How do I implement that approach or if there is another method that can be used to achieve such large values?
One thing that I think should be pointed out is there's other ways to implement fib that are much easier for something like C++ to compute
consider the following pseudo code
function fib (n) {
let a = 0, b = 1, _;
while (n > 0) {
_ = a;
a = b;
b = b + _;
n = n - 1;
}
return a;
}
This doesn't require memoisation and you don't have to be concerned about blowing up your stack with too many recursive calls. Recursion is a really powerful looping construct but it's one of those fubu things that's best left to langs like Lisp, Scheme, Kotlin, Lua (and a few others) that support it so elegantly.
That's not to say tail call elimination is impossible in C++, but unless you're doing something to optimise/compile for it explicitly, I'm doubtful that whatever compiler you're using would support it by default.
As for computing the exceptionally large numbers, you'll have to either get creative doing adding The Hard Way or rely upon an arbitrary precision arithmetic library like GMP. I'm sure there's other libs for this too.
Adding The Hard Way™
Remember how you used to add big numbers when you were a little tater tot, fresh off the aluminum foil?
5-year-old math
1259601512351095520986368
+ 50695640938240596831104
---------------------------
?
Well you gotta add each column, right to left. And when a column overflows into the double digits, remember to carry that 1 over to the next column.
... <-001
1259601512351095520986368
+ 50695640938240596831104
---------------------------
... <-472
The 10,000th fibonacci number is thousands of digits long, so there's no way that's going to fit in any integer C++ provides out of the box. So without relying upon a library, you could use a string or an array of single-digit numbers. To output the final number, you'll have to convert it to a string tho.
(woflram alpha: fibonacci 10000)
Doing it this way, you'll perform a couple million single-digit additions; it might take a while, but it should be a breeze for any modern computer to handle. Time to get to work !
Here's an example in of a Bignum module in JavaScript
const Bignum =
{ fromInt: (n = 0) =>
n < 10
? [ n ]
: [ n % 10, ...Bignum.fromInt (n / 10 >> 0) ]
, fromString: (s = "0") =>
Array.from (s, Number) .reverse ()
, toString: (b) =>
b .reverse () .join ("")
, add: (b1, b2) =>
{
const len = Math.max (b1.length, b2.length)
let answer = []
let carry = 0
for (let i = 0; i < len; i = i + 1) {
const x = b1[i] || 0
const y = b2[i] || 0
const sum = x + y + carry
answer.push (sum % 10)
carry = sum / 10 >> 0
}
if (carry > 0) answer.push (carry)
return answer
}
}
We can verify that the Wolfram Alpha answer above is correct
const { fromInt, toString, add } =
Bignum
const bigfib = (n = 0) =>
{
let a = fromInt (0)
let b = fromInt (1)
let _
while (n > 0) {
_ = a
a = b
b = add (b, _)
n = n - 1
}
return toString (a)
}
bigfib (10000)
// "336447 ... 366875"
Expand the program below to run it in your browser
const Bignum =
{ fromInt: (n = 0) =>
n < 10
? [ n ]
: [ n % 10, ...Bignum.fromInt (n / 10 >> 0) ]
, fromString: (s = "0") =>
Array.from (s) .reverse ()
, toString: (b) =>
b .reverse () .join ("")
, add: (b1, b2) =>
{
const len = Math.max (b1.length, b2.length)
let answer = []
let carry = 0
for (let i = 0; i < len; i = i + 1) {
const x = b1[i] || 0
const y = b2[i] || 0
const sum = x + y + carry
answer.push (sum % 10)
carry = sum / 10 >> 0
}
if (carry > 0) answer.push (carry)
return answer
}
}
const { fromInt, toString, add } =
Bignum
const bigfib = (n = 0) =>
{
let a = fromInt (0)
let b = fromInt (1)
let _
while (n > 0) {
_ = a
a = b
b = add (b, _)
n = n - 1
}
return toString (a)
}
console.log (bigfib (10000))
Try not to use recursion for a simple problem like fibonacci. And if you'll only use it once, don't use an array to store all results. An array of 2 elements containing the 2 previous fibonacci numbers will be enough. In each step, you then only have to sum up those 2 numbers. How can you save 2 consecutive fibonacci numbers? Well, you know that when you have 2 consecutive integers one is even and one is odd. So you can use that property to know where to get/place a fibonacci number: for fib(i), if i is even (i%2 is 0) place it in the first element of the array (index 0), else (i%2 is then 1) place it in the second element(index 1). Why can you just place it there? Well when you're calculating fib(i), the value that is on the place fib(i) should go is fib(i-2) (because (i-2)%2 is the same as i%2). But you won't need fib(i-2) any more: fib(i+1) only needs fib(i-1)(that's still in the array) and fib(i)(that just got inserted in the array).
So you could replace the recursion calls with a for loop like this:
int fibonacci(int n){
if( n <= 0){
return 0;
}
int previous[] = {0, 1}; // start with fib(0) and fib(1)
for(int i = 2; i <= n; ++i){
// modulo can be implemented with bit operations(much faster): i % 2 = i & 1
previous[i&1] += previous[(i-1)&1]; //shorter way to say: previous[i&1] = previous[i&1] + previous[(i-1)&1]
}
//Result is in previous[n&1]
return previous[n&1];
}
Recursion is actually discommanded while programming because of the time(function calls) and ressources(stack) it consumes. So each time you use recursion, try to replace it with a loop and a stack with simple pop/push operations if needed to save the "current position" (in c++ one can use a vector). In the case of the fibonacci, the stack isn't even needed but if you are iterating over a tree datastructure for example you'll need a stack (depends on the implementation though). As I was looking for my solution, I saw #naomik provided a solution with the while loop. That one is fine too, but I prefer the array with the modulo operation (a bit shorter).
Now concerning the problem of the size long long int has, it can be solved by using external libraries that implement operations for big numbers (like the GMP library or Boost.multiprecision). But you could also create your own version of a BigInteger-like class from Java and implement the basic operations like the one I have. I've only implemented the addition in my example (try to implement the others they are quite similar).
The main idea is simple, a BigInt represents a big decimal number by cutting its little endian representation into pieces (I'll explain why little endian at the end). The length of those pieces depends on the base you choose. If you want to work with decimal representations, it will only work if your base is a power of 10: if you choose 10 as base each piece will represent one digit, if you choose 100 (= 10^2) as base each piece will represent two consecutive digits starting from the end(see little endian), if you choose 1000 as base (10^3) each piece will represent three consecutive digits, ... and so on. Let's say that you have base 100, 12765 will then be [65, 27, 1], 1789 will be [89, 17], 505 will be [5, 5] (= [05,5]), ... with base 1000: 12765 would be [765, 12], 1789 would be [789, 1], 505 would be [505]. It's not the most efficient, but it is the most intuitive (I think ...)
The addition is then a bit like the addition on paper we learned at school:
begin with the lowest piece of the BigInt
add it with the corresponding piece of the other one
the lowest piece of that sum(= the sum modulus the base) becomes the corresponding piece of the final result
the "bigger" pieces of that sum will be added ("carried") to the sum of the following pieces
go to step 2 with next piece
if no piece left, add the carry and the remaining bigger pieces of the other BigInt (if it has pieces left)
For example:
9542 + 1097855 = [42, 95] + [55, 78, 09, 1]
lowest piece = 42 and 55 --> 42 + 55 = 97 = [97]
---> lowest piece of result = 97 (no carry, carry = 0)
2nd piece = 95 and 78 --> (95+78) + 0 = 173 = [73, 1]
---> 2nd piece of final result = 73
---> remaining: [1] = 1 = carry (will be added to sum of following pieces)
no piece left in first `BigInt`!
--> add carry ( [1] ) and remaining pieces from second `BigInt`( [9, 1] ) to final result
--> first additional piece: 9 + 1 = 10 = [10] (no carry)
--> second additional piece: 1 + 0 = 1 = [1] (no carry)
==> 9542 + 1 097 855 = [42, 95] + [55, 78, 09, 1] = [97, 73, 10, 1] = 1 107 397
Here is a demo where I used the class above to calculate the fibonacci of 10000 (result is too big to copy here)
Good luck!
PS: Why little endian? For the ease of the implementation: it allows to use push_back when adding digits and iteration while implementing the operations will start from the first piece instead of the last piece in the array.

how to generate Narcissistic numbers faster?

The “Narcissistic numbers”, are n digit numbers where the sum of all the nth power of their digits is equal to the number.
So, 153 is a narcissistic number because 1^3 + 5^3 + 3^3 = 153.
Now given N, find all Narcissistic numbers that are N digit length ?
My Approach : was to iterate over all numbers doing sum of powers of digits
and check if its the same number or not, and I per calculated the powers.
but that's not good enough, so is there any faster way ?!
Update:
In nature there is just 88 narcissistic numbers, and the largest is 39 digits long,
But I just need the numbers with length 12 or less.
My Code :
long long int powers[11][12];
// powers[x][y] is x^y. and its already calculated
bool isNarcissistic(long long int x,int n){
long long int r = x;
long long int sum = 0;
for(int i=0; i<n ; ++i){
sum += powers[x%10][n];
if(sum > r)
return false;
x /= 10;
}
return (sum == r);
}
void find(int n,vector<long long int> &vv){
long long int start = powers[10][n-1];
long long int end = powers[10][n];
for(long long int i=start ; i<end ; ++i){
if(isNarcissistic(i,n))
vv.push_back(i);
}
}
Since there are only 88 narcisstic numbers in total, you can just store them in a look up table and iterate over it: http://mathworld.wolfram.com/NarcissisticNumber.html
Start from the other end. Iterate over the set of all nondecreasing sequences of d digits, compute the sum of the d-th powers, and check whether that produces (after sorting) the sequence you started with.
Since there are
9×10^(d-1)
d-digit numbers, but only
(10+d-1) `choose` d
nondecreasing sequences of d digits, that reduces the search space by a factor close to d!.
The code below implements the idea of #Daniel Fischer. It duplicates the table referenced at Mathworld and then prints a few more 11-digit numbers and verifies that there are none with 12 digits as stated here.
It would actually be simplier and probably a little faster to generate all possible histograms of non-increasing digit strings rather than the strings themselves. By a histogram I mean a table indexed 0-9 of frequencies of the respective digit. These can be compared directly without sorting. But the code below runs in < 1 sec, so I'm not going to implement the histogram idea.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DIGITS 12
// pwr[d][n] is d^n
long long pwr[10][MAX_DIGITS + 1];
// Digits and final index of number being considered.
int digits[MAX_DIGITS];
int m;
// Fill pwr.
void fill_tbls(void)
{
for (int d = 0; d < 10; d++) {
pwr[d][0] = 1;
for (int p = 1; p <= MAX_DIGITS; p++)
pwr[d][p] = pwr[d][p-1] * d;
}
}
// qsort comparison for integers descending
int cmp_ints_desc(const void *vpa, const void *vpb)
{
const int *pa = vpa, *pb = vpb;
return *pb - *pa;
}
// Test current number and print if narcissistic.
void test(void)
{
long long sum = 0;
for (int i = 0; i <= m; i++)
sum += pwr[digits[i]][m + 1];
int sum_digits[MAX_DIGITS * 2];
int n = 0;
for (long long s = sum; s; s /= 10)
sum_digits[n++] = s % 10;
if (n == m + 1) {
qsort(sum_digits, n, sizeof(int), cmp_ints_desc);
if (memcmp(sum_digits, digits, n * sizeof(int)) == 0)
printf("%lld\n", sum);
}
}
// Recursive generator of non-increasing digit strings.
// Calls test when a string is complete.
void gen(int i, int min, int max)
{
if (i > m)
test();
else {
for (int d = min; d <= max; d++) {
digits[i] = d;
gen(i + 1, 0, d);
}
}
}
// Fill tables and generate.
int main(void)
{
fill_tbls();
for (m = 0; m < MAX_DIGITS; m++)
gen(0, 1, 9);
return 0;
}
I wrote a program in Lua which found all the narcissistic numbers in 30829.642 seconds. The basis of the program is a recursive digit-value count array generator function which calls a checking function when it's generated the digit-value count for all the digit-values. Each nested loop iterates:
FROM i=
The larger of 0 and the solution to a+x*d^o+(s-x)*(d-1)^o >= 10^(o-1) for x
where
- 'a' is the accumulative sum of powers of digits so far,
- 'd' is the current digit-value (0-9 for base 10),
- 'o' is the total number of digits (which the sum of the digit-value count array must add up to),
- 's' represents the remaining slots available until the array adds to 'o'
UP TO i<=
The smaller of 's' and the solution to a+x*d^o < 10^o for x with the same variables.
This ensures that the numbers checked will ALWAYS have the same number of digits as 'o', and therefore be more likely to be narcissistic while avoiding unnecessary computation.
In the loop, it does the recursive call for which it decrements the digit-value 'd' adds the current digit-value's contribution (a=a+i*d^o) and takes the i digit-slots used up away from 's'.
The gist of what I wrote is:
local function search(o,d,s,a,...) --Original number of digits, digit-value, remaining digits, accumulative sum, number of each digit-value in descending order (such as 5 nines)
if d>0 then
local d0,d1=d^o,(d-1)^o
local dd=d0-d1
--a+x*d^o+(s-x)*(d-1)^o >= 10^(o-1) , a+x*d^o < 10^o
for i=max(0,floor((10^(o-1)-s*d1-a)/dd)),min(s,ceil((10^o-a)/dd)-1) do
search(o,d-1,s-i,a+i*d0,i,...) --The digit counts are passed down as extra arguments.
end
else
--Check, with the count of zeroes set to 's', if the sum 'a' has the same count of each digit-value as the list specifies, and if so, add it to a list of narcissists.
end
end
local digits=1 --Skip the trivial single digit narcissistic numbers.
while #found<89 do
digits=digits+1
search(digits,9,digits,0)
end
EDIT: I forgot to mention that my program finds 89 narcissistic numbers! These are what it finds:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748, 92727, 93084, 548834, 1741725, 4210818, 9800817, 9926315, 24678050, 24678051, 88593477, 146511208, 472335975, 534494836, 912985153, 4679307774, 32164049650, 32164049651, 40028394225, 42678290603, 44708635679, 49388550606, 82693916578, 94204591914, 28116440335967, 4338281769391370, 4338281769391371, 21897142587612075, 35641594208964132, 35875699062250035, 1517841543307505039, 3289582984443187032, 4498128791164624869, 4929273885928088826, 63105425988599693916, 128468643043731391252,449177399146038697307, 21887696841122916288858, 27879694893054074471405, 27907865009977052567814, 28361281321319229463398, 35452590104031691935943, 174088005938065293023722, 188451485447897896036875, 239313664430041569350093, 1550475334214501539088894, 1553242162893771850669378, 3706907995955475988644380, 3706907995955475988644381, 4422095118095899619457938, 121204998563613372405438066, 121270696006801314328439376, 128851796696487777842012787, 174650464499531377631639254, 177265453171792792366489765, 14607640612971980372614873089, 19008174136254279995012734740, 19008174136254279995012734741, 23866716435523975980390369295, 1145037275765491025924292050346, 1927890457142960697580636236639, 2309092682616190307509695338915, 17333509997782249308725103962772, 186709961001538790100634132976990, 186709961001538790100634132976991, 1122763285329372541592822900204593, 12639369517103790328947807201478392, 12679937780272278566303885594196922, 1219167219625434121569735803609966019, 12815792078366059955099770545296129367, 115132219018763992565095597973971522400, 115132219018763992565095597973971522401
For posterity ;-) This is most similar to #Krakow10's approach, generating bags of digits recursively, starting with 9, then 8, then 7 ... to 0.
It's Python3 code and finds all base-10 solutions with 1 through 61 digits (the first "obviously impossible" width) in less than 10 minutes (on my box). It's by far the fastest code I've ever heard of for this problem. What's the trick? No trick - just tedium ;-) As we go along, the partial sum so far yields a world of constraints on feasible continuations. The code just pays attention to those, and so is able to cut off vast masses of searches early.
Note: this doesn't find 0. I don't care. While all the references say there are 88 solutions, their tables all have 89 entries. Some eager editor must have added "0" later, and then everyone else mindlessly copied it ;-)
EDIT New version is over twice as fast, by exploiting some partial-sum constraints earlier in the search - now finishes in a little over 4 minutes on my box.
def nar(width):
from decimal import Decimal as D
import decimal
decimal.getcontext().prec = width + 10
if width * 9**width < 10**(width - 1):
raise ValueError("impossible at %d" % width)
pows = [D(i) ** width for i in range(10)]
mintotal, maxtotal = D(10)**(width - 1), D(10)**width - 1
def extend(d, todo, total):
# assert d > 0
powd = pows[d]
d1 = d-1
powd1 = pows[d1]
L = total + powd1 * todo # largest possible taking no d's
dL = powd - powd1 # the change to L when i goes up 1
for i in range(todo + 1):
if i:
total += powd
todo -= 1
L += dL
digitcount[d] += 1
if total > maxtotal:
break
if L < mintotal:
continue
if total < mintotal or L > maxtotal:
yield from extend(d1, todo, total)
continue
# assert mintotal <= total <= L <= maxtotal
t1 = total.as_tuple().digits
t2 = L.as_tuple().digits
# assert len(t1) == len(t2) == width
# Every possible continuation has sum between total and
# L, and has a full-width sum. So if total and L have
# some identical leading digits, a solution must include
# all such leading digits. Count them.
c = [0] * 10
for a, b in zip(t1, t2):
if a == b:
c[a] += 1
else:
break
else: # the tuples are identical
# assert d == 1 or todo == 0
# assert total == L
# This is the only sum we can get - no point to
# recursing. It's a solution iff each digit has been
# picked exactly as many times as it appears in the
# sum.
# If todo is 0, we've picked all the digits.
# Else todo > 0, and d must be 1: all remaining
# digits must be 0.
digitcount[0] += todo
# assert sum(c) == sum(digitcount) == width
if digitcount == c:
yield total
digitcount[0] -= todo
continue
# The tuples aren't identical, but may have leading digits
# in common. If, e.g., "9892" is a common prefix, then to
# get a solution we must pick at least one 8, at least two
# 9s, and at least one 2.
if any(digitcount[j] < c[j] for j in range(d, 10)):
# we're done picking digits >= d, but don't have
# enough of them
continue
# for digits < d, force as many as we need for the prefix
newtodo, newtotal = todo, total
added = []
for j in range(d):
need = c[j] - digitcount[j]
# assert need >= 0
if need:
newtodo -= need
added.append((j, need))
if newtodo < 0:
continue
for j, need in added:
newtotal += pows[j] * need
digitcount[j] += need
yield from extend(d1, newtodo, newtotal)
for j, need in added:
digitcount[j] -= need
digitcount[d] -= i
digitcount = [0] * 10
yield from extend(9, width, D(0))
assert all(i == 0 for i in digitcount)
if __name__ == "__main__":
from datetime import datetime
start_t = datetime.now()
width = total = 0
while True:
this_t = datetime.now()
width += 1
print("\nwidth", width)
for t in nar(width):
print(" ", t)
total += 1
end_t = datetime.now()
print(end_t - this_t, end_t - start_t, total)
I think the idea is to generate similar numbers. For example, 61 is similar to 16 as you are just summing
6^n +1^n
so
6^n+1^n=1^n+6^n
In this way you can reduce significant amount of numbers. For example in 3 digits scenario,
121==112==211,
you get the point. You need to generate those numbers first.
And you need to generate those numbers without actually iterating from 0-n.
Python version is:
def generate_power_list(power):
return [i**power for i in range(0,10)]
def find_narcissistic_numbers_naive(min_length, max_length):
for number_length in range(min_length, max_length):
power_dict = generate_power_dictionary(number_length)
max_number = 10 ** number_length
number = 10** (number_length -1)
while number < max_number:
value = 0
for digit in str(number):
value += power_dict[digit]
if value == number:
logging.debug('narcissistic %s ' % number)
number += 1
Recursive solution:
In this solution each recursion handles a single digit of the array of digits being used, and tries all appropriate combinations of that digit
def execute_recursive(digits, number_length):
index = len(digits)
if digits:
number = digits[-1]
else:
number = 0
results = []
digits.append(number)
if len(digits) < number_length:
while number < 10:
results += execute_recursive(digits[:], number_length)
number += 1
digits[index] = number
else:
while number < 10:
digit_value = sum_digits(digits)
if check_numbers_match_group(digit_value, digits):
results.append(digit_value)
logging.debug(digit_value)
number += 1
digits[index] = number
return results
def find_narcissistic_numbers(min_length, max_length):
for number_length in range(min_length, max_length):
digits = []
t_start = time.clock()
results = execute_recursive(digits, number_length)
print 'duration: %s for number length: %s' %(time.clock() - t_start, number_length)
Narcissistic number check
In the base version, when checking that a number matched the digits, we iterated through each digit type, to ensure that there were the same number of each type. In this version we have added the optimisation of checking the digit length is correct before doing the full check.
I expected that this would have more of an effect on small number lengths, because as number length increases, there will tend to be more numbers in the middle of the distribution. This was somewhat upheld by the results:
n=16: 11.5% improvement
n=19: 9.8% improvement
def check_numbers_match_group(number, digits):
number_search = str(number)
# new in v1.3
if len(number_search) != len(digits):
return False
for digit in digit_list:
if number_search.count(digit[0]) != digits.count(digit[1]):
return False
return True
I think you could use Multinomial theorem for some optimisation of cheacking if it is Narcissistic number.
you can calculate (a+b+c+..)^n- sum of non n-th powers values
for example for n=2 you should compare x and (a+b)^2-2*a*b where a and b is digits of number x
'''We can use Nar() function to calculate the Narcissitic Number.'''
import math
def Nar(num):
sum=0
n=len(str(num))
while n>0:
temp=num%10
sum=sum+math.pow(temp,n)
num=num/10
return sum
x=input()
y=Nar(x)
if x==y:
print x,' is a Narcissistic number'
else:
print x,' is not a Narcissistic number'