面試總結:任意一個整數分解為幾個連續正整數之和
前陣子參加了國內某一大公司的面試。到了之後,人家不問出身,不問來歷,就直接開機讓我上機程式設計。因為是第一次在面試時上機操作,儘管題目不是很難,但是由於沒搞清楚機考和筆試的區別,導致最後面試失敗。現在總結一下自己在機考時碰到的一些問題,以免自己以後再犯同樣的錯誤。不多說了,直接上題。
下面這道題,其實有程式碼更簡潔或者演算法複雜度也比較低的解法,這裡不作討論,這裡的重點是指出面試時一些機考和筆試的區別。
題目描述:一個正整數有可能可以被表示為n(n>;=2)個連續正整數之和,如:
15=1+2+3+4+5
15=4+5+6
15=7+8
請編寫程式,根據輸入的任何一個正整數,找出符合這種要求的所有連續正整數序列。
輸入資料:一個大於0並且不大於100正整數,以命令列引數的形式提供給程式。
輸出資料:1.在標準輸出上打印出符合題目描述的全部正整數序列,每個序列都從改序列的最小正整數開始,以從小到大的順序列印
2.如果結果有多個序列,按各序列的最小正整數的大小從小到大列印個序列
3.序列不允許重複,序列內的整數用一個空格分隔,序列之間用英文“,”分隔
4.如果沒有符合要求的序列,輸出“NONE”,如果輸入不符合要求,則輸出“ERROR”
樣例輸入:15
樣例輸出:1 2 3 4 5,4 5 6,7 8
估計很多人面試時看到這樣的題目,心裡都會在偷偷的笑,是的,我也笑了。不過,我只看到了故事的開頭,卻沒猜到故事的結尾。下面是我當時提交的第一份程式碼:
#include <iostream> using namespace std; int main() { int nSplitNum = 0; cout << "請輸入一個大於0並且不大於100的整數:"; cin >> nSplitNum; //判斷合法性 if (nSplitNum < 1 || nSplitNum > 100) { cout << "ERROR" << endl; return 1; } bool bFlag = false; //記錄是否有符合要求的序列 for (int i = 1; i <= nSplitNum / 2; i++) { int nSum = i; for (int j = i + 1; j < nSplitNum; j++) { nSum += j; if (nSum > nSplitNum) { break; } else if (nSum == nSplitNum) { //如果相等,迴圈輸出序列 for (int k = i; k <= j; k++) { cout << k; if (k != j) { cout << " "; //序列最後一個數字時,不用輸出“ ” } } cout << ","; //序列之間用“,”隔開 bFlag = true; break; } } } if (!bFlag) { cout << "NONE" << endl; return 1; } cout << endl; system("pause"); return 0; }
輸出的結果如圖:
乍看之下,這份程式碼是沒有什麼問題的,輸入任意一個在1~100範圍內的整數,也能夠正確輸出分解後的序列,排序也沒有問題。如果是在筆試,這樣寫基本就算是對了。但在機考時,機器卻給了我零分,說我測試一個都沒通過。
看到這個分數,我楞了楞,開始檢查自己的程式碼,發現演算法肯定是沒問題的,那麼會不會問題出在結果上呢?可以看到我輸出的序列的最後還多了一個英文逗號“,”,會不會是這個地方導致了測試沒通過呢?在我上面的程式碼中,我是在序列最後輸出英文逗號“,”的,但是我沒辦法判斷哪個序列是最後一個序列,也就沒辦法禁止最後一個英文逗號“,”的輸出顯示了。
既然不能在序列的最後輸出英文逗號“,”,那麼就考慮放到序列的前面去輸出顯示。只要從第二個序列開始,在序列的前面加上英文逗號“,”就可以了,下面是我當時提交的第二份程式碼:
#include <iostream>
using namespace std;
int main()
{
int nSplitNum = 0;
cout << "請輸入一個大於0並且不大於100的整數:";
cin >> nSplitNum;
//判斷合法性
if (nSplitNum < 1 || nSplitNum > 100)
{
cout << "ERROR" << endl;
return 1;
}
static bool bFirst = true; //記錄是否是第一個序列
bool bFlag = false; //記錄是否有符合要求的序列
for (int i = 1; i <= nSplitNum / 2; i++)
{
int nSum = i;
for (int j = i + 1; j < nSplitNum; j++)
{
nSum += j;
if (nSum > nSplitNum)
{
break;
}
else if (nSum == nSplitNum)
{
//如果相等,迴圈輸出序列
if (!bFirst)
{
cout << ","; //從第二個序列開始,在序列的前面加上英文逗號“,”
}
bFirst = false;
for (int k = i; k <= j; k++)
{
cout << k;
if (k != j)
{
cout << " "; //序列最後一個數字時,不用輸出“ ”
}
}
bFlag = true;
break;
}
}
}
if (!bFlag)
{
cout << "NONE" << endl;
return 1;
}
cout << endl;
system("pause");
return 0;
}
輸出的結果如圖:
很遺憾,結果還是零分,一個測試也沒通過。當時做到這裡,確實有點急了,畢竟這是在面試,時間不等人啊。只能回頭重新看題目了,到底是什麼導致測試通不過呢?當我重新看到最後的樣列輸入時,突然想到既然輸出可能有要求,那麼輸入是不是可能也有要求呢?於是我決定把中文提示去掉試試,下面是我提交的第三份程式碼:
#include <iostream>
using namespace std;
int main()
{
int nSplitNum = 0;
cin >> nSplitNum;
//判斷合法性
if (nSplitNum < 1 || nSplitNum > 100)
{
cout << "ERROR" << endl;
return 1;
}
static bool bFirst = true;
bool bFlag = false; //記錄是否有符合要求的序列
for (int i = 1; i <= nSplitNum / 2; i++)
{
int nSum = i;
for (int j = i + 1; j < nSplitNum; j++)
{
nSum += j;
if (nSum > nSplitNum)
{
break;
}
else if (nSum == nSplitNum)
{
if (!bFirst)
{
cout << ",";
}
bFirst = false;
//如果相等,迴圈輸出序列
for (int k = i; k <= j; k++)
{
cout << k;
if (k != j)
{
cout << " "; //序列最後一個數字時,不用輸出“ ”
}
}
bFlag = true;
break;
}
}
}
if (!bFlag)
{
cout << "NONE" << endl;
return 1;
}
cout << endl;
system("pause");
return 0;
}
輸出結果如圖:
至此,終於提示測試全部通過!不過,這卻影響到了我的面試結果。。。。。。
簡簡單單的題目,在機考時卻幾經波折,可見在機考時,不僅要確保程式碼正確,還要嚴格按照給出的輸入輸出格式進行顯示。在普通的筆試中,只要關鍵程式碼部分寫對了,面試官一般就會認為你掌握相應的知識了,所以機考的難度明顯要大於筆試的難度。同時機考時需要注意一些更加細節的地方,由於是機器判卷,只要稍有不合理其規則的地方,就會導致全部被判斷出錯,就比如我這裡第二份程式碼中的“請輸入一個大於0並且不大於100的整數”這樣的一個提示,在平時的Win32程式編寫中,加上這個提示會顯得人性化一點,但是這道題裡已經給出了樣例輸入,如果加了那麼肯定就錯了。因此,在機考時還要注意自己在平時的一些程式設計習慣是否和題目的要求相吻合。