Medium
题目描述
给你一个整数数组 groups,其中 groups[i] 表示第 i 个组的大小。还给你一个整数数组 elements。
你的任务是根据以下规则为每个组分配一个元素:
- 如果
groups[i]能被elements[j]整除,则索引j处的元素可以分配给组i。 - 如果有多个元素可以分配,选择索引
j最小的元素。 - 如果没有元素满足条件,为该组分配
-1。
返回一个整数数组 assigned,其中 assigned[i] 是为组 i 选择的元素索引,如果没有合适的元素则为 -1。
注意:一个元素可以分配给多个组。
示例 1:
输入:groups = [8,4,3,2,4], elements = [4,2]
输出:[0,0,-1,1,0]
解释:
- elements[0] = 4 分配给组 0、1 和 4。
- elements[1] = 2 分配给组 3。
- 组 2 无法分配任何元素。
示例 2:
输入:groups = [2,3,5,7], elements = [5,3,3]
输出:[-1,1,0,-1]
解释:
- elements[1] = 3 分配给组 1。
- elements[0] = 5 分配给组 2。
- 组 0 和 3 无法分配任何元素。
示例 3:
输入:groups = [10,21,30,41], elements = [2,1]
输出:[0,1,0,1]
解释:
elements[0] = 2 分配给偶数值的组,elements[1] = 1 分配给奇数值的组。
约束条件:
1 <= groups.length <= 10^51 <= elements.length <= 10^51 <= groups[i] <= 10^51 <= elements[i] <= 10^5
解题思路
这道题需要为每个组找到能整除该组大小的最小索引元素。
思路分析:
朴素方法:对每个组遍历所有元素,找到第一个能整除的元素。时间复杂度为 O(n*m),可能超时。
哈希表优化:使用哈希表记录每个元素值的最小索引,然后对每个组找其所有因子,选择索引最小的。
推荐解法 - 埃氏筛变形:从小索引开始,对于每个元素,找到所有它的倍数对应的组,并尝试更新这些组的分配结果。这样确保了索引小的元素优先被考虑。
具体步骤:
- 初始化结果数组为 -1
- 使用哈希表记录每个元素值的最小索引
- 对于每个不同的元素值(按索引从小到大),遍历其所有倍数
- 如果某个倍数是某个组的大小,且该组还未分配元素,则分配当前元素
- 由于按索引顺序处理,自然保证了最小索引优先的要求
这种方法的优势是避免了对每个组都去找所有因子的重复计算,而是反向地从元素出发找能整除的组。
代码实现
class Solution {
public:
vector<int> assignElements(vector<int>& groups, vector<int>& elements) {
int n = groups.size();
vector<int> assigned(n, -1);
// 记录每个元素值的最小索引
unordered_map<int, int> elementIndex;
for (int i = 0; i < elements.size(); i++) {
if (elementIndex.find(elements[i]) == elementIndex.end()) {
elementIndex[elements[i]] = i;
}
}
// 按索引排序元素
vector<pair<int, int>> sortedElements; // {value, index}
for (auto& p : elementIndex) {
sortedElements.push_back({p.first, p.second});
}
sort(sortedElements.begin(), sortedElements.end(),
[](const pair<int,int>& a, const pair<int,int>& b) {
return a.second < b.second;
});
// 建立组大小到索引的映射
unordered_map<int, vector<int>> groupMap;
for (int i = 0; i < n; i++) {
groupMap[groups[i]].push_back(i);
}
// 为每个元素找到它能整除的组
for (auto& elem : sortedElements) {
int value = elem.first;
int index = elem.second;
// 找到所有value的倍数
for (int multiple = value; multiple <= 100000; multiple += value) {
if (groupMap.count(multiple)) {
for (int groupIdx : groupMap[multiple]) {
if (assigned[groupIdx] == -1) {
assigned[groupIdx] = index;
}
}
}
}
}
return assigned;
}
};
class Solution:
def assignElements(self, groups: List[int], elements: List[int]) -> List[int]:
n = len(groups)
assigned = [-1] * n
# 记录每个元素值的最小索引
element_index = {}
for i, elem in enumerate(elements):
if elem not in element_index:
element_index[elem] = i
# 按索引排序元素
sorted_elements = sorted(element_index.items(), key=lambda x: x[1])
# 建立组大小到索引的映射
group_map = {}
for i, size in enumerate(groups):
if size not in group_map:
group_map[size] = []
group_map[size].append(i)
# 为每个元素找到它能整除的组
for value, index in sorted_elements:
# 找到所有value的倍数
multiple = value
while multiple <= 100000:
if multiple in group_map:
for group_idx in group_map[multiple]:
if assigned[group_idx] == -1:
assigned[group_idx] = index
multiple += value
return assigned
public class Solution {
public int[] AssignElements(int[] groups, int[] elements) {
int n = groups.Length;
int[] assigned = new int[n];
Array.Fill(assigned, -1);
// 记录每个元素值的最小索引
Dictionary<int, int> elementIndex = new Dictionary<int, int>();
for (int i = 0; i < elements.Length; i++) {
if (!elementIndex.ContainsKey(elements[i])) {
elementIndex[elements[i]] = i;
}
}
// 按索引排序元素
var sortedElements = elementIndex.OrderBy(p => p.Value).ToList();
// 建立组大小到索引的映射
Dictionary<int, List<int>> groupMap = new Dictionary<int, List<int>>();
for (int i = 0; i < n; i++) {
if (!groupMap.ContainsKey(groups[i])) {
groupMap[groups[i]] = new List<int>();
}
groupMap[groups[i]].Add(i);
}
// 为每个元素找到它能整除的组
foreach (var elem in sortedElements) {
int value = elem.Key;
int index = elem.Value;
// 找到所有value的倍数
for (int multiple = value; multiple <= 100000; multiple += value) {
if (groupMap.ContainsKey(multiple)) {
foreach (int groupIdx in groupMap[multiple]) {
if (assigned[groupIdx] == -1) {
assigned[groupIdx] = index;
}
}
}
}
}
return assigned;
}
}
var assignElements = function(groups, elements) {
const assigned = new Array(groups.length);
for (let i = 0; i < groups.length; i++) {
assigned[i] = -1;
for (let j = 0; j < elements.length; j++) {
if (groups[i] % elements[j] === 0) {
assigned[i] = j;
break;
}
}
}
return assigned;
};
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(M × MAX_VALUE / elements[i]),其中 M 是不同元素值的个数,MAX_VALUE = 10^5 |
| 空间复杂度 | O(N + M),用于存储结果数组和哈希表映射 |