How to get all digit summation in BigInteger Value? - java

I have the following problem:
If n1 & n2 are natural numbers while n1 < 10 and n2 <10000.
find the summation of all digits in z where z = n1n2.
ex. n1 = 3, n2 = 10, z= 3^10 = 59049 if you sum the digits 5+9+0+4+9= 27. result =27
ex. n1 = 2, n2 = 12, z= 2^12 = 4096 if you sum the digits 4+0+9+6 = 19. result =19
And my current solution is:
public static long Solving(int n1, int n2) {
if (n1 >= 0 && n2 >= 0) {
BigInteger z = BigInteger.valueOf((long) Math.pow(n1, n2));
long sum = 0;
for (BigInteger i = z; i.compareTo(BigInteger.ZERO) > 0; i = i.divide(BigInteger.TEN)) {
sum += Integer.valueOf(String.valueOf(i.remainder(BigInteger.TEN)));
}
return sum;
}
return 0;
}
Why all cases doesn't success in that problem?

The actual problem is Math.pow(n1, n2).
Here you are treating both arguments as double and trying to calculate n1n2 which can easily cause an overflow.
Instead you can use BigInteger#pow() to get rid of overflow:
BigInteger z = BigInteger.valueOf(n1).pow(n2);
This will solve the issue.

I think you can solve this easily by doing something like this :
Step 1. Convert n1 to BigInteger
Step 2. Use native power function of BigInteger [exponent of pow function of big integer must be int]
Step 3. Convert the result back into string
Step 4. Iterate over the string and calculate the sum of digits.
Reference : https://www.tutorialspoint.com/java/math/java_math_biginteger.htm
https://www.tutorialspoint.com/java/math/biginteger_pow.htm

Related

Array form of integer

I was trying to convert the array to integer sum=999999999999 (twelve 9) , when i am limiting the array to less than ten 9s it is giving the result but when i am giving the array of more than ten 9s it is giving an unexpected result , please explain it will be really helpful for me
int[] arr={9,9,9,9,9,9,9,9,9,9,9,9};
int p=arr.length-1;
int m;
int num=0;
for (int i = 0; i <= p; i++) {
m=(int) Math.pow(10, p-i);
num += arr[i]*m; // it is executing like: 900+90+9=999
}
this happens because you're exceeding the Integer.MAX_VALUE.
You can read about it here.
You can use instead of int a long, to store large values,
and if that is not enough for you, you can use - BigInteger
BigInteger num = BigInteger.valueOf(0);
for (int i = 0; i <= p; i++) {
BigInteger m = BigInteger.valueOf((int) Math.pow(10, p-i));
BigInteger next = BigInteger.valueOf(arr[i]).multiply(m));
num = num.add(BigInteger.valueOf(arr[i]*m));
}
A couple of things.
You don't need to use Math.pow.
for up to 18 digits, you can use a long to do the computation.
I added some extra digits to demonstrate
int[] arr={9,9,9,9,9,9,9,9,9,9,9,9,1,1,2,3,4};
long sum = 0; // or BigInteger sum = BigInteger.ZERO;
for (int val : arr) {
sum = sum * 10 + val; // or sum.multiply(BigInteger.TEN).add(BigInteger.valueOf(val));
}
System.out.println(sum);
prints
99999999999911234
Here is the sequence for 1,2,3,4 so you can see what is happening.
- sum = 0
- sum = sum(0) * 10 + 1 (sum is now 1)
- sum = sum(1) * 10 + 2 (sum is now 12)
- sum = sum(12)* 10 + 3 (sum is now 123)
- sum = sum(123)*10 + 4 (sum is now 1234)
It is because an int is coded on 4 byte so technically you can only go from -2,147,483,648 to 2,147,483,647.
Consider using the long type.
Try using long (or any other type which can represent larger numbers) instead of int.
I suggest this because the int overflows: see https://en.wikipedia.org/wiki/Integer_overflow
Because it overflows integer boundry. The maximum integer value that can be stored in Java is 2147483647. When you try to store a value greater than this, the result will be an unexpected value. To solve this issue, you can use a long data type instead of an int data type
you can read about it here and here

Reducing the time complexity/Optimizing the solution

