Did I just increase the complexity of reversing a number? [duplicate] - java

This question already has answers here:
Java Math.pow(a,b) time complexity
(2 answers)
Closed 4 years ago.
public class HelloWorld{
public static void main(String []args){
int orig=103, reverse=0, mod;
int numOfDigits=0;
int n = orig;
while (n>0){
n /= 10;
numOfDigits++;
}
n = orig;
while (n > 0){
mod = n % 10;
reverse = reverse + (int)(mod * java.lang.Math.pow(10, numOfDigits-1));
numOfDigits--;
n /= 10;
}
System.out.println("Reversed is : " + reverse);
}
}
I do know that reverse = reverse + (int)(mod * java.lang.Math.pow(10, numOfDigits-1)); can be replaced by reverse = mod + (reverse*10).
Was wondering if I had just increased the complexity of a simple program by calculating total number of digits and applying power?
P.S: Kindly assume that orig can be taken as an input from the user and could be a number of any number of digits. I have hard coded only for experiment.

You didn't increase the complexity ... but you did make it slower. The expression pow(10, numOfDigits - 1) will be substantially slower than reverse = mod + (reverse * 10)
It is also possible that a computation that uses Math.pow instead of integer multiplication is inaccurate due to floating point imprecision. A double has only 52 bits of precision, compared with 63 for a long. In this example, this probably doesn't apply, but it is something to be wary of, in general

Probably, this would be the best approach with less iteration & complexity:
public class NumReverse {
public long reverseNumber(long number){
long reverse = 0;
while(number != 0){
reverse = (reverse*10)+(number%10);
number = number/10;
}
return reverse;
}
public static void main(String a[]){
System.out.println("Reversed is: "+new NumReverse().reverseNumber(103));
}
}

compute the multiply times and add times:
suppose f(x) = an * x^n + an-1 * x^n-1 + ... + a1 * x + a0
1. If calculate f(x) by computing one item by one item,
it will take (n+1) + n + (n-1) + ... + 1 + 0 = (n+1)(n+2)/2 multiply times and n addition times.
2. If calculate f(x) by n = n*10 + mod,
it will take n multiply times and n addition times.
Of course, if pow() has some optimization such as "divide and conquer", the complexity of pow() should be O(logN).

Related

What is the time complexity of calculating factorial n! using Java's BigInteger

Suppose the algorithm is as below:
public static BigInteger getFactorial(int num) {
BigInteger fact = BigInteger.valueOf(1);
for (int i = 1; i <= num; i++)
fact = fact.multiply(BigInteger.valueOf(i)); // ? time complexity
return fact;
}
It seems hard to calculate number of digits of fact.
Optimized version:
public BigInteger getFactorial2(long n) {
return subFactorial(1, n);
}
private BigInteger subFactorial(long a, long b) {
if ((b - a) < 10) {
BigInteger res = BigInteger.ONE;
for (long i = a; i <= b; i++) {
res = res.multiply(BigInteger.valueOf(i));
}
return res;
} else {
long mid = a + (b - a) / 2;
return subFactorial(a, mid).multiply(subFactorial(mid + 1, b));
}
}
The number of digits contained in fact is log(fact). It can be shown that O(log(n!)) == O(nlogn), so the number of digits in n! grows proportionally to nlogn. Since your algorithm piles values on to a partial product without splitting them into smaller intermediate values (divide and conquer fashion), we can assert that one of the numbers being multiplied will be less than n for calculating n!. Using grade school multiplication, we have O(logn * nlogn) time to multiply each of these numbers, and we have n-1 multiplies, so this is O(n * logn * nlogn) == O((nlogn)^2). I do believe this is a tight upper bound for grade-school multiplication, because even though the beginning multiplications are far smaller, the latter half are all larger than O((n/2)log^2(n/2)), and there are (n/2) of them, so O((n/2)^2 *log^2(n/2)) == O((nlogn)^2).
However, it is entirely possible that BigInteger uses Karatsuba multiplication, Toom-Cook multiplication, or maybe even the Schönhage–Strassen algorithm. I do not know how these perform on integers of such drastically varying sizes (logn vs nlogn), so I cannot give a tight upper bound on those. The best I can do is speculate that it will be less than that of the O(n*F(nlogn)), where F(x) is the time to multiply two numbers of length x using a specific algorithm.

