
本文详解如何正确生成指定范围内无重复的随机整数,指出原始 do-while 方法的逻辑缺陷,并推荐使用「填充+洗牌」这一简洁、可靠且时间复杂度最优的标准方案。
你遇到的问题非常典型:试图用 do-while 循环逐个生成随机数并简单比较相邻元素(如 list[i] == list[i-1]),但这种策略仅检测与前一个数是否重复,完全无法保证与之前所有已生成数字都不重复——因此会出现 0, 0, 6, 7, 13, 16, 16, ... 这类明显重复。
更严重的是,该方法存在逻辑漏洞与潜在死循环风险:当剩余可选数字极少(例如已填入 9 个不同数,只剩 1 个合法值),而 Math.random() 反复命中已用数字时,循环可能长时间卡住;若范围更小(如生成 10 个 0–5 的数),甚至永远无法终止。
✅ 正确解法:先构建候选池,再随机打乱,最后截取
这是算法设计中的经典思路(即 Fisher-Yates shuffle 的简化应用),兼具正确性、效率与可读性:
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Assignment2_Q2 {
public static void main(String[] args) {
int[] myList = number(10, 0, 20); // 生成10个[0,20]内不重复随机整数
Arrays.sort(myList);
System.out.println("The array in the sorted order:\n" + Arrays.toString(myList) + "\n");
}
// ✅ 推荐实现:安全、高效、一行逻辑清晰
public static int[] number(int count, int min, int max) {
if (count > (max - min + 1)) {
throw new IllegalArgumentException(
String.format("Cannot generate %d unique numbers in range [%d, %d]", count, min, max)
);
}
// 1. 生成 [min, max] 全集 → 2. 打乱 → 3. 取前 count 个 → 4. 转为 int[]
return IntStream.rangeClosed(min, max)
.boxed()
.collect(Collectors.collectingAndThen(
Collectors.toList(),
list -> {
Collections.shuffle(list);
return list.subList(0, count).stream()
.mapToInt(Integer::intValue)
.toArray();
}
));
}
}? 关键说明:
- IntStream.rangeClosed(0, 20) 生成 21 个连续整数(0 到 20 含端点);
- boxed() 转为 Integer 流以支持集合操作;
- Collections.shuffle() 基于 Fisher-Yates 算法,确保均匀随机;
- subList(0, 10) 安全截取——因已校验 count ≤ 总数量,不会越界;
- 最终通过 mapToInt 转回原始 int[],无缝对接原有 sortedOrder 和 display 逻辑。
⚠️ 为什么不推荐 Set + 循环重试?
虽可行(如 while(set.size()
? 进阶提示:若需多次调用或追求极致性能,可预生成 List
立即学习“Java免费学习笔记(深入)”;
综上,摒弃基于局部比较的脆弱循环逻辑,拥抱“构造全集→随机化→采样”的函数式范式,是解决此类问题最稳健、最符合 Java 8+ 编程习惯的实践方式。










