如何解决经理同行问题?

How to solve manager peer problem question?

我在 google 采访中被问到以下问题但无法回答。我进行了 google 搜索,但找不到解决此问题的任何正确方法。你能帮我解决这个问题吗?

Design a data structure to support following functions:

  1. setManager(A, B) sets A as a direct manager of B
  2. setPeer(A, B) sets A as a colleague of B. After that, A and B will have the same direct Manager.
  3. query(A, B) returns if A is in the management chain of B. Every person only has 1 direct manager.

让我们将每组同行视为代表公司管理链的层次结构树中的一个节点。我们知道它是一棵树,因为每个人只有 1 个直接经理。

我们将拥有以下形式的树:

快速想法:

  • setManager 只是连接 2 个节点(如果节点不存在,也会创建节点)。
  • setPeer 只是更新一个节点以包含另一个节点(如果节点已经存在);或为两个对等体创建一个节点(如果该节点的 none 存在);或合并 2 个现有节点(如果为每个对等体独立创建 2 个节点)。
  • query(A, B)只是向上遍历树,检查该路径上的节点是否包含员工A。
  • 一个额外的问题:给定一个员工 X,我们需要获得对相应节点的访问权限(可以通过额外的哈希 table 来解决,它从每个员工映射到他们对应的引用节点)。

上述思路的代码

public class EmployeeManagement {
  private Dictionary < string, Node > _employeeToNode;

  public EmployeeManagement() {
    _employeeToNode = new Dictionary < string, Node > ();
  }

  public void SetManager(string manager, string employee) {
    if (!_employeeToNode.ContainsKey(manager)) {
      _employeeToNode[manager] = new Node(null, manager);
    }

    if (!_employeeToNode.ContainsKey(employee)) {
      _employeeToNode[employee] = new Node(_employeeToNode[manager], employee);
    } else {
      _employeeToNode[employee].SetManagerNode(_employeeToNode[manager]);
    }
  }

  public void SetPeer(string employeeA, string employeeB) {
    if (_employeeToNode.ContainsKey(employeeA) && _employeeToNode.ContainsKey(employeeB)) {
      if (_employeeToNode[employeeA].HasEmployee(employeeB) &&
        _employeeToNode[employeeB].HasEmployee(employeeA)) {
        return;
      }
      // Merge node of A and B if distinct
      Node newNode = _employeeToNode[employeeA];
      Node oldNode = _employeeToNode[employeeB];
      if (_employeeToNode[employeeB].EmployeeCount() > newNode.EmployeeCount()) {
        newNode = _employeeToNode[employeeB];
        oldNode = _employeeToNode[employeeA];
      }

      if (!newNode.HasManager()) {
        newNode.SetManagerNode(oldNode.GetManagerNode());
      }

      foreach(var employee in oldNode.GetEmployees()) {
        newNode.AddEmployee(employee);
      }

      _employeeToNode[employeeA] = newNode;
      _employeeToNode[employeeB] = newNode;
      foreach(var employee in oldNode.GetEmployees()) {
        _employeeToNode[employee] = newNode;
      }
    } else if (_employeeToNode.ContainsKey(employeeA)) {
      _employeeToNode[employeeB] = _employeeToNode[employeeA];
    } else if (_employeeToNode.ContainsKey(employeeB)) {
      _employeeToNode[employeeA] = _employeeToNode[employeeB];
    } else {
      // Create a new node for both A and B
      Node forAB = new Node(null, employeeA);
      forAB.AddEmployee(employeeB);
      _employeeToNode[employeeA] = forAB;
      _employeeToNode[employeeB] = forAB;
    }
  }

  /// <summary>
  /// Check if A is in the management chain of B
  /// </summary>
  public bool Query(string employeeA, string employeeB) {
    if (!_employeeToNode.ContainsKey(employeeA) || !_employeeToNode.ContainsKey(employeeB)) {
      return false; // no info of employee A or employee B yet
    }

    Node managersOfB = _employeeToNode[employeeB].GetManagerNode();
    while (managersOfB != null) {
      if (managersOfB.HasEmployee(employeeA)) {
        return true;
      }

      managersOfB = managersOfB.GetManagerNode();
    }

    return false; // not found A in the management chain of B
  }
}

private class Node {
  private Node _directManagers;
  private HashSet < string > _employees;

  public Node(Node directManagers, string employee) {
    _directManagers = directManagers;
    _employees = new HashSet < string > ();
    _employees.Add(employee);
  }

  public bool HasManager() {
    return _directManagers != null;
  }

