Jump Game II

Given an array of non-negative integers, you are initially positioned at the first index of the array.

Each element in the array represents your maximum jump length at that position. 

Your goal is to reach the last index in the minimum number of jumps.

For example:
Given array A = [2,3,1,1,4]

The minimum number of jumps to reach the last index is 2. (Jump 1 step from index 0 to 1, then 3 steps to the last index.)

 这一题是Jump Game的follow up。既然有判断能不能,就会有最少多少步可以达到的问法。延续之前的DP和Greedy,这题同样有两种解法。

首先DP,DP的转移方程是f(i)=Min(f(j)+1)(j<i && nums[j]+j >= i)。和之前的OR一样,min的存在使DP是二维的,代码如下:

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        res = [sys.maxint]*len(nums)
        res[0] = 0
        for i in xrange(1,len(nums)):
            for j in xrange(i):
                if nums[j] != sys.maxint and nums[j] + j >= i:
                   res[i] = min(res[i],res[j]+1)
        return res[-1]

上述代码可以优化,首先可以证明一点,f(j)<=f(i)(j<i)。即到达数组之前点的步数不多于到达后面的步数。一个是如果j在f(i)最后一步的范围里,则减小步伐就可以到达,f(i)=f(j)。如果不在这个范畴,说明用更小的步数就可以到达。所以上述代码可以剪枝,最里层循环,从小到大,一旦可以找到到达i的j,就可以break,因为后面的小于i的j的步数不会更优。优化代码如下:

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        res = [sys.maxint]*len(nums)
        res[0] = 0   #bound situation that can't be handled by the normal formulation.
        for i in xrange(1,len(nums)):
            for j in xrange(i):
                if res[j] != sys.maxint and nums[j]+j >= i:
                    res[i] = res[j]+1
                    break    #剪枝,break

return res[-1]

上述优化过的DP解法依然在Leetcode里超时,所以不得不使用贪心算法。

和之前在Jump Game里面的思路很像,我们维护一个当前可以到达的最远距离curMax,但是这一题需要计算步数,所以一个办法是维护一个之前步可以到达的最远距离lastMax,然后在之前步所走的范围里寻找当前步可以到达的最远距离,是BFS的思想。在更新步数时,需要更新lastMax,代码如下:

class Solution(object):
    def jump(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        step, lastMax, curMax, i = 0, 0, 0, 0
        while curMax < len(nums)-1:
            step += 1
            lastMax = curMax
            while i <= lastMax:
                curMax = max(curMax,nums[i]+i)
                i += 1 
            if lastMax == curMax: #防止连续为0,无解的情况
                return -1
        return step

可以看到step为1时,lastMax为0,此时curMax为第一步可以到达的最远距离。所以一旦curMax>=len(nums)-1,就说明已经可以到达终点了。

这题可以有相当多的follow up,比如求最短路径的具体跳转地点,思路是维护一个动态可增的数组,比如list或者vector,max(curMax,nums[i]+i)换成时机的比较,如果有比较则更新值。每一步的跳转的地方都是上一步可以到达的最远的点。

注意数组中有0,比如[2,3,0,0,1],用上述的贪心是也是解的。

转载于:https://www.cnblogs.com/sherylwang/p/5521399.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C#跳跃游戏的源代码: using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerController : MonoBehaviour { public float jumpForce = 10f; public float moveSpeed = 5f; public Transform groundCheck; public LayerMask groundLayer; public GameObject gameOverPanel; private Rigidbody2D rb; private Animator anim; private bool isJumping = false; private bool isGrounded = false; void Start() { rb = GetComponent<Rigidbody2D>(); anim = GetComponent<Animator>(); } void Update() { if (Input.GetKeyDown(KeyCode.Space) && isGrounded) { isJumping = true; rb.velocity = Vector2.up * jumpForce; } anim.SetBool("isJumping", isJumping); anim.SetFloat("yVelocity", rb.velocity.y); float horizontalInput = Input.GetAxisRaw("Horizontal"); rb.velocity = new Vector2(horizontalInput * moveSpeed, rb.velocity.y); if (rb.velocity.x > 0) { transform.localScale = new Vector3(1, 1, 1); } else if (rb.velocity.x < 0) { transform.localScale = new Vector3(-1, 1, 1); } isGrounded = Physics2D.OverlapCircle(groundCheck.position, 0.1f, groundLayer); if (!isGrounded) { gameOverPanel.SetActive(true); Time.timeScale = 0f; } } private void OnTriggerEnter2D(Collider2D collision) { if (collision.CompareTag("Coin")) { Destroy(collision.gameObject); } } } 在此代码中,我们定义了玩家控制器的变量和属性。我们还定义了开始和更新函数,以便在游戏中实现跳跃和移动。我们还在代码中添加了碰撞检测和游戏结束的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值