小于n的最大数

289 阅读3分钟

算法题:问题描述:给一个数组nums=[5,4,8,2],给一个n=5416, 让你从nums中选出一些元素,使得组成的数字是小于n的最大数

import java.util.*;

class Solution {
    // 该方法用于找出小于给定数字 num 且由 candidates 集合中的数字组成的最大数
    public Integer get_num(Set<Integer> candidates, int num) {
        // 找出 candidates 集合中的最大值
        int maxVal = Collections.max(candidates);
        // 将最大值转换为字符串,方便后续使用
        String maxStr = String.valueOf(maxVal);
        // 将给定的数字 num 转换为字符串,方便逐位处理
        String numStr = String.valueOf(num);

        // 调用 getLowerLargestDigitDic 方法生成每个数字对应的小于它的最大候选数字的映射
        Map<String, String> lowerLargestDigitDic = getLowerLargestDigitDic(candidates);

        // 初始化索引 i 为 0,用于遍历 numStr 字符串
        int i = 0;
        // 获取 numStr 字符串的长度
        int l = numStr.length();
        // 创建一个长度为 l 的字符数组 resStrArr,用于存储最终结果的每一位数字,初始值都设为 '0'
        char[] resStrArr = new char[l];
        Arrays.fill(resStrArr, '0');

        // 开始遍历 numStr 字符串
        while (i < l) {
            // 获取当前位置的数字,并将其转换为整数
            int currentDigit = numStr.charAt(i) - '0';
            // 如果当前数字在 candidates 集合中,并且不是最后一位数字
            if (candidates.contains(currentDigit) && i < l - 1) {
                // 第一阶段:将当前数字直接填入结果数组中
                resStrArr[i] = numStr.charAt(i);
                // 索引 i 加 1,继续处理下一位数字
                i++;
            } else {
                // 第二阶段:遇到最后一位数字,或者当前数字不在 candidates 集合中
                // 从映射中获取小于当前数字的最大候选数字
                String digit = lowerLargestDigitDic.get(String.valueOf(currentDigit));
                // 如果没有找到合适的数字,并且索引 i 大于 0,则进行回溯操作
                while (digit == null && i > 0) {
                    // 索引 i 减 1,回到上一位数字
                    i--;
                    // 再次从映射中获取小于上一位数字的最大候选数字
                    digit = lowerLargestDigitDic.get(String.valueOf(numStr.charAt(i)));
                }
                // 处理回溯后仍然没有找到合适数字的情况
                if (i == 0 && digit == null && l == 1) {
                    // 如果只有一位数字且没有合适的候选数字,返回 null
                    return null;
                }
                if (i == 0 && digit == null && l > 1) {
                    // 如果是多位数且第一位没有合适的候选数字,将结果数组的第一位设为 '0'
                    resStrArr[0] = '0';
                } else {
                    // 将找到的合适数字填入结果数组的当前位置
                    resStrArr[i] = digit.charAt(0);
                }
                // 从当前位置的下一位开始,将结果数组的剩余位置都填入最大值
                for (int j = i + 1; j < l; j++) {
                    resStrArr[j] = maxStr.charAt(0);
                }
                // 将结果数组转换为字符串,再转换为整数并返回
                return Integer.parseInt(new String(resStrArr));
            }
        }
        // 如果遍历完整个字符串都没有返回结果,返回 null
        return null;
    }

    // 该方法用于生成每个数字对应的小于它的最大候选数字的映射
    private Map<String, String> getLowerLargestDigitDic(Set<Integer> candidates) {
        // 创建一个 HashMap 用于存储映射关系
        Map<String, String> dic = new HashMap<>();
        // 初始化上一个合适的数字为 null
        String prev = null;
        // 遍历 0 到 9 的数字
        for (int i = 0; i < 10; i++) {
            // 将当前数字对应的小于它的最大候选数字存入映射中
            dic.put(String.valueOf(i), prev);
            // 如果当前数字在 candidates 集合中,更新 prev 为当前数字
            if (candidates.contains(i)) {
                prev = String.valueOf(i);
            }
        }
        // 返回生成的映射
        return dic;
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建 Solution 类的实例
        Solution s = new Solution();
        // 调用 get_num 方法,传入候选数字集合和目标数字,打印结果
        System.out.println(s.get_num(new HashSet<>(Arrays.asList(1, 2, 9, 4)), 2533));  // 2499
        System.out.println(s.get_num(new HashSet<>(Arrays.asList(1, 2, 5, 4)), 2543));  // 2542
        System.out.println(s.get_num(new HashSet<>(Arrays.asList(1, 2, 5, 4)), 2541));  // 2525
        System.out.println(s.get_num(new HashSet<>(Arrays.asList(1, 2, 9, 4)), 2111));  // 1999
        System.out.println(s.get_num(new HashSet<>(Arrays.asList(5, 9)), 5555)); // 999
    }
}    

代码的整体思路

  1. 对数组 nums 进行排序,以便后续查找合适的数字。
  2. 把目标值 target 转换为字符串,方便逐位处理。
  3. 定义 search 函数,借助二分查找从 nums 里找出小于等于给定值的最大数字。
  4. 定义 getMaxNumbers 函数,通过遍历目标值的每一位,逐步构建小于目标值的最大数字。
  5. 最终输出构建好的最大数字。