算法题:问题描述:给一个数组nums=[5,4,8,2],给一个n=5416, 让你从nums中选出一些元素,使得组成的数字是小于n的最大数
java
import java.util.Arrays;
public class FindMaxNumberLessThanTarget {
public static void main(String[] args) {
// 定义数组 nums
int[] nums = {5, 6, 8, 7};
// 定义目标值 target
int target = 500;
// 对数组进行排序
Arrays.sort(nums);
// 将目标值转换为字符串,方便逐位处理
String targetStr = String.valueOf(target);
// 调用 getMaxNumbers 方法获取小于目标值的最大数字
int result = getMaxNumbers(nums, targetStr);
// 输出结果
System.out.println(result);
}
// 二分查找方法,用于在 nums 中找到小于等于 target 的最大数字
public static int search(int[] nums, int target) {
// 初始化二分查找的左边界
int low = 0;
// 初始化二分查找的右边界
int high = nums.length - 1;
// 二分查找循环
while (low < high) {
// 计算中间位置,使用 (high - low + 1) / 2 避免整数溢出
int mid = low + (high - low + 1) / 2;
// 如果中间位置的数字小于等于目标值
if (nums[mid] <= target) {
// 更新左边界为中间位置
low = mid;
} else {
// 否则更新右边界为中间位置减 1
high = mid - 1;
}
}
// 如果左边界对应的数字小于等于目标值,返回该数字,否则返回 -1
return nums[low] <= target ? nums[low] : -1;
}
// 主方法,用于构建小于目标值的最大数字
public static int getMaxNumbers(int[] nums, String target) {
// 用于存储构建的数字的每一位
int[] res = new int[target.length()];
// 最终结果
int ans = 0;
// 标记是否已经确定了小于目标值的最大数字
boolean flag = false;
// 遍历目标值的每一位
for (int i = 0; i < target.length(); i++) {
// 如果已经确定了小于目标值的最大数字
if (flag) {
// 直接将 nums 中的最大值添加到 res 中
res[i] = nums[nums.length - 1];
continue;
}
// 获取当前位的数字
int subtarget = target.charAt(i) - '0';
// 调用 search 方法,找到小于等于当前位的最大数字
int temp = search(nums, subtarget);
// 如果没有找到合适的数字
if (temp == -1) {
// 如果是第一位
if (i == 0) {
// 如果目标值长度为 1,返回 0
if (target.length() == 1) {
return 0;
} else {
// 否则返回由 nums 中最大值重复 target.length() - 1 次组成的数字
StringBuilder sb = new StringBuilder();
for (int j = 0; j < target.length() - 1; j++) {
sb.append(nums[nums.length - 1]);
}
return Integer.parseInt(sb.toString());
}
} else {
// 向前回溯,尝试找到一个合适的数字
int index = i - 1;
while (temp == -1 && index >= 0) {
temp = search(nums, target.charAt(index) - '0' - 1);
index--;
}
// 如果仍然没有找到合适的数字
if (temp == -1) {
// 返回由 nums 中最大值重复 target.length() - 1 次组成的数字
StringBuilder sb = new StringBuilder();
for (int j = 0; j < target.length() - 1; j++) {
sb.append(nums[nums.length - 1]);
}
return Integer.parseInt(sb.toString());
}
// 更新 res 中相应位置的数字
res[index + 1] = temp;
// 将中间位置的数字设为 nums 中的最大值
for (int j = index + 2; j < i; j++) {
res[j] = nums[nums.length - 1];
}
// 将当前位设为 nums 中的最大值
res[i] = nums[nums.length - 1];
// 标记已经确定了小于目标值的最大数字
flag = true;
}
} else {
// 如果找到的数字等于当前位
if (temp == subtarget) {
// 将该数字添加到 res 中
res[i] = temp;
} else {
// 否则将该数字添加到 res 中,并标记已经确定了小于目标值的最大数字
res[i] = temp;
flag = true;
}
}
}
// 将 res 中的数字组合成一个整数
for (int i = 0; i < res.length; i++) {
ans = ans * 10 + res[i];
}
// 返回最终结果
return ans;
}
}
代码的整体思路
- 对数组
nums
进行排序,以便后续查找合适的数字。 - 把目标值
target
转换为字符串,方便逐位处理。 - 定义
search
函数,借助二分查找从nums
里找出小于等于给定值的最大数字。 - 定义
getMaxNumbers
函数,通过遍历目标值的每一位,逐步构建小于目标值的最大数字。 - 最终输出构建好的最大数字。