题目:
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.
分析:
一道动态规划题目。这道题目的关键是找到适当的dp数组。想法也很简单,从第一块石头开始尝试着往前跳,对于一块石头上的每一个k,无非是3种可能情况(k - 1, k, k + 1)。从第一块石头开始,在每个石头上都这样尝试,看最终能否到达最后一块石头。状态d[i]是一个集合,是从前面的石头跳到第i块石头上所用的步数的集合。d[i]限定了在第i块石头上可以向前跳多少步。整个动态规划算法通过遍历一遍数组即可,时间复杂度为O(n)。
因为没有找到好的状态压缩的方式来表示在第i块石头上可以向前跳跃的步数,便用STL中的set来存储。在前几次的提交中,存储用vector,超时了。find函数是一个二分查找的函数,增加查询效率。
代码如下:beats 45.58% runtime 409ms
class Solution {
public:
bool canCross(vector<int>& stones) {
int size = stones.size();
vector<set<int> > d;
set<int>::iterator it;
for (int i = 0; i < size; i++)
d.push_back(set<int>());
if (stones[1] != 1) return false;
d[1].insert(1);
for (int i = 1; i < size - 1; i++) {
for (it = d[i].begin(); it != d[i].end(); it++) {
for (int k = -1; k <= 1; k++) {
int index = find(stones, i + 1, stones[i] + *it + k);
if (index != -1) d[index].insert(*it + k);
}
}
}
return !d[size - 1].empty();
}
int find(vector<int>& stones, int s, int key) {
int end = stones.size() - 1;
int mid;
while (s <= end) {
mid = (s + end) / 2;
if (stones[mid] == key) {
return mid;
} else if (stones[mid] > key) {
end = mid - 1;
} else {
s = mid + 1;
}
}
return -1;
}
};