2021华为软件工程师笔试题第一道

2020-09-26

题目阐述

  • 某公司要发传单。
  • 现有主管、组员和外包人员三个层级,主管将发传单任务委托给组员,组员再把任务委托给外包。
  • 实际干活的只有外包,主管和组员的传单数(名义上)为其手下的外包人员的传单数目之和。
  • 要求输出所有人的传单总数,格式如下:姓名<传单数目>
  • 此外,为了清晰,输出要以树形结构输出,用---分别作为组员外包人员的前缀。

样例

输入

  • performance后面的为外包人员姓名,该人员的传单数目
  • organization后面的为层级制度,如Aaron为主管,Abel为组员,Adam为外包人员
  • 样例约束:每个外包人员只能被一个组员负责,每个组员只能被一个主管负责
performance
Adam,125
Andy,110
Bill,92
Evan,154

organization
Aaron,Abel,Adam
Aaron,Abel,Andy
Aaron,Jone,Bill
Aaron,Jone,Evan
eof

输出:

Aaron<481>
Abel<235>
--Adam<125>
--Andy<110>
Jone<246>
--Bill<92>
--Evan<154>

思路

  • 使用面向对象的方式实现
  • 自底层(外包人员)向顶层(主管)逐层收集数据
  • 自底层(外包人员)向顶层(主管)逐层计算名义传单数

实现

// @ts-lint
const readline = require('readline')
const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout,
})
const lines = []
rl.on('line', handle)

// -------------------------------------------------- 定义主管、组员、外包人员这三个类 --------------------------------------------------
// 主管,字母越靠前,层级越高
function A(name) {
  this.name = name
  // 他的手下们(他的组员们)
  this.subs = []
  // 他的名义传单数目
  this.num = 0
}

A.prototype.add = function(item){
  this.subs.push(item)
}
// 待收集完他的手下们,主管计算他的名义传单数
A.prototype.cal = function(){
  this.subs.forEach(item => {
    this.num += Number(item.num)
  })
}

// 组员
function B(name) {
  this.name = name
  this.subs = []
  this.num = 0
}
// 组员本质上和主管一样,啥活不干,所以可以继承主管的 add 和 cal 方法
B.prototype = Object.create(A.prototype)

// 外包
function C(name, num) {
  this.name = name
  this.num = Number(num)
}

// -------------------------------------------------- 用于存放各级人员的三个数组 --------------------------------------------------
/**
 *
 * @type {Array<C>}
 */
let cList = []
/**
 *
 * @type {Array<B>}
 */
let bList = []
/**
 *
 * @type {Array<A>}
 */
let aList = []

let status = ''

/**
 *
 * @param {string}line
 */
function handle(line) {
  // -------------------------------------------------- 面向牛客网的输入编程 --------------------------------------------------
  if (line.trim() === '') return
  if (line.trim() === 'eof') {
    // 最后一行时,输入的数据已经全部接收,可以计算数据并进行输出了
    calculateAndPrintResult()
  }
  if (line === 'performance') {
    status = 'p'
    return
  }
  if (line === 'organization') {
    status = 'o'
    return
  }
  // -------------------------------------------------- 收集数据进数组 --------------------------------------------------
  if (status === 'p') {
    let twins = line.split(',')
    cList.push(new C(twins[0], twins[1]))
  }
  if (status === 'o') {
    let triplets = line.split(',')
    let cName = triplets[2]
    let bName = triplets[1]
    let aName = triplets[0]
    // let c = cList.find(item => item.name === cName) // must has one
    let b = bList.find(item => item.name === bName)
    let a = aList.find(item => item.name === aName)
    if (!a) { // 不得重复
      aList.push(new A(aName))
    }
    if (!b) {
      bList.push(new B(bName))
    }
    // -------------------------------------------------- 建立ABC这三个类的关联(通过subs) --------------------------------------------------
    // cc bb aa must exists
    let cc = cList.find(item => item.name === cName)
    let bb = bList.find(item => item.name === bName)
    let aa = aList.find(item => item.name === aName)
    if (!bb.subs.find(c => c === cc)) { // 不得重复
      bb.add(cc)
    }
    if (!aa.subs.find(b => b === bb)) {
      aa.add(bb)
    }
  
  // -------------------------------------------------- 计算并打印 --------------------------------------------------
  function calculateAndPrintResult() {
    bList.forEach(b => {
      b.cal()
    })
    aList.forEach(a => {
      a.cal()
    })
    aList.forEach(a => {
      console.log(`${a.name}<${a.num}>`)
      a.subs.forEach(b => {
        console.log(`-${b.name}<${b.num}>`)
        b.subs.forEach(c => {
          console.log(`--${c.name}<${c.num}>`)
        })
      })
    })
    process.exit(0)
  }
}