华为非AI方向0527笔试真题-微服务部署依赖依赖(详细思路+多语言题解)

微服务部署依赖依赖

华为笔试真题 5月27号 非AI方向 200分题型

题目内容

你正在参与一个大规模微服务架构的部署平台开发,系统中包含多个微服务,每个微服务在上线前需要其所有依赖的微服务都已部署并运行。

一个微服务通过字符串来表示,如:"userservice",一个微服务可能依赖多个微服务的部署。

如果依赖关系存在环 (例如:AAA 依赖 BBB,BBB 依赖 CCC,CCC 依赖 AAA),那么就无法部署,因为存在"循环依赖"。

请给出一个函数,判断给定的微服务依赖"无环",并返回部署顺序,如果存在环,返回字符串 CanCanCan notnotnot deploydeploydeploy。

输入描述

  • 第一行输入:NNN 为参与部署的微服务的数量(1≤N≤10001 \le N \le 10001≤N≤1000,整数)
  • 接下来接着 NNN 行,每行描述一个服务的依赖关系(依赖关系是有向的,即 AAA 依赖 BBB,表示 BBB 要在 AAA 之前部署,否则 AAA 就会依赖失败):
  • 格式:serviceName1serviceName1serviceName1 M1M1M1 upstreamService1upstreamService1upstreamService1 upstreamService2upstreamService2upstreamService2 .........
  • 格式:serviceName2serviceName2serviceName2 M2M2M2 upstreamService1upstreamService1upstreamService1 upstreamService2upstreamService2upstreamService2 .........
  • 格式:serviceName3serviceName3serviceName3 M3M3M3 upstreamService1upstreamService1upstreamService1 upstreamService2upstreamService2upstreamService2 .........
  • serviceNameserviceNameserviceName:微服务名称,名称不重复,每个微服务名称字符长度 ≤100\le 100≤100 个字符,字符包含 262626 个小写字母,数字 0−90-90−9。
  • MMM:本行为微服务依赖的前驱服务数量,整数,0≤M≤9990 \le M \le 9990≤M≤999,当 M=0M=0M=0 时,说明本微服务不依赖其他微服务。
  • upstreamServiceupstreamServiceupstreamService:本行为微服务依赖的前驱服务名称。
    注意:
  1. 被依赖的前驱服务 upstreamServiceupstreamServiceupstreamService 必须存在 serviceNameserviceNameserviceName 中,且同一 upstreamServiceupstreamServiceupstreamService 不重复。
  2. 本行微服务不能依赖自己,即同一行的被依赖的前驱服务 upstreamServiceupstreamServiceupstreamService 的值不等于本行的 serviceNameserviceNameserviceName。

输出描述

如果本微服务图无环,返回部署顺序,一行输出全部微服务名称,以空格隔开。 规则:

  1. 一个微服务部署时,它所依赖的前驱服务都已经部署。
  2. 如果存在多个前置依赖已经部署的微服务,输出时以微服务名称字符从小到大排序(即首字符 asciiasciiascii 码小的微服务排在前面,首字符相同的则比较下一个字符,依次类推)。
  3. 如果存在环,返回字符串 CanCanCan notnotnot deploydeploydeploy。

样例1

输入

复制代码
3
aa 1 bb
bb 1 cc
cc 1 aa

输出

复制代码
Can not deploy

说明

图中依赖存在环,故输出 CanCanCan notnotnot deploydeploydeploy。

样例2

输入

复制代码
5
payment 2 auth order
order 1 user
auth 1 database
user 0
database 0

输出

复制代码
database auth user order payment

说明

111.以拓扑排序顺序输出,当前 databasedatabasedatabase 和 useruseruser 依赖的微服务均为 000,按照字符序优先输出 databasedatabasedatabase

222.从拓扑网中删除 databasedatabasedatabase 及其入边,形成新图的 authauthauth 和 useruseruser 依赖的微服务均为 000,按照字符序优先输出 authauthauth

