本文最后更新于:2021年5月4日 中午
题目 一只青蛙想要过河。 假定河流被等分为若干个单元格,并且在每一个单元格内都有可能放有一块石子(也有可能没有)。 青蛙可以跳上石子,但是不可以跳入水中。
给你石子的位置列表 stones(用单元格序号 升序 表示), 请判定青蛙能否成功过河(即能否在最后一步跳至最后一块石子上)
开始时, 青蛙默认已站在第一块石子上,并可以假定它第一步只能跳跃一个单位(即只能从单元格 1 跳至单元格 2 )
如果青蛙上一步跳跃了 k 个单位,那么它接下来的跳跃距离只能选择为 k - 1、k 或 k + 1 个单位。 另请注意,青蛙只能向前方(终点的方向)跳跃。
示例 1:
输入:stones = [0,1,3,5,6,8,12,17] 输出:true 解释:青蛙可以成功过河,按照如下方案跳跃: 跳 1 个单位到第 2 块石子 跳 2 个单位到第 3 块石子 跳 2 个单位到第 4 块石子 跳 3 个单位到第 6 块石子 跳 4 个单位到第 7 块石子 跳 5 个单位到第 8 个石子
示例 2:
输入:stones = [0,1,2,3 ,4,8,9,11 ] 输出:false 解释:这是因为第 5 和第 6 个石子之间的间距太大,没有可选的方案供青蛙跳跃过去
个人解法 记忆化搜索 + 二分查找 遍历每一块石头,二分法寻找能到达的下一块石头,保存到达下一块石头后的速度 判断最后一块石头有没有记录速度即可知道能不能通过
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution : def canCross (self, stones: List[int ] ) -> bool: stones_speeds = [{0 }] river_len = len (stones) for i in range (1 , len (stones)): if stones[i] > i + stones[i-1 ]: return False else : stones_speeds.append(set ()) for stone_index, stone in enumerate (stones): for stone_speed in stones_speeds[stone_index]: for next_speed in (stone_speed - 1 , stone_speed, stone_speed + 1 ): next_stone = stone + next_speed if next_stone <= stone or next_stone > stones[river_len - 1 ]: continue left, right = stone_index + 1 , river_len - 1 while left <= right: avg_index = (left + right) // 2 if stones[avg_index] == next_stone: stones_speeds[avg_index].add(next_speed) break elif stones[avg_index] > next_stone: right = avg_index - 1 else : left = avg_index + 1 return bool (stones_speeds[-1 ])
大佬解法-动态规划 关键 定义dp为字典,其中key=stone
, value={可以到达stone的跳跃步长组成的集合}
那么能够到达stone
等价于dp[stone]
非空。
def canCross (stones: List[int ] ) -> bool: set_stones=set (stones) dp = defaultdict(set ) dp[0 ]={0 } for s in stones: for step in dp[s]: for d in [-1 ,0 ,1 ]: if step+d>0 and s+step+d in set_stones: dp[s+step+d].add(step+d) return len (dp[stones[-1 ]])>0