Related
I recently came across an interview question which although had an immediately obvious solution, I struggled to find a more efficient one.
The actual question involved counting numbers from a to b (up to 2^64) which satisfied having either the digit 6 or 8, but not both. They called it a 'lucky number'. So for example:
126 - lucky
88 - lucky
856 - not lucky
The obvious thought was to brute force it by testing each number between a and b as a string, to check for the relevant characters. However, this was prohibitively slow as expected.
A much better solution that I tried, involved first computing all the 'lucky numbers' which had the number of digits between the number of digits that a and b have (by counting possible combinations):
long n = 0;
for (int occurrences = 1; occurrences <= maxDigits; occurrences++) {
n += (long) Math.pow(8, digits - occurrences) * choose(digits, occurrences);
}
return 2 * n;
and then using the brute force method to compute the number of extra lucky numbers that I had counted. So for example, if a = 3 and b = 21, I could count the number of 1 and 2 digit lucky numbers, then subtract the count of those in [1, 3) and (21, 99].
However, although this was a massive improvement, the brute force element still slowed it down way too much for most cases.
I feel like there must be something I am missing, as the rest of the interview questions were relatively simple. Does anyone have any idea of a better solution?
Although I have tagged this question in Java, help in any other languages or pseudocode would be equally appreciated.
I would say you are at the right track. The gut feeling is that dealing with the a and b separately is easier. Making a function count_lucky_numbers_below(n) allows
return count_lucky_numbers_below(b) - count_lucky_numbers_below(a);
The combinatorial approach is definitely a way to go (just keep in mind that the sum is actually equal to 9**n - 8**n, and there is no need to compute the binomial coefficients).
The final trick is to recurse down by a numbeer of digits.
Lets say n is an N-digit number, and the most significant digit is 5. Each set of N-digit numbers starting with a smaller digit contributes S = 9**(N-1) - 8**(N-1) to the total; you immediately have 5*S of lucky numbers. To deal with the remainder, you need to compute the lucky numbers for the N-1-digit tail.
Of course, care must be taken if the most significant digit is above 5. You need to special case it being 6 or 8, but it doesn't seem to be too complicated.
In the end the answer from #user58697 pushed me in the right direction towards finding a solution. With my (albeit extremely primitive) benchmark, it handles 1 to 2^63 - 1 in less than 2 nanoseconds, so it is definitely fast enough. However it is still more verbose than I would have liked, especially given that I was originally expected to write it in half an hour, so I feel like there is still an easier solution that gives comparable performance.
long countLuckyNumbersBetween(long a, long b) {
return countLuckyNumbersBelow(b) - countLuckyNumbersBelow(a - 1);
}
long countLuckyNumbersBelow(long n) {
return countNumbers(n, 6, 8) + countNumbers(n, 8, 6);
}
/**
* Counts the natural numbers in [0, {to}] that have {including} as a digit, but not {excluding}.
* {excluding} should be in (0, 9] or -1 to exclude no digit.
*/
long countNumbers(long to, int including, int excluding) {
if (including == -1) return 0;
if (to < 10) {
if (to >= including) {
return 1;
} else {
return 0;
}
}
int nSignificand = significand(to);
int nDigits = countDigits(to);
long nTail = to % (long) Math.pow(10, nDigits - 1);
// The count of numbers in [0, 10^(nDigits-1)) that include and exclude the relevant digits
long bodyCount;
if (excluding == -1) {
bodyCount = (long) (Math.pow(10, nDigits - 1) - Math.pow(9, nDigits - 1));
} else {
bodyCount = (long) (Math.pow(9, nDigits - 1) - Math.pow(8, nDigits - 1));
}
long count = 0;
for (int i = 0; i < nSignificand; i++) {
if (i == including) {
if (excluding == -1) {
count += Math.pow(10, nDigits - 1);
} else {
count += Math.pow(9, nDigits - 1);
}
} else if (i != excluding) {
count += bodyCount;
}
}
if (nSignificand == including) {
count += 1 + nTail - countNumbers(nTail, excluding, -1);
} else if (nSignificand != excluding) {
count += countNumbers(nTail, including, excluding);
}
return count;
}
int significand(long n) {
while (n > 9) n /= 10;
return (int) n;
}
int countDigits(long n) {
if (n <= 1) {
return 1;
} else {
return (int) (Math.log10(n) + 1);
}
}
Here is another approach:
264 = 18446744073709551616
We can represent the number as a sum of components (one component per every digit position):
18446744073709551616 associated range of numbers
———————————————————— ———————————————————————————————————————————
0xxxxxxxxxxxxxxxxxxx => [00000000000000000000;09999999999999999999]
17xxxxxxxxxxxxxxxxxx => [10000000000000000000;17999999999999999999]
183xxxxxxxxxxxxxxxxx => [18000000000000000000;18399999999999999999]
1843xxxxxxxxxxxxxxxx => [18400000000000000000;18439999999999999999]
18445xxxxxxxxxxxxxxx => [18440000000000000000;18445999999999999999]
...
1844674407370955160x => [18446744073709551600;18446744073709551609]
18446744073709551616 => [18446744073709551610;18446744073709551616]
If we could compute the amount of lucky numbers for every component, then the sum of the amounts for every component will be the total amount for 264.
Note that every component consists of a prefix followed by xs.
Imagine that we know how many lucky numbers there are in an n-digit xx..x (i.e. numbers [0..0 - 9..9]), let's call it N(n).
Now let's look at a component 18445x..x. where 18445 is a prefix and an n-digit xx..x.
In this component we look at all numbers from 18440xx..x to 18445xx..x.
For every item 1844dxx..x we look at the prefix 1844d:
if prefix contains no 6 or 8, then it's the same as x..x without prefix => N(n) special numbers
if prefix contains 6 and no 8, then x..x cannot contain 8 => 9ⁿ special numbers
if prefix contains 8 and no 6, then x..x cannot contain 6 => 9ⁿ special numbers
if prefix contains 6 and 8 => 0 special numbers
Now let's compute N(n) — the amount of lucky numbers in an n-digit xx..x (i.e. in [0..0 - 9..9]).
We can do it iteratively:
n=1: there are only 2 possible numbers: 8 and 6 => N(1)=2.
n=2: there are 2 groups:
8 present: 8x and x8 where x is any digit except 6
6 present: 6x and x6 where x is any digit except 8
=> N(2)=4*9=34.
n=3: let's fix the 1st digit:
0xx — 5xx, 7xx, 9xx => 8 * N(2)
6xx: xx are any 2 digits except 8 => 9²
8xx: xx are any 2 digits except 6 => 9²
=> N(3) = 8*N(2) + 2*9².
n=k+1 => N(k+1) = 7*N(k) + 2*9ᵏ
Here is an implementation (not 100% tested):
public final class Numbers {
public long countLuckyNumbersBelow(BigInteger num) {
if (num.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("num < 0: " + num);
}
var numberText = num.toString();
var result = 0L;
for (var digitPosition = 0; digitPosition < numberText.length(); digitPosition++) {
result += countLuckyNumbersForComponent(numberText, digitPosition);
}
return result;
}
private long countLuckyNumbersForComponent(String numberText, int digitPosition) {
var prefixEndIdx = numberText.length() - 1 - digitPosition;
var prefixHas6s = containsChar(numberText, '6', prefixEndIdx);
var prefixHas8s = containsChar(numberText, '8', prefixEndIdx);
if (prefixHas6s && prefixHas8s) {
return 0;
}
var result = 0L;
for (var c = numberText.charAt(prefixEndIdx) - 1; c >= '0'; c--) {
var compNo6s = (!prefixHas6s) && (c != '6');
var compNo8s = (!prefixHas8s) && (c != '8');
if (compNo6s && compNo8s) {
result += countLuckyNumbers(digitPosition);
} else if (compNo6s || compNo8s) {
result += power9(digitPosition);
}
}
return result;
}
private static boolean containsChar(String text, char c, int endIdx) {
var idx = text.indexOf(c);
return (idx > 0) && (idx < endIdx);
}
private long[] countLuckyNumbersCache = {0L, 0L};
/**
* Computes how many lucky numbers are in an n-digit `xx..x`
*/
private long countLuckyNumbers(int numDigits) {
if (countLuckyNumbersCache[0] == numDigits) {
return countLuckyNumbersCache[1];
}
long N;
if (numDigits <= 1) {
N = (numDigits == 1) ? 2 : 0;
} else {
var prevN = countLuckyNumbers(numDigits - 1);
N = (8 * prevN) + (2 * power9(numDigits-1));
}
countLuckyNumbersCache[0] = numDigits;
countLuckyNumbersCache[1] = N;
return N;
}
private long[] power9Cache = {0L, 1L};
/**
* Computes 9<sup>power</sup>
*/
private long power9(int power) {
if (power9Cache[0] == power) {
return power9Cache[1];
}
long res = 1;
var p = power;
if (power > power9Cache[0]) {
p -= power9Cache[0];
res = power9Cache[1];
}
for (; p > 0; p--) {
res *= 9;
}
power9Cache[0] = power;
power9Cache[1] = res;
return res;
}
}
BTW it took me half a day, and I have no idea how is that possible to complete it in 30 minutes.
I guess your interviewers expected from you to demonstrate them your thought process.
Here is the result of my attempt.
First, let me explain a little bit what logic I used.
I used formula S = 9N — 8N (mentioned in the user58697's answer) to compute how many of N-digit numbers are lucky.
How to get this formula:
for N-digit numbers there are 10N numbers in total: N digits, each can take one of 10 values: [0-9].
if we only count numbers without 6, then each digit can only take one of 9 values [0-5,7-9] — it's 9N numbers in total
now we also want only numbers with 8.
We can easily compute how many numbers don't have both 6 and 8: digits in these numbers can only take one of 8 values [0-5,7,9] — it's 8N numbers in total.
As a result, there are S = 9N — 8N numbers which have 8 and no 6.
For numbers with 6 and without 8 the formula is the same.
Also numbers without 6 do not intersect with numbers without 8 — so we can just sum them.
And finally, since we know how to count lucky numbers for intervals [0;10N], we need to split the interval [0; our arbitrary number] into suitable sub-intervals.
For instance, we can split number 9845637 this way:
Sub-interval
Prefix
Digit
N-digit interval
0000000 - 8999999
0 - 8
000000 - 999999
9000000 - 9799999
9
0 - 7
00000 - 99999
9800000 - 9839999
98
0 - 3
0000 - 9999
9840000 - 9844999
984
0 - 4
000 - 999
9845000 - 9845599
9845
0 - 5
00 - 99
9845600 - 9845629
98456
0 - 2
0 - 9
9845630 - 9845637
Now we can compute the number for every sub-interval (just keep attention to digits in prefix — they might contains 8 or 6) and then just sum those numbers to get the final result.
Here is the code:
// Special value for 'requiredDigit': no required digit
private static char NIL = Character.MAX_VALUE;
public static long countLuckyNumbersUpTo(BigInteger number) {
if (number.compareTo(BigInteger.ZERO) < 0) {
throw new IllegalArgumentException("number < 0: " + number);
}
var numberAsDigits = number.toString();
return countNumbersUpTo(numberAsDigits, '6', '8') + countNumbersUpTo(numberAsDigits, '8', '6');
}
// count all numbers in [0;'numberAsDigits'] which have 'requiredDigit' and no 'excludeDigit'
private static long countNumbersUpTo(String numberAsDigits, char requiredDigit, char excludeDigit) {
var highDigit = numberAsDigits.charAt(0);
if (numberAsDigits.length() == 1) {
return (requiredDigit != NIL)
? ((highDigit >= requiredDigit) ? 1 : 0)
: numDigitsInInterval('0', highDigit, excludeDigit);
}
var tailDigits = numberAsDigits.substring(1);
var result = 0L;
// numbers where the highest digit is in [0;`highDigit`)
var numGoodDigits = numDigitsInInterval('0', (char) (highDigit - 1), excludeDigit);
var containsRequiredDigit = (requiredDigit != NIL) && (highDigit > requiredDigit);
if (containsRequiredDigit) {
result += totalNumbers(tailDigits.length(), NIL);
numGoodDigits--;
}
if (numGoodDigits > 0) {
result += numGoodDigits * totalNumbers(tailDigits.length(), requiredDigit);
}
// remaining numbers where the highest digit is `highDigit`
if (highDigit != excludeDigit) {
var newRequiredDigit = (highDigit == requiredDigit) ? NIL : requiredDigit;
result += countNumbersUpTo(tailDigits, newRequiredDigit, excludeDigit);
}
return result;
}
private static int numDigitsInInterval(char firstDigit, char lastDigit, char excludeDigit) {
var totalDigits = lastDigit - firstDigit + 1;
return (excludeDigit <= lastDigit) ? (totalDigits - 1) : totalDigits;
}
// total numbers with given requiredDigit in [0;10^numDigits)
private static long totalNumbers(int numDigits, char requiredDigit) {
return (requiredDigit == NIL) ? pow(9, numDigits) : (pow(9, numDigits) - pow(8, numDigits));
}
private static long pow(int base, int exponent) {
return BigInteger.valueOf(base).pow(exponent).longValueExact();
}
Problem statement: Three digit sum - Find all the numbers between 1 and 999 where the sum of the 1st digit and the 2nd digit is equal to the 3rd digit.
Examples:
123 : 1+2 = 3
246 : 2+4 = 6
Java:
public class AssignmentFive {
public static void main(String[] args) {
int i=1;
int valuetwo;
int n=1;
int sum = 0;
int valuethree;
int valueone = 0;
String Numbers = "";
for (i = 1; i <= 999; i++) {
n = i;
while (n > 1) {
valueone = n % 10;/*To get the ones place digit*/
n = n / 10;
valuetwo = n % 10;/*To get the tens place digit*/
n = n / 10;
valuethree = n;/*To get the hundreds place digit*/
sum = valuethree + valuetwo;/*adding the hundreds place and
tens place*/
}
/*Checking if the ones place digit is equal to the sum and then print
the values in a string format*/
if (sum == valueone) {
Numbers = Numbers + n + " ";
System.out.println(Numbers);
}
}
}
}
I got my result :
1
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
10000000001
100000000011
1000000000111
10000000001111
100000000011111
1000000000111111
10000000001111111
100000000011111111
1000000000111111111
Process finished with exit code 0
The result is not showing the actual result like it should be which should show values like: 123, 246 (Please refer to the problem statement above.)
Please let me know what seems to be the issue with the code and how to tweak it.
Don't know what you're trying to do with that while loop, or why you are building up a space-separated string of numbers.
Your code should be something like:
for (int n = 1; n <= 999; n++) {
int digit1 = // for you to write code here
int digit2 = // for you to write code here
int digit3 = // for you to write code here
if (digit1 + digit2 == digit3) {
// print n here
}
}
So basically your question is how to calculate the numbers, right?
My first hint for you would be how to get the first, second and third value from a 2 or 3 digit number.
For example for 3 digits you can do int hundretDigit = (n - (n % 100)) % 100. Of course this is really inefficient. But just get code working before optimizing it ;)
Just think about a way to get the "ten-digit" (2nd number). Then you add them and if they equal the third one you write System.out.println(<number>);
EDIT:
For 2 digit numbers I will give you the code:
if(i >= 10 && i <= 99) {
int leftDigit = (i - (i % 10)) / 10;
if(leftDigit == (i % 10)) {
//Left digit equals right digit (for example 33 => 3 = 3
System.out.println(i);
}
}
Try again and edit your source code. If you have more questions I will edit my (this) answer to give you a little bit more help if you need!
I had to write a program that will receive an int 'n' and another one 'd' - and will print the number n with commas every d digits from right to left.
If 'n' or 'd' are negative - the program will print 'n' as is.
I although had to make sure that there is no commas before or after the number and I'm not allowed to use String or Arrays.
for example: n = 12345678
d=1: 1,2,3,4,5,6,7,8
d=3: 12,345,678
I've written the following code:
public static void printWithComma(int n, int d) {
if (n < 0 || d <= 0) {
System.out.println(n);
} else {
int reversedN = reverseNum(n), copyOfrereversedN = reversedN, counter = numberLength(n);
while (reversedN > 0) {
System.out.print(reversedN % 10);
reversedN /= 10;
counter--;
if (counter % d == 0 && reversedN != 0) {
System.out.print(",");
}
}
/*
* In a case which the received number will end with zeros, the reverse method
* will return the number without them. In that case the length of the reversed
* number and the length of the original number will be different - so this
* while loop will end the zero'z at the right place with the commas at the
* right place
*/
while (numberLength(copyOfrereversedN) != numberLength(n)) {
if (counter % d == 0) {
System.out.print(",");
}
System.out.print(0);
counter--;
copyOfrereversedN *= 10;
}
}
}
that uses a reversNum function:
// The method receives a number n and return his reversed number(if the number
// ends with zero's - the method will return the number without them)
public static int reverseNum(int n) {
if (n < 9) {
return n;
}
int reversedNum = 0;
while (n > 0) {
reversedNum += (n % 10);
reversedNum *= 10;
n /= 10;
}
return (reversedNum / 10);
}
and numberLength method:
// The method receives a number and return his length ( 0 is considered as "0"
// length)
public static int numberLength(int n) {
int counter = 0;
while (n > 0) {
n /= 10;
counter++;
}
return counter;
}
I've been told that the code doesn't work for every case, and i am unable to think about such case (the person who told me that won't tell me).
Thank you for reading!
You solved looping through the digits by reversing the number, so a simple division by ten can be done to receive all digits in order.
The comma position is calculated from the right.
public static void printWithComma(int n, int d) {
if (n < 0) {
System.out.print('-');
n = -n;
}
if (n == 0) {
System.out.print('0');
return;
}
int length = numberLength(n);
int reversed = reverseNum(n);
for (int i = 0; i < length; ++i) {
int nextDigit = reversed % 10;
System.out.print(nextDigit);
reversed /= 10;
int fromRight = length - 1 - i;
if (fromRight != 0 && fromRight % d == 0) {
System.out.print(',');
}
}
}
This is basically the same code as yours. However I store the results of the help functions into variables.
A zero is a special case, an exception of the rule that leading zeros are dropped.
Every dth digit (from right) needs to print comma, but not entirely at the right. And not in front. Realized by printing the digit first and then possibly the comma.
The problems I see with your code are the two while loops, twice printing the comma, maybe? And the println with a newline when <= 0.
Test your code, for instance as:
public static void main(String[] args) {
for (int n : new int[] {0, 1, 8, 9, 10, 234,
1_234, 12_345, 123_456, 123_456_789, 1_234_567_890}) {
System.out.printf("%d : ", n);
printWithComma(n, 3);
System.out.println();
}
}
Your code seems overly complicated.
If you've learned about recursion, you can do it like this:
public static void printWithComma(int n, int d) {
printInternal(n, d, 1);
System.out.println();
}
private static void printInternal(int n, int d, int i) {
if (n > 9) {
printInternal(n / 10, d, i + 1);
if (i % d == 0)
System.out.print(',');
}
System.out.print(n % 10);
}
Without recursion:
public static void printWithComma(int n, int d) {
int rev = 0, i = d - 1;
for (int num = n; num > 0 ; num /= 10, i++)
rev = rev * 10 + num % 10;
for (; i > d; rev /= 10, i--) {
System.out.print(rev % 10);
if (i % d == 0)
System.out.print(',');
}
System.out.println(rev);
}
Are you allowed to use the whole Java API?
What about something as simple as using DecimalFormat
double in = 12345678;
DecimalFormat df = new DecimalFormat( ",##" );
System.out.println(df.format(in));
12,34,56,78
Using...
,# = 1 per group
,## = 2 per group
,### = 3 per group
etc...
It took me a bunch of minutes. The following code snippet does the job well (explanation below):
public static void printWithComma(int n, int d) { // n=number, d=commaIndex
final int length = (int) (Math.log10(n) + 1); // number of digits;
for (int i = 1; i < Math.pow(10, length); i*=10) { // loop by digits
double current = Math.log10(i); // current loop
double remains = length - current - 1; // loops remaining
int digit = (int) ((n / Math.pow(10, remains)) % 10); // nth digit
System.out.print(digit); // print it
if (remains % d == 0 && remains > 0) { // add comma if qualified
System.out.print(",");
}
}
}
Using (Math.log10(n) + 1) I find a number of digits in the integer (8 for 12345678).
The for-loop assures the exponents of n series (1, 10, 100, 1000...) needed for further calculations. Using logarithm of base 10 I get the current index of the loop.
To get nth digit is a bit tricky and this formula is based on this answer. Then it is printed out.
Finally, it remains to find a qualified position for the comma (,). If modulo of the current loop index is equal zero, the dth index is reached and the comma can be printed out. Finally the condition remains > 0 assures there will be no comma left at the end of the printed result.
Output:
For 4: 1234,5678
For 3: 12,345,678
For 2: 12,34,56,78
For 1: 1,2,3,4,5,6,7,8
I write down a code which find out quotient after dividing two number but without using multiplication,division or mod operator.
My code
public int divide(int dividend, int divisor) {
int diff=0,count=0;
int fun_dividend=dividend;
int fun_divisor=divisor;
int abs_dividend=abs(dividend);
int abs_divisor=abs(divisor);
while(abs_dividend>=abs_divisor){
diff=abs_dividend-abs_divisor;
abs_dividend=diff;
count++;
}
if(fun_dividend<0 && fun_divisor<0){
return count;
}
else if(fun_divisor<0||fun_dividend<0) {
return (-count);
}
return count;
}
My code passes the test cases like dividend=-1, divisor=1 or dividend=1 and divisor=-1. But it cannot pass the test case like dividend = --2147483648 and divisor =-1. However I have a if statement when both inputs are negative.
if(fun_dividend<0 && fun_divisor<0){
return count;
}
When my inputs are -2147483648 and -1 it returned zero. I debugged my code and find out that it cannot reach the the inner statements of while loop. It just check the while loop and terminated and execute
if(fun_dividend<0 && fun_divisor<0){
return count;
}
It is very obvious, both inputs are negative, so I was using Math.abs function to make them positive. But when I try to see the values of variables abs_dividend and abs_divisor they show me negative values.
Integer max can take a 9 digit number. So how could I pass this test case? As per this test case dividend is a 10 digit number which is not valid for a integer range.
As per the test case the output that I get should be 2147483647.
How could I solve the bug?
Thank you in advance.
Try using the bit manipulation for this as follows:
public static int divideUsingBits(int dividend, int divisor) {
// handle special cases
if (divisor == 0)
return Integer.MAX_VALUE;
if (divisor == -1 && dividend == Integer.MIN_VALUE)
return Integer.MAX_VALUE;
// get positive values
long pDividend = Math.abs((long) dividend);
long pDivisor = Math.abs((long) divisor);
int result = 0;
while (pDividend >= pDivisor) {
// calculate number of left shifts
int numShift = 0;
while (pDividend >= (pDivisor << numShift)) {
numShift++;
}
// dividend minus the largest shifted divisor
result += 1 << (numShift - 1);
pDividend -= (pDivisor << (numShift - 1));
}
if ((dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0)) {
return result;
} else {
return -result;
}
}
I solve it this way. Give preference to data type long over int wherever there is a chance of overflow upon left-shift. Handle the edge case at the very beginning to avoid the input values getting modified in the process. This algorithm is based upon the division technique we used to make use in school.
public int divide(int AA, int BB) {
// Edge case first.
if (BB == -1 && AA == Integer.MIN_VALUE){
return Integer.MAX_VALUE; // Very Special case, since 2^31 is not inside range while -2^31 is within range.
}
long B = BB;
long A = AA;
int sign = -1;
if ((A<0 && B<0) || (A>0 && B>0)){
sign = 1;
}
if (A < 0) A = A * -1;
if (B < 0) B = B * -1;
int ans = 0;
long currPos = 1; // necessary to be long. Long is better for left shifting.
while (A >= B){
B <<= 1; currPos <<= 1;
}
B >>= 1; currPos >>= 1;
while (currPos != 0){
if (A >= B){
A -= B;
ans |= currPos;
}
B >>= 1; currPos >>= 1;
}
return ans*sign;
}
Ran with the debugger and found that abs_dividend was -2147483648.
Then the comparison in while (abs_dividend >= abs_divisor) { is false and count is never incremented.
Turns out the explanation is in the Javadoc for Math.abs(int a):
Note that if the argument is equal to the value of Integer.MIN_VALUE, the most negative representable int value, the result is that same value, which is negative.
Presumably, this is because Integer.MAX_VALUE is 2147483647, so there is no way of representing positive 2147483648 with an int. (note: 2147483648 would be Integer.MAX_VALUE + 1 == Integer.MIN_VALUE)
I recently has a test in university and I was struggling with a problem. The task was defined very specifically as following:
Write a recursive method (don't change the signature, or parameters; no global variables allowed; don't use Strings or the method Stringbuffer; no loops) which returns "true" if the number of zeros in number "n" is odd and "false" if the number of zeros is even.
Signature and Parameter:
public static boolean oddZeros(int n) {
}
So for:
n = 10 //true
n = 100 //false
n = 1402050 //true
n = 0 // true
n = 12 // false
you get the idea..
I understand the concept of recursion but i fail to see how i can count something, given only booleans. I tried adding a counter variable inside the method but whenever i make a recursive call, obviously the variable would be reset to its initialization.
Since this is a very specific problem, i didn't find any solutions so far. How would a method like this look like?
public static boolean oddZeroes(int n) {
if (n < 10) {
return n == 0;
}
return (n % 10 == 0) ^ oddZeroes(n / 10);
}
You can even make it one-liner:
public static boolean oddZeroes(int n) {
return n < 10 ? n == 0 : (n % 10 == 0) ^ oddZeroes(n / 10);
}
And if you want to process negative inputs as well, add something like if (n < 0) {return oddZeroes(-n);} in the beginning, i.e.:
public static boolean oddZeroes(int n) {
if (n < 0) {
return oddZeroes(-n);
}
if (n < 10) {
return n == 0;
}
return (n % 10 == 0) ^ oddZeroes(n / 10);
}
You don't have to count anything.
You only have to observe that:
if you remove a 0 digit from a number that has an odd number of zeroes, the resulting (smaller) number does not have an odd number of zeroes.
if you remove a non 0 digit from a number that has an odd number of zeroes, the resulting (smaller) number also has an odd number of zeroes.
Finally, as the base of the recursion, if 0 < number < 10, it has an even number of 0s (0 0s), so your method should return false.
You can write a shorter implementation, but I preferred readability:
public static boolean oddZeros(int n) {
if (n == 0)
return true;
else if (n < 10)
return false;
else if (oddZeros (n / 10)) {
return n % 10 != 0; // removed digit is not 0
} else {
return n % 10 == 0; // removed digit is 0
}
}
EDIT:
This assumes the input is non-negative. If you need to support negative input, you can add an initial condition of:
if (n < 0) {
return oddZeros (-n);
}