本文正在参加「Java主题月 - Java 刷题打卡」,详情查看 活动链接
一、题目描述:
二、思路分析:
今天给大家分享的是一道HARD难度的题目。 题目的意思是河流被分成了好多单元格,每个单元格有可能放石头,只有踩着石头才能过河。给一个石头列表,青蛙一开始在第一块石头上。第一次只能跳1步。之后可以跳跃多少步取决于上一步跳了多远。如果上次跳了K步,那么接下来只能跳跃K-1,K,K+1步。问问青蛙最后能不能过河,即到达最后一块石头上。青蛙只能往前走哦。
- 拿到题目,一看每次到一个位置都有三个选择,k-1,k,k+1。我的第一思路是BFS,因为之前看过labuladong的一些类似的题目分析,有了这么个印象。
- 具体实现呢就是使用一个队列保存当前可能跳跃到的位置,然后从队列里取出位置开始往下跳。如果取出来的位置恰好是我们的目的地,那么直接返回true即可。否则就开始下次跳跃。
- 而下次要跳多少步,需要知道上一步是怎么过来的,所以需要记录一个K,对应到当前位置是跳了几步来的,使用额外的数组记录一下。
- 直接提交,不出意外,超时了。
- 想一下有没有可以优化的地方。
- 优化: 可以记录一下青蛙跳跃过的路径情况,比如说跳了K步跳到某个石头上,后面再有别的选择跳到这个石头上,可以直接忽略,算是一波剪枝了。
三、AC 代码:
//未剪枝,超时
class Solution {
/**
* @param Integer[] $stones
* @return Boolean
*/
function canCross($stones) {
$len_n = count($stones);
$dest = $stones[$len_n - 1];
$map = [];
for ($i = 0; $i < $len_n; $i++) {
$map[$stones[$i]] = 1;
}
$queue = new SplQueue();
$arrK = [];
$queue->enqueue($stones[0]);
array_push($arrK, 1);
$first = true;
while (!$queue->isEmpty()) {
$size = count($queue);
for ($i = 0; $i < $size; $i++) {
$curK = array_shift($arrK);
if ($first) {
$nextSteps = [$curK];
$first = false;
} else {
$nextSteps = [$curK, $curK - 1, $curK + 1];
}
$curStone = $queue->dequeue();
if ($curStone == $dest) {
return true;
}
foreach ($nextSteps as $nextStep) {
if ($nextStep == 0) {
continue;
}
if (isset($map[$nextStep + $curStone])) {
$queue->enqueue($nextStep + $curStone);
array_push($arrK, $nextStep);
}
}
}
}
return false;
}
}
//通过
class Solution {
/**
* @param Integer[] $stones
* @return Boolean
*/
function canCross($stones) {
$len_n = count($stones);
$dest = $stones[$len_n - 1];
$map = [];
$pathMap = [];
for ($i = 0; $i < $len_n; $i++) {
$map[$stones[$i]] = 1;
}
$queue = new SplQueue();
$arrK = [];
$queue->enqueue($stones[0]);
array_push($arrK, 1);
$first = true;
while (!$queue->isEmpty()) {
$size = count($queue);
for ($i = 0; $i < $size; $i++) {
$curK = array_shift($arrK);
if ($first) {
$nextSteps = [$curK];
$first = false;
} else {
$nextSteps = [$curK, $curK - 1, $curK + 1];
}
$curStone = $queue->dequeue();
if ($curStone == $dest) {
return true;
}
foreach ($nextSteps as $nextStep) {
if ($nextStep == 0 || isset($pathMap["{$curStone}_{$nextStep}"])) {
continue;
}
if (isset($map[$nextStep + $curStone])) {
$pathMap["{$curStone}_{$nextStep}"] = 1;
$queue->enqueue($nextStep + $curStone);
array_push($arrK, $nextStep);
}
}
}
}
return false;
}
}
四、总结:
一般看到这种做选择的问题,可以考虑一下使用BFS暴力搞一下,要是超时的话可以尝试剪枝。实在不行的话只能再考虑别的方法了,比如动态规划。