leetcode
leetcode 1451 ~ 1500
分配重复整数

分配重复整数

难度:

标签:

题目描述

代码结果

运行时间: 71 ms, 内存: 24.7 MB


import java.util.HashMap;
import java.util.Map;
import java.util.Arrays;
import java.util.stream.Collectors;

/**
 * Solution for the given problem using Java Streams.
 * The approach is similar to the standard Java solution but uses streams for frequency calculation and sorting.
 */
public class SolutionStream {
    public boolean canDistribute(int[] nums, int[] quantity) {
        // Count the frequency of each number in nums
        Map<Integer, Long> freqMap = Arrays.stream(nums).boxed()
            .collect(Collectors.groupingBy(e -> e, Collectors.counting()));
        // Convert frequency map values to a list
        List<Long> freqList = new ArrayList<>(freqMap.values());
        // Sort quantity in descending order to try larger orders first
        Arrays.sort(quantity);
        reverse(quantity);
        return backtrack(freqList, quantity, 0);
    }

    private void reverse(int[] quantity) {
        int left = 0, right = quantity.length - 1;
        while (left < right) {
            int temp = quantity[left];
            quantity[left] = quantity[right];
            quantity[right] = temp;
            left++;
            right--;
        }
    }

    private boolean backtrack(List<Long> freqList, int[] quantity, int idx) {
        if (idx == quantity.length) {
            return true;
        }
        for (int i = 0; i < freqList.size(); i++) {
            if (freqList.get(i) >= quantity[idx]) {
                freqList.set(i, freqList.get(i) - quantity[idx]);
                if (backtrack(freqList, quantity, idx + 1)) {
                    return true;
                }
                freqList.set(i, freqList.get(i) + quantity[idx]);
            }
        }
        return false;
    }
}

解释

方法:

这个题解采用了回溯的方法。首先,统计nums中每个数字出现的次数,并按照出现次数降序排序。然后,也将顾客订单的数量按照降序排序。接着,使用深度优先搜索(DFS)尝试为每个顾客分配订单。对于每个顾客,遍历统计的数字出现次数列表,尝试从中分配足够的数量给顾客。如果当前数字剩余的数量足够,并且之前没有尝试过这个数量(通过一个集合Map来记录),则进行尝试,并递归地处理下一个顾客。如果所有顾客都能成功分配,则返回true,否则回溯并尝试其他分配方案。

时间复杂度:

O(N^m)

空间复杂度:

O(m + N)

代码细节讲解

🦆
在题解中提到使用了回溯方法,你能解释一下什么是回溯以及它在这个问题中是如何应用的吗?
回溯是一种通过探索所有可能的候选解来找出所有解的算法。如果候选解被证明不是一个有效的解,回溯算法会丢弃它,并回退到之前的步骤,尝试其他可能的解。在这个问题中,回溯用于尝试为每个顾客分配他们需要的数量。从第一个顾客开始,尝试给他分配足够的数量,如果能成功,递归地尝试为下一个顾客分配。如果某一步分配失败,算法则取消上一步的分配(即回溯),尝试其他可能的分配方式。这样,算法可以找到是否存在一种分配方式能满足所有顾客的需求。
🦆
题解中提到将数字出现的次数和顾客订单数量都降序排序,这样做的具体目的是什么?
将数字出现的次数和顾客订单数量进行降序排序的目的是为了尽可能快地减少搜索空间。通过优先考虑需要更多数量的顾客和拥有更多库存的数字,算法首先尝试满足最难满足的订单,这样在早期阶段可能就能确定某些分配是不可能的,从而提前终止无效的搜索路径,加快算法的效率。
🦆
为什么在尝试分配给顾客之后,如果失败需要进行回溯?具体的回溯操作是怎样实现的?
在尝试分配给顾客之后,如果失败,需要进行回溯是因为当前尝试的分配方案不能满足后续顾客的需求,我们需要撤销当前的分配,并尝试其他可能的分配方案。具体的回溯操作是通过在递归函数中,当一个分配尝试失败(即dfs返回False)后,恢复之前修改的状态(即将先前分配给顾客的数量加回到对应数字的剩余数量中),然后继续尝试下一个可能的分配。这样可以确保每一次递归调用都在探索一个新的分配可能性。
🦆
题解中使用了一个集合`Map`来记录尝试过的数量,这个集合的作用是什么,它如何帮助优化算法的性能?
集合`Map`用于记录在尝试分配过程中已经尝试过的数字的数量,以避免重复尝试相同的失败分配方案。当尝试为一个顾客分配某个数量而失败后,该数量会被加入到`Map`中。如果后续再次考虑到相同的数量,算法会直接跳过,避免无意义的重复计算。这样可以减少算法的时间复杂度,提高效率。

相关问题