动态规划 构成值的最少硬币数量

112 阅读1分钟

题目

给定一个都为正数的数组和一个数值n,求构成n的最小数量

  • 通过递归过程来保存每一次的硬币数量,如果无效会通过返回值 -1 来抵消
// -1表示无效值,0表示有效
function process(arr, index, rest) {
  if (rest < 0) {
    return -1;
  }

  if (rest === 0) {
    return 0;
  }

  if (index === arr.length) {
    return -1;
  }
  const no = process(arr, index + 1, rest);
  const yes = process(arr, index + 1, rest - arr[index]);

  if (no == -1 && yes == -1) {
    // 要或不要当前硬币都无解
    return -1;
  } else {
    if (no == -1) {
      return yes + 1; // 在要当前硬币下的解
    }
    if (yes == -1) {
      return no; // 不要当前硬币下的解
    }

    return Math.min(no, yes + 1); // 在要或不要都有解的情况下取最小值
  }
}

进阶2:记忆化搜索

const dp = [];

for (let i = 0; i < arr.length; i++) {
  for (let j = 0; j < target; j++) {
    dp[i][j] = -2;
  }
}

// -1表示无效值,0表示有效
function process(arr, index, rest) {
  if (rest < 0) {
    return -1;
  }

  if (dp[index][rest] !== -2) {
    return dp[index][rest];
  }

  if (rest === 0) {
    dp[index][rest] = 0;
  } else if (index === arr.length) {
    dp[index][rest] = -1;
  } else {
    const no = process(arr, index + 1, rest);
    const yes = process(arr, index + 1, rest - arr[index]);

    if (no == -1 && yes == -1) {
      // 要或不要当前硬币都无解
      dp[index][rest] = -1;
    } else {
      if (no == -1) {
        dp[index][rest] = yes + 1; // 在要当前硬币下的解
      } else if (yes == -1) {
        dp[index][rest] = no; // 不要当前硬币下的解
      } else {
        dp[index][rest] = Math.min(no, yes + 1); // 在要或不要都有解的情况下取最小值
      }
    }
  }

  return dp[index][rest];
}

进阶3:严格表结构

image.png