Do-while loop factorial. ( factorial *= x will eventually give a negative number) [duplicate]

I am currently taking pre-calculus and thought that I would make a quick program that would give me the results of factorial 10. While testing it I noticed that I was getting incorrect results after the 5th iteration. However, the first 4 iterations are correct.
public class Factorial
{
public static void main(String[] args)
{
int x = 1;
int factorial;
for(int n = 10; n!=1; n--)
{
factorial = n*(n-1);
x = x * factorial;
System.out.printf("%d ", x);
}
}//end of class main
}//end of class factorial
That is an Integer Overflow issue. Use long or unsigned long instead of int. (And as #Dunes suggested, your best bet is really BigInteger when working with very large numbers, because it will never overflow, theoretically)
The basic idea is that signed int stores numbers between -2,147,483,648 to 2,147,483,647, which are stored as binary bits (all information in a computer are stored as 1's and 0's)
Positive numbers are stored with 0 in the most significant bit, and negative numbers are stored with 1 in the most significant bit. If your positive number gets too big in binary representation, digits will carry over to the signed bit and turn your positive number into the binary representation of a negative one.
Then when the factorial gets bigger than even what an unsigned int can store, it will "wrap around" and lose the carry-over from its most significant (signed) bit - that's why you are seeing the pattern of sometimes alternating positive and negative values in your output.
You're surpassing the capacity of the int type (2,147,483,647), so your result is wrapping back around to the minimum int value. Try using long instead.
Having said the that, the method you are currently employing will not result in the correct answer: actually, you are currently computing 10! ^ 2.
Why complicate things? You could easily do something like this:
long x = 1L;
for(int n = 1; n < 10; n++)
{
x *= n;
System.out.println(x);
}
1
2
6
24
120
720
5040
40320
362880
which shows successive factorials until 10! is reached.
Also, as others have mentioned, if you need values bigger than what long can support you should use BigInteger, which supports arbitrary precision.
Your formula for the factorial is incorrect. What you will have is this:
Step 1 : n*(n-1) = 10 * 9 = 90 => x = 1*90 = 90
Step 2 : n*(n-1) = 9 * 8 = 72 => x = 90*72 = 6480 or, it should be : 10 * 9 * 8 => 720
But the wrong results are coming from the fact that you reached the maximum value for the type int as pointed out by others
Your code should be
public class Factorial
{
public static void main(String[] args)
{
double factorial = 1;
for(int n = factorial; n>=1; n--)
{
factorial = factorial * n;
System.out.printf("%d ", factorial );
}
}
}
In addition to what the other answers mention about the overflow, your factorial algorithm is also incorrect. 10! should calculate 10*9*8*7*6*5*4*3*2*1, you are doing (10*9)*(9*8)*(8*7)*(7*6)*...
Try changing your loop to the following:
int x = 1;
for(int n = 10; n > 1 ; n--)
{
x = x * n;
System.out.printf("%d ", x);
}
You will eventually overflow if you try to calculate the factorial of higher numbers, but int is plenty large enough to calculate the factorial of 10.

Competitive Programing: Factorial Time limit exceeded

I am working on a very simple spoj problem in which we have to take input N calculate its factorial then find out number of trailing zeros and display it some thing like
Sample Input:
6
3
60 // fact of 60 has 14 trailing zeros
100
1024
23456
8735373
Sample Output:
0
14
24
253
5861
2183837
so i have written a code which is working fine on my machine but when i am submitting it is giving me time limit error. i don't know how to make this code fast. So i want suggestions from you guys.
public class Factorial {
public static void main(String[] args) throws IOException {
try {
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
int t = Integer.parseInt(bf.readLine());
for (int i = 0; i < t; i++) {
Long num = Long.parseLong(bf.readLine());
BigInteger bd = BigInteger.valueOf(num);
System.out.println(countTrailinZeros(factorial(bd.toString())));
}
} catch (IllegalStateException e) {
return;
}
}
public static BigInteger factorial(String n) {
BigInteger x = BigInteger.valueOf(1);
for (long i = 1; i <= Integer.parseInt(n); i++) {
x = x.multiply(BigInteger.valueOf(i));
}
return x;
}
public static int countTrailinZeros(BigInteger bd) {
String s = bd.toString();
int glen = s.length();
s = s.replaceAll("[0.]*$", "");
int llen = s.length();
return glen - llen;
}
}
I have googled about some possible solutions and found out that lookup table may work i don't have much idea about this. I'd be very thankful if some can explain me about lookup table.
edit: Could it be java is too slow to solve this problem in given time? or in general it is not favorable to use java for competitive programing?
you dont need to calculate factorial to get number of trailing zeroes.
Solution :
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int lines = Integer.parseInt(br.readLine());
int sum, N, p;
for (int i = 0; i < lines; i++) {
N = Integer.parseInt(br.readLine());
sum = 0;
p = 5;
while (N / p != 0) {
sum = sum + N / p;
p = p * 5;
}
System.out.println(sum);
}
}
}
Logic is :
The highest power of a prime number p in N! is given by
floor(N/p) + floor(N/p*p) + floor(N/p*p*p) ... so on till [floor(N/p^n) = 0]
so since number of ending zeroes is required , ans = min(max power of 2 in N!, max power of 5 in N!)
because zeroes appears on multiplication by ten and ten can be decomposed to 10 = (2 * 5).
It is fine to assume that max power of 5 in N! is always less than max power of 2 in N!.
as multiples of 2 occur more frequently than multiples of 5.
So problem reduces to finding max power of 5 in N! and hence the solution.
Example :
N = 5
max power of 5 in 5! = floor(5/5) + floor(5/25) => 1 + 0 => ans = 1
N = 100
max power of 5 in 100! = floor(100/5) + floor(100/25) + floor(100/125) => 20 + 4 + 0 => ans = 24
I have solved the same problem in spoj platform, you just have to divide the value by 5 until the value becomes less than 5. print all the result of the division and that's your output.
To solve this problem, consider prime factorization of N factorial:
N! = 2^a1 * 3^a2 * 5^a3 * .... where a1, a2, a3, ... >= 0
Since N! = N*(N-1)(N-2)..., multiples of 2 are more frequent than 5.
So, a1 >= a3 in this expansion.
Number of trailing zeros = how many times you can divide N! by 10.
Which implies, ans = min(a1, a3) based on the prime factorization given above.
Since we already proved a1 >= a3, hence ans = a3, i.e power of 5 in the prime factorization of N!.
There will be floor(N/5) numbers that will contribute to power of 5 atleast once.
There will be floor(N/25) numbers that will contribute to power of 5 atleast twice.
There will be floor(N/125) numbers that will contribute atleast thrice
and so on.
The total power of 5 = floor(N/5) + floor(N/25) + floor(N/125) + ...
Implementation of this formula in code is left as an exercise.

