You need to enable JavaScript to run this app. Android Studio 如何实现指定范围内逐个生成不重复随机数
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio 如何实现指定范围内逐个生成不重复随机数

逐次生成不重复区间随机数的Android实现方案

核心实现思路

采用惰性版本的Fisher-Yates洗牌算法实现,完全满足逐次调用、不重复、全量覆盖指定区间的需求,规避传统“生成随机数+去重校验”方案的后期性能崩塌问题。整个实现不需要预先生成全量打乱的数字序列,所有随机交换动作都在方法被调用时按需完成,每次调用的时间复杂度稳定为O(1)。

具体实现逻辑

  • 初始化阶段:
    • 记录指定随机区间的上下限min、max,计算区间内总元素个数totalCount = max - min + 1
    • 维护剩余可抽取元素的游标remainingIndex,初始值为totalCount - 1
    • 初始化数值池数组:位置i存储的数值为min + i,无需提前做全量打乱,无额外初始化计算开销
  • 单次调用generateAnyRandom()的执行流程:
    1. 先做边界校验:如果remainingIndex < 0,代表区间内所有数字已经全部生成完毕,可根据业务规则抛出异常或返回约定错误值
    2. 在[0, remainingIndex]的闭区间内生成一个随机整数randomPos作为本次抽取的位置
    3. 取出数值池中randomPos位置的数值,作为本次要返回的随机结果
    4. 将数值池中randomPos位置的元素,和remainingIndex位置的元素做交换——把已经被抽走的元素移到数组末尾的“已使用区”,后续的随机抽取范围永远不会覆盖这个区域
    5. 将remainingIndex向前移动1位,等待下一次方法调用

常见实现误区

  • 误区1:用HashSet存储已经返回过的数字,每次生成随机数后校验是否存在于集合中。这种方案在剩余可选数字越少时,随机生成的碰撞概率越高:比如最后只剩2个可选数时,平均需要生成4次随机数才能命中未重复的值;只剩1个可选数时,理论上需要上千次随机生成才能命中,性能完全不可控。
  • 误区2:一次性生成全量打乱的数字列表存在内存中,每次调用弹出一个值。这种方案虽然性能达标,但如果区间范围过大(比如1到100万),一次性打乱并生成全量列表会占用不必要的计算和内存资源,而惰性洗牌方案在初始化时仅生成连续的有序数组,没有提前打乱的额外开销,所有随机动作按需触发,内存占用和前者一致,但实现逻辑更轻量化。

参考代码实现

import java.util.Random;

public class UniqueRandomGenerator {
    private final int min;
    private final int max;
    private int remainingIndex;
    private int[] numberPool;
    private final Random random = new Random();

    /**
     * 初始化生成器
     * @param min 随机区间下限
     * @param max 随机区间上限
     */
    public UniqueRandomGenerator(int min, int max) {
        this.min = min;
        this.max = max;
        int totalCount = max - min + 1;
        this.remainingIndex = totalCount - 1;
        this.numberPool = new int[totalCount];
        // 初始化数值池,无提前打乱开销
        for (int i = 0; i < totalCount; i++) {
            numberPool[i] = min + i;
        }
    }

    /**
     * 对外暴露的随机数生成方法
     * @return 区间内未返回过的随机数
     */
    public int generateAnyRandom() {
        if (remainingIndex < 0) {
            throw new IllegalStateException("指定区间内的所有数值已全部生成完毕");
        }
        // 在剩余可抽取范围内生成随机位置
        int randomPos = random.nextInt(remainingIndex + 1);
        int result = numberPool[randomPos];
        // 交换抽取位置和剩余范围末尾位置
        int temp = numberPool[randomPos];
        numberPool[randomPos] = numberPool[remainingIndex];
        numberPool[remainingIndex] = temp;
        // 剩余游标前移
        remainingIndex--;
        return result;
    }
}

内容的提问来源于stack exchange,提问作者Bhaskar Jyoti Dutta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.22 20:06:06