Catching Car Mileage Numbers(4Kyu) - 图1

题目

Let’s make it so Bob never misses another interesting number. We’ve hacked into his car’s computer, and we have a box hooked up that reads mileage numbers. We’ve got a box glued to his dash that lights up yellow or green depending on whether it receives a 1 or a 2 (respectively). It’s up to you, intrepid warrior, to glue the parts together. Write the function that parses the mileage number input, and returns a 2 if the number is “interesting” (see below), a 1 if an interesting number occurs within the next two miles, or a 0 if the number is not interesting. Note: In Haskell, we use No, Almost and Yes instead of 0, 1 and 2. “Interesting” Numbers Interesting numbers are 3-or-more digit numbers that meet one or more of the following criteria: Any digit followed by all zeros: 100, 90000 Every digit is the same number: 1111 The digits are sequential, incementing†: 1234 The digits are sequential, decrementing‡: 4321 The digits are a palindrome: 1221 or 73837 The digits match one of the values in the awesomePhrases array † For incrementing sequences, 0 should come after 9, and not before 1, as in 7890. ‡ For decrementing sequences, 0 should come after 1, and not before 9, as in 3210. 让我们这样做,鲍勃永远不会错过另一个有趣的数字。我们侵入了他车上的电脑,我们连了一个盒子,上面写着里程数。我们在他的仪表板上粘了一个盒子,它会根据收到的是1还是2(分别)亮起黄色或绿色。这取决于你,勇敢的战士,把这些部件粘在一起。编写解析里程数输入的函数,如果数字“有趣”(见下文),则返回2;如果在接下来的两英里内出现有趣的数字,则返回1;如果数字不有趣,则返回0有趣。 注意:在Haskell中,我们使用No、几乎和Yes来代替0、1和2 “有趣”数字 有趣的数字是满足下列一个或多个条件的3位数或更多位数标准: 任意数字后跟全零:100,90000 每个数字都是相同的数字:1111 数字是连续的,递增†:1234 数字是连续的,递减‡:4321 数字是回文:1221或73837 数字匹配awesomePhrases数组中的一个值 †对于递增序列,0应在9之后,而不是在1之前,如7890所示。 ‡对于递减序列,0应在1之后,而不是在9之前,如3210所示。

例子

// “boring” numbers CarMileage.isInteresting(3, new int[]{1337, 256}); // 0 CarMileage.isInteresting(3236, new int[]{1337, 256}); // 0 // progress as we near an “interesting” number CarMileage.isInteresting(11207, new int[]{}); // 0

CarMileage.isInteresting(11208, new int[]{}); // 0

CarMileage.isInteresting(11209, new int[]{}); // 1

CarMileage.isInteresting(11210, new int[]{}); // 1

CarMileage.isInteresting(11211, new int[]{}); // 2

// nearing a provided “awesome phrase”

CarMileage.isInteresting(1335, new int[]{1337, 256}); // 1

CarMileage.isInteresting(1336, new int[]{1337, 256}); // 1

CarMileage.isInteresting(1337, new int[]{1337, 256}); // 2

错误检查

A number is only interesting if it is greater than 99!

Input will always be an integer greater than 0, and less than 1,000,000,000.

The awesomePhrases array will always be provided, and will always be an array, but may be empty. (Not everyone thinks numbers spell funny words…)

You should only ever output 0, 1, or 2. 只有大于99的数字才有趣! 输入将始终是一个大于0且小于1000000000的整数。 将始终提供awesomePhrases数组,该数组将始终是一个数组,但可能为空。(不是每个人都认为数字能拼出有趣的单词……) 你应该只输出0、1或2。

原题链接

分析

判断一个数是否”有趣”,其实就是判断这个数是否满足给定的这些条件。每个条件单独拿出来都比较简单,常规的解法就是将数字分解代入每个条件的判断函数中判断一遍,我这里是为了练习正则表达式和Stream的用法,就用正则表达式来判断是否为0结尾、是否是回文、是否每个数字都相同。

我的解法

  1. import java.util.*;
  2. public class CarMileage {
  3. public static int isInteresting(int number, int[] awesomePhrases) {
  4. if (number>99 && isInterest(number, awesomePhrases)){
  5. return 2;
  6. }else if (number>97 && (isInterest(number+1, awesomePhrases) || isInterest(number+2, awesomePhrases))){
  7. return 1;
  8. }else {
  9. return 0;
  10. }
  11. }
  12. public static boolean isInterest(int number, int[] awesomePhrases){
  13. if( Arrays.stream(awesomePhrases).anyMatch(e -> e == number) ) return true;
  14. String temp = number+"";
  15. if( temp.matches("\\d*00+$") || temp.matches("(\\d)\\1+") || temp.matches("^(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?).?\\9\\8\\7\\6\\5\\4\\3\\2\\1$") ) return true;
  16. if( "1234567890".contains(temp) || "9876543210".contains(temp) ) return true;
  17. return false;
  18. }
  19. }

