Leetcode 1345. 跳躍遊戲 IV
題意:
給一個一維的數組,你從下標0開始出發,有三種操作:每次可以向左,右移動一位,或者移動到與自己數值相同的位置。
思路:
這類搜索求最短步數的解法是典型的bfs,注意這題數據的特殊性,裸bfs會超時。
這是因爲第三個操作枚舉所有相同數值的位置時候,如果出現很多
相同值的數值,光枚舉相同值時間複雜度會近似O(n),整體就變成O(n^2)。
這一步枚舉,可以把連續出現相同值的區間只保留左右兩個端點,起到搜索剪枝的作用。
代碼:
python
class Solution:
def minJumps(self, arr) -> int:
import collections
n = len(arr)
if n == 1: return 0
poss = collections.defaultdict(list)
for index, value in enumerate(arr):
if (index and arr[index]!= arr[index-1] or
(index < n-1 and arr[index]!=arr[index + 1])): # 剪枝
poss[value] .append(index)
que= collections.deque([(0,0)])
vis = set([0])
while que:
pos, cur = que.popleft()
for nxt in poss[arr[pos]] + [pos+1 ,pos -1]:
if nxt == n -1: return cur +1
if 0 < nxt < n-1 and nxt not in vis:
que.append((nxt , cur+1))
vis.add(nxt)
c++
class Solution {
public:
int minJumps(vector<int>& arr) {
int n = arr.size();
if(n==1) return 0;
unordered_map<int, vector<int>> pos;
for(int i =0 ;i<n;i++){
if((i>0&&arr[i]!=arr[i-1])||(i<n-1&&arr[i]!=arr[i+1])){
pos[arr[i]].push_back(i);
}
}
queue<pair<int,int> > que;
que.push(make_pair(0 ,0));
set<int> vis;
vis.insert(0);
int ans =0 ;
bool flag = false;
while(!que.empty()){
int p = que.front().first, cur = que.front().second;
que.pop();
for(int i=0;i<pos[arr[p]].size();i++){
int nxt = pos[arr[p]][i];
if((nxt == n-1)||(p+1 == n-1)){
ans = cur + 1;
flag = true;
break;
}
if(nxt>1&&nxt<n&&vis.count(nxt)==0){
que.push(make_pair(nxt, cur+1));
vis.insert(nxt);
}
}
if(flag) break;
if(p+1>0&&p+1<n&&vis.count(p+1)==0){
que.push(make_pair(p+1, cur+1));
vis.insert(p+1);
}
if(p-1>0&&p-1<n&&vis.count(p-1)==0){
que.push(make_pair(p-1, cur+1));
vis.insert(p-1);
}
}
return ans;
}
};