333.重复步骤1、2,最终顺序为 database、auth、user、order、paymentdatabase、auth、user、order、paymentdatabase、auth、user、order、payment

题解

思路

标准的拓扑排序遍历题,借助拓扑排序的概念理解这个题,一个服务依赖另一个服务对应入度 + 1, 只有入度为0的服务才能被部署。代码求解逻辑如下:

  1. 定义depend哈希表保存指定服务 依赖于它的服务,使用dependCount记录每个服务的入度 ,定义ans存储部署结果。
  2. 使用队列进行每一轮遍历,初始找出其中入度为0的服务并且尚未激活加入队列,队列中的服务为本轮被激活的服务,遍历队列中服务,依靠depend更新依赖于它服务的入度,如果入度变为0,保存用于下一轮遍历。每一轮被激活的服务排序之后加入ans中
  3. 按照2的逻辑进行处理,直到无服务可被激活。如果ans.size() != 总服务数说明存在循环依赖,输出Can not deploy . 不存在循环依赖的情况下按顺序输出ans中服务即可。

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;


int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;
    // 依赖关系
    unordered_map<string, vector<string>>  depend;
    // 入度
    unordered_map<string, int>  dependCount;
    // 是否已激活
    unordered_map<string, bool> serviceFlag;
    
    vector<string> ans;

    while (n--) {
        string serviceName;
        int m;
        cin >> serviceName;
        cin >> m;
        string upstreamService;
        serviceFlag[serviceName] = false;
        // 入度初始化为0
        dependCount[serviceName] = 0;
        for (int i = 0; i < m; i++) {
            cin >> upstreamService;
            depend[upstreamService].push_back(serviceName);
            // 入度+1
            dependCount[serviceName]++;
        }
    }
    
    // 存储入度为0的服务
    queue<string> q;
    for (auto& service : dependCount) {
        if (service.second == 0) {
            q.push(service.first);
            serviceFlag[service.first] = true;
        }
    }
    
    queue<string> q_back;
    while (!q.empty()) {
        
        vector<string> current_ans;
        
        while (!q.empty()) {
            string service = q.front();
            q.pop();
            current_ans.push_back(service);
            
            // 更新指定节点入度
            for (auto& name : depend[service]) {
                // 防止重复入队
                if (serviceFlag[name]) {
                    continue;
                }
                dependCount[name]--;
                if (dependCount[name] == 0) {
                    q_back.push(name);
                    serviceFlag[name] = true;
                } 
            }
        }
        
        swap(q, q_back);
        sort(current_ans.begin(), current_ans.end());
        for (auto &name : current_ans) {
            ans.push_back(name);
        }
    }
    
    
    // 说明存在环
    if (ans.size() != serviceFlag.size()) {
        cout << "Can not deploy";
        return 0;
    }
    
    // 输出结果
    for (int i = 0; i < ans.size(); i++) {
        if (i != 0) {
            cout << " ";
        }
        cout << ans[i];
    }
    return 0;  
    
}