参考解法

  1. import java.util.Arrays;
  2. import java.util.function.Predicate;
  3. import java.util.stream.Stream;
  4. import static java.lang.Integer.parseInt;
  5. public class CarMileage {
  6. public static boolean isReallyInteresting(int number, final int[] awesomePhrases) {
  7. return Stream.<Predicate<String>>of(
  8. s -> s.matches("\\d0+"),
  9. s -> new StringBuilder(s).reverse().toString().equals(s),
  10. s -> "1234567890".contains(s),
  11. s -> "9876543210".contains(s),
  12. s -> Arrays.stream(awesomePhrases).anyMatch(n -> parseInt(s) == n)
  13. ).anyMatch( p -> number > 99 && p.test(Integer.toString(number)));
  14. }
  15. public static int isInteresting(int number, int[] awesomePhrases) {
  16. return isReallyInteresting(number, awesomePhrases) ? 2 :
  17. isReallyInteresting(number + 1, awesomePhrases) ? 1 :
  18. isReallyInteresting(number + 2, awesomePhrases) ? 1 : 0;
  19. }
  20. }

将字符串分解逐个查看是否满足条件的解法

  1. import java.util.stream.*;
  2. public class CarMileage {
  3. public static int isInteresting(int number, int[] awesomePhrases) {
  4. if (isExactlyInteresting(number, awesomePhrases)) {
  5. return 2;
  6. }
  7. else if (isExactlyInteresting(number + 1, awesomePhrases)) {
  8. return 1;
  9. }
  10. else if (isExactlyInteresting(number + 2, awesomePhrases)) {
  11. return 1;
  12. }
  13. else {
  14. return 0;
  15. }
  16. }
  17. private static boolean isExactlyInteresting(int number, int[] awesomePhrases) {
  18. // is big enough to be interesting?
  19. if (number < 100)
  20. return false;
  21. // is number in awesomePhrases?
  22. if (IntStream.of(awesomePhrases).anyMatch(x -> x == number)) {
  23. return true;
  24. }
  25. String digits = Integer.toString(number);
  26. // is number a digit followed by all zeros?
  27. // is every digit the same?
  28. // are the digits an incrementing sequence?
  29. // are the digits a decrementing sequence?
  30. // are the digits a palindrome?
  31. return
  32. isDigitFollowedByZeros(digits)
  33. || areAllDigitsEqual(digits)
  34. || areAllDigitsIncrementing(digits)
  35. || areAllDigitsDecrementing(digits)
  36. || isPalindrome(digits);
  37. }
  38. private static boolean isDigitFollowedByZeros(String digits) {
  39. for (int i = 1; i < digits.length(); i++) {
  40. if (digits.charAt(i) != '0') {
  41. return false;
  42. }
  43. }
  44. return true;
  45. }
  46. private static boolean areAllDigitsEqual(String digits) {
  47. for (int i = 1; i < digits.length(); i++) {
  48. if (digits.charAt(i) != digits.charAt(0)) {
  49. return false;
  50. }
  51. }
  52. return true;
  53. }
  54. private static boolean areAllDigitsIncrementing(String digits) {
  55. String s = "1234567890";
  56. return s.contains(digits);
  57. }
  58. private static boolean areAllDigitsDecrementing(String digits) {
  59. String s = "9876543210";
  60. return s.contains(digits);
  61. }
  62. private static boolean isPalindrome(String digits) {
  63. for (int i = 0; i < digits.length() / 2; i++) {
  64. if (digits.charAt(i) != digits.charAt(digits.length() - i - 1)) {
  65. return false;
  66. }
  67. }
  68. return true;
  69. }
  70. }

提升

  1. 关于正则表达式分组
  • 括号表示组 将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用 一个括号的表达式就表示一个分组
  • \1表示组里面第一个匹配到的内容 例如
    • (.)\1 匹配两个连续的相同字符
    • (A)\1 \1代表A匹配到的内容
    • (A)(B)\2 \2代表B匹配到的内容
    • (A(B))\2 \2代表A匹配到的内容中B匹配到的内容
  1. Predicate是一个功能性的接口,其功能是判断某个参数是否满足表达式。

    参考资料

    Predicate详解
    Java基础学习之函数式编程Predicate接口(JDK8)
    docs.oracle

ps:大佬的写法真是6的不行Orz