对于每一个位置,无论是odd还是even jump,jump后的位置要么不存在,要么就是符合要求的唯一位置。因此最关键的问题是解决:
给定一个index i,找出jump后的位置
如果对每个index都能找到jump后的位置,那么利用递归 (DP) 很容易就能判断能否jump到最后一个位置。
由于数组是无序的,因此也没法直接用二分有效搜索。
方法一:Ordered Map + DP
可以利用一个map,key是数组的元素,value是index,根据key排序,利用map有序的特性二分来做。
可以先把所有元素放到map里,然后遍历数组里元素后从map里erase掉。
也可以从后往前遍历,这样就只需往map里添加元素即可,就不用先插入后删除了。
DP部分可以和前面一个for循环写在一起更加美观,分开写思路更加清楚。
时间复杂度 O(nlogn),C++ map是RBT,插入删除搜索都是O(logn),对每个数组元素都要操作。
class Solution { public: int oddEvenJumps(vector<int>& A) { int n=A.size(); vector<int> oddnext(n,-1), evennext(n,-1); map<int,int> m; // value->index for (int i=n-1;i>=0;--i){ auto it_lb=m.lower_bound(A[i]); if (it_lb!=m.end()) oddnext[i] = it_lb->second; auto it_up=m.upper_bound(A[i]); if (it_up!=m.begin()) evennext[i] = (--it_up)->second; m[A[i]] = i; } // oddjump[i] - if now it odd jumps from index i, whether it could reach the end. vector<bool> oddjump(A.size(),false), evenjump(A.size(),false); oddjump[A.size()-1] = evenjump[A.size()-1] = true; for (int i=A.size()-2;i>=0;--i){ if (oddnext[i]!=-1) oddjump[i] = evenjump[oddnext[i]]; if (evennext[i]!=-1) evenjump[i] = oddjump[evennext[i]]; } int count=0; for (int x:oddjump){ if (x) ++count; } return count; } };
方法二:Monotonic Stack + DP
这里也可以利用单调栈来做。
对于odd jump,我们要找到之后的第一个>= 的数。先建立一个index数组,将index数组根据对应 A[i] 的值从小到大排序,依次放入一个index单调递减的stack内。
while 循环,如果新入栈的index比栈顶元素大 (这里就可以保证当前index i>s.top() && A[i]>=A[s.top()]),那么 oddnext[s.top()] = i.
时间复杂度 O(nlogn),因为排序 O(nlogn),后面单调栈只要 O(n)。
注意:排序时一定要加上 if (A[a]==A[b]) return a<b; 因为快排是无序的,如果A[i]相等,我们必须让index小的排在前面,这样在单调栈时才会更新较小元素位置的oddnext/evennext.
C++ 用lambda function时,如果要用到function外的变量,需要用 [&] 去 capture.
Lambda of a lambda : the function is not captured
class Solution { public: int oddEvenJumps(vector<int>& A) { vector<int> index; for (int i=0;i<A.size();++i) index.push_back(i); // sort index the value in the given index sort(index.begin(),index.end(),[&A](const int &a, const int &b){ if (A[a]==A[b]) return a<b; return A[a]<A[b]; }); vector<int> oddnext=make(index); sort(index.begin(),index.end(),[&A](const int &a, const int &b){ if (A[a]==A[b]) return a<b; return A[a]>A[b]; }); vector<int> evennext=make(index); // oddjump[i] - if now it odd jumps from index i, whether it could reach the end. vector<bool> oddjump(A.size(),false), evenjump(A.size(),false); oddjump[A.size()-1] = evenjump[A.size()-1] = true; for (int i=A.size()-2;i>=0;--i){ if (oddnext[i]!=-1) oddjump[i] = evenjump[oddnext[i]]; if (evennext[i]!=-1) evenjump[i] = oddjump[evennext[i]]; } int count=0; for (int x:oddjump){ if (x) ++count; } return count; } vector<int> make(vector<int> &index){ vector<int> res(index.size(),-1); stack<int> s; // 维护下标减小的单调栈 for (int i:index){ while(!s.empty() && s.top()<i){ res[s.top()] = i; s.pop(); } s.push(i); } return res; } };