  public void SetManagerNode(Node directManagers) {
    _directManagers = directManagers;
  }

  public Node GetManagerNode() {
    return _directManagers;
  }

  public void AddEmployee(string employee) {
    _employees.Add(employee);
  }

  public HashSet < string > GetEmployees() {
    return _employees;
  }

  public bool HasEmployee(string employee) {
    return _employees.Contains(employee);
  }

  public int EmployeeCount() {
    return _employees.Count;
  }
}

假设您有以下人员class:

struct Person {
  // we need to store the manager, obviously
  Person* manager = nullptr;
  // we also need to store the peers to assign the correct
  // manager for all when it is set for one person in the group
  shared_ptr<vector<Person*>> peerGroup = make_shared<vector<Person*>>({this});
};

一个人,当新创建的时候,没有经理和一个只包含这个人本身的对等组。

假设A、B等不是字符串而是Person*,可以实现方法如下:

void setManager(Person* a, Person* b) {
  for (Person* person : *b->peerGroup) person->manager = a;
}

void setPeer(Person* a, Person* b) {
  // merge peer groups of a and b
  // by first adding b's peers to a's peer group
  // and then setting b's peer group to a's peer group
  for (Person* person : *b->peerGroup) a->peerGroup->push_back(person);
  b->peerGroup = a->peerGroup;
}

bool query(Person* a, Person* b) {
  // we want to find out if a is managed by b
  // so we go up the hierarchy, starting from a
  Person* current = a;
  while (current->manager != nullptr) {
    // stop if b is (indirect) manager of a
    if (current->manager == b) return true;
    current = current->manager;
  }
  // we reached the top of the hierarchy and did not find b
  return false;
}

如果您确实收到了字符串(如“A”、“B”、...),您可以使用散列映射来查看您是否已经为此名称创建了一个 Person 对象,如果没有创建一个:

map<string, unique_ptr<Person>> persons;

Person* getPerson(string name) {
  if (!persons.contains(name)) {
    persons[name] = make_unique<Person>();
  }
  return persons[name].get()
}

这可以通过单个 class、Employee 来完成,其中包含一个 attribute/member _manager,它是对该员工经理的引用(如果有的话)和一个attribute/member '_managees',该员工管理的所有员工 instances/objects 的集合。

注意:我完全按照我对问题定义的解释,即要点 1-3,而不是 OP 或任何其他人的解释。 setPeer的描述是将A设置为B的同事,之后A和B将拥有同一个直属Manager。这样调用setPeer(A, B)时,就是设置A 的经理成为 B 的经理,除非 B 有经理,否则这没有任何意义。而且每个人都有一个经理,除了老板老板,而老板老板顾名思义是没有同行的。因此,也许 A 刚刚升职(或降级或只是横向调动到另一个部门)。这并不意味着 A 的每个前同事都获得了相同的晋升,现在也有相同的新经理。所以我认为这是一个 less-complicated 问题,而不是其他人所认为的问题。

class Employee:
    def __init__(self, name, manager=None):
        self._name = name
        self._managees = set()
        self._manager = None # so far
        if manager:
            self.set_manager(manager) # Could be none if this is the "top dog"

    def __repr__(self):
        return f'Name: {self._name}, Managed By: {self._manager._name if self._manager else ""}, Manages: {[managee._name for managee in self._managees]}'

    def get_name(self):
        return self._name

    def get_manager(self):
        return self._manager

    def get_managees(self):
        return self._managees

    def manages(self, employee):
        return employee in self._managees

    def is_managed_by(self, employee):
        return self._manager is employee

    def remove_manager(self):
        """
        We are no longer managed by anyone.
        """
        if self._manager:
            self._manager.remove_managee(self)
            self._manager = None
        return self

    def remove_managee(self, managee):
        """
        This manager no longer manages managee.
        """
        self._managees.remove(managee)
        managee._manager = None # No longer has a manager
        return self

    def set_manager(self, manager):
        if not manager:
            self.remove_manager()
            return self
        if self._manager:
            # We have an existing manager:
            self._manager.remove_managee(self)
        self._manager = manager
        manager._managees.add(self)
        return self

    def add_managee(self, managee):
        """
        This manager now manages managee.
        """
        managee.set_manager(self)
        return sell

    def set_peer(self, managee):
        assert managee._manager # Make sure managee can have a peer
        self.set_manager(managee._manager)
        return self

    @staticmethod
    def query(employee1, employee2):
        """
        Is employee1 in the management chain of employee2?
        """
        manager = employee2._manager
        while manager:
            if manager is employee1:
                return True
            manager = manager._manager
        return False


