题目
- 给定一个数字limit和一组数组,根据数组中的元素,返回小于 limit 的最大值
- 递归回溯情况
- 如果递归结果最终返回 -1,说明构造的树无法和limit位数相同,所以低一位然后最大值补全
- 如果递归过程返回 -1,说明当前位可以,但是下一位不行,当前位换成更小的位,后续补全最大值
递归最终结果返回-1
递归过程返回-1
function process(arr, limit) {
arr.sort();
// 满足可以等于的情况,题目是只能小于limit
limit--;
// offset 取出limit上对应位的数字, (limit / offset) %10
// 6888 => offset = 1000
let offset = 1;
// /10 防溢出
while (offset <= limit / 10) {
offset = offset * 10;
}
const res = find(arr, limit, offset);
if (res === -1) {
// 结果返回-1,说明位数相同无法满足,需要位数-1,然后拿最大值补全即可
offset /= 10;
let rest = 0;
while (offset > 0) {
rest += arr[arr.length - 1] * offset;
offset /= 10;
}
return rest;
} else {
return res;
}
}
function find(arr, limit, offset) {
// 每一步选择都和 limit 一样
if (offset === 0) {
return limit;
}
// 从最高位开始,当前位数字
let cur = Math.floor(limit / offset) % 10;
let nearIndex = near(cur);
// 错误决定,交给上游调整,用于首次和后续判断
if (nearIndex === -1) {
return -1;
} else if (arr[nearIndex] === cur) {
let ans = find(arr, limit, offset / 10);
if (ans !== -1) {
return ans;
// 下一位超过了无法满足,当前位取更小一个的数字,后续填充最大
} else if (near > 0) {
near--;
return (
// 高位
(limit / (offset * 10)) * offset * 10 +
// 当前位
arr[near] * offset +
// 后续位
rest(arr, offset / 10)
);
// 后续没成功,自身也不能再下降了!宣告失败,往上返回!
} else {
return -1;
}
} else {
// 查找到的当前位比limit当前位小,后续位补充最大值即可
return (
(limit / (offset * 10)) * offset * 10 +
arr[nearIndex] * offset +
reset(arr, offset / 10)
);
}
}
// 拼接位数
function rest(arr, offset) {
let rest = 0;
while (offset > 0) {
rest += arr[arr.length - 1] * offset;
offset /= 10;
}
return rest;
}
// 查找小于等于 target 最右的位置 , [3,5,5] 查找4 返回 0
function near(arr, target) {
let left = 0,
right = arr.length - 1,
mid,
near = -1;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (arr[mid] <= target) {
near = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return near;
}
const arr = [1, 2, 2, 2, 3, 4, 4, 5, 5];
console.log(near(arr, 2));