递归回溯 返回小于limit的最大值

73 阅读2分钟

题目

  • 给定一个数字limit和一组数组,根据数组中的元素,返回小于 limit 的最大值
  • 递归回溯情况
    • 如果递归结果最终返回 -1,说明构造的树无法和limit位数相同,所以低一位然后最大值补全
    • 如果递归过程返回 -1,说明当前位可以,但是下一位不行,当前位换成更小的位,后续补全最大值

递归最终结果返回-1 image.png

递归过程返回-1 image.png

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));