java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {

    public static void main(String[] args) throws Exception {

        Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();

        // 依赖关系
        Map<String, List<String>> depend = new HashMap<>();

        // 入度
        Map<String, Integer> dependCount = new HashMap<>();

        // 是否已激活
        Map<String, Boolean> serviceFlag = new HashMap<>();

        List<String> ans = new ArrayList<>();

        while (n-- > 0) {

            String serviceName = sc.next();
            int m = sc.nextInt();

            serviceFlag.put(serviceName, false);

            // 入度初始化为0
            dependCount.put(serviceName, 0);

            for (int i = 0; i < m; i++) {

                String upstreamService = sc.next();

                depend.computeIfAbsent(upstreamService, k -> new ArrayList<>())
                        .add(serviceName);

                // 入度+1
                dependCount.put(serviceName,
                        dependCount.get(serviceName) + 1);
            }
        }

        // 存储入度为0的服务
        Queue<String> q = new LinkedList<>();

        for (Map.Entry<String, Integer> entry : dependCount.entrySet()) {
            if (entry.getValue() == 0) {
                q.offer(entry.getKey());
                serviceFlag.put(entry.getKey(), true);
            }
        }

        Queue<String> qBack = new LinkedList<>();

        while (!q.isEmpty()) {

            List<String> currentAns = new ArrayList<>();

            while (!q.isEmpty()) {

                String service = q.poll();

                currentAns.add(service);

                for (String name :
                        depend.getOrDefault(service, Collections.emptyList())) {

                    // 防止重复入队
                    if (serviceFlag.get(name)) {
                        continue;
                    }

                    dependCount.put(name,
                            dependCount.get(name) - 1);

                    if (dependCount.get(name) == 0) {
                        qBack.offer(name);
                        serviceFlag.put(name, true);
                    }
                }
            }

            Queue<String> tmp = q;
            q = qBack;
            qBack = tmp;

            Collections.sort(currentAns);

            ans.addAll(currentAns);
        }

        // 说明存在环
        if (ans.size() != serviceFlag.size()) {
            System.out.print("Can not deploy");
            return;
        }

        // 输出结果
        for (int i = 0; i < ans.size(); i++) {
            if (i != 0) {
                System.out.print(" ");
            }
            System.out.print(ans.get(i));
        }
    }
}

python

python 复制代码
from collections import deque
import sys

tokens = sys.stdin.read().split()

idx = 0
n = int(tokens[idx])
idx += 1

# 依赖关系
depend = {}

# 入度
depend_count = {}

# 是否已激活
service_flag = {}

ans = []

for _ in range(n):

    service_name = tokens[idx]
    idx += 1

    m = int(tokens[idx])
    idx += 1

    service_flag[service_name] = False

    # 入度初始化为0
    depend_count[service_name] = 0

    for _ in range(m):

        upstream_service = tokens[idx]
        idx += 1

        depend.setdefault(upstream_service, []).append(service_name)

        # 入度+1
        depend_count[service_name] += 1

# 存储入度为0的服务
q = deque()

for service, cnt in depend_count.items():
    if cnt == 0:
        q.append(service)
        service_flag[service] = True

q_back = deque()

while q:

    current_ans = []

    while q:

        service = q.popleft()

        current_ans.append(service)

        for name in depend.get(service, []):

            # 防止重复入队
            if service_flag[name]:
                continue

            depend_count[name] -= 1

            if depend_count[name] == 0:
                q_back.append(name)
                service_flag[name] = True

    q, q_back = q_back, q

    current_ans.sort()

    ans.extend(current_ans)

# 说明存在环
if len(ans) != len(service_flag):
    print("Can not deploy", end="")
else:
    print(" ".join(ans), end="")

javascript

js 复制代码
const readline = require("readline");

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const lines = [];

rl.on("line", line => {
    lines.push(line.trim());
});

