程式設計之美--只考加法的面試題(尺取法)
阿新 • • 發佈:2019-01-14
問題: 對於一個任意的自然數,問是否能將其拆分成2個或2個以上的連續自然數之和,寫出所有的等式。
解題思路: 第一種解法是推匯出數學公式,因為連續的自然數可以用等差數列Sn求和公式,判斷可行性。公式推導以及證明過程:數學解法;
第二種解法是直接窮舉解法,不過對於較大的數字複雜度O(n^2)可能不夠解決,由於連續的自然數一定是遞增狀態,我們可以用尺取法,也就是雙指標法將複雜度降低到O(n)
雙指標解法:
#include <bits/stdc++.h> using namespace std; typedef long long ll; void print_Answer (ll l, ll r) { printf("AC Answer is : "); for (ll i = l; i<= r; i++) { printf("%d%c", i, " \n"[i==r]); } } //寫法1 void get_Answer (ll goal) { ll i, j, tmp, flag; i = 1, j = 1; flag = 0; //搜尋首項i和尾項j while (i <= goal/2 && j <= goal) { tmp = (i+j)*(j-i+1)/2; if(tmp == goal) { print_Answer(i,j); flag = 1; i++; j++; continue; } if(tmp > goal) { i++; continue; } j++; } if(flag == 0) { printf("不存在該數的拆分策略!\n"); } return ; } //寫法2 void get_Answer2 (ll goal) { ll i, j, sum, flag = 0; i = j = 1; sum = 0; while (i <= goal/2) { while (j <= goal && sum < goal) { sum += j; j++; } if(sum < goal) { break; } if(sum == goal) { print_Answer(i,j-1); flag = 1; } sum -= i++; //移位 } if(flag == 0) { printf("不存在該數的拆分策略!\n"); } return ; } int main() { int N; scanf("%d", &N); printf("寫法1:\n"); get_Answer(N); printf("\n寫法2:\n"); get_Answer2(N); return 0; }