【Leetcode】403. Frog Jump

题目地址:

https://leetcode.com/problems/frog-jump/

给定一个长 n n n的非负整数数组 A A A A [ 0 ] = 0 A[0]=0 A[0]=0,代表若干石头的坐标,一个青蛙从 A [ 0 ] A[0] A[0]出发,第一步只能跳 1 1 1个单位距离,如果其跳了 k k k个单位距离到达了某个位置,那它下一步可以跳 k − 1 , k , k + 1 k-1,k,k+1 k1,k,k+1三者之一的距离,但它只能向后跳不能往回跳(也就是它每次跳的位移必须是正的)。问其是否能跳到 A [ n − 1 ] A[n-1] A[n1]这个石头上。

思路是动态规划。设 f [ i ] f[i] f[i]代表最后一步可以到达 i i i这个位置的最后一跳距离的集合,注意,这里 f [ i ] f[i] f[i]是个集合(哈希表)。这里的意思是, ∀ x ∈ f [ i ] \forall x\in f[i] xf[i],那意味着存在一种跳法,最后一步跳 x x x的距离,可以恰好跳到 i i i这个位置。当然,我们只需要存 i i i位置有石头的情形。最后只需要知道 f [ A [ n − 1 ] ] f[A[n-1]] f[A[n1]]是否为空即可,如果空,说明跳不到,否则能跳到。那么如果已知 f [ i ] f[i] f[i]这个集合,对于任何 x ∈ f [ i ] x\in f[i] xf[i],应该就有 x − 1 ∈ f [ i + x − 1 ] , x ∈ f [ i + x ] , x + 1 ∈ f [ i + x + 1 ] x-1\in f[i+x-1],x\in f[i+x],x+1\in f[i+x+1] x1f[i+x1],xf[i+x],x+1f[i+x+1],我们可以对这三个集合进行更新。遍历完 A A A之后,看一下 f [ A [ n − 1 ] ] f[A[n-1]] f[A[n1]]是否为空。代码如下:

import java.util.*;

public class Solution {
    public boolean canCross(int[] stones) {
        if (stones == null || stones.length == 0) {
            return false;
        }
    
        int len = stones.length;
        // key存的是石头下标,value存的是能到达key的跳法的最后一跳距离
        Map<Integer, Set<Integer>> dp = new HashMap<>();
        for (int i = 0; i < len; i++) {
            dp.put(stones[i], new HashSet<>());
        }
        
        dp.get(stones[0]).add(0);
        
        for (int i = 0; i < len - 1; i++) {
        	// 由于后面要修改dp这个哈希表,必须先缓存,直接遍历会导致ConcurrentModificationException
            List<Integer> tmp = new ArrayList<>(dp.get(stones[i]));
            
            for (int step : tmp) {
                for (int dx = -1; dx <= 1; dx++) {
                	// 求出下一跳能到达的位置
                    int next = stones[i] + step + dx;
                    // 如果next这个位置恰好是石头,则更新能到它的最后一跳的距离
                    if (dp.containsKey(next)) {
                    	// 如果这个石头恰好是终点,则直接返回true
                    	if (next == stones[len - 1]) {
                    		return true;
                    	}
                    	
                        dp.get(next).add(step + dx);
                    }
                }
            }
        }
        
        return false;
    }
}

时空复杂度 O ( n 2 ) O(n^2) O(n2),步数的可能性一共是 O ( n ) O(n) O(n)级别的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值