算法经典问题

面试题算法:金矿问题-动态规划

  • 很久很久以前,有一位国王拥有5座金矿,每座金矿的黄金储量不同,需要参与挖掘的工人人数也不同。例如有的金矿储量是500kg黄金,需要5个工人来挖掘;有的金矿储量是200kg黄金,需要3个工人来挖掘…
  • 如果参与挖矿的工人的总数是10。每座金矿要么全挖,要么不挖,不能派出一半人挖取一半的金矿。要求用程序求出,要想得到尽可能多的黄金,应该选择挖取哪几座金矿?

递归求解

// 时间复杂度O(2^n)
function getBestGold(workers, canSelectGold, needWorkersArray, goldCountArray) {
    // 人用完或金矿挖完停止递归
    if (workers === 0 || canSelectGold === 0) {
        return 0;
    }
    // 如果
    if (workers < needWorkersArray[canSelectGold - 1]) {
        return getBestGold(workers, canSelectGold - 1, needWorkersArray, goldCountArray)
    }
    return Math.max(
        getBestGold(workers, canSelectGold - 1, needWorkersArray, goldCountArray),
        getBestGold(workers - needWorkersArray[canSelectGold - 1], canSelectGold - 1, needWorkersArray, goldCountArray) + goldCountArray[canSelectGold - 1]
    )
}

let workers = 10;// 总人数
let needWorkersArray = [5, 5, 3, 4, 3];// 每个金矿所需人数
let goldCountArray = [400, 500, 200, 300, 350];// 每个金矿储量
// let res = getBestGold(workers, goldCountArray.length, needWorkersArray, goldCountArray);
// console.log(res)

自底向上求解

  • 状态转移方程: n是当前金矿储量,w是当前金矿所需人数 ,p是挖掘金矿所需人数数组,g是金矿储量数组
  • F(n,w) = F(n-1,w) (n>1,w<p[n-1])
  • F(n,w) = max( F(n-1,w),F(n-1,w-p[n-1])+g[n-1]) (n>1,w>=p[n-1])
    二维数组表示 ,这个比上一个递归好理解
// 时间复杂度O(nw)
function getBestGold2(workers, needWorks, goldArray) {
    let resultArray = []
    // 填充二维数组
    for (let i = 0; i < goldArray.length + 1; i++) {
        resultArray.push([0])
        for (let j = 0; j < workers + 1; j++) {
            let arr = resultArray[i]
            arr.push(0)
        }
    }
    console.log(resultArray)
    // 计算每个位置的值
    for (let i = 1; i <= goldArray.length; i++) {
        for (let j = 1; j <= workers; j++) {
            if (j < needWorks[i - 1]) {
                resultArray[i][j] = resultArray[i - 1][j]
            } else {
                resultArray[i][j] = Math.max(resultArray[i - 1][j], resultArray[i - 1][j - needWorks[i - 1]] + goldArray[i - 1])
            }
        }
    }
    console.log(resultArray[goldArray.length][workers])
    return resultArray[goldArray.length][workers]
}

getBestGold2(workers, needWorkersArray, goldCountArray)// 900

结果如下:
算法经典问题
优化:只保存一行最大值

// 时间复杂度O(nw),空间复杂度O(n)
// 只保存一行最大值
function getBestGold3(workers,needWorkers,goldArray) {
    let resultArray = new Array(workers+1).fill(0)
    console.log(resultArray)
    // 计算每个位置的值
    // 计算行
    for (let i = 1; i <= goldArray.length; i++) {
        // 计算列,从右向左,人数多挖的金矿肯定多,所以可以避免很多不必要的计算
        // 比如说最后一列大于倒数第二列,那么接下来就不用再计算,直接进入下一行
        for (let j = workers; j >=1; j--) {
            if (j >= needWorkers[i - 1]) {
                resultArray[j] = Math.max(resultArray[j], resultArray[j - needWorkers[i - 1]] + goldArray[i - 1])
            }
        }
    }
    console.log(resultArray[workers])
    return resultArray[workers]
}
getBestGold3(workers, needWorkersArray, goldCountArray)// 900

算法经典问题

上一篇:_pickle.PicklingError: Can‘t pickle <function <lambda> at 0x000001C172C848C8


下一篇:科普,想成为厉害的 Java 后端程序员,你需要懂这 13 个知识点