String representation of a number - java

So I was asked this question in a recent interview. There are two numbers, really large and thus they are represented as Strings. Now write a function to multiply them and come up with a resultant String.
This was the solution, I managed to come up with, but I think it's an impossible problem.
I'm using Integer for example.
public String multiply(String str1, String str2){
int count = 0;
for(int i=0; i < str1.length(); i++){
int num1 = Integer.parseInt(str1.substring(str1.length()-2 -i, str2.length()-1-i));
for(int j=0; j < str2.length(); j++){
int num2 = Integer.parseInt(str2.substring(str2.length()-1 -j, str2.length()-1);
count+= num1*num2;
}
}
return String.valueOf(count);
}
However, I feel that since the premise of the problem is that the numerical values of the two strings cannot be stored in a variable then the variable count will also overflow. Thus I think my solution is incorrect. Is there a way to do this. The numbers are beyond the scope of Long or any possible numeric type available.

Generally, you could use BigInteger or BigDecimal for something like this...
final String number1 = "12345678902374287346293649376492342...";
final String number2 = "12345678902374287346293649376492342...";
final BigDecimal result = new BigDecimal(number1).multiply(new BigDecimal(number2));
System.out.println("Huge Number: " + result);

The problem of "big integers" is very well handled by a number of programming languages and libraries, such as the BigInteger class. In terms of implementing it yourself, there are different ways to approach the problem, depending on what your needs are (e.g. computational efficiency vs. storage efficiency).
The basic idea is to break the arithmetic down into manageable chunks, just like arithmetic you probably learned in school. If you're storing the number in decimal as a string of digits, then you'd simply do digit-by-digit decimal multiplication, starting at the least significant digit (probably the right-hand end). If the result of any digit multiplication is 10 or more, you carry the extra ten(s) across and add it to the calculation of the next digit.
There are some example implementations here: An interview question - implement Biginteger Multiply

Using BigDecimal multiply method it rather a simple answer to this question.
See https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html

Instead of using BigDecimal, you can follow the comment provided by #svasa.
You should consider the count to be a String as well.
From my experience they want you to implement the multiplication algorithm much like the one you were taught in elementary school.

the complexity is O ( N ^ 2 ) for the "manual" aproach. Better is to use an exotic algorithm such as https://en.wikipedia.org/wiki/Karatsuba_algorithm or peek an existing class from your base class library (java / C# or whatever .. such as BigInteger)

They want String, which is circumstantial, but you can decompose, till they loose interest.
String multiply(String x, String y) {
String sum = "0";
String pow10 = "";
for (int i = 0; i < x.length(); ++i) {
char digit = x.charAt(x.length() - 1 - i);
String term = multiplyDigit(digit, y);
sum = add(sum, term + pow10);
pow10 += "0";
}
return sum;
}
And so on: add, multiplyDigit.
The choice of data: char arrays, maybe digit values (byte), StringBuilder (flexible length) order and such is not really helpful for a quick implementation here (in java that is).
You could spare yourself much juggling by simplification as:
String multiplyDigit(char c, String x) {
String carries = "0";
String term = "";
int cvalue = c - '0';
for (int i = 0; i < x.length(); ++i) {
char digit = x.charAt(x.length() - 1 - i);
int product = cvalue * (digit - '0');
char carry = (char)('0' + (product / 10));
char t = (char)('0' + (product % 10));
carries = carry + carries;
term = t + term;
}
return add(carries, term);
}
where you do not add the carry immediately, but reuse add(String, String).

Related

Getting the second digit from a long variable [duplicate]

This question already has answers here:
Java: parse int value from a char
(9 answers)
Closed 5 years ago.
I am trying to fetch second digit from a long variable.
long mi = 110000000;
int firstDigit = 0;
String numStr = Long.toString(mi);
for (int i = 0; i < numStr.length(); i++) {
System.out.println("" + i + " " + numStr.charAt(i));
firstDigit = numStr.charAt(1);
}
When I am printing firstDigit = numStr.charAt(1) on console. I am getting 1 which is expected but when the loop finishes firstDigit has 49.
Little confused why.
Because 49 is the ASCII value of char '1'.
So you should not assign a char to int directly.
And you don't need a loop here which keeps ovveriding the current value with charAt(1) anyway.
int number = numStr.charAt(1) - '0'; // substracting ASCII start value
The above statement internally works like 49 -48 and gives you 1.
If you feel like that is confusious, as others stated use Character.getNumericValue();
Or, although I don't like ""+ hack, below should work
int secondDigit = Integer.parseInt("" + String.valueOf(mi).charAt(1));
You got confused because 49 is ASCII value of integer 1. So you may parse character to integer then you can see integer value.
Integer.parseInt(String.valueOf(mi).charAt(1)):
You're probably looking for Character.getNumericValue(...) i.e.
firstDigit = Character.getNumericValue(numStr.charAt(1));
Otherwise, as the variable firstDigit is of type int that means you're assigning the ASCII representation of the character '1' which is 49 rather than the integer at the specified index.
Also, note that since you're interested in only a particular digit there is no need to put the statement firstDigit = numStr.charAt(1); inside the loop.
rather, just do the following outside the loop.
int number = Character.getNumericValue(numStr.charAt(1));
you only need define firstDigit as a char type variable, so will print as character.
since you define as int variable, it's value is the ASCII value of char '1': 49. this is why you get 49 instead of 1.
the answer Integer.parseInt(String.valueOf(mi).charAt(1)+""); is correct.
However, if we want to consider performace in our program, we need some improvements.
We have to time consuming methods, Integer.parseInt() and String.valueOf(). And always a custom methods is much faster than Integer.parseInt() and String.valueOf(). see simple benchmarks.
So, high performance solution can be like below:
int y=0;
while (mi>10)
{
y=(int) (mi%10);
mi=mi/10;
}
System.out.println("Answer is: " + y);
to test it:
long mi=4642345432634278834L;
int y=0;
long start = System.nanoTime();
//first solution
//y=Integer.parseInt(String.valueOf(mi).charAt(1)+"");
//seconf solution
while (mi>10)
{
y=(int) (mi%10);
mi=mi/10;
}
long finish = System.nanoTime();
long d = finish - start;
System.out.println("Answer is: " + y + " , Used time: " + d);
//about 821 to 1232 for while in 10 runs
//about 61225 to 76687 for parseInt in 10 runs
Doing string manipulation to work with numbers is almost always the wrong approach.
To get the second digit use the following;
int digitnum = 2;
int length = (int)Math.log10(mi));
int digit = (int)((mi/Math.pow(base,length-digitnum+1))%base);
If you want a different digit than the second change digitnum.
To avoid uncertainty with regards to floating point numbers you can use a integer math library like guavas IntMath
Let's take a look
System.out.println(numStr.charAt(1));
firstDigit = numStr.charAt(1);
System.out.println(firstDigit);
The result wouldn't be the same you will get
1
49
This happens because your firstDigit is int. Change it to char and you will get expected result
You can also do like below,
firstDigit = Integer.parseInt( numStr.charAt(1)+"");
So it will print second digit from long number.
Some things which have not been mentioned yet:
The second digit for integer datatypes is undefined if the long number is 0-9 (No, it is not zero. Integers do not have decimal places, this is only correct for floating-point numbers. Even then you must return undefined for NaN or an infinity value). In this case you should return a sentinel like e.g. -1 to indicate that there is no second digit.
Using log10 to get specific digits looks elegant, but they are 1. one of the numerically most expensive functions and 2. do often give incorrect results in edge cases. I will give some counterexamples later.
Performance could be improved further:
public static int getSecondDigit(long value) {
long tmp = value >= 0 ? value : -value;
if (tmp < 10) {
return -1;
}
long bigNumber = 1000000000000000000L;
boolean isBig = value >= bigNumber;
long decrement = isBig ? 100000000000000000L : 1;
long firstDigit = isBig ? bigNumber : 10;
int result = 0;
if (!isBig) {
long test = 100;
while (true) {
if (test > value) {
break;
}
decrement = firstDigit;
firstDigit = test;
test *= 10;
}
}
// Remove first
while (tmp >= firstDigit) {
tmp -= firstDigit;
}
// Count second
while (tmp >= decrement) {
tmp -= decrement;
result++;
}
return result;
}
Comparison:
1 000 000 random longs
String.valueOf()/Character.getNumericValue(): 106 ms
Log/Pow by Taemyr: 151 ms
Div10 by #Gholamali-Irani: 45 ms
Routine above: 30 ms
This is not the end, it can be even faster by lookup tables
decrementing 1/2/4/8, 10/20/40/80 and avoid the use of multiplication.
try this to get second char of your long
mi.toString().charAt(1);
How to get ASCII code
int ascii = 'A';
int ascii = 'a';
So if you assign a character to an integer, the integer will be holding the ASCII value of that character. Here I explicitly gave the values, in your code you are calling a method that returns a character, that's why you are getting ASCII instead of digit.

