华为OD机试 新系统 C++实现【社交网络相同爱好好友查询】
社交网络相同爱好好友查询
华为OD新系统机试真题 华为OD新系统上机考试真题 5月13号 200分题型
本题更多语言题解,可点击查看:华为OD机试新系统真题 - 社交网络相同爱好好友查询(C/C++/Py/Java/Js/Go)题解
题目内容
在一个社交网络中,用户之间通过"关注"关系形成有向图。每个用户有两个属性:
-
用户 I D ID ID(整数字符串)
-
兴趣标签列表(字符串数组)
现在需要实现一个函数,查询在指定用户 k k k 跳内( k k k 度关系内)其他用户的兴趣和给定用户兴趣相符的用户 I D ID ID 列表(不含自己)。
注意:兴趣相符是指两个用户的兴趣列表有交集。实现函数: q u e r y F r i e n d s ( n o d e s , r e l a t i o n s , m y I d , m a x H o p ) queryFriends(nodes, relations, myId, maxHop) queryFriends(nodes,relations,myId,maxHop)
输入参数
- n o d e s nodes nodes - 用户节点数据
- 类型:整数二维数组/向量
- 每行表示一个用户,包含:[ i d id id, 兴趣 1 1 1, 兴趣 2 2 2, …]
- 示例:[“ 0 0 0”, “ m u s i c music music”, “ r e a d i n g reading reading”] 表示用户 0 0 0,有 2 2 2 个兴趣: m u s i c music music 和 r e a d i n g reading reading
- 所有用户 I D ID ID 是 0 0 0 到 n − 1 n-1 n−1 的连续整数对应的字符串
- r e l a t i o n s relations relations - 关注关系
- 类型:整数二维数组/向量
- 每行表示一个关注关系:[关注者 I D ID ID, 被关注者 I D ID ID]
- 示例:[“ 0 0 0”, “ 1 1 1”] 表示用户 0 0 0 关注了用户 1 1 1
- m y I d myId myId - 起始用户 I D ID ID,示例:“ 0 0 0”
- m a x H o p maxHop maxHop - 最大跳数 k k k,示例: 2 2 2
返回值
- 内容:所有满足条件的用户 I D ID ID 及共同的兴趣列表,如[[“ 0 0 0”, “ m u s i c music music”, “ r e a d i n g reading reading”],[“ 1 1 1”, “ r e a d i n g reading reading”]]
- 格式 1 1 1:不同用户之间按以下规则排序:
按与起始用户的最短距离从小到大排序
距离相同的用户,按ID对应整数值进行从小到大排序 - 格式 2 2 2:对于具体某用户与起始用户的共同兴趣列表按以下规则排序: 按照 a s c i i ascii ascii 码序从小到大排序
- 如果没有满足条件的用户,返回空数组
约束条件
- 用户数 n : 1 ≤ n ≤ 10 4 n: 1 ≤ n ≤ 10^4 n:1≤n≤104,可认为用户的 i d id id 字符串对应整数范围符合该条件
- 关注关系数 m : 0 ≤ m ≤ 2 × 10 4 m: 0 ≤ m ≤ 2×10^4 m:0≤m≤2×104,若关系任一端包含不存在的点应该自动忽略,不影响原始查询诉求
- 最大跳数 k : 1 ≤ k ≤ 100 k: 1 ≤ k ≤ 100 k:1≤k≤100,大于最大跳数,按照上限 100 100 100 对待
- 每个用户最多 10 10 10 个兴趣标签,可认为所有用户的兴趣个数符合该条件
- 给定查询条件中的起始用户 I D ID ID 一定存在
样例1
输入
0,music,sports 1,music,reading 2,music 3,play,music,sports
0,1 1,2 2,3 0,3
0
2
输出
1,music
3,music,sports
2,music
说明
从 I D = ID= ID=“ 0 0 0” 出发兴趣相同( 2 2 2 跳内)可以匹配到用户" 1 1 1"、“ 2 2 2”、“ 3 3 3”,同时用户" 1 1 1"、“ 3 3 3"跳数少,因此用户" 1 1 1”、“ 3 3 3"在用户" 2 2 2"之前。,又因为" 1 1 1"相比于" 3 3 3"整数序靠前,因此用户" 1 1 1"在用户" 3 3 3”。用户" 3 3 3"中,匹配到了多项爱好,根据字母序排列," m u s i c music music"在" s p o r t s sports sports"之前。
样例2
输入
0,music 1,music 2,music 3,music 4,music
0,1 1,2 2,3 3,4
0
1
输出
1,music
说明
所有用户都满足兴趣条件,但是跳数限制在 1 1 1 跳内,因此仅用户" 1 1 1"满足条件
样例3
输入
0,music
0
2
输出
说明
不存在满足条件的结果,无输出
题解
思路:BFS
- 先提取出每个用户的兴趣爱好,根据id进行保存
- 将用户作为节点,关注关系看作有向边。根据输入关注关系创建对应
邻接表。 - 指定
k跳级就是用户之间的距离,用户之间的距离可以使用最短路算法或者BFS算法实现,下面代码利用BFS计算其它用户与指定用户的距离。使用dist数组存储其它用户与指定用户距离。具体逻辑为- 初始将
myId加入队列中,更新dist[myId] = 0 - 每次从队列中取出队首元素
current,更新相邻节点的距离,对应节点node处理如下:- 如果
dist[node] != -1,说明之前已访问,不做处理 dist[node] == 1的情况,更新对应距离为dist[node] = dist[current] + 1,如果dist[node] >= maxHop不加入队列(本题距离大于maxHop可认为不可达)。否则加入队列中。
- 如果
- 重复执行2的逻辑直到队列为空。
- 初始将
- 利用
dist找到可达用户,并且提取出拥有公共爱好的用户加入结果数组中。共同爱好需要进行排序 - 按照题目要求利用
dist进行自定义按与起始用户的最短距离从小到大排序 距离相同的用户,按ID对应整数值进行从小到大排序规则排序。
c++
#include<iostream>
#include<vector>
#include<string>
#include <utility>
#include <sstream>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
using namespace std;
// 通用 切割函数 函数 将字符串str根据delimiter进行切割
vector<string> split(const string& str, const string& delimiter) {
vector<string> result;
size_t start = 0;
size_t end = str.find(delimiter);
while (end != string::npos) {
result.push_back(str.substr(start, end - start));
start = end + delimiter.length();
end = str.find(delimiter, start);
}
// 添加最后一个部分
result.push_back(str.substr(start));
return result;
}
vector<string> findSameLike(vector<string>& a, vector<string>& b) {
if (a.empty() || b.empty()) {
return {};
}
vector<string> res;
for (int i = 0; i < a.size(); i++) {
string item = a[i];
for (int j = 0; j < b.size(); j++) {
if (b[j] == item) {
res.push_back(item);
}
}
}
return res;
}
vector<vector<string>> queryFriends(vector<vector<string>>& nodes, vector<vector<string>>& relations, string myId, int maxHop) {
int n = nodes.size();
// 限制不超过100
maxHop = min(maxHop, 100);
vector<vector<int>> graph(n);
// 根据关注关系,建表
for (auto& relation : relations) {
int u = stoi(relation[0]);
int v = stoi(relation[1]);
// 存在不存在的点
if (u < 0 || v < 0 || u > n - 1 || v > n - 1) {
continue;
}
graph[u].push_back(v);
}
// 映射每个用户的爱好
vector<vector<string>> like(n);
for (auto &node : nodes) {
string id = node[0];
int idValue = stoi(id);
for (int j = 1; j < node.size(); j++) {
like[idValue].push_back(node[j]);
}
}
// 处于指定用户跳数
vector<int> dist(n, -1);
int myIdValue = stoi(myId);
//指定用户不存在爱好情况,肯定没有结果
if (like[myIdValue].empty()) {
return {};
}
// 使用BFS求跳数
queue<int> q;
q.push(myIdValue);
dist[myIdValue] = 0;
while (!q.empty()) {
int current = q.front();
q.pop();
for (auto& v : graph[current]) {
if (dist[v] != -1) {
continue;
}
dist[v] = dist[current] + 1;
if (dist[v] < maxHop) {
q.push(v);
}
}
}
vector<vector<string>> res;
// 找出具备相同爱好并且在指定跳内的结果
for (int i = 0; i < n; i++) {
if (dist[i] == -1) {
continue;
}
if (i == myIdValue) {
continue;
}
vector<string> sameLike = findSameLike(like[i], like[myIdValue]);
if (sameLike.empty()) {
continue;
}
// 将爱好升序
sort(sameLike.begin(), sameLike.end());
vector<string> item;
item.push_back(to_string(i));
for (string s : sameLike) {
item.push_back(s);
}
res.push_back(item);
}
// 自定义进行排序
sort(res.begin(), res.end(), [&](vector<string>&a , vector<string>& b) {
int id1 = stoi(a[0]);
int id2 = stoi(b[0]);
if (dist[id1] == dist[id2]) {
return id1 < id2;
}
return dist[id1] < dist[id2];
});
return res;
}
int main() {
string input1,input2,myId,maxHopStr;
getline(cin, input1);
getline(cin, input2);
getline(cin, myId);
getline(cin, maxHopStr);
vector<vector<string>> nodes;
vector<string> tmp;
if (!input1.empty()) {
tmp = split(input1, " ");
for (int i = 0; i < tmp.size(); i++) {
nodes.push_back(split(tmp[i], ","));
}
}
vector<vector<string>> relations;
if (!input2.empty()) {
tmp = split(input2, " ");
for (int i = 0; i < tmp.size(); i++) {
relations.push_back(split(tmp[i], ","));
}
}
vector<vector<string>> res = queryFriends(nodes, relations, myId, stoi(maxHopStr));
// 输出结果
for (int i = 0; i < res.size(); i++) {
vector<string> current = res[i];
for (int j = 0; j < current.size(); j++) {
if (j != 0) {
cout << ",";
}
cout << current[j];
}
cout << endl;
}
}
JAVA
import java.util.*;
public class Main {
public static List<List<String>> queryFriends(
List<List<String>> nodes,
List<List<String>> relations,
String myId,
int maxHop) {
int n = nodes.size();
// 限制不超过100
maxHop = Math.min(maxHop, 100);
// 根据关注关系,建表
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i < n; i++) graph.add(new ArrayList<>());
for (List<String> r : relations) {
int u = Integer.parseInt(r.get(0));
int v = Integer.parseInt(r.get(1));
// 存在不存在的点
if (u < 0 || u >= n || v < 0 || v >= n) continue;
graph.get(u).add(v);
}
// 映射每个用户的爱好
List<List<String>> like = new ArrayList<>();
for (int i = 0; i < n; i++) like.add(new ArrayList<>());
for (List<String> node : nodes) {
int id = Integer.parseInt(node.get(0));
for (int i = 1; i < node.size(); i++) {
like.get(id).add(node.get(i));
}
}
// 处于指定用户跳数
int[] dist = new int[n];
Arrays.fill(dist, -1);
int myIdValue = Integer.parseInt(myId);
// 指定用户不存在爱好情况,肯定没有结果
if (like.get(myIdValue).isEmpty()) {
return new ArrayList<>();
}
// 使用BFS求跳数
Queue<Integer> q = new LinkedList<>();
q.offer(myIdValue);
dist[myIdValue] = 0;
while (!q.isEmpty()) {
int cur = q.poll();
for (int v : graph.get(cur)) {
if (dist[v] != -1) continue;
dist[v] = dist[cur] + 1;
if (dist[v] < maxHop) {
q.offer(v);
}
}
}
List<List<String>> res = new ArrayList<>();
// 找出具备相同爱好并且在指定跳内的结果
for (int i = 0; i < n; i++) {
if (dist[i] == -1) continue;
if (i == myIdValue) continue;
List<String> sameLike = new ArrayList<>();
for (String a : like.get(i)) {
for (String b : like.get(myIdValue)) {
if (a.equals(b)) sameLike.add(a);
}
}
if (sameLike.isEmpty()) continue;
// 将爱好升序
Collections.sort(sameLike);
List<String> item = new ArrayList<>();
item.add(String.valueOf(i));
item.addAll(sameLike);
res.add(item);
}
// 自定义进行排序
res.sort((a, b) -> {
int id1 = Integer.parseInt(a.get(0));
int id2 = Integer.parseInt(b.get(0));
if (dist[id1] == dist[id2]) return id1 - id2;
return dist[id1] - dist[id2];
});
return res;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String input1 = sc.nextLine();
String input2 = sc.nextLine();
String myId = sc.nextLine();
int maxHop = Integer.parseInt(sc.nextLine());
List<List<String>> nodes = new ArrayList<>();
List<List<String>> relations = new ArrayList<>();
if (!input1.isEmpty()) {
for (String s : input1.split(" ")) {
nodes.add(Arrays.asList(s.split(",")));
}
}
if (!input2.isEmpty()) {
for (String s : input2.split(" ")) {
relations.add(Arrays.asList(s.split(",")));
}
}
List<List<String>> res = queryFriends(nodes, relations, myId, maxHop);
for (List<String> r : res) {
System.out.println(String.join(",", r));
}
}
}
更多推荐


所有评论(0)