算法题:问题描述:给一个数组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
}
}
代码的整体思路
- 对数组
nums进行排序,以便后续查找合适的数字。 - 把目标值
target转换为字符串,方便逐位处理。 - 定义
search函数,借助二分查找从nums里找出小于等于给定值的最大数字。 - 定义
getMaxNumbers函数,通过遍历目标值的每一位,逐步构建小于目标值的最大数字。 - 最终输出构建好的最大数字。