網易2017年校招筆試題 最大的奇約數


題目:

定義函數f(x)為x的最大奇數約數,x為正整數,例如f(44) = 11.

現在給出一個N,需要求出f(1) + f(2) + f(3) + ... + f(N)

例如: N = 7

f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) = 1 + 1 + 3 + 1 + 5 + 7 = 21.

 

分析:

奇數的最大奇約數是自身, 偶數的最大奇約數是是除去所有偶因子之后的那個奇數。所以直觀的思路就是挨個遍歷一遍加起來。

代碼:

 1 #include <iostream>
 2 using namespace std;
 3 int main() {
 4     long long N;
 5     cin >> N;
 6     long long result = 0;
 7     for (long long i = 1; i <= N; ++i) {
 8         int temp = i;
 9         while (temp % 2 == 0) {
10             temp /= 2;
11         }
12         result += temp;
13     }
14     cout << result << endl;
15     return 0;
16 } 

然而, N的取值范圍時10^10,所以O(n)的算法是超時的。

考慮優化,設sum(i) = f(1) + f(2) + ... + f(i);

求sum(i)的過程中,對於f(i), i 為奇數可以直接求,就是 i 本身。

問題就是求所有f(i), i為偶數的和。

因為要求的是最大奇約數,所以f(2k) = f(k),所以f(2) + f(4) + ... + f(2k) = f(1) + f(2) + ... + f(k);

所以

sum(i) =  sum (i / 2) + 1 + 3 + ... + i - 1  (i 為偶數)

          =  sum (i - 1) + i (i 為奇數)

時間復雜度O(logn),可以解決。

 1 #include<iostream>
 2 using namespace std;
 3 long long sum(long long n) {
 4     if (n == 1) {
 5         return 1;
 6     }
 7     if (n % 2 == 0) {
 8         return  sum(n / 2) + n * n / 4;
 9     }
10     else {
11         return sum(n - 1) + n; 
12     }
13 }
14 int main() {
15     long long N;
16     cin >> N;
17     cout << sum(N) << endl;
18 }

有朋友回復可能擔心stackoverflow,當時寫的時候也覺得可能會遞歸層數太多,但是提交還是過了的。

還是可以寫成非遞歸的。

代碼:

 1 #include<iostream>
 2 using namespace std;
 3 long long sum(long long n) {
 4     long long result = 0;
 5     while (n > 0) {
 6         if (n % 2 == 0) {
 7             result += n * n / 4;
 8             n /= 2;
 9         }
10         else {
11             result += n;
12             n--;
13         }
14     }
15     return result;
16 }
17 int main() {
18     long long N;
19     cin >> N;
20     cout << sum(N) << endl;
21 }

 


免責聲明!

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



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