华为od | (C卷,200分)- 猜密码Java(对数器验证)
139(C卷,200分)- 猜密码
(本题仅仅关注逻辑,并没有完全按照oj模式 输入输出格式)
题目描述
小杨申请了一个保密柜,但是他忘记了密码。只记得密码都是数字,而且所有数字都是不重复的。
请你根据他记住的数字范围和密码的最小数字数量,帮他算下有哪些可能的组合,规则如下:
- 输出的组合都是从可选的数字范围中选取的,且不能重复;
- 输出的密码数字要按照从小到大的顺序排列,密码组合需要按照字母顺序,从小到大的顺序排序。
- 输出的每一个组合的数字的数量要大于等于密码最小数字数量;
- 如果可能的组合为空,则返回“None”
输入描述
输入的第一行是可能的密码数字列表,数字间以半角逗号分隔
输入的第二行是密码最小数字数量
输出描述
可能的密码组合,每种组合显示成一行,每个组合内部的数字以半角逗号分隔,从小到大的顺序排列。
输出的组合间需要按照字典序排序。
比如:2,3,4放到2,4的前面
备注
字典序是指按照单词出现在字典的顺序进行排序的方法,比如:
- a排在b前
- a排在ab前
- ab排在ac前
- ac排在aca前
用例
| 输入 | 2,3,4 2 |
|---|---|
| 输出 | 2,3 2,3,4 2,4 3,4 |
| 说明 | 最小密码数量是两个,可能有三种组合: 2,3 2,4 3,4 三个密码有一种: 2,3,4 |
| 输入 | 2,0 1 |
|---|---|
| 输出 | 0 0,2 2 |
| 说明 | 可能的密码组合,一个的有两种: 0 2 两个的有一个: 0,2 |
回溯递归三部曲
- 函数的返回值 参数
void backtracking()
参数: 结果集res, 路径path, 最小长度k, 数组arr, 以及控制的startIindex
- 终止条件
当长度达到当前目标长度 k,加入结果� 前提首先调用的时候使用使用for控制最小长度
- 单层递归逻辑
排序层面去重, statIndex 传入的i+1
套模版得出代码:
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 用户输入
String[] inputArr = scanner.nextLine().split(",");
int[] arr = Arrays.stream(inputArr).mapToInt(Integer::parseInt).toArray();
int k = Integer.parseInt(scanner.nextLine());
// 调用方法
pwd obj = new pwd();
List<List<Integer>> result = obj.combine(arr, k);
// 输出结果
for (List<Integer> combination : result) System.out.println(combination);
}
public List<List<Integer>> combine(int[] arr, int k) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
Arrays.sort(arr); // 排序去重
// for循环确保 最小长度大于等于指定的数
for (int i = k; i <= arr.length; i++) backtracking(arr, i, 0, res, path);
return res;
}
private void backtracking(int[] arr, int k, int sIndex, List<List<Integer>> res, List<Integer> path) {
if (path.size() == k) { // 当长度达到当前目标长度 k,加入结果 因为for循环控制k每次进入都会加1
res.add(new ArrayList<>(path));
return;
}
for (int i = sIndex; i < arr.length; i++) {
if (i > sIndex && arr[i] == arr[i - 1]) continue; // 去重逻辑,防止同层重复
path.add(arr[i]);
backtracking(arr, k, i + 1, res, path);
path.remove(path.size() - 1);
}
}
}
提供对数器版本:
package od;
import java.util.*;
/**
* 华为od -- 猜密码
*
*/
public class pwd {
public List<List<Integer>> combine(int[] arr, int k) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
Arrays.sort(arr); // 排序去重
// for循环确保 最小长度大于等于指定的数
for (int i = k; i <= arr.length; i++) backtracking(arr, i, 0, res, path);
return res;
}
private void backtracking(int[] arr, int k, int sIndex, List<List<Integer>> res, List<Integer> path) {
if (path.size() == k) { // 当长度达到当前目标长度 k,加入结果 因为for循环控制k每次进入都会加1
res.add(new ArrayList<>(path));
return;
}
for (int i = sIndex; i < arr.length; i++) {
if (i > sIndex && arr[i] == arr[i - 1]) continue; // 去重逻辑,防止同层重复
path.add(arr[i]);
backtracking(arr, k, i + 1, res, path);
path.remove(path.size() - 1);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 用户输入
System.out.println("Enter array (comma-separated):");
String[] inputArr = scanner.nextLine().split(",");
int[] arr = Arrays.stream(inputArr).mapToInt(Integer::parseInt).toArray();
System.out.println("Enter minimum combination size:");
int k = Integer.parseInt(scanner.nextLine());
// 调用方法
pwd obj = new pwd();
List<List<Integer>> result = obj.combine(arr, k);
// 输出结果
System.out.println("Your Code Output:");
for (List<Integer> combination : result) {
System.out.println(combination);
}
// 对数器测试逻辑
System.out.println("\nStarting Comparator Tests...");
Random random = new Random();
int testCases = 1000;
for (int t = 0; t < testCases; t++) {
// 随机生成测试用例
int[] testArr = obj.generateRandomArray(random);
int testK = random.nextInt(testArr.length) + 1;
// 调用两个方法
List<List<Integer>> result1 = obj.combine(testArr, testK); // 你的方法
List<List<Integer>> result2 = obj.referenceCombine(testArr, testK); // 参考实现
// 排序结果以便比较
result1.sort(Comparator.comparing(Object::toString));
result2.sort(Comparator.comparing(Object::toString));
// 对比结果
if (!result1.equals(result2)) {
System.out.println("Test Failed!");
System.out.println("Input Array: " + Arrays.toString(testArr));
System.out.println("Combination Size: " + testK);
System.out.println("Your Code Output: " + result1);
System.out.println("Expected Output: " + result2);
return;
}
}
System.out.println("All tests passed!");
}
// 对数器参考实现
private List<List<Integer>> referenceCombine(int[] arr, int k) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(arr);
for (int i = k; i <= arr.length; i++) { // 从 k 到 arr.length 遍历
referenceBacktrack(arr, i, 0, new LinkedList<>(), res);
}
return res;
}
private void referenceBacktrack(int[] arr, int k, int index, LinkedList<Integer> path, List<List<Integer>> res) {
if (path.size() == k) {
res.add(new ArrayList<>(path));
return;
}
for (int i = index; i < arr.length; i++) {
if (i > index && arr[i] == arr[i - 1]) continue; // 去重
path.add(arr[i]);
referenceBacktrack(arr, k, i + 1, path, res);
path.removeLast();
}
}
// 随机生成数组
private int[] generateRandomArray(Random random) {
int size = random.nextInt(5) + 1; // 数组长度 1 到 5
int[] nums = new int[size];
for (int i = 0; i < size; i++) {
nums[i] = random.nextInt(10); // 数字范围 0 到 9
}
return nums;
}
}

浙公网安备 33010602011771号