华为od | (C卷,200分)- 猜密码Java(对数器验证)

139(C卷,200分)- 猜密码

(本题仅仅关注逻辑,并没有完全按照oj模式 输入输出格式)

题目描述

小杨申请了一个保密柜,但是他忘记了密码。只记得密码都是数字,而且所有数字都是不重复的。

请你根据他记住的数字范围和密码的最小数字数量,帮他算下有哪些可能的组合,规则如下

  1. 输出的组合都是从可选的数字范围中选取的,且不能重复;
  2. 输出的密码数字要按照从小到大的顺序排列,密码组合需要按照字母顺序,从小到大的顺序排序。
  3. 输出的每一个组合的数字的数量要大于等于密码最小数字数量;
  4. 如果可能的组合为空,则返回“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

回溯递归三部曲

  1. 函数的返回值 参数

void backtracking()

参数: 结果集res, 路径path, 最小长度k, 数组arr, 以及控制的startIindex

  1. 终止条件

当长度达到当前目标长度 k,加入结果� 前提首先调用的时候使用使用for控制最小长度

  1. 单层递归逻辑

排序层面去重, 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;
    }
}

posted @ 2024-11-27 13:18  小杭呀  阅读(53)  评论(0)    收藏  举报