力扣热门算法题 174. 地下城游戏,189. 轮转数组,198. 打家劫舍

本文主要是介绍力扣热门算法题 174. 地下城游戏,189. 轮转数组,198. 打家劫舍,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

174. 地下城游戏,189. 轮转数组,198. 打家劫舍,每题做详细思路梳理,配套Python&Java双语代码, 2024.03.31 可通过leetcode所有测试用例。

目录

174. 地下城游戏

解题思路

完整代码

Python

Java

189. 轮转数组

解题思路

完整代码

Python

Java

198. 打家劫舍

解题思路

完整代码

Python

Java


174. 地下城游戏

        恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m * n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

        骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

        有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。

返回确保骑士能够拯救到公主所需的最低初始健康点数。

        注意:任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

示例 1:

输入:dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
输出:7
解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7 。

示例 2:

输入:dungeon = [[0]]
输出:1

解题思路

恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。

骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻降至 0 或以下,他会立即死亡。

有些房间由恶魔守卫,因此骑士在进入这些房间时会失去健康点数(若房间里的值为负整数,则表示骑士将损失健康点数);其他房间要么是空的(房间里的值为 0),要么包含增加骑士健康点数的魔法球(若房间里的值为正整数,则表示骑士将增加健康点数)。

为了尽快解救公主,骑士决定每次只 向右 或 向下 移动一步。

返回确保骑士能够拯救到公主所需的最低初始健康点数。

注意:任何房间都可能对骑士的健康点数造成威胁,也可能增加骑士的健康点数,包括骑士进入的左上角房间以及公主被监禁的右下角房间。

示例 1:

输入:dungeon = [[-2,-3,3],[-5,-10,1],[10,30,-5]]
输出:7
解释:如果骑士遵循最佳路径:右 -> 右 -> 下 -> 下 ,则骑士的初始健康点数至少为 7 。

示例 2:

输入:dungeon = [[0]]
输出:1

完整代码

Python
class Solution:def calculateMinimumHP(self, dungeon: List[List[int]]) -> int:m, n = len(dungeon), len(dungeon[0])dp = [[float('inf')] * (n + 1) for _ in range(m + 1)]dp[m][n - 1] = dp[m - 1][n] = 1for i in range(m - 1, -1, -1):for j in range(n - 1, -1, -1):min_health = min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]dp[i][j] = max(1, min_health)return dp[0][0]
Java
class Solution {public int calculateMinimumHP(int[][] dungeon) {int m = dungeon.length, n = dungeon[0].length;int[][] dp = new int[m + 1][n + 1];for (int i = 0; i <= m; ++i) Arrays.fill(dp[i], Integer.MAX_VALUE);dp[m][n - 1] = dp[m - 1][n] = 1;for (int i = m - 1; i >= 0; --i) {for (int j = n - 1; j >= 0; --j) {int minHealth = Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j];dp[i][j] = Math.max(1, minHealth);}}return dp[0][0];}}

189. 轮转数组

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

示例 1:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

示例 2:

输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释: 
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]

解题思路

解决这个问题的关键在于找到一种高效的方法来旋转数组,而不仅仅是简单地执行 k 次单步旋转。一种有效的方法是通过反转数组的部分来实现旋转效果。具体步骤如下:

  1. 反转整个数组:首先,将整个数组反转。这一步会将原本应该被移动到数组前面的元素移动到数组的后面。

  2. 反转数组的前 k 个元素:接着,反转数组中前 k 个元素。由于数组已经被整体反转过,这一步实际上是将那些应该位于数组前面的元素放到了正确的位置。

  3. 反转数组剩余部分:最后,反转数组中剩余的部分,即从索引 k 到数组结束的部分。这一步是将剩余的元素放到它们应该在的位置。

注意   由于 k 可能大于数组的长度,所以在进行操作之前需要将 k 对数组长度取模,以确保 k 在数组长度范围内。

完整代码

Python
class Solution:def rotate(self, nums: List[int], k: int) -> None:n = len(nums)k %= ndef reverse(start, end):while start < end:nums[start], nums[end] = nums[end], nums[start]start, end = start + 1, end - 1reverse(0, n - 1)reverse(0, k - 1)reverse(k, n - 1)
Java
class Solution {public void rotate(int[] nums, int k) {int n = nums.length;k %= n;reverse(nums, 0, n - 1);reverse(nums, 0, k - 1);reverse(nums, k, n - 1);}private void reverse(int[] nums, int start, int end) {while (start < end) {int temp = nums[start];nums[start] = nums[end];nums[end] = temp;start++;end--;}}}

198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。偷窃到的最高金额 = 2 + 9 + 1 = 12 。

解题思路

这个问题可以通过动态规划(Dynamic Programming, DP)来解决。我们可以定义一个一维数组 dp,其中 dp[i] 表示到达第 i 个房屋时能偷窃到的最高金额,注意这里的 i 是从 0 开始的索引。

解题步骤如下:

  1. 基本情况:当只有一间房屋时(即数组长度为 1),那么偷窃到的最高金额就是这间房屋中的金额。所以 dp[0] = nums[0](如果数组不为空)。

  2. 第二间房屋:当有两间房屋时,由于不能同时偷窃相邻的房屋,因此偷窃到的最高金额是这两间房屋中金额较大的那一个。所以 dp[1] = max(nums[0], nums[1])

  3. 状态转移方程:对于第 i 间房屋(i > 1),有两种选择:

    • 不偷窃第 i 间房屋,那么最高金额为到达前一间房屋时的最高金额,即 dp[i-1]
    • 偷窃第 i 间房屋,那么由于不能偷窃相邻的房屋,最高金额为第 i-2 间房屋的最高金额加上第 i 间房屋中的金额,即 dp[i-2] + nums[i]

    因此,状态转移方程为 dp[i] = max(dp[i-1], dp[i-2] + nums[i])

  4. 结果:数组 nums 中最后一个房屋的索引为 nums.length - 1,所以 dp[nums.length - 1] 就是不触动警报装置情况下能偷窃到的最高金额。

完整代码

Python
class Solution:def rob(self, nums: List[int]) -> int:if not nums:return 0if len(nums) == 1:return nums[0]dp = [0] * len(nums)dp[0], dp[1] = nums[0], max(nums[0], nums[1])for i in range(2, len(nums)):dp[i] = max(dp[i-1], dp[i-2] + nums[i])return dp[-1]
Java
class Solution {public int rob(int[] nums) {if (nums == null || nums.length == 0) {return 0;}if (nums.length == 1) {return nums[0];}int[] dp = new int[nums.length];dp[0] = nums[0];dp[1] = Math.max(nums[0], nums[1]);for (int i = 2; i < nums.length; i++) {dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);}return dp[nums.length - 1];}}

 

这篇关于力扣热门算法题 174. 地下城游戏,189. 轮转数组,198. 打家劫舍的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/865731

相关文章

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

C++一个数组赋值给另一个数组方式

《C++一个数组赋值给另一个数组方式》文章介绍了三种在C++中将一个数组赋值给另一个数组的方法:使用循环逐个元素赋值、使用标准库函数std::copy或std::memcpy以及使用标准库容器,每种方... 目录C++一个数组赋值给另一个数组循环遍历赋值使用标准库中的函数 std::copy 或 std::

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::