一个趣题的Java解法

最近看了有道出的几个复赛题,觉得很好玩,现给出Java版的答案。先看看提干部分

  如果一个数字十进制表达时,不存在连续两位数字相等,则称之为“不重复数”。例如,105,1234和12121都是“不重复数”,而11,100和 1225不算。给定一个long类型数字A,返回大于A的最小“不重复数”。下面是几个测试用例,我又加了几个

  Examples:

  0) 54

  returns: 56

  大于54的最小数字是55,但55不是“不重复数”。下一个数字是56,它满足条件。

  1) 10

  returns: 12

  2) 9

  returns: 10

  3) 98

  returns: 101

  99和100都不是“不重复数”, 101是。

  4) 21099

  returns: 21201

  5) 99123

  returns: 101010

  6) 1134567

  returns: 1201010

  ok,现在看看解题思路,其实这个题单纯从题本身上看并不复杂,主要是效率问题。估计不会有人一个数一个数地循环查找吧,那样如果给定的long数很大时,可能会进行成千上万次的循环,会很慢很慢。技巧还是有的,现在来看看怎么快速搞定这个问题。

  首先来拿一个例子看,就选 21099了。

  这个数低两位(99)是重复的。既然要找比21099大的最新不重复数,就需要从这两位开始递增,但不是逐1的递增。比21099大的数是 21100,这个数也是个重复的数,有两对重复的(11和00)。从右侧开始处理它们。先处理00。我们现在要做的就是把00变成不重复的,很简单,就成 01就可以了。现在21100就变成了21101,这个数还是有两个重复数(11)。现在处理11,把11变成12就不重复的,那么现在21101就变成了21201,ok,现在就得到了最终结果。我们看看,只结果了两步,是很快地,因此,我们可以总结一下算法,步骤如下:

  1. 将给定的long数加1。

  2. 从这个数开始检测是否为重复数,如果不是,ok,这个数就是最终结果。如果是,那么从数的右侧开始找第1对重复的数,然后将其加1,得到一个新的数。

  3. 然后用这个数再从第2步开始。

  这个算法首先需要编写一个方法用于将给定数最右侧第一对重复的数找出,并且加1,最后得到一个新的数。如果这个数是不重复的数,那么直接返回0。代码如下:

  // sb表示指定的数,以StringBuilder对象表示

  public static long getNextNum(StringBuilder sb)

  {

  String result = ”“;

  char c = ’a‘; // c表示数字中待检测位中高位的字符

  int i = 0;

  for (i = sb.length() - 1; i 》= 0; i–)

  {

  // 如果相邻的两个数字不相同,那么将当前字符保存在c中

  if (sb.charAt(i) != c)

  {

  c = sb.charAt(i);

  }

  // 如果相邻的两个数字相同,那进行下一步地处理

  else

  {

  // 将相同的两个数字组成的数加1

  long n = Long.parseLong(String.valueOf(c) + String.valueOf(c)) + 1;

  // 先将这两个相同的数字的位置的值设为0,以便进行相加

  // 计算数字后面要补的0的数,如21443中重复的数字是44,加1后是45,那么首先将44设成00,

  // 也就是21003,然后将45后面补0,就是450,最后用21003和450相加,就变成了21453

  int m = sb.length() - i - 2;

  sb.setCharAt(i, ’0′);

  sb.setCharAt(i + 1, ’0′);

  for (int k = 0; k 《 m; k++)

  n *= 10;

  long num = Long.parseLong(sb.toString()) + n;

  sb = new StringBuilder(String.valueOf(num));

  // 开始将重复数后面的数变成最小的

  m = i + 2;

  for (int x = m; x 《 sb.length(); x++)

  {

  for (int y = 0; y 《 10; y++)

  {

  if (sb.charAt(x - 1) != (y + 48))

  {

  sb.setCharAt(x, (char) (y + 48));

  break;

  }

  }

  }

  return Long.parseLong(sb.toString());

  }

  }

  return 0;

  }

  要注意的是,虽然把每一对重复的数都变成了不重复的,但仍然不是最小的数,需要将当前重复数后面的数变成最小的,例如,99123将99变成不重复的数,也就是100,原来的数变成了100123,但100123还需要继续变成100101,再查找重复数,把到了00,再变成101101,然后再变成101010,就ok了。

  最后调用getNextNum方法来返回最终结果,代码如下:

  public static long getMinNoRepetitionNum(long num)

  {

  String s = String.valueOf(num + 1);

  long n = 0;

  long result = 0;

  while ((n = getNextNum(new StringBuilder(s))) != 0)

  {

  s = String.valueOf(n);

  result = n;

  }

  if (result == 0)

  return num + 1;

  else

  return result;

  }

  现在可以使用下面的代码来测试一下:

  System.out.println(getMinNoRepetitionNum(1999));

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。