最近就開始找實習了,特意把上學期買的編程之美拿出來練練手,算法還是比較關鍵的。據說很多題的思路都可以在編程之美中找到,為紀念這段有意義的時光,特准備寫下下面系列博文。每篇博文講主要研究兩至三個算法。
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 }
當然上述兩道題還可以用排序的方法解答,也可以通過哈希表的方式解決。
版權所有,歡迎轉載,但是轉載請注明出處:瀟一
