文章目錄
騰訊2018春招技術類編程題彙總
1、翻轉數列
小Q定義了一種數列稱爲翻轉數列:
給定整數n和m, 滿足n能被2m整除。對於一串連續遞增整數數列1, 2, 3, 4…, 每隔m個符號翻轉一次, 最初符號爲’-’;。
例如n = 8, m = 2, 數列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 數列就是: -1, +2, -3, + 4.
小Q現在希望你能幫他算算前n項和爲多少。
輸入描述:
輸入包括兩個整數n和m(2 <= n <= 109, 1 <= m), 並且滿足n能被2m整除。
輸出描述:
輸出一個整數, 表示前n項和。
輸入例子1:
8 2
輸出例子1:
8
#include <iostream>
using namespace std;
// 暴力法 case通過率爲80.00%,超時
long long fun(int n, int m) {
long long res = 0;
int k = 0, flag = -1;
for (int i = 0; i < n/m; i++){
for (int j = 0; j < m; j++){
k = flag * (abs(k) + 1);
res += k;
}
flag *= -1;
}
return res;
}
// 找規律:第一個加號值加上第一個減號值,差值剛好是m,共有n/2對
// -1, -2, +3, +4, -5, -6, +7, +8
long long fun2(int n, int m) {
return n/2*m;
}
int main() {
int n, m;
cin >> n >> m;
cout << fun2(n,m) << endl;
return 0;
}
2、紙牌遊戲
牛牛和羊羊正在玩一個紙牌遊戲。這個遊戲一共有n張紙牌, 第i張紙牌上寫着數字ai。
牛牛和羊羊輪流抽牌, 牛牛先抽, 每次抽牌他們可以從紙牌堆中任意選擇一張抽出, 直到紙牌被抽完。
他們的得分等於他們抽到的紙牌數字總和。
現在假設牛牛和羊羊都採用最優策略, 請你計算出遊戲結束後牛牛得分減去羊羊得分等於多少。
輸入描述:
輸入包括兩行。
第一行包括一個正整數n(1 <= n <= 105),表示紙牌的數量。
第二行包括n個正整數ai(1 <= ai <= 109),表示每張紙牌上的數字。
輸出描述:
輸出一個整數, 表示遊戲結束後牛牛得分減去羊羊得分等於多少。
輸入例子1:
3
2 7 4
輸出例子1:
5
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
int main(){
int n;
cin >> n;
priority_queue<int, vector<int>,less<int>> card;
int t;
for (int i = 0; i < n; i++){
cin >> t;
card.push(t);
}
int res = 0;
int flag = 1;
while (!card.empty()){
int c = card.top();
res += flag*c;
flag *= -1;
card.pop();
}
cout << res << endl;
return 0;
}
3、貪喫的小Q
小Q的父母要出差N天,走之前給小Q留下了M塊巧克力。小Q決定每天喫的巧克力數量不少於前一天喫的一半,但是他又不想在父母回來之前的某一天沒有巧克力喫,請問他第一天最多能喫多少塊巧克力
輸入描述:
每個輸入包含一個測試用例。
每個測試用例的第一行包含兩個正整數,表示父母出差的天數N(N<=50000)和巧克力的數量M(N<=M<=100000)。
輸出描述:
輸出一個數表示小Q第一天最多能喫多少塊巧克力。
輸入例子1:
3 7
輸出例子1:
4
#include <iostream>
#include <cmath>
using namespace std;
int fun(int n, int m){
int start = ceil(m / 2.0);
for (int i = start; i >= 1; i--){
int t = 0;
int ti = i;
for (int j = 0; j < n; j++){
t += ti;
if (ti != 1)
ti = ceil(ti / 2.0);
}
if (t <= m)
return i;
}
return 0;
}
int main(){
int n, m;
cin >> n >> m;
if (n == 1)
cout << m << endl;
else
cout << fun(n, m) << endl;
return 0;
}
4、小Q的歌單
小Q有X首長度爲A的不同的歌和Y首長度爲B的不同的歌,現在小Q想用這些歌組成一個總長度正好爲K的歌單,每首歌最多隻能在歌單中出現一次,在不考慮歌單內歌曲的先後順序的情況下,請問有多少種組成歌單的方法。
輸入描述:
每個輸入包含一個測試用例。
每個測試用例的第一行包含一個整數,表示歌單的總長度K(1<=K<=1000)。
接下來的一行包含四個正整數,分別表示歌的第一種長度A(A<=10)和數量X(X<=100)以及歌的第二種長度B(B<=10)和數量Y(Y<=100)。保證A不等於B。
輸出描述:
輸出一個整數,表示組成歌單的方法取模。因爲答案可能會很大,輸出對1000000007取模的結果。
輸入例子1:
5
2 3 3 3
輸出例子1:
9
#include <iostream>
#include <vector>
using namespace std;
// n選k組合數C(n,k) = C(n-1,k) + C(n-1,k-1)
void CreatSelect(vector<vector<long long>> &arr){
arr[0][0] = 1;
for (int i = 1; i <= 100; i++){
arr[i][0] = 1;
for (int j = 1; j <= 100; j++){
arr[i][j] = (arr[i - 1][j] + arr[i - 1][j - 1] )% 1000000007;
}
}
}
long long fun(int k, int a, int x, int b, int y, vector<vector<long long>> arr){
long long res = 0;
for (int i = 0; i <= k / a && i <= x; i++){
if ((k - a*i) % b == 0 && (k - a*i) / b <= y){
// x裏選i個a,y裏選(k - a*i) / b個b
res = (res + arr[x][i] * arr[y][(k - a*i) / b] % 1000000007) % 1000000007;
}
}
return res;
}
int main(){
int k;
cin >> k;
int a, b, x, y;
cin >> a >> x >> b >> y;
vector<vector<long long>> arr(101, vector<long long>(101));
CreatSelect(arr);
cout << fun(k, a, x, b, y, arr) << endl;
return 0;
}
5、安排機器
小Q的公司最近接到m個任務, 第i個任務需要xi的時間去完成, 難度等級爲yi。
小Q擁有n臺機器, 每臺機器最長工作時間zi, 機器等級wi。
對於一個任務,它只能交由一臺機器來完成, 如果安排給它的機器的最長工作時間小於任務需要的時間, 則不能完成,如果完成這個任務將獲得200 * xi + 3 * yi收益。
對於一臺機器,它一天只能完成一個任務, 如果它的機器等級小於安排給它的任務難度等級, 則不能完成。
小Q想在今天儘可能的去完成任務, 即完成的任務數量最大。如果有多種安排方案,小Q還想找到收益最大的那個方案。小Q需要你來幫助他計算一下。
輸入描述:
輸入包括N + M + 1行,
輸入的第一行爲兩個正整數n和m(1 <= n, m <= 100000), 表示機器的數量和任務的數量。
接下來n行,每行兩個整數zi和wi(0 < zi < 1000, 0 <= wi <= 100), 表示每臺機器的最大工作時間和機器等級。
接下來的m行,每行兩個整數xi和yi(0 < xi < 1000, 0 <= yi<= 100), 表示每個任務需要的完成時間和任務的難度等級。
輸出描述:
輸出兩個整數, 分別表示最大能完成的任務數量和獲取的收益。
輸入例子1:
1 2
100 3
100 2
100 1
輸出例子1:
1 20006
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
struct Node {
int time, grade;
};
bool Cmp(const Node &a, const Node &b) {
if (a.time == b.time)
return a.grade > b.grade;
return a.time > b.time;
}
// case通過率爲90.00%,超時
int main() {
int n, m; //機器的數量和任務的數量 1 <= n, m <= 100000
cin >> n >> m;
vector<Node> machine(n);
vector<Node> task(m);
for (int i = 0; i < n; i++){
cin >> machine[i].time >> machine[i].grade;
}
for (int i = 0; i < m; i++){
cin >> task[i].time >> task[i].grade;
}
sort(machine.begin(), machine.end(), Cmp);
sort(task.begin(), task.end(), Cmp);
int res = 0, value = 0;
bool* flag = new bool[n];
memset(flag, true, n);
for (int i = 0; i < m; i++){
int min_grade = 101;
int min_j;
for (int j = 0; j < n; j++){
if (flag[j]){
if (task[i].time <= machine[j].time){
if (task[i].grade <= machine[j].grade && machine[j].grade < min_grade){
min_grade = machine[j].grade;
min_j = j;
}
}
else{
break;
}
}
}
if (min_grade != 101){
res++;
value += 200 * task[i].time + 3 * task[i].grade;
flag[min_j] = false;
}
}
delete[] flag;
cout << res << " " << value << endl;
return 0;
}
6、畫家小Q
畫家小Q又開始他的藝術創作。小Q拿出了一塊有NxM像素格的畫板, 畫板初始狀態是空白的,用’X’表示。
小Q有他獨特的繪畫技巧,每次小Q會選擇一條斜線, 如果斜線的方向形如’/’,即斜率爲1,小Q會選擇這條斜線中的一段格子,都塗畫爲藍色,用’B’表示;如果對角線的方向形如’’,即斜率爲-1,小Q會選擇這條斜線中的一段格子,都塗畫爲黃色,用’Y’表示。
如果一個格子既被藍色塗畫過又被黃色塗畫過,那麼這個格子就會變成綠色,用’G’表示。
小Q已經有想畫出的作品的樣子, 請你幫他計算一下他最少需要多少次操作完成這幅畫。
輸入描述:
每個輸入包含一個測試用例。
每個測試用例的第一行包含兩個正整數N和M(1 <= N, M <= 50), 表示畫板的長寬。
接下來的N行包含N個長度爲M的字符串, 其中包含字符’B’,‘Y’,‘G’,‘X’,分別表示藍色,黃色,綠色,空白。整個表示小Q要完成的作品。
輸出描述:
輸出一個正整數, 表示小Q最少需要多少次操作完成繪畫。
輸入例子1:
4 4
YXXB
XYGX
XBYY
BXXY
輸出例子1:
3
例子說明1:
XXXX
XXXX
XXXX
XXXX
->
YXXX
XYXX
XXYX
XXXY
->
YXXB
XYBX
XBYX
BXXY
->
YXXB
XYGX
XBYY
BXXY
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int n, m; //N和M(1 <= N, M <= 50), 表示畫板的長寬
vector<vector<char>> arr;
void fun_b(int i, int j){
if (i >= 0 && i < n && j >= 0 && j < m && (arr[i][j] == 'B' || arr[i][j] == 'G')){
if (arr[i][j] == 'B')
arr[i][j] = 'X';
else
arr[i][j] = 'Y';
fun_b(i - 1,j + 1);
fun_b(i + 1, j - 1);
}
return;
}
void fun_y(int i, int j){
if (i >= 0 && i < n && j >= 0 && j < m && (arr[i][j] == 'Y' || arr[i][j] == 'G')){
if (arr[i][j] == 'Y')
arr[i][j] = 'X';
else
arr[i][j] = 'B';
fun_y(i + 1, j + 1);
fun_y(i - 1, j - 1);
}
return;
}
/*
YXXB
XYGX
XBYY
BXXY
*/
int fun() {
int res = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (arr[i][j] == 'B'){
fun_b(i, j);
res++;
}
if (arr[i][j] == 'Y'){
fun_y(i, j);
res++;
}
if (arr[i][j] == 'G'){
fun_b(i, j);
fun_y(i, j);
res += 2;
}
}
}
return res;
}
int main() {
cin >> n >> m;
arr = vector<vector<char>> (n, vector<char>(m));
string str;
for (int i = 0; i < n; i++){
cin >> str;
for (int j = 0; j < m; j++){
arr[i][j] = str[j];
}
}
cout << fun() << endl;
return 0;
}
騰訊2017秋招筆試編程題
1、編碼
假定一種編碼的編碼範圍是a ~ y的25個字母,從1位到4位的編碼,如果我們把該編碼按字典序排序,形成一個數組如下: a, aa, aaa, aaaa, aaab, aaac, … …, b, ba, baa, baaa, baab, baac … …, yyyw, yyyx, yyyy 其中a的Index爲0,aa的Index爲1,aaa的Index爲2,以此類推。 編寫一個函數,輸入是任意一個編碼,輸出這個編碼對應的Index.
輸入描述:
輸入一個待編碼的字符串,字符串長度小於等於100.
輸出描述:
輸出這個編碼的index
輸入例子1:
baca
輸出例子1:
16331
#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<int> loop = { 0, 1, 26, 651, 16276 };
int fun(string str) {
int res = 0, len = str.size();
for (int i = 0; i < len; i++){
res += (str[i] - 'a')*loop[4 -i]+1;
}
return res-1;
}
int main() {
string str;
while (cin >> str){
cout << fun(str) << endl;
}
return 0;
}
2、遊戲任務標記
遊戲裏面有很多各式各樣的任務,其中有一種任務玩家只能做一次,這類任務一共有1024個,任務ID範圍[1,1024]。請用32個unsigned int類型來記錄着1024個任務是否已經完成。初始狀態都是未完成。 輸入兩個參數,都是任務ID,需要設置第一個ID的任務爲已經完成;並檢查第二個ID的任務是否已經完成。 輸出一個參數,如果第二個ID的任務已經完成輸出1,如果未完成輸出0。如果第一或第二個ID不在[1,1024]範圍,則輸出-1。
輸入描述:
輸入包括一行,兩個整數表示人物ID.
輸出描述:
輸出是否完成
輸入例子1:
1024 1024
輸出例子1:
1
#include <iostream>
using namespace std;
unsigned int flag[32];
// unsigned int爲32位,32個unsigned int爲32*32=1024
int fun(int n, int m) {
// Index(N) = N / 32 = N >> 5;
// Position(N) = N % 32 = N & 31; (對於2的冪的數才能)
int index, position;
index = (n - 1) >> 5;
position = (n-1) & 31;
flag[index] |= 1 << position;
if (m >= 1 && m <= 1024){
index = (m - 1) >> 5;
position = (m - 1) & 31;
return (flag[index]&(1<<position))!=0;
}
return -1;
}
int main() {
int n,m;
cin >> n >> m;
cout << fun(n, m) << endl;
return 0;
}
3、素數對
給定一個正整數,編寫程序計算有多少對質數的和等於輸入的這個正整數,並輸出結果。輸入值小於1000。
如,輸入爲10, 程序應該輸出結果爲2。(共有兩對質數的和爲10,分別爲(5,5),(3,7))
輸入描述:
輸入包括一個整數n,(3 ≤ n < 1000)
輸出描述:
輸出對數
輸入例子1:
10
輸出例子1:
2
#include <iostream>
using namespace std;
// 質數:只能被1和本身整除,最小質數爲2
bool is_zhishu(int x) {
for (int i = 2; i*i <= x; i++){
if (x%i == 0)
return false;
}
return true;
}
int fun(int n) {
int res = 0;
for (int i = 2; i <= n / 2; i++){
if (is_zhishu(i) && is_zhishu(n - i))
res++;
}
return res;
}
int main() {
int n;
cin >> n;
cout << fun(n) << endl;
return 0;
}
4、geohash編碼
geohash編碼:geohash常用於將二維的經緯度轉換爲字符串,分爲兩步:第一步是經緯度的二進制編碼,第二步是base32轉碼。
此題考察緯度的二進制編碼:算法對緯度[-90, 90]通過二分法進行無限逼近(取決於所需精度,本題精度爲6)。注意,本題進行二分法逼近過程中只採用向下取整來進行二分,針對二分中間值屬於右區間。算法舉例如下: 針對緯度爲80進行二進制編碼過程:
- 區間[-90, 90]進行二分爲[-90, 0),[0, 90],成爲左右區間,可以確定80爲右區間,標記爲1;
- 針對上一步的右區間[0, 90]進行二分爲[0, 45),[45, 90],可以確定80是右區間,標記爲1;
- 針對[45, 90]進行二分爲[45, 67),[67,90],可以確定80爲右區間,標記爲1;
- 針對[67,90]進行二分爲[67, 78),[78,90],可以確定80爲右區間,標記爲1;
- 針對[78, 90]進行二分爲[78, 84),[84, 90],可以確定80爲左區間,標記爲0;
- 針對[78, 84)進行二分爲[78, 81), [81, 84),可以確定80爲左區間,標記爲0;
輸入描述:
輸入包括一個整數n,(-90 ≤ n ≤ 90)
輸出描述:
輸出二進制編碼
輸入例子1:
80
輸出例子1:
111100
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
// -66
string fun(int n) {
string res;
int k = 0;
int l = -90, r = 90;
while (k != 6){
int mid = floor((l + r) / 2.0);
if (mid <= n){
res.push_back('1');
l = mid;
}
else{
res.push_back('0');
r = mid;
}
k++;
}
return res;
}
string fun2(int n) {
string res;
int k = 0;
int l = -90, r = 90;
while (k != 6){
int mid = l + r > 0 ? floor((l + r) / 2.0) : -floor(-(l + r) / 2.0);
if (mid <= n){
res.push_back('1');
l = mid;
}
else{
res.push_back('0');
r = mid;
}
k++;
}
return res;
}
int main() {
int n; // (-90 ≤ n ≤ 90)
cin >> n;
cout << fun2(n) << endl;
return 0;
}
注:題中向下取整存在歧義
騰訊2017暑期實習生編程題
1、構造迴文
給定一個字符串s,你可以從中刪除一些字符,使得剩下的串是一個迴文串。如何刪除才能使得迴文串最長呢?
輸出需要刪除的字符個數。
輸入描述:
輸入數據有多組,每組包含一個字符串s,且保證:1<=s.length<=1000.
輸出描述:
對於每組數據,輸出一個整數,代表最少需要刪除的字符個數。
輸入例子1:
abcda
google
輸出例子1:
2
2
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
// 求原字符串和其反串的最大公共子序列的長度
int fun(string s1, string s2) {
if (s1.size() == 1) return 1;
int len = s1.size();
vector<vector<int>> arr(len + 1, vector<int>(len + 1));
for (int i = 0; i <= len; i++){
for (int j = 0; j <= len; j++){
if (i == 0 || j == 0){
arr[i][j] =0;
}
else if (s1[i-1] == s2[j-1]){
arr[i][j] = arr[i - 1][j - 1] + 1;
}
else{
arr[i][j] = max(arr[i][j - 1], arr[i-1][j]);
}
}
}
return arr[len][len];
}
int main() {
string s; // 1 <= s.length <= 1000
while (cin >> s){
string s2 = s;
reverse(s2.begin(), s2.end());
cout << s.size()-fun(s,s2) << endl;
}
return 0;
}
2、算法基礎-字符移位
小Q最近遇到了一個難題:把一個字符串的大寫字母放到字符串的後面,各個字符的相對位置不變,且不能申請額外的空間。
你能幫幫小Q嗎?
輸入描述:
輸入數據有多組,每組包含一個字符串s,且保證:1<=s.length<=1000.
輸出描述:
對於每組數據,輸出移位後的字符串。
輸入例子1:
AkleBiCeilD
輸出例子1:
kleieilABCD
#include <iostream>
#include <string>
using namespace std;
bool is_upper(char c){
return c >= 'A' && c <= 'Z';
}
string fun(string &s) {
if (s.size() == 1) return s;
for (int i = 0; i < s.size(); i++){
if (is_upper(s[i])){
for (int j = i + 1; j < s.size(); j++){
if (!is_upper(s[j])){
int k = j;
char t = s[j];
while (k>i){
s[k] = s[k - 1];
k--;
}
s[i] = t;
break;
}
}
}
}
return s;
}
int main() {
string s; // 1 <= s.length <= 1000
while (cin >> s){
cout << fun(s) << endl;
}
return 0;
}
3、有趣的數字
小Q今天在上廁所時想到了這個問題:有n個數,兩兩組成二元組,相差最小的有多少對呢?相差最大呢?
輸入描述:
輸入包含多組測試數據。
對於每組測試數據:
N - 本組測試數據有n個數
a1,a2…an - 需要計算的數據
保證:
1<=N<=100000,0<=ai<=INT_MAX.
輸出描述:
對於每組數據,輸出兩個數,第一個數表示差最小的對數,第二個數表示差最大的對數。
輸入例子1:
6
45 12 45 32 5 6
輸出例子1:
1 2
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
void fun(int n,vector<int> &vec) {
int min_count = 0, max_count = 0;
if (n > 1){
sort(vec.begin(), vec.end());
if (vec[0] == vec[n - 1]){ // 11111
min_count = n*(n - 1) / 2;
max_count = n*(n - 1) / 2;
}
else{
// min
int min = vec[1] - vec[0];
for (int i = 0; i < n - 1; i++){
if (vec[i + 1] - vec[i] < min){
min = vec[i + 1] - vec[i];
}
}
if (min == 0){ // 11233
int time;
for (int i = 0; i < n; i++){
time = 1;
while (i + 1 < n && vec[i + 1] == vec[i]){
time++;
i++;
}
min_count += time*(time - 1)/2;
}
}
else{ // 12457
for (int i = 0; i < n - 1; i++){
if (vec[i + 1] - vec[i] == min){
min_count++;
}
}
}
// max
int max = vec[n - 1] - vec[0];
int l = 0, r = 0;
for (int i = 0; i < n; i++){
if (vec[i] == vec[0]) l++;
else break;
}
for (int i = n - 1; i >= 0; i--){
if (vec[i] == vec[n-1]) r++;
else break;
}
max_count = l*r;
}
}
cout << min_count << " " << max_count << endl;
}
int main() {
int n;
while (cin >> n){
vector<int> vec(n);
for (int i = 0; i < n; i++){
cin >> vec[i];
}
fun(n, vec);
}
return 0;
}
騰訊2016研發工程師編程題
1、生成格雷碼
在一組數的編碼中,若任意兩個相鄰的代碼只有一位二進制數不同, 則稱這種編碼爲格雷碼(Gray Code),請編寫一個函數,使用遞歸的方法生成N位的格雷碼。
給定一個整數n,請返回n位的格雷碼,順序爲從0開始。
測試樣例:
1
返回:[“0”,“1”]
/*n: 0 1 2 3
0 0 00 000
1 10 100
110
11 010
01
011
111
101
001
*/
class GrayCode {
public:
// 題目不嚴謹case通過率爲9.09%
// 用例:2
// 對應輸出應該爲:["00","01","11","10"]
// 你的輸出爲:["00","10","11","01"]
vector<string> getGray2(int n) {
if (n == 0) return{ "0" };
vector<string> res{ "0", "1" };
for (int i = 1; i < n; i++){
for (int j = 0; j < res.size(); j++){
res[j].push_back('0');
}
for (int j = res.size()-1; j >=0; j--){
string t = res[j];
t[t.size() - 1] = '1';
res.push_back(t);
}
}
return res;
}
vector<string> getGray(int n) {
if (n == 0) return{ "0" };
vector<string> res{ "0", "1" };
for (int i = 1; i < n; i++){
for (int j = 0; j < res.size(); j++){
res[j]='0' + res[j];
}
for (int j = res.size()-1; j >=0; j--){
string t = res[j];
t[0] = '1';
res.push_back(t);
}
}
return res;
}
};
2、微信紅包
春節期間小明使用微信收到很多個紅包,非常開心。在查看領取紅包記錄時發現,某個紅包金額出現的次數超過了紅包總數的一半。請幫小明找到該紅包金額。寫出具體算法思路和代碼實現,要求算法儘可能高效。
給定一個紅包的金額數組gifts及它的大小n,請返回所求紅包的金額。
若沒有金額超過總數的一半,返回0。
測試樣例:
[1,2,3,2,2],5
返回:2
class Gift {
public:
/*
如果重複的次數超過一半的話,一定有相鄰的數字相同這種情況的
對數組同時去掉兩個不同的數字,到最後剩下的一個數就是該數字
*/
int getValue(vector<int> gifts, int n) {
int res = gifts[0], time = 1;
for(int i=1;i<gifts.size();i++){
if(gifts[i]==res) time++;
else{
time--;
if(time == 0){
res = gifts[i];
}
}
}
time = 0;
for(int i=0;i<gifts.size();i++){
if(gifts[i] == res) time++;
}
return time>gifts.size()/2?res:0;
}
};