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

本文解析了四个经典的算法问题,包括哈夫曼编码、筛选序列、矩阵打印及股票交易最大收益计算。通过实例和代码详细说明了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

输入描述:
每组数据一行,为待编码的字符串。保证字符串长度小于等于1000。
输出描述:
一行输出最短的编码后长度。
示例1
输入
MT-TECH-TEAM

输出

33

解析:哈夫曼编码。先统计各字符次数,按照从小到大排序。初始化每个字符编码长度为0,然后每次找到次数最少的两个结点,合并为一个结点,新结点的次数为两个结点的和,直到最后只剩下一个结点,计算各个字符的编码长度(即在树中的深度),最后,对原始字符串每个字符的编码长度求和。(其实就是找到最小的两个数,求累加和,结果就是哈夫曼权值)

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
	char str[1005];
	while (scanf_s("%s", str,2005) != 0)
	{
		int tmp[255] = { 0 };
		int len = strlen(str);
		for (int i = 0; i < len; i++)
			tmp[str[i]]++;
		vector<int> vec;
		for (int i = 0; i < 255; i++)
			if (tmp[i] != 0)
				vec.push_back(tmp[i]);
		int sum = 0;
		while (vec.size() > 1)
		{
			sort(vec.begin(), vec.end());
			int temp = vec[0] + vec[1];
			sum += temp;
			vec.erase(vec.begin());
			vec.erase(vec.begin());
			vec.push_back(temp);
		}
		printf("%d\n",sum);	
	}
	system("pause");
	return 0;
}

2.对于一个由0..n的所有数按升序组成的序列,我们要进行一些筛选,每次我们取当前所有数字中从小到大的第奇数位个的数,并将其丢弃。重复这一过程直到最后剩下一个数。请求出最后剩下的数字。

输入描述:
每组数据一行一个数字,为题目中的n(n小于等于1000)。
输出描述:
一行输出最后剩下的数字。
示例1

输入

500

输出

255

解析:一共n+1个数,从数组0位置开始,第0个位置的元素为第一个数,第i个位置的元素为底i+1个数。设置两个下标 i、j,i 记录现在访问的数组下标,j 每层循环都从0开始,i 每遍历到偶数个位置时,位置 j 处就把位置 i 处的元素记录下来,i每次步长为2,i 第一次遍历到位置 n处,以后每次都遍历到上次 j的最大位置,直到 j 最大为0是结束。

#include<stdio.h>
int arr[1001];
int main()
{
     
    int n;
    while (scanf("%d", &n) != EOF)
    {
        for (int i = 0; i <=n; i++)
            arr[i] = i;
        int i = 0, j, flag = n;
        while (flag != 0)
        {
            j = 0;
            i = 0;
            for (; i <= n; i += 2)
            {
                arr[j++] = arr[i + 1];
            }
            n = j - 1;
            flag = j - 1;
        }
        printf("%d\n", arr[0]);
    }
    return 0;
}

3.有一个二维数组(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]

解析:找规律。从数组右上角开始,第一个数为最右上的元素,第二个为第一行倒数第二个元素,设此时元素的行列坐标位置分别为 i、就,之后,沿主对角线打印,即下一个元素为i++,j++;只需考虑 j=n-1 和 i=n-1的情况,其他情况都可以用(i++,j++)进行打印下一个元素。当j=n-1时,换行,换到第一行即i=0,j位置为上一次i=0的时候的j的位置向左移一位;当j的位置左移到最左端时,即arr[0][0]位置,下次在换行时,从i=1,j=0开始,再次换行是从i=2,j=0开始,以此类推;当i=n-1时,换行,和最后一次因j=n-1而换行后的位置向下移一位(记此位置为pos),之后再换行时,从pos向下移一位的位置开始,同时pos更新,依次类推,直到最后一个元素arr[n-1][0]打印后结束。


vector<int> arrayPrint(vector<vector<int> > arr, int n) {
       vector<int> res;
        if (n == 0)
            return res;
        if (n == 1)
        {
            res.push_back(arr[0][0]);
            return res;
        }
        res.push_back(arr[0][n - 1]);
        res.push_back(arr[0][n - 2]);
        int i = 0, j = n - 2;
        int flagi = n - 2, flagj = 0, flag = 0;
        while (i != n - 1 || j != 0)
        {
            if (i != n-1 && j != n-1)
            {
                i++;
                j++;
                res.push_back(arr[i][j]);
            }
            else if (j == n - 1)
            {
                if (flagi != 0)
                {
                    j = --flagi;
                    i = 0;
                    res.push_back(arr[i][j]);
                }
                else
                {
                    j = 0;
                    i = ++flagj;
                    res.push_back(arr[i][j]);
                }
            }
            else
            {
                j = 0;
                i = ++flagj;
                res.push_back(arr[i][j]);
            }
        }
        return res;
    }

4.在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。

给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。

测试样例:
[10,22,5,75,65,80],6
返回:87

解析:每次选择一个标志位置,分别计算标志位置前的最大差值max1和标志位置及之后的最大差值max2,记录最大的差值和max = max(max1+max2)。只不过在求分区间最大max1和max2的时候,用一个min记录当前遍历到的最低股票价格,当有以后某个prices[i]-min<0时,更新min为prices[i]。

int maxProfit(vector<int> prices, int n) {
        int max1, max2, max=0, min;
        for (int j = 1; j < n; j++)
        {
            min = prices[0], max1 = 0, max2 = 0;
            for (int i = 0; i <= j; i++)
            {
                if (prices[i] - min > max1)
                    max1 = prices[i] - min;
                else if(prices[i] - min < 0)
                    min = prices[i];
            }
            min = prices[j];
            for (int i = j+1; i < n; i++)
            {
                if (prices[i] - min > max2)
                    max2 = prices[i] - min;
                else if(prices[i] - min < 0)
                    min = prices[i];
            }
            max = max > max1 + max2 ? max : max1 + max2;
        }
        return max;
    }


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值