I need to print the 215th Lucas Numbers using an efficient algorithm. Using recursion takes way too long.

The purpose of this class is to calculate the nth number of the Lucas Sequence. I am using data type long because the problems wants me to print the 215th number. The result of the 215th number in the Lucas Sequence is: 855741617674166096212819925691459689505708239. The problem I am getting is that at some points, the result is negative. I do not understand why I am getting a negative number when the calculation is always adding positive numbers. I also have two methods, since the question was to create an efficient algorithm. One of the methods uses recursion but the efficiency is O(2^n) and that is of no use to me when trying to get the 215th number. The other method is using a for loop, which the efficiency is significantly better. If someone can please help me find where the error is, I am not sure if it has anything to do with the data type or if it is something else.
Note: When trying to get the 91st number I get a negative number and when trying to get the 215th number I also get a negative number.
import java.util.Scanner;
public class Problem_3
{
static long lucasNum;
static long firstBefore;
static long secondBefore;
static void findLucasNumber(long n)
{
if(n == 0)
{
lucasNum = 2;
}
if(n == 1)
{
lucasNum = 1;
}
if(n > 1)
{
firstBefore = 1;
secondBefore = 2;
for(int i = 1; i < n; i++)
{
lucasNum = firstBefore + secondBefore;
secondBefore = firstBefore;
firstBefore = lucasNum;
}
}
}
static long recursiveLucasNumber(int n)
{
if(n == 0)
{
return 2;
}
if(n == 1)
{
return 1;
}
return recursiveLucasNumber(n - 1) + recursiveLucasNumber(n - 2);
}
public static void main(String[] args)
{
System.out.println("Which number would you like to know from "
+ "the Lucas Sequence?");
Scanner scan = new Scanner(System.in);
long num = scan.nextInt();
findLucasNumber(num);
System.out.println(lucasNum);
//System.out.println(recursiveLucasNumber(num));
}
}
Two observations:
The answer you are expecting (855741617674166096212819925691459689505708239) is way larger than you can represent using a long. So (obviously) if you attempt to calculate it using long arithmetic you are going to get integer overflow ... and a garbage answer.
Note: this observation applies for any algorithm in which you use a Java integer primitive value to represent the Lucas numbers. You would run into the same errors with recursion ... eventually.
Solution: use BigInteger.
You have implemented iterative and pure recursion approaches. There is a third approach: recursion with memoization. If you apply memorization correctly to the recursive solution, you can calculate LN in O(N) arithmetical operations.
Java data type long can contain only 64-bit numbers in range -9223372036854775808 .. 9223372036854775807. Negative numbers arise due to overflow.
Seems you need BigInteger class for arbitrary-precision integer numbers
I wasn't aware of the lucas numbers before this thread, but from wikipedia it looks like they are related to the fibonacci sequence with (n = nth number, F = fibonacci, L = lucas):
Ln = F_(n-1) + F_(n+1)
Thus, if your algorithm is too slow, you could use the closed form fibonacci and than compute the lucas number from it, alternative you could also use the closed form given in the wikipedia article directly (see https://en.wikipedia.org/wiki/Lucas_number).
Example code:
public static void main(String[] args) {
long n = 4;
double fibo = computeFibo(n);
double fiboAfter = computeFibo(n + 1);
double fiboBefore = computeFibo(n - 1);
System.out.println("fibonacci n:" + Math.round(fibo));
System.out.println("fibonacci: n+1:" + Math.round(fiboAfter));
System.out.println("fibonacci: n-1:" + Math.round(fiboBefore));
System.out.println("lucas:" + (Math.round(fiboAfter) + Math.round(fiboBefore)));
}
private static double computeFibo(long n) {
double phi = (1 + Math.sqrt(5)) / 2.0;
double psi = -1.0 / phi;
return (Math.pow(phi, n) - Math.pow(psi, n)) / Math.sqrt(5);
}
To work around the long size limit you could use java BigDecimal (https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html). This is needed earlier in this approach as the powers in the formula will grow very quickly.

Checking whether a number is in Fibonacci Sequence?

It was asked to find a way to check whether a number is in the Fibonacci Sequence or not.
The constraints are
1≤T≤10^5
1≤N≤10^10
where the T is the number of test cases,
and N is the given number, the Fibonacci candidate to be tested.
I wrote it the following using the fact a number is Fibonacci if and only if one or both of (5*n2 + 4) or (5*n2 – 4) is a perfect square :-
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for(int i = 0 ; i < n; i++){
int cand = sc.nextInt();
if(cand < 0){System.out.println("IsNotFibo"); return; }
int aTest =(5 * (cand *cand)) + 4;
int bTest = (5 * (cand *cand)) - 4;
int sqrt1 = (int)Math.sqrt(aTest);// Taking square root of aTest, taking into account only the integer part.
int sqrt2 = (int)Math.sqrt(bTest);// Taking square root of bTest, taking into account only the integer part.
if((sqrt1 * sqrt1 == aTest)||(sqrt2 * sqrt2 == bTest)){
System.out.println("IsFibo");
}else{
System.out.println("IsNotFibo");
}
}
}
}
But its not clearing all the test cases? What bug fixes I can do ?
A much simpler solution is based on the fact that there are only 49 Fibonacci numbers below 10^10.
Precompute them and store them in an array or hash table for existency checks.
The runtime complexity will be O(log N + T):
Set<Long> nums = new HashSet<>();
long a = 1, b = 2;
while (a <= 10000000000L) {
nums.add(a);
long c = a + b;
a = b;
b = c;
}
// then for each query, use nums.contains() to check for Fibonacci-ness
If you want to go down the perfect square route, you might want to use arbitrary-precision arithmetics:
// find ceil(sqrt(n)) in O(log n) steps
BigInteger ceilSqrt(BigInteger n) {
// use binary search to find smallest x with x^2 >= n
BigInteger lo = BigInteger.valueOf(1),
hi = BigInteger.valueOf(n);
while (lo.compareTo(hi) < 0) {
BigInteger mid = lo.add(hi).divide(2);
if (mid.multiply(mid).compareTo(x) >= 0)
hi = mid;
else
lo = mid.add(BigInteger.ONE);
}
return lo;
}
// checks if n is a perfect square
boolean isPerfectSquare(BigInteger n) {
BigInteger x = ceilSqrt(n);
return x.multiply(x).equals(n);
}
Your tests for perfect squares involve floating point calculations. That is liable to give you incorrect answers because floating point calculations typically give you inaccurate results. (Floating point is at best an approximate to Real numbers.)
In this case sqrt(n*n) might give you n - epsilon for some small epsilon and (int) sqrt(n*n) would then be n - 1 instead of the expected n.
Restructure your code so that the tests are performed using integer arithmetic. But note that N < 1010 means that N2 < 1020. That is bigger than a long ... so you will need to use ...
UPDATE
There is more to it than this. First, Math.sqrt(double) is guaranteed to give you a double result that is rounded to the closest double value to the true square root. So you might think we are in the clear (as it were).
But the problem is that N multiplied by N has up to 20 significant digits ... which is more than can be represented when you widen the number to a double in order to make the sqrt call. (A double has 15.95 decimal digits of precision, according to Wikipedia.)
On top of that, the code as written does this:
int cand = sc.nextInt();
int aTest = (5 * (cand * cand)) + 4;
For large values of cand, that is liable to overflow. And it will even overflow if you use long instead of int ... given that the cand values may be up to 10^10. (A long can represent numbers up to +9,223,372,036,854,775,807 ... which is less than 1020.) And then we have to multiply N2 by 5.
In summary, while the code should work for small candidates, for really large ones it could either break when you attempt to read the candidate (as an int) or it could give the wrong answer due to integer overflow (as a long).
Fixing this requires a significant rethink. (Or deeper analysis than I have done to show that the computational hazards don't result in an incorrect answer for any large N in the range of possible inputs.)
According to this link a number is Fibonacci if and only if one or both of (5*n2 + 4) or (5*n2 – 4) is a perfect square so you can basically do this check.
Hope this helps :)
Use binary search and the Fibonacci Q-matrix for a O((log n)^2) solution per test case if you use exponentiation by squaring.
Your solution does not work because it involves rounding floating point square roots of large numbers (potentially large enough not to even fit in a long), which sometimes will not be exact.
The binary search will work like this: find Q^m: if the m-th Fibonacci number is larger than yours, set right = m, if it is equal return true, else set left = m + 1.
As it was correctly said, sqrt could be rounded down. So:
Even if you use long instead of int, it has 18 digits.
even if you use Math.round(), not simply (int) or (long). Notice, your function wouldn't work correctly even on small numbers because of that.
double have 14 digits, long has 18, so you can't work with squares, you need 20 digits.
BigInteger and BigDecimal have no sqrt() function.
So, you have three ways:
write your own sqrt for BigInteger.
check all numbers around the found unprecise double sqrt() for being a real sqrt. That means also working with numbers and their errors simultaneously. (it's horror!)
count all Fibonacci numbers under 10^10 and compare against them.
The last variant is by far the simplest one.
Looks like to me the for-loop doesn't make any sense ?
When you remove the for-loop for me the program works as advertised:
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int cand = sc.nextInt();
if(cand < 0){System.out.println("IsNotFibo"); return; }
int aTest = 5 * cand *cand + 4;
int bTest = 5 * cand *cand - 4;
int sqrt1 = (int)Math.sqrt(aTest);
int sqrt2 = (int)Math.sqrt(bTest);
if((sqrt1 * sqrt1 == aTest)||(sqrt2 * sqrt2 == bTest)){
System.out.println("IsFibo");
}else{
System.out.println("IsNotFibo");
}
}
}
You only need to test for a given candidate, yes? What is the for loop accomplishing? Could the results of the loop be throwing your testing program off?
Also, there is a missing } in the code. It will not run as posted without adding another } at the end, after which it runs fine for the following input:
10 1 2 3 4 5 6 7 8 9 10
IsFibo
IsFibo
IsFibo
IsNotFibo
IsFibo
IsNotFibo
IsNotFibo
IsFibo
IsNotFibo
IsNotFibo
Taking into account all the above suggestions I wrote the following which passed all test cases
import java.io.*;
import java.util.*;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long[] fib = new long[52];
Set<Long> fibSet = new HashSet<>(52);
fib[0] = 0L;
fib[1] = 1L;
for(int i = 2; i < 52; i++){
fib[i] = fib[i-1] + fib[i - 2];
fibSet.add(fib[i]);
}
int n = sc.nextInt();
long cand;
for(int i = 0; i < n; i++){
cand = sc.nextLong();
if(cand < 0){System.out.println("IsNotFibo");continue;}
if(fibSet.contains(cand)){
System.out.println("IsFibo");
}else{
System.out.println("IsNotFibo");
}
}
}
}
I wanted to be on the safer side hence I choose 52 as the number of elements in the Fibonacci sequence under consideration.

