题目地址:
https://www.lintcode.com/problem/minimum-step/description
给定一个长 n n n的数组 A A A,每个位置编号 0 ∼ n − 1 0\sim n-1 0∼n−1。 A [ i ] A[i] A[i]代表下标 i i i这个位置的颜色。从下标 0 0 0开始出发,每次可以向左或右移动一步,或者走到相同颜色的任意位置。问至少多少次能走到下标 n − 1 n-1 n−1的位置。
思路是BFS。注意,如果某个颜色已经走过,下次再走到这个颜色的时候可以直接略过,因为第二次走到之前走过的颜色所得的路径一定不会更短。这样可以节省时间。代码如下:
import java.util.*;
public class Solution {
/**
* @param colors: the colors of grids
* @return: return the minimum step from position 0 to position n - 1
*/
public int minimumStep(List<Integer> colors) {
// write your code here
if (colors.isEmpty() || colors.size() == 1) {
return 0;
}
// 统计一下每个颜色在哪些位置出现过
Map<Integer, List<Integer>> map = new HashMap<>();
for (int i = 0; i < colors.size(); i++) {
int color = colors.get(i);
map.putIfAbsent(color, new ArrayList<>());
map.get(color).add(i);
}
int res = 0;
boolean[] visited = new boolean[colors.size()];
visited[0] = true;
Queue<Integer> queue = new LinkedList<>();
queue.offer(0);
while (!queue.isEmpty()) {
res++;
// 要分层,所以记录size
int size = queue.size();
for (int i = 0; i < size; i++) {
int cur = queue.poll();
for (int next : getNexts(cur, colors, map, visited)) {
// 如果走到了n - 1的位置,则返回步数
if (next == colors.size() - 1) {
return res;
}
visited[next] = true;
queue.offer(next);
}
// cur对应的颜色都走过了,将其在哈希表里删除
map.remove(colors.get(cur));
}
}
return -1;
}
private List<Integer> getNexts(int cur, List<Integer> colors, Map<Integer, List<Integer>> map, boolean[] visited) {
List<Integer> nexts = new ArrayList<>();
int n = colors.size();
// 向右走
if (cur + 1 <= n - 1 && !visited[cur + 1]) {
nexts.add(cur + 1);
}
// 如果走到n - 1的位置了,直接返回
if (nexts.contains(n - 1)) {
return nexts;
}
// 向左走
if (cur - 1 >= 0 && !visited[cur - 1]) {
nexts.add(cur - 1);
}
// 向相同颜色走
if (map.containsKey(colors.get(cur))) {
for (int next : map.get(colors.get(cur))) {
if (next == n - 1) {
return Arrays.asList(n - 1);
}
if (!visited[next]) {
nexts.add(next);
}
}
}
return nexts;
}
}
时空复杂度 O ( n ) O(n) O(n)。