Algorithm to solve an equation

I have this problem for the course "Algorithm and data structures"
You have a equation x^2+s(x)+200·x=N, where x and N are natural numbers and S(x) is the sum of digits of number x.
On the input we have N and A, B such that A≤B and A, B≤1,000,000,000. You need to check if there is a natural number x in the interval [A, B] that solves the equation. If found you need to return that number, otherwise return -1.
Example Input:
1456
10 80
Output
-1
I managed to solve this problem by using some math and a bit modified version of brute force algorithm. But are there any more effective(algorithm based) ways to solve this problem?
This is my code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Range {
static int proveri(long N, long A, long B) {
long res = 0;
long start = (long)((-200 + Math.sqrt(4*N + 4))/2);
//System.out.println(start);
for (long i = Math.max(A, start); i <= B; i++) {
res = i * i + S(i) + 200 * i;
if(res == N)
return (int)i;
if(res > N)
return -1;
}
return -1;
}
static int S(long x) {
int sum = 0;
while(x > 0) {
sum += x % 10;
x /= 10;
}
return sum;
}
public static void main(String[] args) throws Exception {
int i,j,k;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
long N = Long.parseLong(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
long A = Long.parseLong(st.nextToken());
long B = Long.parseLong(st.nextToken());
int res = proveri(N, A, B);
System.out.println(res);
br.close();
}
}
Here's a way where you can cut down on the amount of numbers you have to search.
Consider the equation anxn +
an-1xn-1 + ... + a1x + a0 = 0.
The rational root theorem states that if x = p/q is a solution,
then p divides a0 and q divides an
In your case, an is 1 and a0 is equal to S(x)-N. Thus, we know that any solution must divide S(x)-N.
This is where ben75's tip comes in. Since S(x) can't be bigger than 81, we can loop through all of the possible values of S(x), and solve separately. Something like this:
for each possible value of S(x)
loop through every factor x of S(x) - N
check if it is between A and B, if its digits sum to S(x)
and if it is a solution to x*x + 200x + S(x) = N.
if it is, return it.
return -1
There's also a pretty slick way for you to loop through all of the factors of a number, but I'll let you work that one out for yourself since this is for a course. My hint there is to look at the prime factorization of a number.
For the equation x^2+s(x)+200·x=N, consider
x^2 + 200·x + (N - s(x)) = 0
For a solution to a*x^2 + b*x + c = 0 equation with integer solutions, we need to have:
b^2 - 4*a*c >= 0 and must be a perfect square
Hence 200^2 - 4 * (N - s(x)) >=0 and a square or
10000 >= (N - s(x)) and (10,000 - (N - s(x)) must be a square. The square value is therefore less than 10,000 and hence there can be at most 100 values you need to check. With proper values of N it can be much lesser.
Also note that since N < 10,000, s(x) can be at most 36. These should cut down the range quite a bit.

Factorial loop results are incorrect after the 5th iteration

I am currently taking pre-calculus and thought that I would make a quick program that would give me the results of factorial 10. While testing it I noticed that I was getting incorrect results after the 5th iteration. However, the first 4 iterations are correct.
public class Factorial
{
public static void main(String[] args)
{
int x = 1;
int factorial;
for(int n = 10; n!=1; n--)
{
factorial = n*(n-1);
x = x * factorial;
System.out.printf("%d ", x);
}
}//end of class main
}//end of class factorial
That is an Integer Overflow issue. Use long or unsigned long instead of int. (And as #Dunes suggested, your best bet is really BigInteger when working with very large numbers, because it will never overflow, theoretically)
The basic idea is that signed int stores numbers between -2,147,483,648 to 2,147,483,647, which are stored as binary bits (all information in a computer are stored as 1's and 0's)
Positive numbers are stored with 0 in the most significant bit, and negative numbers are stored with 1 in the most significant bit. If your positive number gets too big in binary representation, digits will carry over to the signed bit and turn your positive number into the binary representation of a negative one.
Then when the factorial gets bigger than even what an unsigned int can store, it will "wrap around" and lose the carry-over from its most significant (signed) bit - that's why you are seeing the pattern of sometimes alternating positive and negative values in your output.
You're surpassing the capacity of the int type (2,147,483,647), so your result is wrapping back around to the minimum int value. Try using long instead.
Having said the that, the method you are currently employing will not result in the correct answer: actually, you are currently computing 10! ^ 2.
Why complicate things? You could easily do something like this:
long x = 1L;
for(int n = 1; n < 10; n++)
{
x *= n;
System.out.println(x);
}
1
2
6
24
120
720
5040
40320
362880
which shows successive factorials until 10! is reached.
Also, as others have mentioned, if you need values bigger than what long can support you should use BigInteger, which supports arbitrary precision.
Your formula for the factorial is incorrect. What you will have is this:
Step 1 : n*(n-1) = 10 * 9 = 90 => x = 1*90 = 90
Step 2 : n*(n-1) = 9 * 8 = 72 => x = 90*72 = 6480 or, it should be : 10 * 9 * 8 => 720
But the wrong results are coming from the fact that you reached the maximum value for the type int as pointed out by others
Your code should be
public class Factorial
{
public static void main(String[] args)
{
double factorial = 1;
for(int n = factorial; n>=1; n--)
{
factorial = factorial * n;
System.out.printf("%d ", factorial );
}
}
}
In addition to what the other answers mention about the overflow, your factorial algorithm is also incorrect. 10! should calculate 10*9*8*7*6*5*4*3*2*1, you are doing (10*9)*(9*8)*(8*7)*(7*6)*...
Try changing your loop to the following:
int x = 1;
for(int n = 10; n > 1 ; n--)
{
x = x * n;
System.out.printf("%d ", x);
}
You will eventually overflow if you try to calculate the factorial of higher numbers, but int is plenty large enough to calculate the factorial of 10.

Categories