How to sort digits of an integer using binary number technique?

Yesterday I went for an interview and they asked me to create a method which takes an integer value and displays the number with its digits in descending order. I used string manipulation and solved it but they asked me to do it using binary number technique. I still don't know how to approach this problem.
"Binary number technique"? It's a bullshit question, one where the correct answer is to walk out from the interview because it's a bullshit company.
Anyway, the best answer I can think of is
public static int solveBullshitTaskInASmartWay(int n) {
// get characters and sort them
char[] chars = Integer.toString(n).toCharArray();
Arrays.sort(chars);
// comparators don't work in Java for primitives,
// so you either have to flip the array yourself
// or make an array of Integer or Character
// so that Arrays.sort(T[] a, Comparator<? super T> c)
// can be applied
for (int i = 0, j = chars.length - 1; i < j; i++, j--) {
char t = chars[i]; chars[i] = chars[j]; chars[j] = t;
}
// reconstruct the number
return Integer.parseInt(new String(chars));
}
There is no numeric way to sort a number's digits, if you're expecting a nifty mathematical answer you will be waiting for a while.
EDIT: I need to add this - "digit" is solely a property of display of numbers. It is not a property of a number. Mathematically, the number 0b1000 is the same as 0x8 or 0o10, or 008.00000, or 8e0 (or even trinary 22, if anyone used trinary; alas, no conventional notation for that in programming). It is only the string representations of numbers that have digits. Solving this problem without use of characters or strings is not only pretty hard, it is stupid.
EDIT2: It is probably obvious, but I should make it clear that I have no beef with the OP, it is the interviewer I that I am entirely laying the blame on.
The is a simple (but not efficient) way of doing it without conversion to string. You can perform insertion sort on digits by extracting them from number using modulo and division, comparing them, and swapping if needed. There will be at most 9*8 comparsions need.
Here is code in C++
int sortDigits(int number)
{
for(int j = 0; j < 9; ++j) //because number can have 9+1 digits (we don't need 10 because digits are sorted in pairs)
{
int mul = 1;
for(int i = 0; i < 8; ++i) //because with i == 7 mul * 10 is biggest number fitting in int (will extract last digit)
{
if (mul * 10 > number) break; //by doing that we ensure there will be no zeroes added to number
int digitRight = number / mul % 10;
int digitLeft = number / (mul * 10) % 10;
if(digitRight > digitLeft) //swapping digits
{
/*
number -= digitLeft * mul * 10;
number += digitLeft * mul;
number -= digitRight * mul;
number += digitRight * mul * 10;
*/
number -= digitLeft * mul * 9;
number += digitRight * mul * 9;
}
mul *= 10;
}
}
return number;
}

