腾讯2016研发工程师编程题(2道)
2016-07-07 11:58
381 查看
1.生成格雷码
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同, 则称这种编码为格雷码(Gray Code),请编写一个函数,使用递归的方法生成N位的格雷码。给定一个整数n,请返回n位的格雷码,顺序为从0开始。
测试样例:1
返回结果:["0","1"]
方法一:递归法
考点:n位格雷码的排列中,其低n-1位排列是对称的。递归的思想体现在n位gray码由n-1位gray码生成。
举例:
假设求n=3的gray码,首先已知n=2的gray码是(00,01,11,10),那么n=3的gray码其实是对n=2的gray码首位(最高位)添加0或1后生成的。
添加0后变成(000,001,011,010)
添加1后变成(110,111,101,100)(注意逆序)
组合在一起是3位的gray码(000,001,011,010,110,111,101,100)
方法二:非递归法
考点:二进制与对应的格雷码的转换公式:格雷码 = 二进制码^(二进制码右移一位)
2.微信红包
春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。
给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。若没有金额超过总数的一半,返回0。
测试样例:[1,2,3,2,2],5
返回结果:2
方法一:中位数法
如果一个给定的数组中存在一个数字,它的出现次数超过一半,那么将数组排序后这个数字一定出现在中位数的位置。注意结果有可能并不存在这样的数。
方法二:不同数字两两消除法(适用于所求的数字一定存在,见 LeetCode169 Majority Element)
在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同, 则称这种编码为格雷码(Gray Code),请编写一个函数,使用递归的方法生成N位的格雷码。给定一个整数n,请返回n位的格雷码,顺序为从0开始。
测试样例:1
返回结果:["0","1"]
方法一:递归法
考点:n位格雷码的排列中,其低n-1位排列是对称的。递归的思想体现在n位gray码由n-1位gray码生成。
举例:
假设求n=3的gray码,首先已知n=2的gray码是(00,01,11,10),那么n=3的gray码其实是对n=2的gray码首位(最高位)添加0或1后生成的。
添加0后变成(000,001,011,010)
添加1后变成(110,111,101,100)(注意逆序)
组合在一起是3位的gray码(000,001,011,010,110,111,101,100)
#include <bits/stdc++.h> using namespace std; class Solution { public: vector<string> getGray(int n) { vector<string> grayCode; if(n == 1) { grayCode.push_back("0"); grayCode.push_back("1"); return grayCode; } vector<string> last_grayCode = getGray(n - 1); for(int i = 0; i < last_grayCode.size(); ++i) { grayCode.push_back("0" + last_grayCode[i]); } for(int i = last_grayCode.size() - 1; i >= 0 ; --i) { grayCode.push_back("1" + last_grayCode[i]); } return grayCode; } }; //main 函数是为了测试自己添加的 int main() { int n; cin >> n; Solution syq; vector<string> ans = syq.getGray(n); for(int i = 0; i < ans.size(); ++i) { cout << ans[i] << endl; } return 0; }
方法二:非递归法
考点:二进制与对应的格雷码的转换公式:格雷码 = 二进制码^(二进制码右移一位)
#include <bits/stdc++.h> using namespace std; class Solution { public: string getBinStr(int num, int n) { string binaryStr = ""; while(num) { int remain = num % 2; //string remainStr = to_string(remain); string remainStr; stringstream ss; ss << remain; ss >> remainStr; binaryStr = remainStr + binaryStr;//新的余数放在高位 num = num / 2; n--; } while(n--) { binaryStr = "0" + binaryStr;//n位格雷码,不足位数的前面补“0” } return binaryStr; } vector<string> getGray(int n) { int size = 1 << n; vector<string> grayCode; for(int i = 0; i < size; ++i) { int tmp = i ^ (i >> 1);//二进制与对应的格雷码的转换公式:格雷码 = 二进制码^(二进制码右移一位) string grayStr = getBinStr(tmp, n); grayCode.push_back(grayStr); } return grayCode; } }; //main 函数是自己为了测试添加的 int main() { int n; cin >> n; Solution syq; vector<string> ans = syq.getGray(n); for(int i = 0; i < ans.size(); ++i) { cout << ans[i] << endl; } return 0; }
2.微信红包
春节期间小明使用微信收到很多个红包,非常开心。在查看领取红包记录时发现,某个红包金额出现的次数超过了红包总数的一半。请帮小明找到该红包金额。写出具体算法思路和代码实现,要求算法尽可能高效。
给定一个红包的金额数组gifts及它的大小n,请返回所求红包的金额。若没有金额超过总数的一半,返回0。
测试样例:[1,2,3,2,2],5
返回结果:2
方法一:中位数法
如果一个给定的数组中存在一个数字,它的出现次数超过一半,那么将数组排序后这个数字一定出现在中位数的位置。注意结果有可能并不存在这样的数。
#include <bits/stdc++.h> using namespace std; class Gift { public: int getValue(vector<int> gifts, int n) { sort(gifts.begin(), gifts.end()); int ans = gifts[n/2]; int cout = 0; for(int i = 0; i < n; ++i) { if(gifts[i] == ans) ++cout; } return cout > n/2 ? ans : 0; } }; //main 函数是自己为了测试添加的 int main() { int n; Gift gift; while(cin >> n) { vector<int> syq(n); for(int i = 0; i < n; ++i) { cin >> syq[i]; } cout << gift.getValue(syq, n) << endl; } return 0; }
方法二:不同数字两两消除法(适用于所求的数字一定存在,见 LeetCode169 Majority Element)
class Solution { public: int majorityElement(vector<int>& nums) { int ans = nums[0]; int cnt = 0; for(int i = 0; i < nums.size(); ++i) { if(ans == nums[i]) cnt++; else cnt--; if(cnt == 0) ans = nums[i+1]; } return ans; } };