美团点评2016研发工程师编程题(二)
请设计一个算法,给一个字符串进行二进制编码,使得编码后字符串的长度最短。
输入描述:
每组数据一行,为待编码的字符串。保证字符串长度小于等于1000。
输出描述:
一行输出最短的编码后长度。
输入例子:
MT-TECH-TEAM
输出例子:
33
分析:哈夫曼编码的过程,用一个最小堆实现,将当前最小的两个数取出来,求和后继续推入堆中。
代码:
- #include<map>
- #include<iostream>
- #include<string>
- using namespace std;
- struct BTreeNode
- {
- int weight;
- char value;
- struct BTreeNode* left;
- struct BTreeNode* right;
- };
- struct BTreeNode* CreateHuffman(int weight[],char value[], int n)
- {
- int i, j;
- struct BTreeNode **b, *q;
- b = (BTreeNode **) malloc(n*sizeof(struct BTreeNode));
- for (i = 0; i < n; i++) //初始化b指针数组,使每个指针元素指向a数组中对应的元素结点
- {
- b[i] = (BTreeNode *) malloc(sizeof(struct BTreeNode));
- b[i]->weight= weight[i];
- b[i]->value=value[i];
- b[i]->left = b[i]->right = NULL;
- }
- for (i = 1; i < n; i++)//进行 n-1 次循环建立哈夫曼树
- {
- //k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标
- int k1 = -1, k2;
- for (j = 0; j < n; j++)//让k1初始指向森林中第一棵树,k2指向第二棵
- {
- if (b[j] != NULL && k1 == -1)
- {
- k1 = j;
- continue;
- }
- if (b[j] != NULL)
- {
- k2 = j;
- break;
- }
- }
- for (j = k2; j < n; j++)//从当前森林中求出最小权值树和次最小
- {
- if (b[j] != NULL)
- {
- if (b[j]->weight < b[k1]->weight)
- {
- k2 = k1;
- k1 = j;
- }
- else if (b[j]->weight < b[k2]->weight)
- k2 = j;
- }
- }
- //由最小权值树和次最小权值树建立一棵新树,q指向树根结点
- q = (BTreeNode *) malloc(sizeof(struct BTreeNode));
- q->weight = b[k1]->weight + b[k2]->weight;
- q->value='\0';
- q->left = b[k1];
- q->right = b[k2];
- b[k1] = q;//将指向新树的指针赋给b指针数组中k1位置
- b[k2] = NULL;//k2位置为空
- }
- free(b); //删除动态建立的数组b
- return q; //返回整个哈夫曼树的树根指针
- };
- int HuffManCoding(struct BTreeNode* FBT, int len)//len初始值为0
- {
- if (FBT != NULL)//访问到叶子结点时输出其保存在数组a中的0和1序列编码
- {
- if (FBT->left == NULL && FBT->right == NULL)
- {
- return FBT->weight*len;
- }
- else//访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组a
- { //的对应元素中,向下深入一层时len值增1
- return HuffManCoding(FBT->left, len + 1)+ HuffManCoding(FBT->right, len + 1);
- }
- }
- }
- int getMinCode(string s)
- {
- map<char,int> m;
- map<char,int>::iterator it;;
- int len=s.length();
- //统计每个字符的频率
- for(int i=0;i<len;i++)
- {
- it=m.find(s[i]);//返回的是一个指针
- if(it==m.end())//没找到
- {
- m.insert(pair<char,int> (s[i],1));
- }else
- {
- m[s[i]]=m.find(s[i])->second+1;
- }
- }
- //构建哈夫曼树
- int size=m.size();
- int* weight=(int *)malloc(size*sizeof(int));
- char* value=(char *)malloc(size*sizeof(char));
- int j=0;
- for ( it = m.begin( ) ; it != m.end() ; it++ )
- {
- weight[j]=it->second;
- value[j]=it->first;
- j++;
- }
- BTreeNode* root= CreateHuffman(weight,value, size);
- //深度优先遍历
- return HuffManCoding(root,0);
- }
- int main()
- {
- string s;
- cin>>s;
- cout<<getMinCode(s);
- return 0;
- }
我的代码:
#include<iostream>
#include<string>
#include<queue>
using namespace std;
class Node {
public: int data;
Node* lchild;
Node* rchild;
Node(int data_input) {
data = data_input;
lchild = NULL;
rchild = NULL;
}
~Node() {
if(lchild == NULL) {
delete lchild;
}
if(rchild == NULL) {
delete rchild;
}
}
};
int num(string str, int predata[]) {
int num = 0;
for(int i = 0; i < str.length(); i++)
{
int flag = 0;;
for(int j = i - 1; j >= 0; j--)
{
flag = 0;
if(str[i] == str[j]) {
flag = 1;
break;
}
}
if(flag == 1) {
}
else if(flag == 0) {
predata[num] = str[i];
num++;
}
}
return num;
}
void nodenum(string str, int predata[],int data[], int length) {
for(int i = 0; i < length; i++) {
for(int j = 0; j < str.length(); j++) {
if(predata[i] == str[j]) {
data[i]++;
}
}
}
}
void sort(int data[], int l, int r) {
int i = l, j = r;
int flag = data[l];
do{
while(i <= j && data[i] < flag) {
i++;
}
while(i <= j && data[j] > flag) {
j--;
}
if(i <= j) {
swap(data[i], data[j]);
i++;
j--;
}
}while(i <= j);
if(i < r) {
sort(data, i, r);
}
if(j > l) {
sort(data, l, j);
}
}
int main() {
string str;
while(getline(cin, str)) {
int* predata = new int[str.length()];
int length = num(str, predata);
int* data = new int[length];
for(int i = 0; i < length; i++) {
data[i] = 0;
}
nodenum(str, predata, data, length);
sort(data, 0, length - 1);
priority_queue<int, vector<int>, greater<int> > pq;
for(int n = 0; n < length; n++) {
pq.push(data[n]);
}
int rec = 0;
for(int x = 0; x < length - 1; x++) {
int A = pq.top(); pq.pop();
int B = pq.top(); pq.pop();
rec += A + B;
pq.push(A + B);
}
cout << rec << endl;
}
/*
for(int m = 0; m < length; m++) {
cout << pq.top() << " ";
pq.pop();
}
cout << num(str, predata) << endl;
for(int j = 0; j < length; j++) {
printf("%d", data[j]);
}
*/
return 0;
}
对于一个由0..n的所有数按升序组成的序列,我们要进行一些筛选,每次我们取当前所有数字中从小到大的第奇数位个的数,并将其丢弃。重复这一过程直到最后剩下一个数。请求出最后剩下的数字。
输入描述:
每组数据一行一个数字,为题目中的n(n小于等于1000)。
输出描述:
一行输出最后剩下的数字。
输入例子:
500
输出例子:
255
0,1,2,3,⋯,499,500共501个数按升序排列,每次取奇数序位的数丢掉,然后取剩下的数的奇数序位的数丢掉,重复这个过程,那么最后剩下的数是多少?正确答案: C 你的答案: C (正确)
249253255257499不同于以上答案
答案是C其实你可以推导一下,我以前类似的题目有推导过的过程,过程比较麻烦,故我在此不细推导,总结下来就是接近末尾这个数的最大的数是2的n次方比如末尾是65,那么剩下就是64,末尾是127也是64,是130就是128,当然这都是从1开始,这个题目从0开始,故而是255简单例举下:0 1 2 3 4 5 6 7 8 9 10 11第一次剩下的 1 3 5 7 9 11 规律: 2i-1( i为整数 1<=i<= n/2 (n表示给出序列的元素个数,例子中是12,而题目中是501))
第二次剩下的 3 7 11 4i- 1 1<=i<= n/4第3次剩下的 7 8i- 1 1<=i<= n/8
相信已经差不多了。每次剩下的元素为 2^x-1满足条件的只有255=2^8-1.当然这是选择题可以直接选答案。正确做法是: 最后剩下一个元素,那么进行了几次筛选过程呢? i取值只能是1,那么 501/(2^x)<2 取x=8;那么剩下的元素是2^8-1=255
package 美团;
import java.util.*;
import java.lang.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while(scan.hasNext()) {
int m = scan.nextInt();
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i <= m; i++) {
list.add(i);
}
while(list.size() > 1) {
for(int i = list.size(); i >= 1; i--) {
if(i % 2 != 0) {
list.remove(i - 1);
}
}
}
System.out.println(list.get(0));
}
}
}
有一个二维数组(n*n),写程序实现从右上角到左下角沿主对角线方向打印。
给定一个二位数组arr及题目中的参数n,请返回结果数组。
[[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]],4
返回:[4,3,8,2,7,12,1,6,11,16,5,10,15,9,14,13]package 美团;
import java.util.*;
public class Printer {
public int[] arrayPrint(int[][] arr, int n) {
int a[] = new int[n * n];
int len = 2 * n - 1; //一共分几次输出
int index = 0;
for(int i = 0; i < len; i++) {
for(int j = 0; j < n; j++) {//行
for(int z = 0; z < n; z++) {//列
if(z - j == n - 1 - i) {
a[index++] = arr[j][z];
}
}
}
}
return a;
// write code here
}
public static void main(String[] args) {
int[][] a = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}};
int n = a.length;
int[] aa = new int[n * n];
Printer printer = new Printer();
aa = printer.arrayPrint(a, n);
for(int i = 0; i < n * n; i++) {
System.out.print(aa[i] + " ");
}
}
}
在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。
给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。
[10,22,5,75,65,80],6
返回:87
package 美团;
import java.util.*;
public class Stock {
public int maxProfit(int[] prices, int n) {
int max = max(prices, 0, n -1 );
System.out.println(max);
for(int i = 0; i < n - 3; i++) {
if(max(prices, 0, i + 1) + max(prices, i + 2, n - 1) > max) {
max = max(prices, 0, i + 1) + max(prices, i + 2, n - 1);
}
//System.out.println(max);
}
return max;
// write code here
}
public int max(int[] prices, int l, int r) {
int max = prices[r] - prices[r - 1];
for(int i = r; i >= l; i--) {
for(int j = i - 1; j >= l; j--) {
if(prices[i] - prices[j] > max) {
max = prices[i] - prices[j];
}
}
}
//System.out.println(max);
return max;
}
public static void main(String[] args) {
Stock stock = new Stock();
int[] prices = {10,22,5,75,65,80};
int max = stock.maxProfit(prices, prices.length);
System.out.println(max);
}
}