how does Float.toString() and Integer.toString() works?

How can i implement an algorithm to convert float or int to string?
I found one link
http://geeksforgeeks.org/forum/topic/amazon-interview-question-for-software-engineerdeveloper-0-2-years-about-algorithms-13
but i cant understand the algorithm given there
the numbers 0-9 are sequential in most character encoding so twiddling with the integral value of it will help here:
int val;
String str="";
while(val>0){
str = ('0'+(val%10)) + str;
val /= 10;
}
Here's a sample of how to do the integer to string, from it I hope you'll be able to figure out how to do the float to string.
public String intToString(int value) {
StringBuffer buffer = new StringBuffer();
if (value < 0) {
buffer.append("-");
}
// MAX_INT is just over 2 billion, so start by finding the number of billions.
int divisor = 1000000000;
while (divisor > 0) {
int digit = value / divisor; // integer division, so no remainder.
if (digit > 0) {
buffer.append('0'+digit);
value = value - digit * divisor; // subtract off the value to zero out that digit.
}
divisor = divisor / 10; // the next loop iteration should be in the 10's place to the right
}
}
This is of course, very unoptimized, but it gives you a feel for how the most basic formatting is accomplished.
Note that the technique of "" + x is actually rewritten to be something like
StringBuffer buffer = new StringBuffer();
buffer.append("");
buffer.append(String.valueOf(x));
buffer.toString();
So don't think that what is written is 100% exactly HOW it is done, look at is as what must happen in a larger view of things.
The general idea is to pick off the least significant digit by taking the number remainder ten. Then divide the number by 10 and repeat ... until you are left with zero.
Of course, it is a bit more complicated than that, especially in the float case.
if i have a single digit in int fomrat then i need to insert it into char , how to convert int to char?
Easy:
int digit = ... /* 0 to 9 */
char ch = (char)('0' + digit);
Well, you can read the code yourself.

Categories