package com.freetymekiyan.algorithms.level.hard;
/**
* Convert a non-negative integer to its english words representation. Given input is guaranteed to be less than 2^31 -
* 1.
* <p>
* For example,
* 123 -> "One Hundred Twenty Three"
* 12345 -> "Twelve Thousand Three Hundred Forty Five"
* 1234567 -> "One Million Two Hundred Thirty Four Thousand Five Hundred Sixty Seven"
* Hint:
* <p>
* Did you see a pattern in dividing the number into chunk of words? For example, 123 and 123000.
* Group the number by thousands (3 digits). You can write a helper function that takes a number less than 1000 and
* convert just that chunk to words.
* There are many edge cases. What are some good test cases? Does your code work with input such as 0? Or 1000010?
* (middle chunk is zero and should not be printed out)
* <p>
* Company Tags: Microsoft, Facebook
* Tags: Math, String
* Similar Problems: (M) Integer to Roman
*/
public class IntegerToEnglishWords {
public static final String[]
LESS_THAN_TWENTY =
{"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight",
"Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen",
"Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"};
// Notice the empty string in the front to make index relate to word.
public static final String[]
TENS =
{"", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"};
public static final String[] THOUSANDS = {"", "Thousand", "Million", "Billion"};
/**
* Math, String.
* Try to find the pattern first.
* The numbers less than 1000, e.g. xyz, can be x Hundred y"ty" z.
* The numbers larger than 1000, we need to add thousand or million or billion.
* Given a number num, we pronounce the least significant digits first.
* Then concat the result to the end to next three least significant digits.
* So the recurrence relation is:
* Next result of num = the pronunciation of least three digits + current result of num
* After that, remove those three digits from number.
* Stop when number is 0.
*/
public String numberToWords(int num) {
if (num == 0) { // The only case that 0 should be pronounced.
return LESS_THAN_TWENTY[0];
}
int i = 0;
StringBuilder res = new StringBuilder();
while (num > 0) {
if (num % 1000 != 0) { // Get last 3 digits and skip intermediate zeros.
res.insert(0, " ");
res.insert(0, THOUSANDS[i]); // THOUSAND[0] is empty for first 3 digits.
res.insert(0, helper(num % 1000));
}
num /= 1000; // Remove last 3 digits.
i++; // Move to next THOUSANDS word.
}
return res.toString().trim();
}
/**
* Recursive.
* Convert number n < 1000 to English words string.
* Base cases:
* If n == 0, no need to convert except when the number is only 0.
* If n < 20, can be directly fetch from less than 20 string array.
* Recurrence relation:
* 3 digits is the most significant digit + Hundred + recursive call on the 2 digits.
* 2 digits is TENS + space + recursive call on the 1 digit.
* If n < 100, combine tens' digit with the rest.
* If 100 < n < 1000, combine hundreds' digit with " Hundred ", with the words less than 100.
* Every word should be followed with a space, very important.
*/
private String helper(int n) {
if (n == 0) {
return ""; // Only one 0 is already handled as a special case.
} else if (n < 20) {
return LESS_THAN_TWENTY[20] + " "; // Note the blank is the space at the end.
} else if (n < 100) {
return TENS[n / 10] + " " + helper(n % 10); // Note the space in between.
} else {
return LESS_THAN_TWENTY[n / 100] + " Hundred " + helper(n % 100);
}
}
}