1. 程式人生 > >騰訊2016春招模擬筆試題 —— 程式設計題(3道)

騰訊2016春招模擬筆試題 —— 程式設計題(3道)

寫在前面的話~

      春招 + 模擬筆試  【C++研發】

      模擬筆試時間是    2016-03-25   21:30 ~ 22:30   

      試題主要包括兩部分:不定項選擇 + 程式設計  分別計時 時間都是30分鐘。(逃~。。。

         前面的不定項選擇15道 大部分都是往年的題 所以我基本上15分鐘就提交了。。。(然~。。。

         程式設計題有三道 印象中前兩道好像也是往年的題      第三道以前見過 (但。。。

         不思考 30分鐘三道題完全不夠用。 第三道題基本上就要20分鐘

          很顯然 前兩道 10分鐘

          最後一道 寫了一大半 然後就沒有然後 被自動提交 提交。。。

          還有現在的OJ怎麼不給除錯了。。沒有測試用例了。。

          唉  不說了~

-------------------我是分割線----------------------------

上題目(只記得題目大意了 大家將就看哈~):

第一題(n位格雷碼)

在一組數的編碼中,若任意兩個相鄰的程式碼只有一位二進位制數不同, 則稱這種編碼為格雷碼(Gray Code),請編寫一個函式,使用遞迴的方法生成N位的格雷碼。

給定一個整數n,請返回n位的格雷碼,順序為從0開始。

測試樣例:
1
返回:["0","1"]

分析:

首先需要知道格雷碼 n位格雷碼最後返回2^n個元素。

另外,注意題意要求用遞迴求解。

上個圖(from WIKI) 程式碼的思路可參考該圖。

Leetcode上也有一道題89. Gray Code可以做一下。


程式碼如下:

vector<string> getGray(int n) 
{
	vector<string> v;
	if(n == 1)
	{
		v.push_back("0");
		v.push_back("1");

		return v;
	}
	else
	{
		vector<string> v = getGray(n - 1);
		int vSize = v.size();

		vector<string> v2;

		for(int i = 0; i < vSize; i++)
		{
			if(i % 2 == 0)
			{
				v2.push_back(v[i]+"0");
				v2.push_back(v[i]+"1");
			}
			else
			{
				v2.push_back(v[i]+"1");
				v2.push_back(v[i]+"0");
			}
		}

		return v2;
	}
}

第二題(微信紅包)

春節期間小明使用微信收到很多個紅包,非常開心。在檢視領取紅包記錄時發現,某個紅包金額出現的次數超過了紅包總數的一半。請幫小明找到該紅包金額。寫出具體演算法思路和程式碼實現,要求演算法儘可能高效。

給定一個紅包的金額陣列gifts及它的大小n,請返回所求紅包的金額。

測試樣例:
[1,2,3,2,2],5
返回:2
分析:

使用雜湊當然可以求解,但並不是最優的。

這道題最優的解法類似 《程式設計之美》中"尋找水王"的問題,複雜度為 O(n) O(1)。

設定一個輔助變數cnt 記錄元素出現的次數 假設出現次數大於一半的元素為 target 。

在遍歷陣列元素的過程中,如果元素與target不等,那麼cnt--,否則cnt++;

當cnt<0時,說明目前找到的target肯定不是最終的結果 同時更新target為當前遍歷到元素。

最終遍歷完陣列 剩下的那個就是要找的目標target。

【注:這裡需要注意的是 上面這個思路只能確定出現次數最多的元素 但並不一定是出現次數

超過一半的數,因此一定要驗證一下 否則測試用例不能全部通過】。

程式碼如下:

int getValue(vector<int> gifts, int n) {
		if (n <= 0) return 0;

		int vSize = gifts.size();

		int res = -1, cnt = 0;
		for(int idx = 0; idx < vSize; ++idx)
		{
			if (cnt == 0)
			{
				res = gifts[idx];
				cnt++;
			}

			if (gifts[idx] != res) cnt--;
			else cnt++;
		}

		// 這裡最好驗證一下
		// 如果某個數字出現次數最多 但是並沒有出現超過總數一半
		cnt = 0;
		for (int i = 0; i < vSize; i++)
		{
			if (gifts[i] == res) cnt++;
		}

		return (cnt > vSize/2) ? res : 0;
	}


第三題(大數乘法)

大數乘法題。

給出2個大整數num1, num2,計算num1*num2的結果。

【大數的長度不超過1000  且 > 0(?)  原諒我不太記得是不是大於0】

下面的程式碼按大於0處理。。

分析:

如果是java 自帶了大數類 BigInteger 程式碼不超過10行。。。

(也貼一下程式碼 個人不太擅長java)

import java.util.Scanner;
import java.math.BigInteger;
public class Main
{
	public static void main(String args[])
	{
		Scanner cin = new Scanner(System.in);
		BigInteger a, b;

		while (cin.hasNext())
		{
			a = cin.nextBigInteger();
			b = cin.nextBigInteger();
			System.out.println(a.multiply(b).toString());
		}
	}
}
下面主要分析如果沒有系統庫提供的類,如何實現上面的大數乘法。

【高階的FFT求解大數問題不在這裡的討論範圍】

我們可以模擬乘法實現的過程。

比如:123 * 456

6 分別與3 2 1 相乘。

接著是

5 與 3 2 1相乘。

4 與 3 2 1相乘。

程式碼如下:

#include <iostream>
#include <string>
#include <vector>

using namespace std;

string big_number_multiply(string a, string b)
{
	int a_len = a.length(), b_len = b.length(), len = a_len + b_len;
	vector<int> c(a_len + b_len, 0);

	len = a_len + b_len;
	for (int i = 0; i < b_len; ++i)
	{
		for (int j = 0; j < a_len; ++j)
		{
			c[i + j] += (b[b_len - i - 1] - '0') * (a[a_len - j - 1] - '0');
		}
	}

	string res;
	res.resize(len);
	
	int inc = 0;		// 進位
	for (int i = 0; i < len; ++i)
	{
		c[i] += inc;
		inc = c[i] / 10;
		c[i] %= 10;
		
		res = (char)(c[i] + '0') + res;
	}

	if (inc != 0)
	{
		res = (char)(inc + '0') + res;
	}

	// 最高位為0 需要去除
	int idx = 0;
	while (res[idx] == '0') idx++;

	return res.substr(idx, res.size());
}
int main(void)
{
	string s1, s2;

	cin >> s1 >> s2;
	cout << big_number_multiply(s1, s2) << endl;

	return 0;
}