题目来源:https://leetcode-cn.com/problems/integer-replacement/
大致题意:
给定一个数 n,通过对其进行 +1、-1、÷2 这三种操作(当其为偶数时,一定进行 ÷2 操作)将其变为 1,求出所需的最小次数
思路
就像构造一颗不完全的二叉树:当前节点 num 若为偶数,只有一个子节点 num / 2,反之,则有两个子节点 num + 1、num - 1
而要求的就是叶节点 1 的最小深度
说白了,就是 BFS
BFS
使用队列存下待搜索的节点,使用哈希表存下节点值对应的操作次数(深度 - 1)
- 初始时,将根节点放入队列和哈希表
- 接下来,对于每次遍历的当前节点,判断当前节点是否为偶数
- 为偶数,判断当前节点是否已经出现过,若出现过,那么跳过本次搜索;否则,将其加入队列和哈希表
- 为奇数,判断 num + 1、num - 1 是否已经出现过,若出现过,那么跳过本次搜索;否则,将其加入队列和哈希表
- 每次循环取出当前队首元素,并判断,若当前元素为 1 或者 1 对应的哈希表不为空,直接退出循环
public int integerReplacement(int n) {
if (n == 2147483647) { // 边界数,直接返回
return 32;
}
Deque<Integer> queue = new ArrayDeque<>();
Map<Integer, Integer> numMap = new HashMap<>();
queue.offer(n);
numMap.put(n, 0);
// BFS
while (!queue.isEmpty()) {
int num = queue.poll();
int count = numMap.get(num);
// 已经找到最小次数
if (num == 1 || numMap.containsKey(1)) {
return numMap.get(1);
}
// 偶数直接放入队列
if (num % 2 == 0) {
if (!numMap.containsKey(num / 2)) {
queue.offer(num / 2);
numMap.put(num / 2, count + 1);
}
} else { // 奇数做两次处理
int addOne = num + 1;
int minusOne = num - 1;
if (!numMap.containsKey(addOne)) {
queue.offer(addOne);
numMap.put(addOne, count + 1);
}
if (!numMap.containsKey(minusOne)) {
queue.offer(minusOne);
numMap.put(minusOne, count + 1);
}
}
}
return numMap.getOrDefault(1, 0);
}