← 返回博客列表
Citadel

Citadel OA 真题复盘|进程分配 + 负载均衡两道题完整解析

2026-03-16

Citadel OA 真题复盘|进程分配 + 负载均衡两道题完整解析

Citadel OA Question 1

导读:Citadel 的 OA 考试以系统设计和算法优化著称。这两道题考察的是分布式系统中的核心问题:如何高效分配进程资源,以及如何动态平衡处理器负载。第一题考察组合数学,第二题考察二分查找与贪心策略。


📌 题目一:进程分配方案计数

问题描述

n 个进程分配到 k 个处理器,要求相邻进程不能使用同一处理器。求满足条件的分配方案总数,结果对给定模数取模。

示例

核心思路

这是一个组合数学问题,使用动态规划或数学公式求解。

方法一:数学公式(最优)

关键观察

公式

总方案数 = k × (k-1)^(n-1)

特殊情况

方法二:动态规划

定义 dp[i][j] 表示前 i 个进程分配到处理器 j 的方案数。

def count_allocations_dp(n, k, mod):
    if n == 1:
        return k % mod
    if k == 1:
        return 0
    
    # dp[i][j] = 前i个进程,第i个分配到处理器j的方案数
    dp = [[0] * k for _ in range(n + 1)]
    
    # 初始化:第1个进程可以分配到任何处理器
    for j in range(k):
        dp[1][j] = 1
    
    # 填充DP表
    for i in range(2, n + 1):
        for j in range(k):
            # 第i个进程分配到处理器j
            # 第i-1个进程必须不在处理器j
            for prev_j in range(k):
                if prev_j != j:
                    dp[i][j] = (dp[i][j] + dp[i-1][prev_j]) % mod
    
    # 求和所有可能的最后一个处理器
    result = sum(dp[n]) % mod
    return result

时间复杂度:O(n × k²)
空间复杂度:O(n × k)

最优解:数学公式 + 快速幂

def count_allocations(n, k, mod):
    """
    计算进程分配方案数
    
    Args:
        n: 进程数
        k: 处理器数
        mod: 模数
    
    Returns:
        方案总数 % mod
    """
    if n == 1:
        return k % mod
    if k == 1:
        return 0
    
    # 计算 k × (k-1)^(n-1) % mod
    # 使用快速幂优化
    base = (k - 1) % mod
    power = pow(base, n - 1, mod)  # Python内置快速幂
    result = (k % mod * power) % mod
    
    return result

时间复杂度:O(log n)
空间复杂度:O(1)

完整代码

def processScheduling(n, k, mod):
    """
    Q1: 进程分配方案计数
    
    将n个进程分配到k个处理器,相邻进程不能使用同一处理器
    求方案总数 % mod
    """
    # 特殊情况处理
    if n == 1:
        return k % mod
    if k == 1:
        return 0
    
    # 公式:k × (k-1)^(n-1)
    # 使用Python内置pow函数进行快速幂运算
    result = (k % mod) * pow(k - 1, n - 1, mod) % mod
    return result


# 测试用例
if __name__ == "__main__":
    MOD = 10**9 + 7
    
    # 测试1
    print(processScheduling(2, 3, MOD))  # 输出: 6
    
    # 测试2
    print(processScheduling(1, 3, MOD))  # 输出: 3
    
    # 测试3
    print(processScheduling(3, 2, MOD))  # 输出: 2
    
    # 测试4:大数据
    print(processScheduling(1000000, 1000000, MOD))  # 快速计算

面试要点

澄清问题

优化思路

常见错误


📌 题目二:处理器负载均衡最小轮次

Citadel OA Question 2

问题描述

系统有 k 个处理器,初始任务分配为 tasks[0..k-1]。每一轮中:

求完成所有任务的最小轮次,使得所有处理器的负载均衡。

示例

k = 3, tasks = [1, 2, 3]
初始状态:处理器0有1个任务,处理器1有2个任务,处理器2有3个任务

第1轮:
- 处理器0处理1个任务 → 剩余0个
- 处理器1处理1个任务,转移1个给处理器0 → 剩余1个
- 处理器2处理1个任务,转移1个给处理器1 → 剩余1个

第2轮:
- 处理器0处理1个任务 → 剩余0个
- 处理器1处理1个任务 → 剩余0个
- 处理器2处理1个任务 → 剩余0个

最小轮次 = 2

核心思路

使用二分查找答案。对于给定的轮次 t,检查是否可行。

可行性检查

对于轮次 t,每个处理器最多可以处理 t 个任务。

关键计算

可行条件:所有处理器的总可用容量 ≥ 总需转移任务数

def is_feasible(tasks, k, t):
    """
    检查轮次t是否可行
    """
    need = 0      # 需要转移的任务总数
    avail = 0     # 可用容量总数
    
    for cnt in tasks:
        if cnt > t:
            need += cnt - t
        else:
            avail += (t - cnt) // 2
    
    return avail >= need

二分查找

def minRounds(tasks, k):
    """
    二分查找最小轮次
    """
    # 最坏情况:所有任务都在一个处理器上
    left, right = 1, max(tasks)
    
    while left < right:
        mid = (left + right) // 2
        if is_feasible(tasks, k, mid):
            right = mid
        else:
            left = mid + 1
    
    return left

完整代码

def getMinTime(k, tasks):
    """
    Q2: 处理器负载均衡最小轮次
    
    Args:
        k: 处理器数量
        tasks: 初始任务分配数组,tasks[i]表示处理器i的任务数
    
    Returns:
        完成所有任务的最小轮次
    """
    def is_feasible(t):
        """检查轮次t是否可行"""
        need = 0      # 需要转移的任务总数
        avail = 0     # 可用容量总数
        
        for cnt in tasks:
            if cnt > t:
                # 处理器任务过多,需要转移
                need += cnt - t
            else:
                # 处理器有剩余容量
                # 可用容量 = (t - cnt) // 2
                # 原因:转移1个任务需要1轮,处理需要1轮,共2轮
                avail += (t - cnt) // 2
        
        return avail >= need
    
    # 二分查找最小轮次
    left, right = 1, max(tasks)
    
    while left < right:
        mid = (left + right) // 2
        if is_feasible(mid):
            right = mid
        else:
            left = mid + 1
    
    return left


# 测试用例
if __name__ == "__main__":
    # 测试1
    print(getMinTime(3, [1, 2, 3]))  # 输出: 2
    
    # 测试2
    print(getMinTime(2, [5, 5]))      # 输出: 5
    
    # 测试3
    print(getMinTime(4, [1, 1, 1, 1])) # 输出: 1
    
    # 测试4:不均衡
    print(getMinTime(2, [10, 1]))     # 输出: 5

复杂度分析

时间复杂度:O(k × log(max(tasks)))

空间复杂度:O(1)(不计输入)

面试要点

澄清问题

关键洞察

常见错误


🎯 总结对比

题目 算法 时间复杂度 难度
Q1:进程分配 组合数学 + 快速幂 O(log n) ⭐⭐
Q2:负载均衡 二分查找 + 贪心 O(k log m) ⭐⭐⭐

🚀 面试建议

  1. 时间管理:两道题共 90 分钟,建议各 45 分钟
  2. 代码质量:注重边界条件和模运算
  3. 沟通能力:清晰解释算法思路和复杂度
  4. 优化意识:从暴力解到最优解的演进过程

📞 需要面试辅助?

oavoservice 提供专业的 OA/VO 辅助服务。

👉 立即添加微信:Coding0201