So for the following code I am trying to reduce the amount of time the function call itself so that it is more efficient. The purpose of the code is to perform exponentiation using recursion.
int expo(const int m, const unsigned int n)
{
funcCallCounter++; //counts how many times the function is called
if (n == 0)//base case
{
return 1;
}
else if (n % 2 == 0)// for even numbers
return expo(m*m, n / 2);
else
return m * expo(m, n - 1);//for odd numbers
}
Well this is my favourite approach for the recursive expo which will always give less calls than your approach
int expo(int a, int n) {
funcCallCounter++;
if (n == 0) {
return 1;
}
int r = expo(a, n / 2);
if (n % 2 == 0) {
//Even n
return r * r;
}
else {
// Odd n
return a *r*r;
}
}
You could use shifts to make your execution faster.
n % 2 can be replaced with n & 0x01
n / 2^k can be replaced with n >> k
A division is about 20 cycles while a shift is only 1-2 cycles.
However, maybe the compiler see taht by itself and make this optimisation already.
Best
Related
I'm trying to create an algorithm that will compute the collatz conjecture, this is the code so far:
while (n > 1) {
n % 2 == 0 ? n /= 2 : n = n * 3 + 1;
}
I was wondering if there was a way to optimize this any further since efficiency and speed is crucial for this, and I've heard about branchless programming but I'm not sure how to implement it, or if it's worth it to begin with.
Sure. You need the loop, of course, but the work inside can be done like this:
n /= (n&-n); // remove all trailing 0s
while(n > 1) {
n = 3*n+1;
n /= (n&-n); // remove all trailing 0s
}
It also helps that this technique does all the divisions by 2 at once, instead of requiring a separate iteration for each of them.
One way to make it branchless (except for the loop condition) is to multiply n / 2 with the n % 2 == 0 result (1 for true) and multiply (n * 3 + 1) with the negated result of (n % 2 == 0) and add them together.
void collatz(unsigned long long n) {
std::cout << n << '\n';
while (n > 1) {
auto m = n % 2 == 0;
n = m * (n / 2) + !m * (n * 3 + 1);
std::cout << n << '\n';
}
}
Demo
I have correctly written the program for getting the superdigit of a large number (long long) but can't seem to pass some cases due to timeout and abort calls. Please suggest some optimizations to improve the runtime of my program:
int superDigit(long long m) {
int d=countDigit(m);
if(d==1){
return m;
}
long s=sumDigit(m);
return superDigit(s);
}
//utility functions to calculate digit count and sum of digits
int countDigit(long long n)
{
int count = 0;
while (n != 0) {
n = n / 10;
++count;
}
return count;
}
long sumDigit(long long n)
{
long sum = 0;
while (n != 0) {
sum += n % 10;
n = n / 10;
}
return sum;
}
Theory: A superdigit is defined by the following rules:
If x has only 1 digit, then its super digit is x
Otherwise, the super digit of x is equal to the super digit of the sum of the digits of x
For example:
super_digit(9875): 9+8+7+5 = 29 ,then
super_digit(29): 2 + 9 = 11 ,then
super_digit(11): 1 + 1 = 2 ,then
super_digit(2): = 2
Only looping over the digits once per superDigit call and avoiding recursion should make it faster. Something like this:
long long superDigit(long long m) {
long long sum;
while(true) {
sum = 0;
while(m != 0) {
sum += m % 10;
m /= 10;
}
if(sum >= 10)
m = sum;
else
break;
}
return sum;
}
If you need support for repeated sequences, like 593 10 times (which is usually too big for a long long) you could add a wrapper like this:
long long superDigit(long long m, int times) {
long long r = superDigit(m) * times;
if(r >= 10) r = superDigit(r);
return r;
}
For numbers small enough to fit in a long long, you can check that it works. Example:
superDigit(148148148) == superDigit(148, 3)
If you need support for large numbers that are not repeated sequences, you could add yet another overload, taking the number as a std::string:
long long superDigit(const std::string& m) {
long long sum = 0;
for(auto d : m) sum += d - '0';
if(sum >= 10) return superDigit(sum);
return sum;
}
And you can check that it's also getting the same result as one of the previous overloads:
superDigit(593, 10) == superDigit("593593593593593593593593593593")
I think you are getting abort call for value of m! If the value of m is 0, then the recursion will continue lifetime. And if the value of m can be negative then take care the problem for negative values too.
Please check it!
int superDigit(long long m) {
if(m<=9)return m; // handling case 0
int d=countDigit(m);
if(d==1){
return m;
}
long s=sumDigit(m);
return superDigit(s);
}
Your code has a problem with a '0'. It gets into an endless loop that is terminated if the call stack overflows (if your compiler does not eliminated the tail recursion).
The digit count helper function is completely unnecessary
int superDigit(long long m) {
if(m<10){
return m;
}else{
int s = 0;
do {
s += m % 10;
m = m / 10;
}while (m > 0);
return superDigit(s);
}
}
You can eliminate the recursion by yourself by putting the whole thing into a loop.
int superDigit(long long m) {
while (m >9){
int s = 0;
do {
s += m % 10;
m = m / 10;
}while (m > 0);
m = s;
}
return m;
}
But recursion looks a bit more self explaining and modern compiler should be able to eliminate the tail recursion either.
I need to create a recursive function that counts the 2 and 6 from the number a user inputs.
For example if the user enters 26827 the count is 3.
It works with certain numbers and certain numbers it doesn't. Can someone please modify my function making sure its recursive and using very basic C++ language as I have used. Thank you! (I believe something is wrong with return type.)
int count(int n) {
static int count = 0;
if (n == 2 || n == 6) count++;
if ((n % 10 == 2) || (n % 10 == 6)) {
count++;
count(num / 10);
}
else return count;
}
One liner for fun.
int f(int n) {
return n == 0 ? 0 : (n%10==2 || n%10==6) + f(n/10);
}
int count(int n) {
if(n <= 0) return 0; // Base Condition
int countDig = 0; // Initalizing Count of digits
if(n % 10 == 2 || n % 10 == 6) // Checking whether the LSB is 2 or 6
countDig ++; // If it is then incrementing the countDig
countDig += count(n / 10); // Calling the recurive function by sending the number except its LSB
//And incrementing counter according to it
return countDig; // Returning the final count
}
you don't need to have a static value counter. It can be easily done as above. Please refer to comments given. Second the error in your code is you only calling the recursion if the LSB is 2 or 6. The recursion should be put outside the if condition in your code. Why are you using num variable. I think it should be n
You don't need statics
This should work (note return c + count(n / 10) line. That's the main recursion here)
int count(int n)
{
int c = 0;
if(n % 10 == 2 || n % 10 == 6)
c = 1;
if(n < 10)
return c;
return c + count(n / 10);
}
If you want to make it with recursion , another procedure you can apply using string manipulation.
PseudoCode:
Function ( int n):
1. Make n as a string. ( Convert Number to string)
2. Collect the first character (char C) of the string and remove the character from the string.
3. Make the main string again as a number n. ( Convert String to Number).
4. Check the character C , which is number 2 or 6 or not, count it with a flag.
5. Enter base case for which the recursion will stop.
6. return the number n , inside the Function (n) for recursion.
I am having trouble understanding one of a Leetcode Problem.
Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
Solution:
int numSquares(int n) {
static vector<int> dp {0};
while (dp.size() <= n) {
int m = dp.size(), squares = INT_MAX;
for (int i=1; i*i<=m; ++i)
squares = min(squares, dp[m-i*i] + 1);
dp.push_back(squares);
}
return dp[n];
}
I really dont understand what is going on with min(squares,dp[m-i*i]+1). Can you please explain?
thx.
I had a hard time with this too. Let's take the example number n=13.
First thing to observe is that: 1^2 =1, 2^2=4, 3^2=9, 4^2=16
So 13 can't be composed of anything greater than
3^2. Generically speaking, n can only be composed of numbers 1 to sqrt(n)
So we are left with some combination of the square of the following numbers: 1, 2, or 3.
Next thing we want to do is come up with the recursive formula. This took me a long time to understand. But we basically want to dwindle down to work with a smaller n (that's the whole point of recursion). We do that by subtracting our candidate perfect squares from n. For example:
If we try 3, then dp(13)=dp(13-3^2)+1=dp(4)+1.
The +1 is incrementing the count by 1 and is from the the fact that we already took off a perfect square from 13, which was the 3^2. Each +1 is a perfect square that we took off.
If we try 2, then dp(13)=13-2^2=dp(9)+1
If we try 1, then dp(13)=13-1^2=dp(12)+1
So we are left with comparing which is the smallest out of dp(4), dp(9), and dp(12). Hence the min.
The solution, which you have mentioned, is the bottom-up version of the algorithm. In order to understand the algorithm better, I would advice to look at the top-down version of the solution.
Let's look closer at the recurrence relation for the calculation of the minimal amount of the perfect squares, contained inside the number N. For given N and any arbitrary number x (which is the candidate for being considered as the member of the shortest sequence of numbers, whose perfect squares sums-up to N):
f(N, x) = 0 , if N = 0 ;
f(N, x) = min( f(N, x + 1), f(N - x^2, 1) ) , if N >= x^2 ;
f(N, x) = +infinity , otherwise ;
solution(N) = f(N, 1)
Now, having in mind the considered recurrence, we can construct the top-down solution (I will implement it in Java):
int solve(int n) {
return solve(n, 1);
}
int solve(int n, int curr) {
if (n == 0) {
return 0;
}
if ((curr * curr) > n) {
return POSITIVE_INFINITY;
}
// if curr belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
int inclusive = solve(n - (curr * curr), 1) + 1;
// otherwise:
int exclusive = solve(n, curr + 1);
return Math.min(exclusive, inclusive);
}
The runtime complexity of the given solution is exponential.
However, we can notice that there are only [1..n] possible values of n and [1..sqrt(n)] values of curr. Which, implies, that there are only n * sqrt(n) combinations of different values of arguments of the function solve. Hence, we can create the memoization table and reduce the complexity of the top-down solution:
int solve(int n) {
// initialization of the memoization table
int[][] memoized = new int[n + 1][(int) (Math.sqrt(n) + 1)];
for (int[] row : memoized) {
Arrays.fill(row, NOT_INITIALIZED);
}
return solve(n, 1, memoized);
}
int solve(int n, int curr, int[][] memoized) {
if (n == 0) {
return 0;
}
if ((curr * curr) > n) {
return POSITIVE_INFINITY;
}
if (memoized[n][curr] != NOT_INITIALIZED) {
// the sub-problem has been already solved
return memoized[n][curr];
}
int exclusive = solve(n, curr + 1, memoized);
int inclusive = solve(n - (curr * curr), 1, memoized) + 1;
memoized[n][curr] = Math.min(exclusive, inclusive);
return memoized[n][curr];
}
Given solution has the runtime complexity O(N * sqrt(N)).
However, it is possible to reduce the runtime complexity to O(N).
As far as the recurrence relation for f(N, x) depends only on f(N, x + 1) and f(N - x^2, 1) - it means, that the relation can be equivalently transformed to the loop form:
f(0) = 0
f(N) = min( f(N - x^2) + 1 ) , across the all x, such that x^2 <= N
In this case we have to memoize the f(N) only for N different values of its argument.
Hence, below presented the O(N) top-down solution:
int solve_top_down_2(int n) {
int[] memoized = new int[n + 1];
Arrays.fill(memoized, NOT_INITIALIZED);
return solve_top_down_2(n, memoized);
}
int solve_top_down_2(int n, int[] memoized) {
if (n == 0) {
return 0;
}
if (memoized[n] != NOT_INITIALIZED) {
return memoized[n];
}
// if 1 belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
int result = solve_top_down_2(n - (1 * 1)) + 1;
for (int curr = 2; (curr * curr) <= n; curr++) {
// check, whether some other number belongs to the shortest sequence of numbers, whose perfect squares sums-up to N
result = Math.min(result, solve_top_down_2(n - (curr * curr)) + 1);
}
memoized[n] = result;
return result;
}
Finally, the presented top-down solution can be easily transformed to the bottom-up solution:
int solve_bottom_up(int n) {
int[] memoized = new int[n + 1];
for (int i = 1; i <= n; i++) {
memoized[i] = memoized[i - (1 * 1)] + 1;
for (int curr = 2; (curr * curr) <= i; curr++) {
memoized[i] = Math.min(memoized[i], memoized[i - (curr * curr)] + 1);
}
}
return memoized[n];
}
The clarification to your confusion lies in the question itself. The structure dp holds the least number of squares that sum up to the index position of dp.
E.g., squares would return 3 when n=9, but least possible is 1, which is what dp[m- i*i] + 1 would return.
I tried a code on a coding website to find the largest prime factor of a number and it's exceeding the time limit for the last test case where probably they are using a large prime number. Can you please help me to reduce the complexity of the following code?
int main()
{
long n;
long int lar, fact;
long int sqroot;
int flag;
cin >> n;
lar=2, fact=2;
sqroot = sqrt(n);
flag = 0;
while(n>1)
{
if((fact > sqroot) && (flag == 0)) //Checking only upto Square Root
{
cout << n << endl;
break;
}
if(n%fact == 0)
{
flag = 1;
lar = fact;
while(n%fact == 0)
n = n/fact;
}
fact++;
}
if(flag == 1) //Don't display if loop fact reached squareroot value
cout << lar << endl;
}
Here I've also taken care of the loop checking till Square Root value. Still, how can I reduce its complexity further?
You can speed things up (if not reduce the complexity) by supplying a hard-coded list of the first N primes to use for the initial values of fact, since using composite values of fact are a waste of time. After that, avoid the obviously composite values of fact (like even numbers).
You can reduce the number of tests by skipping even numbers larger than 2, and stopping sooner if you have found smaller factors. Here is a simpler and faster version:
int main() {
unsigned long long n, lar, fact, sqroot;
cin >> n;
lar = 0;
while (n && n % 2 == 0) {
lar = 2;
n /= 2;
}
fact = 3;
sqroot = sqrt(n);
while (fact <= sqroot) {
if (n % fact == 0) {
lar = fact;
do { n /= fact; } while (n % fact == 0);
sqroot = sqrt(n);
}
fact += 2;
}
if (lar < n)
lar = n;
cout << lar << endl;
return 0;
}
I am not sure how large the input numbers may become, using the larger type unsigned long long for these computations will get you farther than long. Using a precomputed array of primes would help further, but not by a large factor.
The better result I've obtained is using the function below (lpf5()). It's based on the primality() function (below) that uses the formulas 6k+1, 6k-1 to individuate prime numbers. All prime numbers >= 5 may be expressed in one of the forms p=k*6+1 or p=k*6-1 with k>0 (but not all the numbers having such a forms are primes). Developing these formulas we can see a sequence like the following:
k=1 5,7
k=2 11,13
k=3 17,19
k=4 23,25*
k=5 29,31
.
.
.
k=10 59,61
k=11 65*,67
k=12 71,73
...
5,7,11,13,17,19,23,25,29,31,...,59,61,65,67,71,73,...
We observe that the difference between the terms is alternatively 2 and 4. Such a results may be obtained also using simple math. Is obvious that the difference between k*6+1 and k*6-1 is 2. It's simple to note that the difference between k*6+1 and (k+1)*6-1 is 4.
The function primality(x) returns x when x is prime (or 0 - take care) and the first divisor occurs when x is not prime.
I think you may obtain a better result inlining the primality() function inside the lpf5() function.
I've also tried to insert a table with some primes (from 1 to 383 - the primes in the first 128 results of the indicated formulas) inside the primality function, but the speed difference is unappreciable.
Here the code:
#include <stdio.h>
#include <math.h>
typedef long long unsigned int uint64;
uint64 lpf5(uint64 x);
uint64 primality(uint64 x);
uint64 lpf5(uint64 x)
{
uint64 x_=x;
while ( (x_=primality(x))!=x)
x=x/x_;
return x;
}
uint64 primality(uint64 x)
{
uint64 div=7,f=2,q;
if (x<4 || x==5)
return x;
if (!(x&1))
return 2;
if (!(x%3))
return 3;
if (!(x%5))
return 5;
q=sqrt(x);
while(div<=q) {
if (!(x%div)) {
return div;
}
f=6-f;
div+=f;
}
return x;
}
int main(void) {
uint64 x,k;
do {
printf("Input long int: ");
if (scanf("%llu",&x)<1)
break;
printf("Largest Prime Factor: %llu\n",lpf5(x));
} while(x!=0);
return 0;
}