How to do str vs. int recursion, one character at a time? - java

So I'm stuck on this problem, where you have a method equalNumbers(String str, int num), that determines whether characters in str represent the same number as num. The empty string is equivalent to zero.
equalNumbers("123", 123) true
equalNumbers("9", 999) false
And so on.
This method is supposed to be recursive, so no loops, and no using stuff like Integer.parseInt, Integer.valueOf, and integer.decode(). Helper functions are allowed.
It encourages the use of charAt(index) and Character.gerNumericValue(ch).
===
Based on what it encourages me to do, I suppose it wants me to iterate through the string char by char, convert that char to an integer, and compare it to one digit in the integer at a time. It seems the only conversion I am allowed to do is char to int. So my questions are:
Should I build a string out of the chars and then convert that whole string into an integer? (Don't think that's allowed)
Is it possible to go index by index in an integer, without converting it into a string?
I would show my own code, but I have a conceptual gap about how these data types work.

Often a public function calls a private recursive function with an extra parameter.
For your code using get_int_at_index the extra recursive function would need i to be passed.
In your case this is not needed, but then you need to work with String (inspecting a tiny part with charAt) and int. Now I suspect String.valueOf(int) was not intended, but inspecting a tiny part of the number, a digit, by number modulo 10 (% 10).
Taking modulo ten would give the rightmost digit first, so:
int num
int digit = num % 10; // Tiny part we deal with
num = num / 10; // Rest
String str
char ch = str.charAt(str.length() - 1); // Tiny part
str = str.substring(0, str.length() - 1); // Rest
So
public static boolean equalNumbers(String str, int num) {
if (str.isEmpty()) { // End recursion.
return num == 0;
}
char ch = str.charAt(str.length() - 1);
int digit = num % 10;
if (Character.getNumericValue(ch) != digit) {
return false;
}
str = str.substring(0, str.length() - 1);
num = num / 10;
return equalNumbers(str, num); // Recurse.
}

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.

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.

Manually calculate output from string compareTo string

I'm trying to see how to manually calculate the output when comparing strings as questions like it have come up in past papers I'm practicing.
I understand that the result is negative if the string lexicographically (according to unicode) precedes the argument string, positive if it follows it and zero if they are equal. I don't see how to calculate the value (beyond the sign).
I have the code which gives the output 1, -1, -3, 3. I see why each is positive or negative but not why it is 1 or 3.
public class CompareToPractice {
public static void main(String[] args) {
String str1 = "bode";
String str2 = "bod";
String str3 = "bodge";
String str4 = "bog";
int result1 = str1.compareTo(str2);
System.out.println(result1);
int result2 = str2.compareTo(str1);
System.out.println(result2);
int result3 = str3.compareTo(str4);
System.out.println(result3);
int result4 = str4.compareTo(str3);
System.out.println(result4);
}
}
Thank you
Its the difference between the characters 'd' and 'e' (ascii difference).
This is the code of compareTo
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
As you can see from line if (c1 != c2). If 2 characters are not equal, then the result will be the subtraction of those 2 values.
In your case str3.compareTo(str4) was "bodge" - "bog".
So 'd'-'g' (ASCII value: 100 - 103 = -3)
I don't see how to calculate the value (beyond the sign).
The value "beyond the sign" is irrelevant. It conveys no information that a normal application could make use of1. It is a mere implementation detail: an accidental artifact of an algorithm that is optimized for speed.
If you really want to know, look at the source code.
1 - Well I suppose you could in theory construct a program that used it. But I can't conceive of a problem that such a program would solve ... apart from circular problems, such as investigating the statistical properties of compareTo!
The documentation of compareTo clearly defines in what cases the result is calculated and how.
This is the definition of lexicographic ordering. If two strings are different, then either they have different characters at some index that is a valid index for both strings, or their lengths are different, or both. If they have different characters at one or more index positions, let k be the smallest such index; then the string whose character at position k has the smaller value, as determined by using the < operator, lexicographically precedes the other string. In this case, compareTo returns the difference of the two character values at position k in the two string -- that is, the value:
this.charAt(k)-anotherString.charAt(k)
If there is no index position at which they differ, then the shorter
string lexicographically precedes the longer string. In this case,
compareTo returns the difference of the lengths of the strings -- that
is, the value:
this.length()-anotherString.length()
Also Bandi Kishore's answer explains the ASCII difference calculation: https://stackoverflow.com/a/36858565/904375

Output for Converting a number in decimal into its Complement

