【牛客】饿了么笔试题目

本文讲述了饿了么24秋招中涉及的两个技术问题:使用Dijkstra算法计算外卖配送的最短路径,以及判断外卖送达时间是否超时的逻辑。文章详细介绍了算法应用和代码实现。

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

饿了么24秋招工程方向&算法方向

题目的具体描述可参考牛客牛客网

1.小红送外卖

题目描述

小红在第三新北林市的学园城送外卖,学园城中有非常多的学校,学园城里有一个美食街。小红每次会接一些同一个学校的订单,然后从美食街取餐出发,再骑车将外卖送到学校,最后回到美食街,以此往复。

学园城有 𝑛 个结点, 𝑚条道路,美食街为1号结点,剩下的结点都是学校,保证学园城中所有结点连通。给出小红每次要送外卖的学校,请计算小红最少需要骑行的距离。

分析

  • 该题目要求最少骑行距离

  • 也就是说,要求起点到终点的最短距离

  • 但是小红每次送完外卖都会回到起点(学校),也就是说,每次都从起点开始求最短路径,然后将这些最短路径相加就是最少距离。

  • 采用dijkstar算法,关于dijkstar算法可看Dijkstar-CSDN博客

  • 采用dijkstar算法求出各个节点到起点的最短路径,然后将目标节点的最短路径相加。

代码

完整代码如下

  • 图的存储方式采用邻接表的形式
  • 采用优先队列对算法进行优化
#include <iostream>
#include <vector>
#include <queue>
#include <climits>

using namespace std;

#define INF INT_MAX

struct Edge {
	int to;
	int weight;
};

vector<vector<Edge>> graph;

vector<int> dijkstra(int start, int n) {
	vector<int> distance(n + 1, INF);
	distance[start] = 0;
	priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
	pq.push({ 0, start });

	while (!pq.empty()) {
		int u = pq.top().second;
		int dist = pq.top().first;
		pq.pop();

		if (dist > distance[u]) continue;

		for (const auto& edge : graph[u]) {
			int v = edge.to;
			int w = edge.weight;

			if (distance[v] > distance[u] + w) {
				distance[v] = distance[u] + w;
				pq.push({ distance[v], v });
			}
		}
	}

	return distance;
}

int main() {
	int n, m;
	cin >> n >> m;
	int num_schools;
	cin >> num_schools;
	graph.resize(n + 1);

	// 构建图
	for (int i = 0; i < m; ++i) {
		int u, v, w;
		cin >> u >> v >> w;
		graph[u].push_back({ v, w });
		graph[v].push_back({ u, w });
	}

	vector<int> schools(num_schools);
	for (int i = 0; i < num_schools; ++i) {
		cin >> schools[i];
	}

	// 计算从美食街到每个学校的最短距离
	vector<int> distances_from_foodcourt = dijkstra(1, n);

	// 计算最小距离之和
	int total_distance = 0;
	for (int school : schools) {
		total_distance += distances_from_foodcourt[school];
	}

	cout << "小红最少需要骑行的距离为: " << total_distance * 2 << " 米" << endl;

	return 0;
}

2.小红等外卖

题目描述

小红在饿了么上面点了一个外卖,饥肠辘辘的她等骑手等得望眼欲穿。

已知小红在时刻𝑡1点了外卖,饿了么上面显示预计送达时间为𝑡2,实际送达时间为𝑡3。请你判断外卖是否超时?

