最近看了有道出的幾個復(fù)賽題,覺得很好玩,現(xiàn)給出Java版的答案。先看看提干部分

  如果一個數(shù)字十進制表達時,不存在連續(xù)兩位數(shù)字相等,則稱之為“不重復(fù)數(shù)”。例如,105,1234和12121都是“不重復(fù)數(shù)”,而11,100和 1225不算。給定一個long類型數(shù)字A,返回大于A的最小“不重復(fù)數(shù)”。下面是幾個測試用例,我又加了幾個

  Examples:

  0) 54

  returns: 56

  大于54的最小數(shù)字是55,但55不是“不重復(fù)數(shù)”。下一個數(shù)字是56,它滿足條件。

  1) 10

  returns: 12

  2) 9

  returns: 10

  3) 98

  returns: 101

  99和100都不是“不重復(fù)數(shù)”, 101是。

  4) 21099

  returns: 21201

  5) 99123

  returns: 101010

  6) 1134567

  returns: 1201010

  ok,現(xiàn)在看看解題思路,其實這個題單純從題本身上看并不復(fù)雜,主要是效率問題。估計不會有人一個數(shù)一個數(shù)地循環(huán)查找吧,那樣如果給定的long數(shù)很大時,可能會進行成千上萬次的循環(huán),會很慢很慢。技巧還是有的,現(xiàn)在來看看怎么快速搞定這個問題。

  首先來拿一個例子看,就選 21099了。

  這個數(shù)低兩位(99)是重復(fù)的。既然要找比21099大的最新不重復(fù)數(shù),就需要從這兩位開始遞增,但不是逐1的遞增。比21099大的數(shù)是 21100,這個數(shù)也是個重復(fù)的數(shù),有兩對重復(fù)的(11和00)。從右側(cè)開始處理它們。先處理00。我們現(xiàn)在要做的就是把00變成不重復(fù)的,很簡單,就成 01就可以了。現(xiàn)在21100就變成了21101,這個數(shù)還是有兩個重復(fù)數(shù)(11)。現(xiàn)在處理11,把11變成12就不重復(fù)的,那么現(xiàn)在21101就變成了21201,ok,現(xiàn)在就得到了最終結(jié)果。我們看看,只結(jié)果了兩步,是很快地,因此,我們可以總結(jié)一下算法,步驟如下:

  1. 將給定的long數(shù)加1。

  2. 從這個數(shù)開始檢測是否為重復(fù)數(shù),如果不是,ok,這個數(shù)就是最終結(jié)果。如果是,那么從數(shù)的右側(cè)開始找第1對重復(fù)的數(shù),然后將其加1,得到一個新的數(shù)。

  3. 然后用這個數(shù)再從第2步開始。

  這個算法首先需要編寫一個方法用于將給定數(shù)最右側(cè)第一對重復(fù)的數(shù)找出,并且加1,最后得到一個新的數(shù)。如果這個數(shù)是不重復(fù)的數(shù),那么直接返回0。代碼如下:

  // sb表示指定的數(shù),以StringBuilder對象表示

  public static long getNextNum(StringBuilder sb)

  {

  String result = ”“;

  char c = ’a‘; // c表示數(shù)字中待檢測位中高位的字符

  int i = 0;

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

  {

  // 如果相鄰的兩個數(shù)字不相同,那么將當前字符保存在c中

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

  {

  c = sb.charAt(i);

  }

  // 如果相鄰的兩個數(shù)字相同,那進行下一步地處理

  else

  {

  // 將相同的兩個數(shù)字組成的數(shù)加1

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

  // 先將這兩個相同的數(shù)字的位置的值設(shè)為0,以便進行相加

  // 計算數(shù)字后面要補的0的數(shù),如21443中重復(fù)的數(shù)字是44,加1后是45,那么首先將44設(shè)成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));

  // 開始將重復(fù)數(shù)后面的數(shù)變成最小的

  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;

  }

  要注意的是,雖然把每一對重復(fù)的數(shù)都變成了不重復(fù)的,但仍然不是最小的數(shù),需要將當前重復(fù)數(shù)后面的數(shù)變成最小的,例如,99123將99變成不重復(fù)的數(shù),也就是100,原來的數(shù)變成了100123,但100123還需要繼續(xù)變成100101,再查找重復(fù)數(shù),把到了00,再變成101101,然后再變成101010,就ok了。

  最后調(diào)用getNextNum方法來返回最終結(jié)果,代碼如下:

  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;

  }

  現(xiàn)在可以使用下面的代碼來測試一下:

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