Output for converting a number in decimal into its 1s complement and then again converting the number into decimal does not come as expected.
MyApproach
I first converted the number from decimal to binary. Replaced all Os with 1 and vice versa and then converted the number into decimal.
Can anyone guide me? What I am doing wrong?
Code:
public static int complimentDecimal(int num) {
int p = 0;
String s1 = "";
// Convert Decimal to Binary
while (num > 0) {
p = num % 2;
s1 = p + s1;
num = num / 2;
}
System.out.println(s1);
// Replace the 0s with 1s and 1s with 0s
for (int j = 0; j < s1.length(); j++) {
if (s1.charAt(j) == 0) {
s1.replace(s1.charAt(j), '1');
} else {
s1.replace(s1.charAt(j), '0');
}
}
System.out.println(s1);
int decimal = 0;
int k = 0;
for (int m = s1.length() - 1; m >= 0; m--) {
decimal += (s1.charAt(m) * Math.pow(2, k));
k++;
}
return decimal;
}
First of all you need to define the amount of Bits your binary representation should have or an complement representation does not make sense.
If you convert 100 the binary is 1100100
complement is 0011011 which is 27
now convert 27. Binary is 11011, complement 00100 which is 4.
Now define yourself a Bit length of 8.
100 is 01100100, complement 10011011, is 155
155 is 10011011, complement 01100100, is 100
Works because every binary representation has a length of 8 bits. This is absolutly necessary for the whole complement thing to make any sense.
Consider that you now have a limit for numbers that are convertable.
11111111 which is 255.
Now that we talked about that I will correct your code
static int MAX_BITS = 8;
static int MAX_INT = (int)Math.pow(2, MAX_BITS) - 1;
public static int complimentDecimal(int num)
{
// check if number is to high for the bitmask
if(num > MAX_INT){
System.out.println("Number=" + num + " to high for MAX_BITS="+MAX_BITS);
return -1;
}
// Your conversion works!
int p=0;
String s1="";
//Convert Decimal to Binary
while(num>0)
{
p=num%2;
s1=p+s1;
num=num/2;
}
// fill starting zeros to match MAX_BITS length
while(s1.length() < MAX_BITS)
s1 = "0" + s1;
System.out.println(s1);
//Replace the 0s with 1s and 1s with 0s
// your approach on that is very wrong
StringBuilder sb = new StringBuilder();
for(int j=0;j<s1.length();j++){
if(s1.charAt(j)=='0') sb.append("1");
else if(s1.charAt(j)=='1') sb.append("0");
}
s1 = sb.toString();
/*
for(int j=0;j<s1.length();j++)
{
if(s1.charAt(j)==0)
{
s1.replace(s1.charAt(j),'1');
}
else
{
s1.replace(s1.charAt(j),'0');
}
}
*/
System.out.println(s1);
int decimal=0;
int k=0;
for(int m=s1.length()-1;m>=0;m--)
{
// you don't want the char code here but the int value of the char code
//decimal += (s1.charAt(m) * Math.pow(2, k));
decimal+=(Character.getNumericValue(s1.charAt(m))*Math.pow(2, k));
k++;
}
return decimal;
}
Additional Note: Don't get bigger then MAX_BITS = 31 or you need to work with long instead of int in your method.
First of all you have to assign the replaced String to the already defined variable that is,
s1.replace(s1.charAt(j),'1');
it should be
s1 = s1.replace(s1.charAt(j),'1');
and the next case is, when you are changing in that order it would change all the characters similar to matched case
refer Replace a character at a specific index in a string?
String.Replace(oldChar, newChar) method returns a new string resulting from replacing all occurrences of oldChar in given string with newChar. It does not perform change on the given string.
The problem (OK, one of the problems) is here:
if(s1.charAt(j)==0)
Characters in Java are actually integers, in the range 0 to 65535. Each of those numbers actually means the character corresponding to that number in the Unicode chart. The character '0' has the value 48, not 0. So when you've created a string of '0' and '1' characters, the characters will have the integer values 48 and 49. Naturally, when you compare this to the integer 0, you'll get false no matter what.
Try
if(s1.charAt(j)=='0')
(Note: OK, the other answer is right--replace does not work. Not only are you using it incorrectly, by not assigning the result, it's not the right method anyway, because s1.replace(s1.charAt(j),'1') replaces all '0' with '1' characters; it doesn't replace character j. If you specifically want to replace the j'th character in a String with something else, you'll need to use substring() and build a new string, not replace().)
A couple other things to note: (1) Integers are not "decimal" or "binary". When your method gets the num parameter, this is just a number, not a decimal number or a binary number. It's represented in your computer as a binary number (unless you're using something like a Burroughs 3500, but I think all of those died before Java was invented). But it really isn't considered decimal, binary, octal, hex, ternary, or whatever, until you do something that converts it to a String. (2) I know you said not to post alternative approaches, but you could replace the entire method with just one line: return ~num;. That complements all the bits. If you were thinking that you couldn't do this because num was a decimal number, see #1. (3) "Compliment" means to say something nice about somebody. If you're talking about flipping all the bits, the correct spelling is "complement".

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