分析

  • left表示预计送达时间,right表示实际送达时间

  • 如果预计送达时间在第二天,但实际送达时间在当天,则没有超时;

    相反,如果预计送达时间在当天,实际送达时间在第二天,超时;

    if (time[right][0] - time[left][0] >= 22) {
    	printf("%s\n", "No");
    }
    if (time[left][0] - time[right][0] >= 22) {
    	printf("%s\n", "Yes");
    }
    
  • 如果实际预计送达时间和实际送达时间都在当天

    • 如果预计送法时间的小时位 > 实际送达时间的小时位,则没有超时

      if (time[left][0] > time[right][0]) {
      	printf("%s\n", "No");
      }
      
    • 如果预计送法时间的小时位 = 实际送达时间的小时位

      //如果如果预计送法时间的小时位 = 实际送达时间的小时位
      if (time[left][0] == time[right][0]) {
          //预计送法时间的分数位 >= 实际送达时间的分数位,没有超时
      	if (time[left][1] >= time[right][1]) {
      		printf("%s\n", "No");
      	}
      	else{
      		printf("%s\n", "Yes");
      	}
      }
      
    • 如果预计送达时间的小时位 < 实际送达时间的小时位,则超时

代码

int num2() {
	int t;
	cin >> t;
	cin.ignore();
    //定义一个vector数组存储时间
	vector<vector<int>> time(3 * t, vector<int>(2, 0));
	for (int i = 0; i < 3 * t; i++) {
		//getline用法
		string line;
		getline(cin, line);
		stringstream ss(line);
		string temp1;
		getline(ss, temp1, ':');
		time[i][0] = stoi(temp1);
		string temp2;
		getline(ss, temp2, ':');
		time[i][1] = stoi(temp2);
	}

	int left = 1;
	int right = 2;
	while (right < 3 * t) {
		if (time[right][0] - time[left][0] >= 22) {
			printf("%s\n", "No");
		}
		else if (time[left][0] - time[right][0] >= 22) {
			printf("%s\n", "Yes");
		}
		else {
			if (time[left][0] > time[right][0]) {
				printf("%s\n", "No");
			}
			else if (time[left][0] == time[right][0]) {
				if (time[left][1] >= time[right][1]) {
					printf("%s\n", "No");
				}
				else
				{
					printf("%s\n", "Yes");
				}
			}
			else {
				printf("%s\n", "Yes");
			}
		}

		left += 3;
		right += 3;
	}

	return 0;
}

3.小红的字符串构造

题目描述

小红拿到了一个字符串𝑠,她准备构造一个和𝑠长度相同的字符串𝑡,满足以下条件:

  1. 𝑡的字符集和𝑠的相同(去重后的,也就是说不考虑数量)
  2. 𝑡的每个位置的字符都和𝑠不同。

例如若 s=“aabbc”,那么𝑡t可以构造为"cbaca"。
你能帮帮小红吗?

分析

  • 本题的关键在于将字符映射
  • 采用set集合剔除s字符串中相同的元素
  • 采用map集合将set中元素的第二位与第三位映射、第三位与第四位映射,…,第一位与最后一位映射

代码

#include <vector>
#include <set>
#include <map>
#include <algorithm>

using namespace std;

class MyCompare {
public:
	bool operator()(char a, char b) {
		return a > b;
	}
};

int num3() {
	string str;
	cin >> str;
	set<char> strSet;

    //采用set集合剔除str中相同的元素
	for (int i = 0; i < str.size(); i++) {
		strSet.insert(str[i]);
	}
	vector<char> v1(strSet.begin(), strSet.end());
    
    //映射前的准备工作
    //准备一个v2数组,v2数组中的元素顺序为set中的第二位、第三位、...、最后一位、第一位
	vector<char> v2;
	for (set<char>::iterator it = strSet.begin(); it != strSet.end(); it++) {
		if (it == strSet.begin()) continue;
		v2.push_back(*it);
	}
	v2.push_back(*strSet.begin());
    
    //采用map集合将v1与v2中的每一个元素映射
	map<char, char> m;
	for (int i = 0; i < v2.size(); i++) {
		m[v1[i]] = v2[i];
	}

    //根据映射关系找到result字符串
	string result = "";
	for (int i = 0; i < str.size(); i++) {
		result += m[str[i]];
	}
	if (result.size() != str.size() || result == str) cout << -1 << endl;
	else cout << result << endl;

	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值