算法问题:8升满壶5升3升空壶倒出4升水,js遍历实现
题目
给一个装满水的 8 升满壶和两个分别是 5 升、3 升的空壶,想个办法,使得其中一个水壶恰好装 4 升水,每一步的操作只能是倒空或倒满。
这种问题,给你一张纸,给你20分钟,枚举一下,应该很容易就可以得出答案。但是,怎么用代码实现呢?似乎有点费脑
先回答几个问题:
1、怎么遍历杯子
2、每次操作会产生多少种可能性
3、怎么防止操作后出现重复的组合
搞定这几个问题,应该就可以写代码了,同时可以拓展一下题目,
给一个装满水的 n升满壶和两个分别是 m升、o升的空壶,想个办法,使得其中一个水壶恰好装 a 升水,每一步的操作只能是倒空或倒满。
下面可以算出一共有多少种方法实现这个需求
var arr = [ { volume: 8, limit: 8, }, { volume: 0, limit: 5, }, { volume: 0, limit: 3, }, ]; var historyArr = [arr]; var count = 1 var stepsArr = [ { step: 0, val: arr.map((obj) => obj.volume).join(',') } ] function operate(arr, count) { var resultArr = []; for (var i = 0; i < arr.length; i++) { // 每次操作一个有水的杯子 for (var k = 0; k < arr.length; k++) { var choiceArr = JSON.parse(JSON.stringify(arr)); if (i !== k && arr[i].volume && arr[k].volume < arr[k].limit) { var distance = (arr[k].limit - arr[k].volume); // 判断操作杯子的水多,还是被倒水的杯子剩余容量多 choiceArr[i].volume -= (distance >= arr[i].volume ? arr[i].volume : distance); choiceArr[k].volume += (distance >= arr[i].volume ? arr[i].volume : distance); // 如果还没记录该次组合,则放入记录 if (!JSON.stringify(historyArr).includes(JSON.stringify(choiceArr))) { historyArr.push(choiceArr); resultArr.push(choiceArr); //记录每次操作产生组合的数量 if (!stepsArr[count]) { stepsArr[count] = [{ step: count, val: choiceArr.map((obj) => obj.volume).join(',') }] } else { stepsArr[count].push({ step: count, val: choiceArr.map((obj) => obj.volume).join(',') }) } } if (choiceArr[i].volume == 4 || choiceArr[k].volume == 4) { // 终止递归 // console.log(historyArr); console.log(JSON.stringify(stepsArr)); return; } } } } count++; for (var n = 0; n < resultArr.length; n++) { operate(resultArr[n], count) } } operate(arr, count)