Leetcode 403. Frog Jump
Problem:
A frog is crossing a river. The river is divided into x units and at each unit there may or may not exist a stone. The frog can jump on a stone, but it must not jump into the water.
Given a list of stones' positions (in units) in sorted ascending order, determine if the frog is able to cross the river by landing on the last stone. Initially, the frog is on the first stone and assume the first jump must be 1 unit.
If the frog's last jump was k units, then its next jump must be either k - 1, k, or k + 1 units. Note that the frog can only jump in the forward direction.
Note:
- The number of stones is ≥ 2 and is < 1,100.
- Each stone's position will be a non-negative integer < 231.
- The first stone's position is always 0.
Example 1:
[0,1,3,5,6,8,12,17] There are a total of 8 stones. The first stone at the 0th unit, second stone at the 1st unit, third stone at the 3rd unit, and so on... The last stone at the 17th unit. Return true. The frog can jump to the last stone by jumping 1 unit to the 2nd stone, then 2 units to the 3rd stone, then 2 units to the 4th stone, then 3 units to the 6th stone, 4 units to the 7th stone, and 5 units to the 8th stone.
Example 2:
[0,1,2,3,4,8,9,11] Return false. There is no way to jump to the last stone as the gap between the 5th and 6th stone is too large.
Solution:
这道题先说说我自己想出动态规划的方法,效率不高不过还是能accept。result[i]表示从i之前的某个石块跳到第i个石块所有可能拥有的跳跃能力,第0块石头拥有跳跃力0和1,如果说result.back().size()为0,说明不存在之前的某个石块有跳跃力能跳到最后一个石块。
1 class Solution { 2 public: 3 bool canCross(vector<int>& stones) { 4 vector<vector<int>> result(stones.size()); 5 vector<int> v(1,0); 6 result [0] = v; 7 for(int i = 1;i != stones.size();++i){ 8 for(int j = i-1;j >= 0;--j){ 9 for(int t = 0;t != result[j].size();++t){ 10 if(stones[j] + result[j][t] == stones[i]){ 11 result[i].push_back(result[j][t]); 12 break; 13 } 14 if(stones[j] + result[j][t] + 1 == stones[i]){ 15 result[i].push_back(result[j][t] + 1); 16 break; 17 } 18 if(stones[j] + result[j][t] - 1== stones[i]){ 19 result[i].push_back(result[j][t] - 1); 20 break; 21 } 22 } 23 } 24 } 25 if(result[stones.size()-1].size() == 0) 26 return false; 27 return true; 28 } 29 };
再来看看标准解法,这种解法严格意义上来说是有记忆的DFS,这个哈系表的键通过位操作记录了位置信息和跳跃力信息(第五行惊呆了有木有),如果下回同样的跳跃力碰到这个位置直接返回就行了,以此提高效率。然后在跳跃力范围内寻找下一个石块,通过DFS判断能否找到最后一个石块。
Code:
1 class Solution { 2 public: 3 bool func(vector<int>& stones,int position,int step,unordered_map<int,bool> &um){ 4 if(position == stones.size()-1) return true; 5 int key = position | (step << 11); 6 if(um.find(key) != um.end()) return um[key]; 7 for(int i = position+1;i != stones.size();++i){ 8 if(stones[i] < stones[position]+step-1) continue; 9 if(stones[i] > stones[position]+step+1) break; 10 if(func(stones,i,stones[i]-stones[position],um)) 11 return true; 12 } 13 um[key] = false; 14 return false; 15 } 16 bool canCross(vector<int>& stones) { 17 int m = stones.size(); 18 if(m == 0) return false; 19 unordered_map<int,bool> um; 20 return func(stones,0,0,um); 21 } 22 };