leetcode
leetcode 1701 ~ 1750
最大兼容性评分和

最大兼容性评分和

难度:

标签:

题目描述

代码结果

运行时间: 51 ms, 内存: 16.0 MB


/*
题目思路:
利用Java Stream API来处理数据流,计算学生和导师之间的兼容性评分。通过构建掩码和递归函数来跟踪最佳分配和评分。
*/

import java.util.stream.IntStream;

public class Solution {
    public int maxCompatibilitySum(int[][] students, int[][] mentors) {
        return maxCompatibilitySumHelper(students, mentors, 0, 0, new int[students.length][1 << students.length]);
    }

    private int maxCompatibilitySumHelper(int[][] students, int[][] mentors, int studentIdx, int mask, int[][] dp) {
        if (studentIdx == students.length) return 0;
        if (dp[studentIdx][mask] != 0) return dp[studentIdx][mask];

        dp[studentIdx][mask] = IntStream.range(0, mentors.length)
            .filter(j -> (mask & (1 << j)) == 0)
            .map(j -> {
                int score = (int) IntStream.range(0, students[studentIdx].length)
                    .filter(k -> students[studentIdx][k] == mentors[j][k])
                    .count();
                return score + maxCompatibilitySumHelper(students, mentors, studentIdx + 1, mask | (1 << j), dp);
            }).max().orElse(0);
        return dp[studentIdx][mask];
    }
}

解释

方法:

此题解采用的是动态规划加状态压缩的策略。首先,计算学生与每位导师之间的兼容性评分,存储在二维数组 f 中,其中 f[i][j] 表示第 i 个学生与第 j 个导师的评分。接着,利用一个一维数组 dp 来存储状态压缩的动态规划结果,dp[i] 表示在状态 i 下的最大兼容性评分和。状态 i 是一个二进制数,表示当前已分配的导师集合。通过遍历所有的状态,并对于每个状态,在考虑分配下一个导师时更新 dp 数组,最终 dp 的最后一个元素即为最大兼容性评分和。

时间复杂度:

O(m^2 n + m * 2^m)

空间复杂度:

O(m^2 + 2^m)

代码细节讲解

🦆
如何理解状态压缩在此问题中的应用,并且它如何帮助提高算法的效率?
状态压缩是一种利用整数的二进制表示来表示集合的技术。在本问题中,每一位的0或1表示一个导师是否已经被分配。例如,如果有三位导师,二进制数 '101' 表示第一位和第三位导师已经被分配。状态压缩能够将问题的空间复杂度从指数级减少到多项式级别,因为它将可能的分配情况从列举每种情况简化为0到2^m-1的整数遍历。这种方法显著提高了算法的空间和时间效率,特别是在处理与组合相关的问题时非常有效。
🦆
在动态规划数组 `dp` 中,`dp[i]` 的值是如何通过前一个状态推导出来的?具体是怎样的计算逻辑?
在动态规划数组 `dp` 中,`dp[i]` 表示在状态i下的最大兼容性评分和。状态i是一个二进制数,每一位代表一个导师是否被分配。计算 `dp[i]` 的值是通过遍历所有可能的前一个状态来完成的。具体来说,对于每个状态i,我们检查每一位(每位代表一个导师),如果这位是1(即这位导师已分配),我们则尝试理解这位导师是如何被分配的。我们通过关闭这一位(将其从1变为0,使用位运算 i ^ (1 << j))来获得一个新的状态,这个新状态代表一个没有当前导师的旧状态。然后,我们将这个旧状态的最大评分和加上当前导师和对应学生的兼容性评分(通过二维数组f计算),取所有可能的组合中的最大值,从而得到 `dp[i]`。
🦆
为什么在动态规划中使用位运算来表示状态?这种表示方式有什么优势和潜在的限制?
在动态规划中使用位运算来表示状态主要是因为它提供了一种高效的方式来处理和表示所有可能的组合状态。这种表示方式的优势在于:1) 它能够高效地使用内存和处理时间,因为状态转换(例如添加或删除一个元素)可以通过简单的位运算实现,这些操作通常比其他数据结构操作更快;2) 它天然适合处理二进制决策问题,如配对、选择等。然而,这种方法也有限制,主要是它仅适用于元素数量较少的情况(通常不超过20-30),因为状态的数量会随着集合大小呈指数增长,导致计算和存储成本急剧上升。

相关问题