tom = Employee('Tom')
dick = Employee('Dick', tom)
harry = Employee('Harry', dick)
sally = Employee('Sally')
sally.set_manager(harry)
assert sally.is_managed_by(harry) and harry.manages(sally)
sally.set_manager(tom)
assert sally.is_managed_by(tom) and tom.manages(sally)
sally.set_peer(harry)
assert sally.is_managed_by(dick) and dick.manages(sally)
assert Employee.query(tom, harry)
assert not Employee.query(harry, dick)
print(tom)
print(dick)
print(harry)
print(sally)

打印:

Name: Tom, Managed By: , Manages: ['Dick']
Name: Dick, Managed By: Tom, Manages: ['Harry', 'Sally']
Name: Harry, Managed By: Dick, Manages: []
Name: Sally, Managed By: Dick, Manages: []

使用三个散列 tables 1. 员工到组 ID 映射 (emp) 2. 组 ID 到员工列表 (gid) 3. 组 ID -> 经理 ID table(经理)

int id = 0;
void setpeer(string A, string B) {
int id1 = 0;
int id2 = 0;
if (emp.find(A) != emp.end())
   id1 = emp[A];
if (emp.find(B) != emp.end())
   id2 = emp[B];

if (!id1 && !id2) {
    ++id;
    emp[A] = id;
    emp[B} = id;
    gid[id].push_back(A);
    gid[id].push_back(B);
} else if (!id1) {
     emp[A] = id2;
     gid[id2].push_back(A);
} else if (!id2) {
     emp[B] = id1;
     gid[id1].push_back(B);
} else {
   for(i = 0;i<gid[id2].size();i++) {
       emp[gid[id2][i]] = id1;
       gid[id1].push_back( gid[id2][i] );
  }
  if (manager.find(id2) != manager.end())
        manager[id1] = manager[id2].
  manager.erase(id2);
  gid.erase(id2);
}

void setManager(string A, string B) {
int id1, id2;
   if (emp.find(A) != emp.end())
         id1 = emp[A];
  else {
       ++id;
      emp[A] = id;
      id1 = id;
      gid[id].push_back(A);
  }
   if (emp.find(B) != emp.end())
         id2 = emp[B];
  else {
       ++id;
      emp[B] = id;
      id2 = id;
      gid[id].push_back(B);
  }
   manager[id2] = id1;
}

bool query(string A, string B) {
   int id1 = 0, id2 = 0;
   if (emp.find(A) != emp.end())
        id1 = emp[A];
   if (emp.find(B) != emp.end())
        id2 = emp[B];
   if (!id1 || !id2) //one of them does not exist
     return false;
  id2 = manager[id2];
  while(id2 != 0) {
     if (id2 == id1)
        return true;
     id2 = manager[id2];
 }
 return false;
}

int id = 0;
void setpeer(string A, string B) {
int id1 = 0;
int id2 = 0;
if (emp.find(A) != emp.end())
   id1 = emp[A];
if (emp.find(B) != emp.end())
   id2 = emp[B];

if (!id1 && !id2) {
    ++id;
    emp[A] = id;
    emp[B} = id;
    gid[id].push_back(A);
    gid[id].push_back(B);
} else if (!id1) {
     emp[A] = id2;
     gid[id2].push_back(A);
} else if (!id2) {
     emp[B] = id1;
     gid[id1].push_back(B);
} else {
   for(i = 0;i<gid[id2].size();i++) {
       emp[gid[id2][i]] = id1;
       gid[id1].push_back( gid[id2][i] );
  }
  if (manager.find(id2) != manager.end())
        manager[id1] = manager[id2].
  manager.erase(id2);
  gid.erase(id2);
}

void setManager(string A, string B) {
int id1, id2;
   if (emp.find(A) != emp.end())
         id1 = emp[A];
  else {
       ++id;
      emp[A] = id;
      id1 = id;
      gid[id].push_back(A);
  }
   if (emp.find(B) != emp.end())
         id2 = emp[B];
  else {
       ++id;
      emp[B] = id;
      id2 = id;
      gid[id].push_back(B);
  }
   manager[id2] = id1;
}

bool query(string A, string B) {
   int id1 = 0, id2 = 0;
   if (emp.find(A) != emp.end())
        id1 = emp[A];
   if (emp.find(B) != emp.end())
        id2 = emp[B];
   if (!id1 || !id2) //one of them does not exist
     return false;
  id2 = manager[id2];
  while(id2 != 0) {
     if (id2 == id1)
        return true;
     id2 = manager[id2];
 }
 return false;
}