Atoi in Java for negative values - java

I am writing an Atoi function in Java. It runs fine for +ve integers. But what I want is when I enter a negative integer it should give me an error. So I tried including continue statement in my class Atoi. The class implemented is:
class Atoi {
int atoi(String tmp) {
int result = 0;
for (int i = 0; i < tmp.length(); i++) {
char digit = (char)(tmp.charAt(i) - '0');
if(digit == '-')
continue;
}
else {
result += (digit * Math.pow(10, (tmp.length() - i - 1)));
}
return result;
}
}
But unfortunately it gives me the negative equivalent of the character i.e for -12 it gives me 655312! Help.
EDIT: Suppose I need to check for floating point numbers what should I do? If I enter 12.1 or 123.2 it should return 12.1 and 123.2 repectively!!

Instead of continue you should give an error (throw an exception, return -1 or whatever you mean with "give an eror").
If you want to ignore the - you can change the else clause to:
result = digit + result * 10;

Quick fix for the obvious problem: the order of the logic was wrong...
Instead of
char digit = (char)(tmp.charAt(i) - '0');
if(digit=='-')
continue;
try
char origChar=tmp.charAt(i);
if(origChar=='-')
continue;
char digit = (char)(origChar - '0');
But there are two more problems:
it does not negate the value, in case of a '-' character is present!
what if this is the input string: -1-2-3-4-5? The result will be interesting! EDIT: try this input also: 'répa'... Even more interesting result!
Don't forget to test with incorrect inputs too, and as #Klaus suggested, don't hesitate to throw an exception, (preferably IllegalArgumentException) with a correct error message, if an incorrect input is given to the function...

If this is not being done as a programming exercise, there is a simpler solution:
static int atoi(String tmp)
{
int result = Integer.parseInt(tmp);
if(result >= 0) {
return result;
} else {
throw new IllegalArgumentException("Negative string "+"\"" + tmp + "\"");
}
}
Substitute the appropriate exception or other action in the negative result case. If you want to just ignore '-', as in the posted code, replace the if-then-else with:
return Math.abs(result);
This code also throws an exception for strings like "abc".
More generally, if a library method does not do exactly what you want, it is often easy to use it in a method that modifies its behavior, rather than re-writing it.

You can write code like this, of course, but you need to check that tmp is a valid number.
int atoi(String tmp) {
int result = 0;
int factor = tmp.charAt(0) == "-" ? -1 : 1;
for (int i = 0; i < tmp.length(); i++) {
if (tmp.chatAt(i) < '0' || tmp.chatAt(i) > '9')
continue;
char digit = (char)(tmp.charAt(i) - '0');
result += (digit * Math.pow(10, (tmp.length() - i - 1)));
}
return result * factor;
}

