题目有点绕,但实际上很简单,只要理清楚题目所描述的东西,很容易写出代码。

已知条件:
1. 音频id取模后的区间是[0,799]
2. 每个机器有一个区间[i,k],如果id%800的值落在这个区间,那么这个id的文件就落在这个机器上
3. 新增机器:实际上就是找到一个[i,k]范围最大的机器,然后一分为二,旧的机器的区间更新为[i,(i+k)/2],新机器的区间为[(i+k)/2+1,k]

思路:
1. 定义一个computer结构体用来描述机器,包含区间信息以及自己的机器id
2. 使用集合存放computer,并对其自定义排序——区间大的放在前面,如果区间一样大则索引小的放在前面
3. 集合初始化只有一个机器——范围为[0,799],机器id为1,
4. 新增机器:每次新增机器的时候都从集合的第一个元素取出范围进行划分,然后创建新的机器
5. 在每次新增机器的时候,对区间进行判断,如果id%800落在这两个机器中的一个上,则更新要返回的机器id

代码如下:

struct computer
{
  int id_start;
  int id_end;
  int index;

  int range() const
  {
    return id_end - id_start;
  }
};

struct compare_obj
{
  // 先根据区间大小进行排序,如果区间大小一致,则根据机器编号排序
  bool operator()(const computer &a, const computer &b)
  {
    if (a.range() != b.range())
    {
      return a.range() > b.range();
    }

    return a.index < b.index;
  }
};

class Solution {
public:
int consistentHashing(int n, int ID)
{
  std::set<computer, compare_obj> s;
  computer c;
  c.id_start = 0;
  c.id_end = 799;
  c.index = 1;
  s.insert(c);

  int index = ID % 800;
  int ans = 1;
  for (int i = 2; i <= n; ++i)
  {
    auto c = *s.begin();
    s.erase(s.begin());
    computer new_computer;
    new_computer.id_start = (c.id_start + c.id_end) / 2 + 1;
    new_computer.id_end = c.id_end;
    new_computer.index = i;
    c.id_end = (c.id_start + c.id_end) / 2;
    s.insert(c);
    s.insert(new_computer);

    if (index >= new_computer.id_start && index <= new_computer.id_end)
    {
      ans = new_computer.index;
    }
    else if (index >= c.id_start && index <= c.id_end)
    {
      ans = c.index;
    }
  }
  return ans;
}
};