请设计一个算法,给一个字符串进行二进制编码,使得编码后字符串的长度最短。(哈弗曼编码)

美团点评2016研发工程师编程题(二)


请设计一个算法,给一个字符串进行二进制编码,使得编码后字符串的长度最短。


输入描述:
每组数据一行,为待编码的字符串。保证字符串长度小于等于1000。


输出描述:
一行输出最短的编码后长度。

输入例子:
MT-TECH-TEAM

输出例子:

33


分析:哈夫曼编码的过程,用一个最小堆实现,将当前最小的两个数取出来,求和后继续推入堆中。

代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <iostream>  
  2. #include <queue>  
  3. #include <algorithm>  
  4. #include <functional>  
  5. #include <string>  
  6. using namespace std;  
  7. int main() {  
  8.     string s;  
  9.     while (getline(cin, s)) {  
  10.         int ret=0;  
  11.         int n = s.size();  
  12.         sort(s.begin(), s.end());  
  13.         int cnt = 0;  
  14.         priority_queue<int, vector<int>, greater<int> > heap;  
  15.         for (int i = 0, j; i < n;) {  
  16.             j = i;  
  17.             while (j < n && s[j] == s[i]) ++j;  
  18.             heap.push(j - i);  
  19.             i = j;  
  20.             ++cnt;  
  21.         }  
  22.         for (int i = 0; i < cnt-1; i++) {  
  23.             int a = heap.top();  
  24.             heap.pop();  
  25.             int b = heap.top();  
  26.             heap.pop();  
  27.             heap.push(a+b);  
  28.             ret += a + b;  
  29.               
  30.   
  31.         }  
  32.         cout << ret << endl;  
  33.   
  34.     }  
  35.     return 0;  
  36. }  



  1. #include<map>  
  2. #include<iostream>  
  3. #include<string>  
  4. using namespace std;  
  5. struct BTreeNode    
  6. {    
  7.     int weight;    
  8.     char value;  
  9.     struct BTreeNode* left;    
  10.     struct BTreeNode* right;    
  11. };    
  12.   
  13.   
  14. struct BTreeNode* CreateHuffman(int weight[],char value[], int n)  
  15. {  
  16.     int i, j;  
  17.     struct BTreeNode **b, *q;  
  18.     b = (BTreeNode **) malloc(n*sizeof(struct BTreeNode));  
  19.     for (i = 0; i < n; i++) //初始化b指针数组,使每个指针元素指向a数组中对应的元素结点  
  20.     {  
  21.         b[i] = (BTreeNode *) malloc(sizeof(struct BTreeNode));  
  22.         b[i]->weight= weight[i];  
  23.         b[i]->value=value[i];  
  24.         b[i]->left = b[i]->right = NULL;  
  25.     }  
  26.     for (i = 1; i < n; i++)//进行 n-1 次循环建立哈夫曼树  
  27.     {  
  28.         //k1表示森林中具有最小权值的树根结点的下标,k2为次最小的下标  
  29.         int k1 = -1, k2;  
  30.         for (j = 0; j < n; j++)//让k1初始指向森林中第一棵树,k2指向第二棵  
  31.         {  
  32.             if (b[j] != NULL && k1 == -1)  
  33.             {  
  34.                 k1 = j;  
  35.                 continue;  
  36.             }  
  37.             if (b[j] != NULL)  
  38.             {  
  39.                 k2 = j;  
  40.                 break;  
  41.             }  
  42.         }  
  43.         for (j = k2; j < n; j++)//从当前森林中求出最小权值树和次最小  
  44.         {  
  45.             if (b[j] != NULL)  
  46.             {  
  47.                 if (b[j]->weight < b[k1]->weight)  
  48.                 {  
  49.                     k2 = k1;  
  50.                     k1 = j;  
  51.                 }  
  52.                 else if (b[j]->weight < b[k2]->weight)  
  53.                     k2 = j;  
  54.             }  
  55.         }  
  56.         //由最小权值树和次最小权值树建立一棵新树,q指向树根结点  
  57.         q = (BTreeNode *) malloc(sizeof(struct BTreeNode));  
  58.         q->weight = b[k1]->weight + b[k2]->weight;  
  59.         q->value='\0';  
  60.         q->left = b[k1];  
  61.         q->right = b[k2];  
  62.   
  63.         b[k1] = q;//将指向新树的指针赋给b指针数组中k1位置  
  64.         b[k2] = NULL;//k2位置为空  
  65.     }  
  66.     free(b); //删除动态建立的数组b  
  67.     return q; //返回整个哈夫曼树的树根指针  
  68. };  
  69. int HuffManCoding(struct BTreeNode* FBT, int len)//len初始值为0    
  70. {    
  71.       
  72.     if (FBT != NULL)//访问到叶子结点时输出其保存在数组a中的0和1序列编码    
  73.     {    
  74.         if (FBT->left == NULL && FBT->right == NULL)    
  75.         {    
  76.            return FBT->weight*len;   
  77.         }    
  78.         else//访问到非叶子结点时分别向左右子树递归调用,并把分支上的0、1编码保存到数组a    
  79.         {   //的对应元素中,向下深入一层时len值增1    
  80.               
  81.             return HuffManCoding(FBT->left, len + 1)+  HuffManCoding(FBT->right, len + 1);    
  82.         }    
  83.     }    
  84. }   
  85. int getMinCode(string s)  
  86. {  
  87.     map<char,int> m;  
  88.     map<char,int>::iterator it;;  
  89.     int len=s.length();  
  90.     //统计每个字符的频率  
  91.     for(int i=0;i<len;i++)  
  92.     {  
  93.         it=m.find(s[i]);//返回的是一个指针  
  94.         if(it==m.end())//没找到  
  95.         {  
  96.             m.insert(pair<char,int> (s[i],1));  
  97.         }else  
  98.         {  
  99.             m[s[i]]=m.find(s[i])->second+1;  
  100.         }  
  101.     }  
  102.     //构建哈夫曼树  
  103.     int size=m.size();  
  104.     int* weight=(int *)malloc(size*sizeof(int));  
  105.     char* value=(char *)malloc(size*sizeof(char));  
  106.     int j=0;  
  107.     for ( it = m.begin( ) ; it != m.end() ; it++ )  
  108.     {  
  109.         weight[j]=it->second;  
  110.         value[j]=it->first;  
  111.         j++;  
  112.     }  
  113.     BTreeNode* root= CreateHuffman(weight,value, size);  
  114.     //深度优先遍历  
  115.     return HuffManCoding(root,0);  
  116.       
  117. }  
  118. int main()  
  119. {  
  120.     string s;  
  121.     cin>>s;  
  122.     cout<<getMinCode(s);  
  123.     return 0;  
  124. }  




我的代码:

#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 (正确)

249
253
255
257
499
不同于以上答案

答案是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);
    }
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值