if(digit=='-')
With
(char)(tmp.charAt(i)
You're code is assuming there are no -'s
(char)(tmp.charAt(i) - '0');
Is an optimization that's blindly clamping the 'digit' variable to a number.
You need to step through what your code is actually doing, search for an ASCII chart and work through what the subtractions of '0' does ('0' == 48), so '1' (49) - '0' (48) = 1 etc...

If you don't want to convert negative numbers then simply return 0 whenever you encounter - sign instead of looping further. Put this code before the if-else block.
if(tmp.charAt(i)=='-')
return 0;

Related

How to sum consecutive equal digits in a number in Java

The following question was asked in my last interview (yesterday), and I'm trying to solve it since then (couldn't solve it in the interview).
Sorry for any grammar mistakes or any logical mistakes, I don't have the question, it was written by memory:
You are given a number in a string format, for example: "14438832066".
You got to sum up the consecutive equal digits in that number. If no
consecutive equal digit was found, just add the digit to the result.
for example: solution(19938832066) => 11831632012
Explanation: first digit is 1.
The second and third digits are both 9 which means they will turn into 18 in the result string.
So on
with the rest of the digits (as you can see, the last 2 digits are both 6 which means they will turn into 12 in the result string).
You are required to do that for the result string as well, if needed, until no equal consecutive digits are found in the number.
Example:: number: 14438832066 solution( "19938832066") ->"11831632012" -> "2831632012"
Explanation: first result is 11831632012, but then you can see that there are still equal consecutive digits : the first and the
second digits are both 1. So process that number as well.
You are given a string and must return a string.
My solution:
I couldn't write the solution, I don't know why. It's a pretty simple question, I thought going recursive at first but didn't want to complex things.
I wrote 2 helper methods:
one that returns a boolean whether the number consists of equal consecutive digits.
one that actually makes the business logic:
turn the string into a char array
create a counter that will count instances of the same digit - (int counter = 1).
loop on the array from the first to the one before the last element :
inside the loop:
//equal digit was found - increment counter and continue to next digit
if char[i] == char[i+1] then counter++
//calculation in case we are done counting the same digit
else if counter > 0 then result.append(counter*digit[i])
// if no consecutive equal digit was found
else result.append(digit[i])
end loop: return result
Problems I had:
I created the counter inside the loop, so each iteration it got rested. took me few minutes to realize.
I had troubles realizing that 'int(digit[i])' doesn't give me the numeric value of the char, it gives the ASCII value. I had to use "Character.getNumericValue" (don't remember the exact name of the method).
Because of these problems, it took me 45 minutes to write the solution which in the end didn't even work.
I'll be glad to get a working solution, and even better - to get any feedback and tips on my solution and what, in your opinion, were my mistakes.
Thank you.
Your pseudo-code seems alright, as far as it goes. What's missing is that you don't repeatedly check the result string to see if another pass is required. I also show how you don't need to remember the API to convert a character to a digit; if you know the digits are decimal, you can interpret them yourself. As an interviewer, I would accept that there is an API that you can't precisely remember or your home-brew solution as equally valid.
String transform(String number) {
while (true) {
String result = collapse(number);
if (result.equals(number)) return result;
number = result;
}
}
private static String collapse(String number) {
StringBuilder result = new StringBuilder();
for (idx = 0; idx < number.length(); ) {
int mark = idx;
int digit = digitAt(number, idx++);
while (idx < number.length() && digitAt(number, idx) == digit) ++idx;
result.append((idx - mark) * digit);
}
return result.toString();
}
private static int digitAt(String num, int index) {
char ch = number.charAt(index);
if (ch < '0' || ch > '9') throw new IllegalArgumentException();
return ch - '0';
}
The preceding is a naïve approach that transforms the string until there are no changes. I suspect there might be a more "elegant" approach that works from left to right through the input in a single pass, but it would take some thought, and I probably couldn't come up with that in an interview.
Here's an algorithm that uses recursion and a for-loop to add consecutive equal digits. I think the code is pretty self-explanatory but please ask if you have any queries.
public static String addConsecutiveDigits(String number) {
char[] arr = number.toCharArray();
StringBuilder result = new StringBuilder();
boolean foundConsecutive = false; // boolean flag for checking if the number contained consecutive equal digits
for (int i = 0; i < arr.length; i++) {
int digit = arr[i] - '0'; //Subtracting ascii values to get integer values
int newNumber = digit;
if (i != arr.length - 1) {
int nextDigit = arr[i + 1] - '0';
if (digit == nextDigit) { // check if the digits are consecutive digits
newNumber = digit + nextDigit;
i++; // increment i as we have already added the i+1 digit
foundConsecutive = true;
}
}
result.append(newNumber);
}
if (!foundConsecutive) // if no consecutive equal digits were found then return the result;
return result.toString();
else // recurse to check for more consecutive equal digits
return addConsecutiveDigits(result.toString());
}
I'm not a Java guy, so this code might not be ideal but I would do something like this:
public String solve(String input)
{
String result = "";
int i = 0;
while (i < input.length())
{
var first = input.charAt(i);
if (i == input.length() - 1){
result += first;
break;
}
var second = input.charAt(i + 1);
if (first == second){
result += (Character.getNumericValue(first) + Character.getNumericValue(second));
i += 2;
} else {
result += first;
i += 1;
}
}
return result;
}
For the second part, I would just run the function in a loop until the result matches the input.

How can I loop through all the characters that are 0 in a given string?

