【筆試題】網易2018秋招內推筆試
今天下午3點到五點做了網易秋招內推筆試題,晚上的時候牛妹就把程式設計題的答案發出來了,聽說有幾萬人參加了,嚇死。。。。。感覺自己太弱。
下面是我做的三道筆試題,一共有八道。。。。。
題目一
問題描述
小易有一個長度為n的整數序列,a_1,…,a_n。然後考慮在一個空序列b上進行n次以下操作:
1、將a_i放入b序列的末尾
2、逆置b序列
小易需要你計算輸出操作n次之後的b序列。
輸入描述
輸入包括兩行,第一行包括一個整數n(2 ≤ n ≤ 2*10^5),即序列的長度。
第二行包括n個整數a_i(1 ≤ a_i ≤ 10^9),即序列a中的每個整數,以空格分割。
輸出描述
在一行中輸出操作n次之後的b序列,以空格分割,行末無空格。
注意:要看一下輸入輸出描述,確定一下,不按要求的話,oj通不過
分析問題
我當初做的時候,通過率才80%。。。。。
例子有兩種,
個數為奇數:3 (1,2,3)
1,翻轉 1,
1,2翻轉 2,1
2,1,3翻轉 3,1,2
最後的結果是 3,1,2
個數為偶數時,4(1,2,3,4)
3,1,2,4翻轉後 4,2,1,3
觀察上面的結果
奇數的時候,先寫1,然後把2放在1的後面,然後把3放在1的前面(先後面,再前面)
偶數的時候,先寫1,然後把2放在1的前面,3放在後面,4放在前面,(先前面,再後面)。
發現,自己的錯誤,只分析了一種情況,,,,還以為是邊界之類的問題
本人AC程式碼
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
int *arr = new int[n];
for (int i = 0; i < n; i++)
cin >> arr[i];
std::list<int> list;
list.push_back(arr[0]);
//奇數,先後面,再前面
if(n %2 == 1)
{
for (int i = 1; i < n; ++i)
{
if (i % 2 == 1)
list.push_back(arr[i]);
else
list.push_front(arr[i]);
}
}
//偶數 先前面,再後面
else
{
for (int i = 1; i < n; ++i)
{
if (i % 2 == 1)
list.push_front(arr[i]);
else
list.push_back(arr[i]);
}
}
//注意:輸出格式要與題目的輸出格式匹配。
int idx = 0;
for (; idx < n - 1; ++idx)
{
cout << list.front() << " ";
list.pop_front();
}
cout << list.front() << endl;
delete[] arr;
return 0;
}
大神的AC程式碼
對比,自己的程式碼,發現自己low啊,寫這麼多的程式碼,解決這個問題。自己的思路太複雜了
大神的思路是:
個數是奇數的時候:奇數放在左邊,偶數放在右邊
個數是偶數的時候:偶數放在左邊,奇數放在右邊
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5; //邊界問題
int a[maxn];
int n;
int main()
{
scanf("%d", &n);
//注意::從1開始,儲存的
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
if(n % 2) // 4,2,1,3
{ //先輸出 4 2
for(int i = n; i >= 1; i -= 2)
printf("%d ", a[i]);
//控制輸出空格,最後一個沒有輸出空格
for(int i = 2; i <= n; i += 2)
i == n - 1 ? printf("%d", a[i]) : printf("%d ", a[i]);
}
else //3,1,2
{
for(int i = n; i >= 1; i -= 2)
printf("%d ", a[i]);
for(int i = 1; i <= n; i += 2)
i == n - 1 ? printf("%d", a[i]) : printf("%d ", a[i]);
}
printf("\n");
return 0;
}
問題二
問題描述
小易現在手裡有f個水果和d元,一天要消耗x元房租和1個水果,商店售賣一個水果p元,請問小易能堅持幾天。
問題分析
簡單的一批,,,呵呵,本菜雞通過率才70%。。。(一把辛酸)
(原來是,沒考慮一天也活不下去。。。。還是弱)
計算1天花多少錢:x+p
先計算能不能活f天,(看d元夠不夠f天的房租)
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x, f, d, p;//房租,水果個數,錢,水果價錢
while (cin >> x >> f >> d >> p)
{
if (x < 1)
return -1;
int onespend = x + p; //一天花費
//先判斷能不能活f天
int day = d / x;
if (day <= f)
{
cout << day;
return 0;
}
d -= f*x;
day = f + d / onespend;
cout << day;
}
return 0;
}
問題三
問題描述
瘋狂佇列,就是給一個數字,要求他們得兩兩的差值和最大,求這個瘋狂值,即:差值。
輸入描述
輸入包括兩行,第一行一個整數n(1 ≤ n ≤ 50),表示學生的人數
第二行為n個整數h[i](1 ≤ h[i] ≤ 1000),表示每個學生的身高
輸出描述
如樣例所示: 5 10 25 40 25
當佇列排列順序是: 25-10-40-5-25, 身高差絕對值的總和為15+30+35+20=100。
這是最大的瘋狂值了
分析問題
要想差值最大,先把最大值放上,然後把兩個最小值,放在左右兩邊,
再將兩個次大值,放在兩個最小值的兩邊。
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
while(cin>>n)
{
vector<int> v(n,0);
for(int i=0;i<n;i++)
{
cin>>v[i];
}
if(n==1)
{
cout<<0<<endl;
}
sort(v.begin(),v.end());
deque<int> d;
int l=0,r=n-1;
d.push_front(v[r]);
r--;
while(l<=r)
{
if(l<=r)
{
d.push_front(v[l++]);
if(l<=r)
d.push_back(v[l++]);
}
if(l<=r)
{
d.push_front(v[r--]);
if(l<=r)
d.push_back(v[r--]);
}
}
//最後一個元素可能會錯位,剩餘中間的三個數字
//{ 10, 15, 30, 45, 50, 60, 70, 90 };
//45-30-10-90-15-60-50
if(abs(d[n-1]-d[n-2])<abs(d[n-1]-d[0])){
d.push_front(d.back());
d.pop_back();
}
int res=0;
for(int i=1;i<n;i++){
res+=abs(d[i]-d[i-1]);
}
cout<<res<<endl;
}
return 0;
}
大神AC程式碼
根據樣例提示,猜想了一個結論:
我們要把這個佇列安排為交錯的形式(證明略)。
交錯有兩種形式,看第一個人是比他相鄰的人高還是矮。
以矮的為例:
總共的瘋狂值為(h2 - h1) + (h2 - h3) + (h4 - h3) + … = -h1 + 2h2 - 2h3 + 2h4 - …,
如果總共是偶數個人,瘋狂值為-h1 + 2h2 - 2h3 + 2h4 - … - 2h{n-1} + h{n},所以我們需要從最大的開始依次安排h2,…h{n-2},然後安排h{n},然後繼續安排剩下的。
如果總共是奇數個人,瘋狂值為-h1 + 2h2 - 2h3 + 2h4 - … + 2h{n-1} - h{n},所以我們需要從最大的開始依次安排h2,…h{n-1},然後安排h1和h{n},然後繼續安排剩下的。
然後另外一種形式類似,維護最大的瘋狂值即可
#include <bits/stdc++.h>
using namespace std
int h[55];
int n;
int main()
{
cin >> n;
for(int i = 0; i < n; i++)
cin >> h[i];
sort(h, h + n);
int tmp, ans = 0, ans1 = 0, ans2 = 0;
if(n % 2 == 0)
{
tmp = n / 2;
for(int i = 0; i < tmp; i++)
{
ans += 2 * (h[tmp + i] - h[i]);
}
ans += h[tmp - 1] - h[tmp];
cout << ans << endl;
return 0;
}
else
{
tmp = n / 2;
for(int i = 0; i < tmp; i++)
{
ans1 += 2 * (h[tmp + 1 + i] - h[i]);
ans2 += 2 * (h[tmp + 1 + i] - h[i]);
}
ans1 += -h[tmp] + h[tmp - 1];
ans2 += h[n] - h[n + 1];
cout << max(ans1, ans2) << endl;
return 0;
}
return 0;
}
問題四
問題描述
判斷數列能否是等差數列,
分析:先排序,然後再比較差值。
#include <bits/stdc++.h>
using namespace std;
int n;
int arr[55];
string solve(){
sort(arr,arr+n);
if(n < 2)
return "Possible";
else{
int d = arr[1] - arr[0];
for(int i = 2; i < n; ++i){
if(arr[i] - arr[i-1] != d)
return "Impossible";
}
}
return "Possible";
}
int main(){
cin >> n;
for(int i = 0; i < n; i++)
cin >> arr[i];
cout << solve() << endl;
}
問題五
s = “ABAB”,那麼小易有六種排列的結果:
“AABB”,”ABAB”,”ABBA”,”BAAB”,”BABA”,”BBAA”
其中只有”AABB”和”BBAA”滿足最多隻有一對不同顏色的相鄰磚塊。
分析
思路就是看字串裡有幾種字元,超過兩種就不可能只有一對相鄰的不同字元,有兩種字元就是兩種正確的排列,有一種字元自然就是一種正確的排列。
就是先排序,然後過濾掉重複的,或者直接把字元放在set中,set預設不能插入相同的值。
int main()
{
string str;
cin >> str;
sort(str.begin(), str.end());
str.erase(unique(str.begin(), str.end()), str.end());
size_t ans = str.size();
if (ans > 2)
ans = 0;
cout << ans << endl;
return 0;
}
問題六
問題描述
如果一個01串任意兩個相鄰位置的字元都是不一樣的,我們就叫這個01串為交錯01串。例如: “1”,”10101”,”0101010”都是交錯01串。
輸入包括字串s,s的長度length(1 ≤ length ≤ 50),字串中只包含’0’和’1’,求出最大字串是01串的長度。
思路:就是按個比較字串,維護最大值。
int main()
{
string str;
cin >> str;
int len = 1, ans = 1;
for (int i = 1; i < str.size(); ++i)
{
if (str[i] != str[i - 1])
len++;
else
len = 1;
}
ans = max(ans, len);
cout << ans << endl;
return 0;
}
問題七
問題描述
小易將n個棋子擺放在一張無限大的棋盤上。第i個棋子放在第x[i]行y[i]列。同一個格子允許放置多個棋子。每一次操作小易可以把一個棋子拿起並將其移動到原格子的上、下、左、右的任意一個格子中。小易想知道要讓棋盤上出現有一個格子中至少有i(1 ≤ i ≤ n)個棋子所需要的最少操作次數.
輸入描述
輸入包括三行,第一行一個整數n(1 ≤ n ≤ 50),表示棋子的個數
第二行為n個棋子的橫座標x[i](1 ≤ x[i] ≤ 10^9)
第三行為n個棋子的縱座標y[i](1 ≤ y[i] ≤ 10^9)
4
1 2 4 9
1 1 1 1
輸出描述
輸出n個整數,第i個表示棋盤上有一個格子至少有i個棋子所需要的運算元,以空格分割。行末無空格
0 1 3 10
如樣例所示:
對於1個棋子: 不需要操作
對於2個棋子: 將前兩個棋子放在(1, 1)中
對於3個棋子: 將前三個棋子放在(2, 1)中
對於4個棋子: 將所有棋子都放在(3, 1)中
暴力列舉,嘗試每個節點
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int INTMAX = 2147483647;
struct Point
{
int x = 0;
int y = 0;
}p[55];
int dis(int x,int y, const Point &b)
{
return abs(x - b.x) + abs(y - b.y);
}
int main()
{
int n, i, j;
cin >> n;
for (i = 1; i <= n; ++i)
{
cin >> p[i].x;
}
for (i = 1; i <= n; ++i)
{
cin >> p[i].y;
}
vector<vector<int>> min_step;
for (int x = 1; x <= n; ++x)
{
for (int y = 1; y <= n; ++y)
{
vector<int> tmp;
for (int k = 1; k <= n; ++k)
{
tmp.push_back(dis(p[x].x, p[y].y, p[k]));
}
sort(tmp.begin(), tmp.end());
min_step.push_back(tmp);
}
}
for (i = 1; i <= n; ++i)
{
int ans = INTMAX;
for (j = 0; j < min_step.size(); ++j)
{
int temp = 0;
for (int k = 0; k < i; ++k)
{
temp += min_step[j][k];
}
ans = min(ans, temp);
}
cout << ans;
if (i != n) cout << " ";
else cout << endl;
}
return 0;
}
問題八
小易非常喜歡擁有以下性質的數列:
1、數列的長度為n
2、數列中的每個數都在1到k之間(包括1和k)
3、對於位置相鄰的兩個數A和B(A在B前),都滿足(A <= B)或(A mod B != 0)(滿足其一即可)
例如,當n = 4, k = 7
那麼{1,7,7,2},它的長度是4,所有數字也在1到7範圍內,並且滿足第三條性質,所以小易是喜歡這個數列的
但是小易不喜歡{4,4,4,2}這個數列。小易給出n和k,希望你能幫他求出有多少個是他會喜歡的數列。
分析問題
可以發現長度為4時的數列是當n為3時數列減去不合法的序列。
定義一個全域性的陣列,記錄每個長度的合法數列的和。
dp[ j ][ i ] 表示長度為i,最後一個數是j的小易喜歡的數列的數量,
dp[j][i] += dp[m][i-1] (1<=m<=k),
判斷非法的情況,直接判斷是約數的情況下,就非法。
const int mod = 1e9 + 7;
const int maxn = 1e5 + 5;
int dp[maxn][15];
int n, k;
int main()
{
cin >> n >> k;//n長度
dp[1][0] = 1;
for (int i = 1; i <= n; i++)
{
int sum = 0;
for (int j = 1; j <= k; j++)
{
sum += dp[j][i - 1];
sum %= mod;
}
for (int j = 1; j <= k; j++)
{
int sum2 = 0;//非法的,約數的時候是非法的
for (int z = j + j; z <= k; z += j)
{
sum2 += dp[z][i - 1];
sum2 %= mod;
}
dp[j][i] = (sum - sum2 + mod) % mod;
}
}
int ans = 0;
for (int j = 1; j <= k; j++)
{
ans += dp[j][n];
ans %= mod;
}
cout << ans << endl;
return 0;
}