編程之美系列01


     最近就開始找實習了,特意把上學期買的編程之美拿出來練練手,算法還是比較關鍵的。據說很多題的思路都可以在編程之美中找到,為紀念這段有意義的時光,特准備寫下下面系列博文。每篇博文講主要研究兩至三個算法。

    1、求二進制中1的個數。對於一個字節的無符號整形變量,求二進制中1的個數,比如5為101,有兩個。

     思路1:直接判定最后1位是否為1,若為1則count加1;同時原數除以2.

1 int modeway(unsigned int num){//通過除法方式
2     int count=0;
3     while(num){
4         if((num%2)==1)
5             count++;
6         num/=2;
7     }
8     return count;
9 }

 

     思路2:通過位判定,原數與0x01,若非零,則count加1;同時原數向右移動一位>>

1 int bitmove(unsigned int num){//通過位操作
2     int count=0;
3     while(num){
4         count+=(num&0x01);
5         num>>=1;
6     }
7     return count;
8 }

 

     思路3:原數“與”原數-1得到一個新的數,count加上該新數。直到數為0為止:原理是因為當碰到第一個XXX10000的時候,然后與該數的XXX01111.得到的是XXX00000,減少了一個1.其他類似。所以可以用這種方式求解。

1 int subway(unsigned int num){//減然后與
2     int count=0;
3     while(num){
4         num&=(num-1);
5         count++;
6     }
7     return count;
8 }

 

    2、給定一個整數N,那么N的階乘末尾有多少個0呢?例如N!=3628800末尾有兩個0.

    思路1:直接求解,如何同10取余數。這種方式可能會造成溢出,顯然不是很好的求解思路。

    思路2: 遇到這種問題,因為任意數都可以分解成多個2*3*5.而一般來說只有2*5=10會出來一個0.可能又童鞋會說4*5=20也出來一個0,但是本質上還是2*5.經過觀察發現,在出現一個5之前,必然會出現一個或者多個5,問題就可以轉化成出現多少個5了。比如10就出現一個5,但是25就出現5*5.等於兩個。現在問題就已經轉化成求解5出現的次數了。當然我們可以通過求解每一個數字m出現5的次數:

 1 int factorial1(int N){//計算每一個數字j中有多少個5
 2     int count=0;
 3     for(int i=1;i<=N;i++){
 4         int j=i;
 5         while(j%5==0){
 6             count++;
 7             j/=5;
 8         }
 9     }
10     return count;
11 }

   思路3:分析5的次數還有一種更精妙的關系,那就是每個5的倍數之間,5,5*5,5*5*5,5*5*5*5.。。。 

1 int factorial2(int N){
2     int count=0;
3     while(N){
4         N/=5;
5         count+=N;
6     }
7     return count;
8 }

 

   3、求N!的二進制表示最低位1的位置。其實這個問題可以轉化二進制之后,最后出現了多少個0,然后加1.(編程之美的程序是錯誤的)

 1 int factorial3(unsigned int N){
 2     if(N<=1)
 3         return N;
 4     int count=1;
 5     while(N){
 6         N>>=1;
 7         count=count+static_cast<int>(N);
 8     }
 9     return count;
10 }

 

   3、尋找水王。超級水王是指在論壇中發帖數量超過1/2的用戶。

   既然超過1/2.那么就可以通過相異的兩個用戶刪除得到,因為如果水王刪除,同時刪除另外一個了,最后留下來的一定是水王。

 1 int findShuiWang(vector<int> idList){//保留一個數,當遇到不同的就同時減掉,相同則加1
 2     int count=0,theNum;
 3     for(vector<int>::size_type i=0;i<idList.size();i++){
 4         if(count){
 5             if(theNum==idList[i])
 6                 count++;
 7             else
 8                 count--;
 9         }else{
10             theNum=idList[i];
11             count++;
12         }
13     }
14     return theNum;
15 }

  擴展:有三個用戶,每個用戶發帖數都超過1/4.求解這三個用戶。

  方法同上,可以通過刪除四個不同的用戶來得到。

 1 void findShuiWangEx(elemType* idList,int length,user* result){
 2     for(int i=0;i<length;i++){
 3         int flag=-1;
 4         for(int j=0;j<3;j++){//比照保存的三個ID
 5             if(result[j].userId==idList[i]){//找到一個和該Id相同,則帖數加1,不再尋找
 6                 result[j].count++;
 7                 break;
 8             }
 9             if(result[j].count==0)
10                 flag=j;
11             if(j==2){//三個結果都掃描了一遍,沒有找到與當前ID相同
12                 if(flag==-1){//三個保存的結果中,都保存了Id,同時減1
13                     for(int m=0;m<3;m++)
14                         result[m].count--;
15                 }else {//三個保存的中有一個沒有保存ID,並且沒有ID與當前ID相同
16                     result[flag].userId=idList[i];
17                     result[flag].count++;
18                 }
19             }
20         }//endfor
21     }//endif
22 }

     當然上述兩道題還可以用排序的方法解答,也可以通過哈希表的方式解決。

 

     版權所有,歡迎轉載,但是轉載請注明出處:瀟一

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM