最近看了有道出的幾個復賽題,覺得很好玩,現給出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));