北京轻而易举笔试题F
先看题目
曾经笔者去这家公司面试,当时没做出来,近段时间翻手机再次看到这道题经过思考解出了题目。给大家提供一种思路,同时祝朋友们封面必过。
题目解析
这道题具体意思就是有一个衣柜高2000,其中有四块板子,从下往上依次为:1、2、3、4号板。
四个板子从上到下的位置分别是:50、600、700、1000。现在要求依次移动四块板子使四块板子均分衣柜,不能跨板移动。
问:一共有多少种移动方法。
说一下我的解法:
首先我们能知道四块板子均分衣柜的正确位置
四块板子进行均分高度为2000的衣柜:2000 / (4+1) = 400
每一块板子的位置比上一块板子高400,这样我们可以得出四块板子的正确位置为:
400、800、1200、1600
并且每一次移动不一定只有一种板子的移动方案,所以需要写一个函数来求出每一次移动所有板子的移动方案。
然后通过递归函数对每一次的分支进行向下递归,最终若没有可以移动的板子就可以根据当前板子的位置判断是否是正确的位置从而得到一种移动方案。
这种将一个分支一直走到头的算法叫做 深度优先遍历
实现代码
package cn.luanshiliunian;
import java.util.ArrayList;
import java.util.List;
public class DfsMainRecursionCount {
/**
* 多少个板子
**/
private static final int N = 4;
// 底部位置
private static final int bottom = 0;
// 顶部位置
private static final int top = 2000;
// 原始位置
private static final Integer[] origPos = new Integer[]{50, 600, 700, 1000};
// 平均间隔位置
private static final int interval = top / (N + 1);
/**
* [400, 800, 1200, 1600]
* [50 , 600, 700 , 1000]
* [700, 900, 950 , 1000]
* <p>
* 正确位置 > 当前位置 向上移动 前一个 - 现在 > 当前位置 - 正确位置
* 正确位置 < 当前位置 向下移动 现在 - 后一个 > 正确位置 - 当前位置
**/
public static void main(String[] args) {
handler(origPos, null, null);
}
/**
* 利用递归
*
* @param snapshot 快照
* @param moveNumber 移动位置
* @param result 最终答案
*/
private static void handler(Integer[] snapshot, Integer moveNumber, List<Integer> result) {
if (snapshot == null || snapshot.length == 0) throw new RuntimeException("tree node is null!");
List<Integer> resultArr = new ArrayList<>();
if (moveNumber == null) {
List<Integer> nextStep = searchForNextStep(snapshot);
for (Integer step : nextStep) {
handler(snapshot, step, resultArr);
}
} else {
Integer[] stepPos = new Integer[snapshot.length];
System.arraycopy(snapshot, 0, stepPos, 0, stepPos.length);
// 移动完成
stepPos[moveNumber] = (moveNumber + 1) * interval;
if (result != null && result.size() > 0) {
// 追加之前的结果
resultArr.addAll(result);
}
resultArr.add(moveNumber + 1);
List<Integer> nextStep = searchForNextStep(stepPos);
if (nextStep.size() == 0) {
int sum = 0;
for (int i = 0; i < stepPos.length; i++) {
if (stepPos[i].equals((i + 1) * interval)) sum++;
}
if (sum == stepPos.length)
System.out.println(resultArr);
}
for (Integer next : nextStep) {
handler(stepPos, next, resultArr);
}
}
}
/**
* 根据当前快照,搜索出所有可移动的步骤
*
* @param snapshot
* @return
*/
public static List<Integer> searchForNextStep(Integer[] snapshot) {
List<Integer> result = new ArrayList<>();
for (int i = 0; i < snapshot.length; i++) {
// 当前板层已经移动到正确位置了
Integer correctPos = (i + 1) * interval;
if (correctPos.equals(snapshot[i])) continue;
// 当前位置
Integer element = snapshot[i];
// 正确位置
if (correctPos > element) {
// 正确位置 > 当前位置 向上移动
if (i == (snapshot.length - 1)) {
if (top - element > correctPos - element)
result.add(i);
} else if (snapshot[i + 1] - element >= correctPos - element) {
result.add(i);
}
} else {
// 正确位置 < 当前位置 向下移动
if (i == 0) {
result.add(i);
} else if (element + snapshot[i - 1] >= element - correctPos) {
result.add(i);
}
}
}
return result;
}
}