I'm trying to remove trailing zeroes from an integer and here is my code so far.
import java.math.BigInteger;
public class newuhu {
public static int numTrailingZeros(int s) {
BigInteger J = BigInteger.valueOf(s);
String sb = J.toString();
String Y = "";
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '0') {
sb.replaceAll("0"," ");
}
return Integer.parseInt(Y);
}
Note: I turned my int into a Biginteger because I've been warned that some inputs may look like 20!, which is 2.432902e+18
However, my IntelliJ debugging tool tells me that variable sb isn't in the loop. So, I'm trying to understand what must be done to make sure sb is in the loop.
Please understand that I'm a beginner in Java so, I'm trying to learn something new.
replaceAll replaces all occurrences of string with character that you want (ie space) so you don't need loop at all, also you're concerned about overflow so you should actually use BigInteger as a parameter, not int (int wont fit anything close to 20!) but there's another issue with your code, you said you want to replace trailing zeros but right now you will replace every 0 with blank character, you should try to use something like https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html
public class newuhu {
public static int numTrailingZeros(BigInteger s) {
String sb = s.toString();
return Integer.parseInt(sb.replaceAll("0", "")); // consider returning something else if you're working with BigInteger
}
Keep in mind that when doing BigInteger.valueOf(int) does not have an effect as a number to big for int will never be stored in an int. Also 20! is fine for int.
public static String trimTrailingZeros(String source) {
for (int i = source.length() - 1; i > 0; ++i) {
char c = source.charAt(i);
if (c != '0') {
return source.substring(0, i + 1);
}
}
return ""; // or return "0";
}
Or if you prever BigInteger.
public static BigInteger trimTrailingZeros(BigInteger num) {
while (num.remainder(BigInteger.TEN).signum() == 0) {
num = num.divide(BigInteger.TEN);
}
return num;
}
This should be fast as you only create one string (via substring).
(First: variables and fields should start with a small letter - when no constants.)
It should be
sb = sb.replaceAll(...)
as sb is not changed by replaceAll, only the replaced value is returned. The class String gives immutable values, that always remain the same, so you can assign a variable to a variable and changing values of either variable will never influence the other - no further sharing.
Then it should be:
sb = sb.replaceFirst("0$", "");
replaceAll would replace every 0, like "23043500" to "23435".
replaceFirst replaces the _regular expression: char '0' at the end $.
Overflow on the input number is not possible, as you are already passing an int.
public static int numTrailingZeros(int n) {
while (n != 0 && n % 10 == 0) {
n /= 10;
}
return n;
}
public static int numTrailingZeros(String n) {
n = n.replaceAll("0+", "");
if (n.isEmpty() || n.equals("-")) { // "-0" for pessimists?
n = "0";
}
return Integer.parseInt(n);
}
% is the modulo operator, the remainder of an integer division 147 % 10 == 7.
The name is misleading, or you are calculating something different.
public static int numTrailingZeros(int n) {
int trailingZeros = 0;
while (n != 0 && n % 10 == 0) {
n /= 10;
++trailingZeros ;
}
return trailingZeros ;
}
The problem here is that sb.replaceAll("0","") won't do anything. You're throwing away the return value that contains your replaced string. See here.
What you probably want is something like this:
while (sb.length() > 0 && sb.charAt(sb.length() - 1) == '0') {
sb = sb.replaceAll("0"," ");
I'm not sure you need a while loop, though. ReplaceAll will... replace all of the zeros with spaces.

Turn Positive into negative?

I've got this code
public class FiboNegativV {
int negativ(int nv) {
if (nv ==0)
return 1;
if (nv ==1)
return 2;
return negativ(nv-1) + negativ(nv-2);
}
}
Now I would like to turn the final number into negative. I've tried a few things like "nv = -nv;" But I usually got stackover when I put it before the
"return negativ(nv-1) + negativ(nv-2)" and it is unreachable when it's after this line.
You don't need function for that just do it like this:
int x *= -1;
All the other answers for some reason disregard your initial intention of a Fibbonacci sequence. But I do not understand why they do not keep the context. Your method obviously tries to do a Fibbonacci sequence with recursion yielding negative numbers.
Now I would like to turn the final number into negative.
The simplest and most intuitive way of negatinv a number is to use a unary minus operator = just add a minus before the expression (so negating x to -x). We use this only on positive numbers, so that the negative ones stay negative: (note: this is a ternary operator)
(result > 0) ? -result : result;
However the big mistake is that you do NOT handle negative numbers in the recursive method in the first place! Of course you run into stack overflow, because the recursive negative numbers are going to get lower and lower.
static int negativFib(int nv)
{
//turn negative input into positive
nv = nv < 0 ? -nv : nv;
//base cases
if (nv == 0)
return 1;
if (nv == 1)
return 2;
final int result = negativFib(nv - 1) + negativFib(nv - 2);
//turn the number into negative
return result > 0 ? -result : result;
}
Alternative algorithm
An another problem which could occur is that with big numbers, the recursion comes to a stack overflow. You could prevent this by using some other algorithm, f.e. dynamic programming. With dynamic programming Fibbonacci sequence you store the previous 2 results every time and solve the problem in iterations, instead of recursion.
If you only want to convert positive into negative then
nv = (nv > 0) ? nv * -1 : nv
if you want to convert positive to negative and negative to positive then
nv = nv * -1
Below your code will look like
public class FiboNegativ
{
public FiboNegativV(){}
int negativ(int nv)
{
return (nv > 0) ? nv*-1 : nv;
}
}
Since you want only the final number to be negative, the easiest way is to work with absolute numbers, and return negative numbers, as per the following:
public class FiboNegativV {
int negativ(int nv) {
return (nv == 0) ? -1 :
(nv == 1) ? -2 :
-(Math.abs(negativ(nv-1)) + Math.abs(negativ(nv-2)));
}
}
The assumption I have made, above, is that the initial input to the function will always be positive. Your original code confirms this assumption.
-1 * (Math.abs(negativ(nv-1) + negativ(nv-2)));
Thus the result will be negative regardless of the values given.

Efficient Parsing of Byte Array to Number

Rather than parsing a byte array to an ASCII string then converting the string to say an integer, it should be more efficient to parse the byte array directly to an integer.
byte[] token = "24000".getBytes(Charset.forName("US-ASCII"));
The following code can do this:
int n = 0;
for (byte b : token)
n = 10*n + (b-'0');
Versus the common approach:
int n = Integer.parseInt(new String(token));
Ref: Dave's answer here >> Converting US-ASCII encoded byte to integer and back
Is there a comprehensive solution that skips String creation and goes straight to result?
Please stop marking the question for closing due to this question:
Convert a byte array to integer in java and vice versa
It deals with non-encoded bytes.
It does not answer my question.
The Java library doesn't seem to have a dedicated tool for the job, but it sure has enough tools to write one yourself.
In my opinion, if you're worried about performance since turning byte arrays to ints is a bottleneck in your code, then I suggest writing your own solution based on the piece of code you provided. If it isn't, then just use parseInt for easier readability.
In any case, if Java had a tool for doing this, it would use pretty much the same code under the hood. That's pretty much what Integer.parseInt() does (except it covers other bases, negative numbers, and is safer):
public static int parseInt(String s, int radix)
throws NumberFormatException
{
/*
* WARNING: This method may be invoked early during VM initialization
* before IntegerCache is initialized. Care must be taken to not use
* the valueOf method.
*/
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}

Java recursion and integer double digit

I'm trying to take an integer as a parameter and then use recursion to double each digit in the integer.
For example doubleDigit(3487) would return 33448877.
I'm stuck because I can't figure out how I would read each number in the digit I guess.
To do this using recursion, use the modulus operator (%), dividing by 10 each time and accumulating your resulting string backwards, until you reach the base case (0), where there's nothing left to divide by. In the base case, you just return an empty string.
String doubleDigit(Integer digit) {
if (digit == 0) {
return "";
} else {
Integer thisDigit = digit % 10;
Integer remainingDigits = (digit - thisDigit) / 10;
return doubleDigit(remainingDigits) + thisDigit.toString() + thisDigit.toString();
}
}
If you're looking for a solution which returns an long instead of a String, you can use the following solution below (very similar to Chris', with the assumption of 0 as the base case):
long doubleDigit(long amt) {
if (amt == 0) return 0;
return doubleDigit(amt / 10) * 100 + (amt % 10) * 10 + amt % 10;
}
The function is of course limited by the maximum size of a long in Java.
I did the same question when doing Building Java Programs. Here is my solution which works for negative and positive numbers (and returns 0 for 0).
public static int doubleDigits(int n) {
if (n == 0) {
return 0;
} else {
int lastDigit = n % 10;
return 100 * doubleDigits(n / 10) + 10 * lastDigit + lastDigit;
}
There's no need to use recursion here.
I'm no longer a java guy, but an approximation of the algorithm I might use is this (works in C#, should translate directly to java):
int number = 3487;
int output = 0;
int shift = 1;
while (number > 0) {
int digit = number % 10; // get the least-significant digit
output += ((digit*10) + digit) * shift; // double it, shift it, add it to output
number /= 10; // move to the next digit
shift *= 100; // increase the amount we shift by two digits
}
This solution should work, but now that I've gone to the trouble of writing it, I realise that it is probably clearer to just convert the number to a string and manipulate that. Of course, that will be slower, but you almost certainly don't care about such a small speed difference :)
Edit:
Ok, so you have to use recursion. You already accepted a perfectly fine answer, but here's mine :)
private static long DoubleDigit(long input) {
if (input == 0) return 0; // don't recurse forever!
long digit = input % 10; // extract right-most digit
long doubled = (digit * 10) + digit; // "double" it
long remaining = input / 10; // extract the other digits
return doubled + 100*DoubleDigit(remaining); // recurse to get the result
}
Note I switched to long so it works with a few more digits.
You could get the String.valueOf(doubleDigit) representation of the given integer, then work with Commons StringUtils (easiest, in my opinion) to manipulate the String.
If you need to return another numeric value at that point (as opposed to the newly created/manipulated string) you can just do Integer.valueOf(yourString) or something like that.

Categories