Java中为二维数组填充不重复随机数的最简实现方法
解决二维数组填充唯一不重复随机数的最简方案
嘿,我来帮你搞定这个问题!首先得先指出你现有代码里的几个小问题:
- 你定义的二维数组是
x,但赋值的时候用了card,变量名不匹配,这肯定会编译报错; - 当前的随机数生成逻辑只是按列划分了范围,但完全没做去重处理,所以必然会出现重复值;
接下来直接给你最简、最高效的解决思路:与其每次生成随机数都检查是否已存在(这种方法不仅代码繁琐,数据量大时还容易卡循环),不如先创建一个包含所有需要的唯一数的序列,把它打乱(洗牌),再依次填充到二维数组里。这种方法逻辑简单,还能100%保证不重复。
通用版:生成全局唯一的随机数填充
如果你的需求是整个二维数组里的所有数都唯一,不管具体区间,代码可以这么写:
import java.util.Arrays; import java.util.Collections; import java.util.List; public class UniqueRandom2D { public static void main(String[] args) { int R = 3; // 替换成你的行数 int C = 4; // 替换成你的列数 int[][] card = new int[R][C]; int totalElements = R * C; // 1. 创建包含所有唯一数的数组(这里范围是1到总元素数,你可以按需修改) Integer[] numbers = new Integer[totalElements]; for (int i = 0; i < totalElements; i++) { numbers[i] = i + 1; } // 2. 打乱数组(用Java内置的洗牌方法,靠谱又省心) List<Integer> numList = Arrays.asList(numbers); Collections.shuffle(numList); // 3. 把打乱后的数填充到二维数组里 int idx = 0; for (int i = 0; i < R; i++) { for (int j = 0; j < C; j++) { card[i][j] = numList.get(idx++); } } // 测试输出(可选) for (int[] row : card) { System.out.println(Arrays.toString(row)); } } }
适配你原需求的版本:按列划分范围且全局唯一
看你原来的代码是想让每列的数落在[30j+1, 30(j+1)]的区间里,同时所有数唯一。因为每列的区间是不重叠的,我们可以针对每列单独生成区间内的数,打乱后取对应行数的数量填充:
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ColumnRangeUnique2D { public static void main(String[] args) { int R = 2; // 你的行数 int C = 3; // 你的列数 int[][] card = new int[R][C]; for (int j = 0; j < C; j++) { int start = 30 * j + 1; int end = 30 * (j + 1); // 生成当前列区间内的所有数 List<Integer> columnNums = new ArrayList<>(); for (int num = start; num <= end; num++) { columnNums.add(num); } // 打乱该列的数 Collections.shuffle(columnNums); // 取前R个填充到当前列的各行 for (int i = 0; i < R; i++) { card[i][j] = columnNums.get(i); } } // 测试输出 for (int[] row : card) { System.out.println(Arrays.toString(row)); } } }
为啥你之前的布尔校验法没成功?
大概率是逻辑细节出了问题,比如没正确维护已使用数的标记集合,或者生成随机数的范围计算错误。如果非要用校验法,正确的写法应该是这样(但还是不如洗牌法简洁):
int R = 3; int C = 4; int[][] card = new int[R][C]; int maxNum = 30 * C; boolean[] used = new boolean[maxNum + 1]; // 用索引对应数值,标记是否已使用 for (int i = 0; i < R; i++) { for (int j = 0; j < C; j++) { int num; do { // 生成当前列范围内的随机数 int start = 30 * j + 1; int end = 30 * (j + 1); num = start + (int)(Math.random() * (end - start + 1)); } while (used[num]); // 重复就重新生成 card[i][j] = num; used[num] = true; // 标记为已使用 } }
总的来说,洗牌法是实现这个需求的最优解:代码少、逻辑清晰、效率高,完全不用操心重复问题。
内容的提问来源于stack exchange,提问作者hairypotter
相关产品推荐
相关产品推荐