rl.on("close", () => {

    let idx = 0;

    const n = Number(lines[idx++]);

    // 依赖关系
    const depend = new Map();

    // 入度
    const dependCount = new Map();

    // 是否已激活
    const serviceFlag = new Map();

    const ans = [];

    for (let t = 0; t < n; t++) {

        const arr = lines[idx++].split(" ");

        const serviceName = arr[0];
        const m = Number(arr[1]);

        serviceFlag.set(serviceName, false);

        // 入度初始化为0
        dependCount.set(serviceName, 0);

        for (let i = 0; i < m; i++) {

            const upstreamService = arr[i + 2];

            if (!depend.has(upstreamService)) {
                depend.set(upstreamService, []);
            }

            depend.get(upstreamService).push(serviceName);

            // 入度+1
            dependCount.set(
                serviceName,
                dependCount.get(serviceName) + 1
            );
        }
    }

    // 存储入度为0的服务
    let q = [];

    for (const [service, cnt] of dependCount) {
        if (cnt === 0) {
            q.push(service);
            serviceFlag.set(service, true);
        }
    }

    let qBack = [];

    while (q.length > 0) {

        const currentAns = [];

        while (q.length > 0) {

            const service = q.shift();

            currentAns.push(service);

            // 更新指定节点入度
            for (const name of (depend.get(service) || [])) {

                // 防止重复入队
                if (serviceFlag.get(name)) {
                    continue;
                }

                dependCount.set(
                    name,
                    dependCount.get(name) - 1
                );

                if (dependCount.get(name) === 0) {
                    qBack.push(name);
                    serviceFlag.set(name, true);
                }
            }
        }

        [q, qBack] = [qBack, q];

        currentAns.sort();

        ans.push(...currentAns);
    }

    // 说明存在环
    if (ans.length !== serviceFlag.size) {
        console.log("Can not deploy");
        return;
    }

    // 输出结果
    console.log(ans.join(" "));
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"os"
	"sort"
)

func main() {

	reader := bufio.NewReader(os.Stdin)

	var n int
	fmt.Fscan(reader, &n)

	// 依赖关系
	depend := make(map[string][]string)

	// 入度
	dependCount := make(map[string]int)

	// 是否已激活
	serviceFlag := make(map[string]bool)

	var ans []string

	for i := 0; i < n; i++ {

		var serviceName string
		var m int

		fmt.Fscan(reader, &serviceName, &m)

		serviceFlag[serviceName] = false

		// 入度初始化为0
		dependCount[serviceName] = 0

		for j := 0; j < m; j++ {

			var upstreamService string
			fmt.Fscan(reader, &upstreamService)

			depend[upstreamService] =
				append(depend[upstreamService], serviceName)

			// 入度+1
			dependCount[serviceName]++
		}
	}

	// 存储入度为0的服务
	var q []string

	for service, cnt := range dependCount {
		if cnt == 0 {
			q = append(q, service)
			serviceFlag[service] = true
		}
	}

	var qBack []string

	for len(q) > 0 {

		var currentAns []string

		for len(q) > 0 {

			service := q[0]
			q = q[1:]

			currentAns = append(currentAns, service)

			// 更新指定节点入度
			for _, name := range depend[service] {

				// 防止重复入队
				if serviceFlag[name] {
					continue
				}

				dependCount[name]--

				if dependCount[name] == 0 {
					qBack = append(qBack, name)
					serviceFlag[name] = true
				}
			}
		}

		q, qBack = qBack, q

		sort.Strings(currentAns)

		ans = append(ans, currentAns...)
	}

	// 说明存在环
	if len(ans) != len(serviceFlag) {
		fmt.Print("Can not deploy")
		return
	}

	// 输出结果
	for i := 0; i < len(ans); i++ {
		if i > 0 {
			fmt.Print(" ")
		}
		fmt.Print(ans[i])
	}
}
相关推荐
●VON1 小时前
AtomGit Flutter鸿蒙客户端:Tab导航架构
flutter·华为·架构·harmonyos·鸿蒙
Swift社区2 小时前
鸿蒙 PC 文件共享:分布式机制 + Demo 实现
分布式·华为·harmonyos
ShallowLin10 小时前
【HarmonyOS闯关习题】——DevEco Studio的使用
华为·harmonyos
科技与数码12 小时前
鸿蒙6.1小艺伴随式AI体验:让阅读效率翻倍
人工智能·华为·harmonyos
程序猿追12 小时前
棋盘上的博弈:我在 HarmonyOS 里塞了一个五子棋“大脑”
人工智能·华为·harmonyos
程序猿追14 小时前
把 255.255.255.0 拆开看——在 HarmonyOS 上写个 IP 地址与子网掩码计算器
华为·harmonyos
坚果的博客15 小时前
【鸿蒙 PC三方库构建系统】SHA 库 鸿蒙PC 适配详解
华为·harmonyos
小雨下雨的雨15 小时前
月相分析工具鸿蒙PC Electron框架技术实现详解
前端·javascript·华为·electron