The motto is to find the sum of all the multiples of 3 or 5 below N.
Here's my code:
public class Solution
{
public static void main(String[] args)
{
Scanner in = new Scanner(System.in);
int t = in.nextInt();
long n=0;
long sum=0;
for(int a0 = 0; a0 < t; a0++)
{
n = in.nextInt();
sum=0;
for(long i=1;i<n;i++)
{
if(i%3==0 || i%5==0)
sum = sum + i;
}
System.out.println(sum);
}
}
}
It's taking more than 1sec to execute for some of the test cases. Can anyone please help me out so as to reduce the time complexity?
We can find the sum of all multiples of number d that are below N as a sum of an arithmetic progression (their sum is equal to d + 2*d + 3*d + ...).
long multiplesSum(long N, long d) {
long highestMultiple = (N-1) / d * d;
long numberOfMultiples = highestMultiple / d;
return (d + highestMultiple) * numberOfMultiples / 2;
}
Then the result will be equal to:
long resultSum(long N) {
return multiplesSum(N, 3) + multiplesSum(N, 5) - multiplesSum(N, 3*5);
}
We need to subtract multiplesSum(N, 15) because there are numbers that are multiples of both 3 and 5 and we added them twice.
Complexity: O(1)
You can't reduce the time complexity in this case as there are still O(N) of each set of numbers. However you can reduce the constant multiplier by using integer division:
static int findMultiples(int N, int s)
{
int c = N / s, sum = 0;
for (int i = 0, k = s; i < c; i++, k += s)
sum += k;
return sum;
}
This way you only loop through the multiples themselves instead of the whole range [0, N].
Note that you will need to do findMultiples(N, 3) + findMultiples(N, 5) - findMultiples(N, 15), to remove the duplicated multiples of both 3 and 5. The number of loops is therefore N/3 + N/5 + N/15 = 0.6N instead of N.
EDIT: in general the solution for an arbitrary number of divisors is sum(findMultiples(N,divisor_i) - findMultiples(N,LCM(all_divisors)); however it is only worth doing this if sum(1/divisor_i) + 1/LCM(all_divisors) < 1, otherwise there will be more loops. Luckily this will never be true for 2 divisors.
The sum of all numbers from 1 to (including) N is known to be N(N+1)/2 (no need for iteration).
So, the sum of all multiples of K, from K to KM is K times the above formula, giving KM(M+1)/2.
Combine this with #meowgoesthedog's findMultiples(N, 3) + findMultiples(N, 5) - findMultiples(N, 15) idea, and you have a constant-time solution.
A solution for your problem.Fastest method for solving your problem.
import java.util.*;
class Solution {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
while(t!=0)
{
long a=in.nextLong();
long q=a-1;
long aa=q/3;
long bb=q/5;
long cc=q/15;
long aaa=((aa*(aa+1))/2)*3;
long bbb=((bb*(bb+1))/2)*5;
long ccc=((cc*(cc+1))/2)*15;
System.out.println(aaa+bbb-ccc);
t-=1;}
}
}

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.

Maths calculation in java Fraction

I am trying to implement a basic calculation. The program take in 2 numbers, it works fine with 10 divided by 5 and give answer 2. If any smaller value divided by a larger value it will give me 0, can I have the answer in fraction?
Example 8 divided by 100 equal 8/100 rather than 0.
public class numtheory {
public static void main(String[] args) {
int n1;
int n2;
Scanner scan = new Scanner(System. in );
System.out.println("input number 1: ");
n1 = scan.nextInt();
System.out.println("input number 2: ");
n2 = scan.nextInt();
int temp1 = n1 / n2;
System.out.print("\n Output :\n");
System.out.print(temp1);
System.exit(0);
}
}
You need to convert your numbers to double:
double temp = ((double) n1) / n2;
If you want to produce a fraction, you can just print out:
System.out.println(n1 + "/" + n2);
This will print out whatever numbers you're given though, they won't be reduced.
You can reduce them yourself however with something like:
int n = n1;
int d = n2;
while (d != 0) {
int t = d;
d = n % d;
n = t;
}
int gcd = n;
n1 /= gcd;
n2 /= gcd;
And then print them out:
System.out.println(n1 + "/" + n2);
Instead of using integers, you need to use double.
This because an integer can only contain while numbers where double can contain decimal numbers.
u could change all the int to double or cast the in to double by dooing
((double) yourIntValue)
you could also get the input as a string, and parse it with
double dval=Double.parseDouble(value);

Finding Number of combinations C(n,r) for large n (Precision of decimal representation)

