隨筆 - 312, 文章 - 14, 評(píng)論 - 1393, 引用 - 0
          數(shù)據(jù)加載中……

          有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)

          本文為原創(chuàng),如需轉(zhuǎn)載,請(qǐng)注明作者和出處,謝謝!

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

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

          Examples:
          0)    54
              returns: 56
              大于54的最小數(shù)字是55,但55不是“不重復(fù)數(shù)”。下一個(gè)數(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)在看看解題思路,其實(shí)這個(gè)題單純從題本身上看并不復(fù)雜,主要是效率問題。估計(jì)不會(huì)有人一個(gè)數(shù)一個(gè)數(shù)地循環(huán)查找吧,那樣如果給定的long數(shù)很大時(shí),可能會(huì)進(jìn)行成千上萬次的循環(huán),會(huì)很慢很慢。技巧還是有的,現(xiàn)在來看看怎么快速搞定這個(gè)問題。
            
              首先來拿一個(gè)例子看,就選 21099了。
              這個(gè)數(shù)低兩位(99)是重復(fù)的。既然要找比21099大的最新不重復(fù)數(shù),就需要從這兩位開始遞增,但不是逐1的遞增。比21099大的數(shù)是21100,這個(gè)數(shù)也是個(gè)重復(fù)的數(shù),有兩對(duì)重復(fù)的(11和00)。從右側(cè)開始處理它們。先處理00。我們現(xiàn)在要做的就是把00變成不重復(fù)的,很簡(jiǎn)單,就成01就可以了。現(xiàn)在21100就變成了21101,這個(gè)數(shù)還是有兩個(gè)重復(fù)數(shù)(11)。現(xiàn)在處理11,把11變成12就不重復(fù)的,那么現(xiàn)在21101就變成了21201,ok,現(xiàn)在就得到了最終結(jié)果。我們看看,只結(jié)果了兩步,是很快地,因此,我們可以總結(jié)一下算法,步驟如下:
          1.  將給定的long數(shù)加1。
          2.  從這個(gè)數(shù)開始檢測(cè)是否為重復(fù)數(shù),如果不是,ok,這個(gè)數(shù)就是最終結(jié)果。如果是,那么從數(shù)的右側(cè)開始找第1對(duì)重復(fù)的數(shù),然后將其加1,得到一個(gè)新的數(shù)。
          3.  然后用這個(gè)數(shù)再?gòu)牡?步開始。
          這個(gè)算法首先需要編寫一個(gè)方法用于將給定數(shù)最右側(cè)第一對(duì)重復(fù)的數(shù)找出,并且加1,最后得到一個(gè)新的數(shù)。如果這個(gè)數(shù)是不重復(fù)的數(shù),那么直接返回0。代碼如下:

              // sb表示指定的數(shù),以StringBuilder對(duì)象表示
              public static long getNextNum(StringBuilder sb)
              {
                  String result 
          = "";
                  
          char c = 'a'// c表示數(shù)字中待檢測(cè)位中高位的字符
                  int i = 0;
                  
          for (i = sb.length() - 1; i >= 0; i--)
                  {
                      
          // 如果相鄰的兩個(gè)數(shù)字不相同,那么將當(dāng)前字符保存在c中
                      if (sb.charAt(i) != c)
                      {
                          c 
          = sb.charAt(i);
                      }
                      
          // 如果相鄰的兩個(gè)數(shù)字相同,那進(jìn)行下一步地處理
                      else
                      {
                          
          // 將相同的兩個(gè)數(shù)字組成的數(shù)加1
                          long n = Long.parseLong(String.valueOf(c) + String.valueOf(c)) + 1;
                          
          // 先將這兩個(gè)相同的數(shù)字的位置的值設(shè)為0,以便進(jìn)行相加

                          
          // 計(jì)算數(shù)字后面要補(bǔ)的0的數(shù),如21443中重復(fù)的數(shù)字是44,加1后是45,那么首先將44設(shè)成00,
                          
          // 也就是21003,然后將45后面補(bǔ)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;
              }
              要注意的是,雖然把每一對(duì)重復(fù)的數(shù)都變成了不重復(fù)的,但仍然不是最小的數(shù),需要將當(dāng)前重復(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)在可以使用下面的代碼來測(cè)試一下:
          System.out.println(getMinNoRepetitionNum(1999));




          Android開發(fā)完全講義(第2版)(本書版權(quán)已輸出到臺(tái)灣)

          http://product.dangdang.com/product.aspx?product_id=22741502



          Android高薪之路:Android程序員面試寶典 http://book.360buy.com/10970314.html


          新浪微博:http://t.sina.com.cn/androidguy   昵稱:李寧_Lining

          posted on 2010-05-11 16:23 銀河使者 閱讀(3586) 評(píng)論(21)  編輯  收藏 所屬分類: javaalgorithm 原創(chuàng)

          評(píng)論

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          算法錯(cuò)了,20097怎么辦?
          按你算法是20198
          實(shí)際應(yīng)該是20101
          2010-05-12 09:32 | zack

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)1  回復(fù)  更多評(píng)論   

          @zack
          少加了些代碼,現(xiàn)在ok了。
          2010-05-12 09:53 | 銀河使者

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          這個(gè)題如果給我做的話我不會(huì)從左往右檢查,相反我會(huì)從右往左檢查
          1.將數(shù)字+1
          2. 從左往右(從高位到低位)判斷是否有重復(fù)數(shù)字,沒有的話進(jìn)入4檢查到第一組重復(fù)數(shù)字進(jìn)入3
          2. 將兩個(gè)重復(fù)數(shù)字的以前的(包括重復(fù)數(shù)字取出來)并且+1,將結(jié)果*(10^n) + 01序列
          3. 輸出結(jié)果
          例 21001224321
          1.加1 = 21001224322
          2. 是重復(fù)數(shù)字進(jìn)入3
          3. 2100 *10^7 + 1* 10^7 + 1* 10^5 + 1* 10^3 + 1* 10^1 =
          21010101010
          4. 輸出 21010101010
          2010-05-12 18:24 | Zhjiang

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @Zhjiang
          你寫的算術(shù)公式真的能算出這21010101010個(gè)數(shù)???

          我都不知道你怎么算出來的。
          2010-05-13 14:29 | Lancelot

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @Lancelot
          試試不用知道了,計(jì)算機(jī)會(huì)告訴你的。
          2010-05-13 15:29 | 銀河使者

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @銀河使者
          你知道10^7等于多少嗎???
          你把
          2100 *10^7 + 1* 10^7 + 1* 10^5 + 1* 10^3 + 1* 10^1
          算出來,你能等于21010101010嗎???

          拜托別說不負(fù)責(zé)任的話,只會(huì)讓自己獻(xiàn)丑。
          2010-05-13 16:33 | Lancelot

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @銀河使者
          而且這個(gè)算式也與他上面寫的:
          2. 將兩個(gè)重復(fù)數(shù)字的以前的(包括重復(fù)數(shù)字取出來)并且+1,將結(jié)果*(10^n) + 01序列
          這句不符,明顯算式里沒有出現(xiàn)括號(hào),那到底是先乘再取余(結(jié)果:21003)還是先取余再乘(結(jié)果:27348)?

          拜托你幫我算算是多少。
          在線等,謝謝。
          2010-05-13 16:41 | Lancelot

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          額 我想你們理解錯(cuò)我的意思了

          10^n 我表示的是10的n次方

          不好意思啊
          2010-05-13 17:24 | Zhjiang

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          各位如果要有更好的算法,把代碼貼出來,不要光說一些理論。
          2010-05-13 18:28 | 銀河使者

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          什么都不說 粗略寫的java 代碼 大家研究下

          import java.io.BufferedReader;
          import java.io.IOException;
          import java.io.InputStreamReader;


          public class Test {

          /**
          * @param args
          */
          public static void main(String[] args)
          {
          BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
          String numStr =null;
          long num = -1;
          long tempnum = 0;
          long bitvalue = -1;
          int numbit1 = -1;
          int numbit2 = -1;
          int flag = -1;
          int size = 0;
          boolean isrepeater = false;

          try
          {
          numStr = br.readLine();
          num = Long.parseLong(numStr);

          } catch (NumberFormatException e)
          {
          return;
          } catch (IOException e)
          {
          return;
          }
          //只解析自然數(shù)
          if(num <= -1)
          return;

          size = (int)Math.log10(num);

          //1. 先將數(shù)字+1
          num ++;
          tempnum = num;

          //2. 判斷是否為重復(fù)數(shù)字
          if(tempnum / Math.pow(10, size) >= 1)
          size ++;

          bitvalue = (long)Math.pow(10, size - 1);

          for(flag = size - 1; flag >= 1; flag --){

          numbit1 = (int)(tempnum / bitvalue);

          tempnum = tempnum % bitvalue;

          bitvalue = (long)Math.pow(10, flag - 1);
          numbit2 = (int)(tempnum / bitvalue);

          if(numbit1 == numbit2){
          isrepeater = true;
          break;
          }
          }
          //2. 如果是重復(fù)數(shù)
          if(isrepeater){
          flag --;
          num -= tempnum % Math.pow(10, flag);

          //以下三行是由于考慮的遺漏,解決了以99開頭數(shù)字(例 9998)的問題
          //按照我以前的算法99123 得到的結(jié)果是100010
          num += (long)Math.pow(10, flag);
          if(Math.log10(num) >= size)
          num += (long)Math.pow(10, flag);

          flag -= 2;
          for(; flag >= 0; flag -=2){
          num += (long)Math.pow(10, flag);
          }
          }

          //4.輸出結(jié)果
          System.out.println(num);

          }

          }
          2010-05-13 18:30 | Zhjiang

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          我也只是剛剛寫的,遺漏之處和我說一下,謝謝了!
          在我看來這個(gè)題目純粹是一個(gè)計(jì)算的問題,不需要過多的循環(huán)的,當(dāng)然 僅爭(zhēng)對(duì)本題,另外解釋一點(diǎn),我上面的代碼沒有把負(fù)數(shù)考慮進(jìn)去,只要稍微改進(jìn)一下就可以把負(fù)數(shù)也包括進(jìn)去,當(dāng)然這點(diǎn)還需要商榷,我只是一個(gè)猜想,因?yàn)闇?zhǔn)備寫代碼的時(shí)候已經(jīng)下班了,不想在公司繼續(xù)熬了,所以代碼寫得很粗糙,沒有優(yōu)化,另外也沒有過多檢查BUG和遺漏的情況,往諒解下!
          2010-05-13 18:34 | Zhjiang

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @Lancelot
          哈哈,上機(jī)測(cè)一下程序不就知道了。你不知道,可計(jì)算機(jī)知道哦。
          2010-05-14 08:23 | 銀河使者

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          看到你在Csdn上寫的,看來不止是我覺得擴(kuò)展01序列是一個(gè)不錯(cuò)的方法!~~
          很慶幸
          2010-05-14 09:10 | Zhjiang

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @銀河使者
          拜托你告訴我你用的什么計(jì)算機(jī)???
          你的計(jì)算機(jī)會(huì)把10^7算成3還是10000000???
          搞笑


          我都懶的理你了,這是最后一次回復(fù)你。
          2010-05-17 17:23 | Lancelot

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          @Lancelot
          什么意思,我的算法沒10^7,估計(jì)是你看到別人的回復(fù)算到我頭上了吧。如果認(rèn)為哪個(gè)具體的數(shù)無法通過算法,請(qǐng)指出,謝謝。

          對(duì)了,忘了說了,上星期我剛從某個(gè)外星種族那得到一臺(tái)先進(jìn)的計(jì)算機(jī),好象10^7既不等于3,也不等于10000000,等于^&%$&*^&*。 :)
          2010-05-17 19:33 | 銀河使者

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          Zhjiang的算法思路不錯(cuò), 不過還是有一些缺陷的.對(duì)于中間含有多個(gè)9的數(shù)字,處理不對(duì)。如99,1990,999...
          2010-05-17 23:42 | 曉風(fēng)待語

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          本人blog中有對(duì)該題的詳細(xì)解法,希望給予意見
          2010-05-17 23:45 | 曉風(fēng)待語

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)[未登錄]  回復(fù)  更多評(píng)論   

          確實(shí)覺得從左至右是合理的,
          比如說一個(gè)數(shù)字,567899882201
          首先+1,然后執(zhí)行如下步驟:
          步驟一:從左至右查找第一對(duì)重復(fù)的是99,操作:(567899 + 1)*10^6 =
          567900 000000
          其實(shí)這樣的操作會(huì)使任何一個(gè)數(shù)字都帶有0到n個(gè)0。如55 的話
          (55+1)*10^0 ,78662為:(7866+1)*10^1;
          步驟二:從左至右查找第一對(duì)重復(fù)的數(shù)字,如果重復(fù)的數(shù)字為0,即為00,執(zhí)
          行步驟三,否則執(zhí)行步驟一;
          步驟三:從左至右查找連續(xù)的兩個(gè)數(shù)字,此時(shí)連續(xù)的兩個(gè)數(shù)字只有可能是00了,
          如果有兩個(gè)連續(xù)的0,這時(shí)按照00+1,如:(567900+1)*10^6;

          只是寫了一個(gè)大致的實(shí)現(xiàn)思路,這個(gè)只是針對(duì)>=0的數(shù)字,^的意思是Math.pow(10, n);只是一個(gè)表現(xiàn)形式,大家也不用太糾結(jié)
          2010-06-25 10:56 | lj

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)[未登錄]  回復(fù)  更多評(píng)論   

          假如上個(gè)月(5月)總銷售額是39980,而本月(6月)總銷售額是59863,問:本月銷售同比上月銷售增長(zhǎng)多少百分比,反比增長(zhǎng)多少百分比?
          2010-07-03 13:35 | 小李

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          看了一下大伙的討論 覺得蠻有意思
          轉(zhuǎn)走了
          http://www.wangdacuo.com/archives/solve-question-use-java
          2010-07-13 19:26 | 特立獨(dú)行

          # re: 有道難題2009復(fù)賽題解答(Java版):求大于給定數(shù)的最小不重復(fù)數(shù)  回復(fù)  更多評(píng)論   

          我感覺這題好簡(jiǎn)單啊……
          1.從高到低位掃描,遇到與高一位數(shù)相同的數(shù),就在該位置上加1,把該為后的全置0,
          2.重復(fù)1直到你掃描到個(gè)位且它與十位不同
          就搞定了……
          2011-04-28 22:41 | 喬磊
          主站蜘蛛池模板: 丽江市| 盐源县| 连南| 武安市| 夏河县| 扬州市| 新沂市| 花垣县| 泗洪县| 宁武县| 育儿| 嘉禾县| 合肥市| 静海县| 泸定县| 荆州市| 正蓝旗| 改则县| 桦南县| 葵青区| 珠海市| 晋宁县| 额尔古纳市| 外汇| 静安区| 韩城市| 天镇县| 龙岩市| 富顺县| 吴堡县| 曲松县| 新和县| 泽库县| 观塘区| 广安市| 利川市| 南漳县| 梨树县| 日喀则市| 长岛县| 搜索|