This is a problem from CodeSprint3
https://cs3.interviewstreet.com/challenges/dashboard/#problem/50877a587c389
Basically the problem is to calculate the number of possible combinations,nCr for given n and r.Also, 1 <= n <= 1000000000 and 0 <= r <= n.
Output all answers modulo 142857.
Since 6C4=6!/4! 2!
=6*5/2!
=6*5/2*1
I thought overflow could be avoided using division at every step.That is
to start with value of n (n is 6 in this case).
Decrement n and multiply it with previous value (so this becomes 6*5)
Perform division with denominator and then decrement it ( 6*5 /2 and denominator 2 becomes 1)
Repeat the steps until n is less than the of maximum of 2 denominators and in same number of iterations the divisor (Minimum of denominators will become 1)
int count(int n,int r)
{int maxDen=r>(n-r)?r:n-r; //larger number in the denominator
int minDen=n-maxDen; //the smaller number in denominator
double num=1;
for(int j=n;j>maxDen;j--)
{num=j*num; //for C(6,4) example num=6*5 and so on
// System.out.println("num "+num +" minDen "+minDen);
num=num/minDen; //divide num 6*5 in this case by 2
minDen--;
}
num=num%142875; //output the result modulo 142875
return (int) num;
}
But perhaps due to loss precision as more divisions are performed,it gives wrong values but then it still gives correct output for some values.As it stands correct for 22 17 but not for 24 17.
(22 17) = 26334 //gives Correct value
(24 17)= 60353 //wrong value correct value is 60390
(25,17)=81450 //wrong value correct value is 81576
(16 15)= 16 //gives correct value
(87 28)= 54384 //wrong value correct value is 141525
I tried to use num as a BigDecimal and as a consequence i had to replace everything with a BigDecimal to perform the operations.The output then was the same for the inputs which gave correct results in above code.But for inputs which gave wrong results,the program throws an exception
Exception in thread "main" **java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.**
at java.math.BigDecimal.divide(Unknown Source)
at Combination.NcRcount2.count(NcRcount2.java:16)
at Combination.NcRcount2.main(NcRcount2.java:37)
Line 16 is num=num.divide(minDen); //in replacement to earlier used num/minDen,both num and minDen are BigDecimal in this case
Even though if the number does not have an exact decimal representation,given the arbitrary precision of BigDecimal the error in results would have been minimized if it didn't threw an exception.
** If the result of division on floats or doubles does not have an exact decimal representation then why isn't an exception thrown?**
I verified the results using BigDecimal with the dynamic programming approach as
C(n,r)=C(n-1,r-1)+C(n-1,r)
This works correctly in all cases as it appears to me but there must be a better way
BigDecimal Comb (int n, int k)
{ if(k>n-k)
k=n-k;
BigDecimal B[][]=new BigDecimal[n+1] [k+1];
for (int i = 0; i <= n; i++)
{ int min;
if(i>=k)
min=k;
else
min=i;
for (int j = 0; j <= min; j++)
{ if (j == 0 || j == i)
B[i][j] =new BigDecimal(1);
else{
if(j>i-j)
B[i][j]=B[i][i-j];
else
B[i][j] = B[i - 1][j - 1].add(B[i - 1] [j]);
}
}
}
BigDecimal div=new BigDecimal(142857);
return B[n][k].remainder(div);
}
Please suggest me a better way to do this without using BigDecimal
public class Solution {
public static void main(String arg[]) {
Scanner s = new Scanner(System.in);
List<BigInteger> ar = new ArrayList<BigInteger>();
int tot = Integer.parseInt(s.nextLine());
BigInteger max = BigInteger.ZERO;
for (int i = 0; i < tot; i++) {
String str[] = s.nextLine().split(" ");
Long n1 = Long.parseLong(str[0]);
Long r1 = Long.parseLong(str[1]);
Long nr1 = n1 - r1;
BigInteger n = BigInteger.valueOf(n1);
BigInteger r = BigInteger.valueOf(r1);
BigInteger nr = BigInteger.valueOf(nr1);
ar.add(n);
ar.add(r);
ar.add(nr);
if (n.compareTo(max)==1) {
max=n;
}
if (r.compareTo(max)==1) {
max=r;
}
if (nr.compareTo(max)==1) {
max=nr;
}
}
HashMap<BigInteger,BigInteger> m=new HashMap<BigInteger,BigInteger>();
m.put(BigInteger.ZERO, BigInteger.ONE);
BigInteger fact=BigInteger.ONE;
for(BigInteger i=BigInteger.ONE;i.compareTo(max.add(BigInteger.ONE))==-1;i=i.add(BigInteger.ONE)){
fact=fact.multiply(i);
if(ar.contains(i)){
m.put(i, fact);
}
}
for(int i=0;i<ar.size();i=i+3){
BigInteger n=m.get(ar.get(i));
BigInteger r=m.get(ar.get(i+1));
BigInteger nr=m.get(ar.get(i+2));
BigInteger rem=r.multiply(nr);
BigInteger act=n.divide(rem);
BigInteger res=act.remainder(BigInteger.valueOf(142857));
System.out.println(res);
}
}
}
I think this code might will help you .
Rather straightforward implementation:
public long combinations(int n, int k) {
BigInteger factorialN = factorial(n);
BigInteger factorialK = factorial(k);
BigInteger factorialNMinusK = factorial(n - k);
return factorialN.divide(factorialK.multiply(factorialNMinusK)).longValue();;
}
private BigInteger factorial(int n) {
BigInteger ret = BigInteger.ONE;
for (int i = 1; i <= n; ++i) ret = ret.multiply(BigInteger.valueOf(i));
return ret;
}
The part of your question about an exception with BigDecimal code isn't clear to me so I won't comment on that.
Regarding a sequence of multiplies and divides to compute nCr, wikipedia shows a formula that's easy to implement. Your first section of code in the question might be equivalent to it, as may be the bit of python code just below. It computes up to 61C30 using 64-bit integer arithmetic; 62C31 requires another bit or two.
def D(n, k):
c, j, k = 1, n, min(k,n-k)
for i in range(1,k+1):
c, j = c*j/i, j-1
return c
The reason that this order of computation works, with all divisions being exact divisions, is that nC(j+1) = nCj * (n-j)/(j+1) as is easily verified from nCj = n!/j!(n-j)! and some algebra. That is, you can compute nCr for large n and r completely in integer arithmetic without needing any decimal places.
Suppose K=142857.
Note that reduction of intermediate terms modulo K will cause problems and may be infeasible. If the numerator is reduced mod K, some divisions won't be exact in ordinary arithmetic. If K were prime, the extended GCD algorithm could be used to find inverses mod K for all numbers. But K=3*9*11*13*37 and inverses mod K will not exist for numbers that are multiples of 3, 11, 13, or 37, as a consequence of Bézout's lemma and some modular algebra.
You should not divide.
Draw Pascal triangle in memory. This will require only additions and will easily allow to apply modular arithmetic.
Also, this will last not longer than with divisions, because you can not avoid of calculating factorials.
package tests.StackOverflow;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class q13241166 {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String s;
String[] ss;
int[] n;
int[] r;
int T;
/*
System.out.println("Input T:");
s = in.readLine();
T = Integer.parseInt(s);
if( T < 1 || T > 100000) {
throw new IllegalArgumentException();
}
*/
T = 9;
/*
n = new int[T];
r = new int[T];
System.out.println("Input n r pairs:");
for(int i=0; i<T; ++i) {
s = in.readLine();
ss = s.split("\\s+");
n[i] = Integer.parseInt(ss[0]);
if( n[i] < 1 || n[i] > 1000000000) {
throw new IllegalArgumentException();
}
r[i] = Integer.parseInt(ss[1]);
if( r[i] < 0 || r[i] > n[i]) {
throw new IllegalArgumentException();
}
}
*/
n = new int[] {2, 4, 5, 10, 22, 24, 25, 16, 87};
r = new int[] {1, 0, 2, 3, 17, 17, 17, 15, 28};
int modulobase = 142857;
int[] answers_old, answers = null;
System.out.println("Output");
for(int i=0; i<T; ++i) {
for( int nn=0; nn<=n[i]; ++nn) {
answers_old = answers;
answers = new int[nn+1];
for( int rr=0; rr<=nn; ++rr) {
if( rr == 0 || rr == nn ) {
answers[rr] = 1;
}
else {
answers[rr] = answers_old[rr-1] + answers_old[rr];
}
answers[rr] %= modulobase;
}
}
System.out.println(answers[r[i]]);
}
}
}
Output follows:
Output
2
1
10
120
26334
60390
81576
16
141525

Categories