一、问题描述
题目描述
小明和朋友玩跳格子游戏,有 n
个连续格子,每个格子有不同的分数,小朋友可以选择以任意格子起跳,但是不能跳连续的格子,也不能回头跳。
给定一个代表每个格子得分的非负整数数组,计算能够得到的最高分数。
输入描述
给定一个数列,如:1 2 3 1
输出描述
输出能够得到的最高分,如:4
备注
1 ≤ nums.length ≤ 100
0 ≤ nums[i] ≤ 1000
用例
用例 1
输入:
1 2 3 1
输出:
4
说明:
选择跳第一个格子和第三个格子
用例 2
输入:
2 7 9 3 1
输出:
12
说明:
2 + 9 + 1 = 12
题目解析
本题是一个典型的动态规划问题。我们可以使用动态规划来解决这个问题,具体步骤如下:
-
定义状态:
dp[i]
表示跳到第i
个格子时能够得到的最高分数。
-
状态转移方程:
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
dp[i-1]
表示不跳第i
个格子,保持上一个格子的最高分数。dp[i-2] + nums[i]
表示跳到第i
个格子,加上第i
个格子的分数。
-
初始化:
dp[0] = nums[0]
,跳到第一个格子的最高分数就是第一个格子的分数。dp[1] = max(nums[0], nums[1])
,跳到第二个格子的最高分数是前两个格子中较大的一个。
-
计算结果:
- 遍历数组,计算每个格子的最高分数。
- 最终结果是
dp
数组的最后一个元素。
详细步骤
-
读取输入:
- 从标准输入读取一个数列,表示每个格子的分数。
-
初始化动态规划数组:
- 创建一个
dp
数组,长度与输入数组相同。 dp[0] = nums[0]
dp[1] = max(nums[0], nums[1])
- 创建一个
-
计算每个格子的最高分数:
- 从第三个格子开始,遍历数组:
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
- 从第三个格子开始,遍历数组:
-
输出结果:
- 输出
dp
数组的最后一个元素,即最高分数。
- 输出
用例解释
用例 1
- 输入:
1 2 3 1
- 输出:
4
解释:
dp[0] = 1
dp[1] = max(1, 2) = 2
dp[2] = max(2, 1 + 3) = 4
dp[3] = max(4, 2 + 1) = 4
- 最终结果为
4
用例 2
- 输入:
2 7 9 3 1
- 输出:
12
解释:
dp[0] = 2
dp[1] = max(2, 7) = 7
dp[2] = max(7, 2 + 9) = 11
dp[3] = max(11, 7 + 3) = 11
dp[4] = max(11, 11 + 1) = 12
- 最终结果为
12
通过上述步骤,我们可以高效地求出能够得到的最高分数。这种方法的时间复杂度为 O(n)
,其中 n
是数组的长度。
二、JavaScript算法源码
以下是 JavaScript 代码 的详细中文注释和逻辑讲解:
JavaScript 代码
javascript
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
// 创建 readline 接口,用于从控制台读取输入
const rl = readline.createInterface({
input: process.stdin, // 输入流为标准输入
output: process.stdout, // 输出流为标准输出
});
// 监听每一行输入
rl.on("line", (line) => {
// 将输入的字符串按空格分割,并转换为数字数组
const nums = line.split(" ").map(Number);
// 调用算法函数并输出结果
console.log(getResult(nums));
});
// 算法函数
function getResult(nums) {
const n = nums.length; // 获取数组的长度
// 创建一个长度为 n 的数组 dp,用于存储动态规划的结果
const dp = new Array(n).fill(0);
// 初始化 dp 数组
if (n >= 1) dp[0] = nums[0]; // 如果数组长度 >= 1,dp[0] 为第一个元素
if (n >= 2) dp[1] = Math.max(nums[0], nums[1]); // 如果数组长度 >= 2,dp[1] 为前两个元素中的最大值
// 动态规划递推
for (let i = 2; i < n; i++) {
// dp[i] 的值取决于两种情况:
// 1. 不选择当前元素,则 dp[i] = dp[i - 1]
// 2. 选择当前元素,则 dp[i] = dp[i - 2] + nums[i]
// 取两者中的最大值
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
// 返回 dp 数组的最后一个值,即最大和
return dp[n - 1];
}
代码逻辑讲解
1. 输入处理
- 使用
readline
模块从控制台读取输入。 - 输入格式为一行数字,用空格分隔。
- 将输入字符串按空格分割,并转换为数字数组
nums
。
2. 算法逻辑
- 动态规划定义 :
dp[i]
表示从数组nums
的前i
个元素中选取不相邻元素的最大和。
- 初始化 :
- 如果数组长度为 1,
dp[0] = nums[0]
。 - 如果数组长度为 2,
dp[1] = Math.max(nums[0], nums[1])
。
- 如果数组长度为 1,
- 递推公式 :
- 对于每个位置
i
,有两种选择:- 不选择当前元素,则最大和为
dp[i - 1]
。 - 选择当前元素,则最大和为
dp[i - 2] + nums[i]
。
- 不选择当前元素,则最大和为
- 取两者中的最大值作为
dp[i]
。
- 对于每个位置
- 结果 :
dp[n - 1]
即为从整个数组中选取不相邻元素的最大和。
3. 示例验证
示例 1:
-
输入:
1 2 3 1
-
处理过程:
- 初始化:
dp[0] = 1
。dp[1] = Math.max(1, 2) = 2
。
- 递推:
dp[2] = Math.max(dp[1], dp[0] + 3) = Math.max(2, 1 + 3) = 4
。dp[3] = Math.max(dp[2], dp[1] + 1) = Math.max(4, 2 + 1) = 4
。
- 结果:
4
。
- 初始化:
-
输出:
4
。
示例 2:
-
输入:
2 7 9 3 1
-
处理过程:
- 初始化:
dp[0] = 2
。dp[1] = Math.max(2, 7) = 7
。
- 递推:
dp[2] = Math.max(dp[1], dp[0] + 9) = Math.max(7, 2 + 9) = 11
。dp[3] = Math.max(dp[2], dp[1] + 3) = Math.max(11, 7 + 3) = 11
。dp[4] = Math.max(dp[3], dp[2] + 1) = Math.max(11, 11 + 1) = 12
。
- 结果:
12
。
- 初始化:
-
输出:
12
。
示例 3:
-
输入:
5 5 10 100 10 5
-
处理过程:
- 初始化:
dp[0] = 5
。dp[1] = Math.max(5, 5) = 5
。
- 递推:
dp[2] = Math.max(dp[1], dp[0] + 10) = Math.max(5, 5 + 10) = 15
。dp[3] = Math.max(dp[2], dp[1] + 100) = Math.max(15, 5 + 100) = 105
。dp[4] = Math.max(dp[3], dp[2] + 10) = Math.max(105, 15 + 10) = 105
。dp[5] = Math.max(dp[4], dp[3] + 5) = Math.max(105, 105 + 5) = 110
。
- 结果:
110
。
- 初始化:
-
输出:
110
。
总结
- 功能:从数组中选取不相邻的元素,使它们的和最大。
- 核心逻辑 :
- 使用动态规划记录每一步的最大和。
- 通过递推公式计算每个位置的最大和。
- 返回最终结果。
- 适用场景:需要从数组中选取不相邻元素并求最大和的场景。
- 注意事项 :
- 数组中的元素可以为负数,但动态规划的逻辑仍然适用。
- 时间复杂度为
O(n)
,空间复杂度为O(n)
。
如果有其他问题,欢迎随时提问!
三、Java算法源码
以下是 Java 代码 的详细中文注释和逻辑讲解:
Java 代码
java
import java.util.Arrays;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// 创建 Scanner 对象,用于从控制台读取输入
Scanner sc = new Scanner(System.in);
// 读取一行输入,按空格分割成字符串数组,并转换为整数数组
int[] nums = Arrays.stream(sc.nextLine().split(" ")).mapToInt(Integer::parseInt).toArray();
// 调用算法函数并输出结果
System.out.println(getResult(nums));
}
// 算法函数
public static int getResult(int[] nums) {
int n = nums.length; // 获取数组的长度
// 创建一个长度为 n 的数组 dp,用于存储动态规划的结果
int[] dp = new int[n];
// 初始化 dp 数组
if (n >= 1) dp[0] = nums[0]; // 如果数组长度 >= 1,dp[0] 为第一个元素
if (n >= 2) dp[1] = Math.max(nums[0], nums[1]); // 如果数组长度 >= 2,dp[1] 为前两个元素中的最大值
// 动态规划递推
for (int i = 2; i < n; i++) {
// dp[i] 的值取决于两种情况:
// 1. 不选择当前元素,则 dp[i] = dp[i - 1]
// 2. 选择当前元素,则 dp[i] = dp[i - 2] + nums[i]
// 取两者中的最大值
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
// 返回 dp 数组的最后一个值,即最大和
return dp[n - 1];
}
}
代码逻辑讲解
1. 输入处理
- 使用
Scanner
从控制台读取输入。 - 输入格式为一行数字,用空格分隔。
- 将输入字符串按空格分割,并转换为整数数组
nums
。
2. 算法逻辑
- 动态规划定义 :
dp[i]
表示从数组nums
的前i
个元素中选取不相邻元素的最大和。
- 初始化 :
- 如果数组长度为 1,
dp[0] = nums[0]
。 - 如果数组长度为 2,
dp[1] = Math.max(nums[0], nums[1])
。
- 如果数组长度为 1,
- 递推公式 :
- 对于每个位置
i
,有两种选择:- 不选择当前元素,则最大和为
dp[i - 1]
。 - 选择当前元素,则最大和为
dp[i - 2] + nums[i]
。
- 不选择当前元素,则最大和为
- 取两者中的最大值作为
dp[i]
。
- 对于每个位置
- 结果 :
dp[n - 1]
即为从整个数组中选取不相邻元素的最大和。
3. 示例验证
示例 1:
-
输入:
1 2 3 1
-
处理过程:
- 初始化:
dp[0] = 1
。dp[1] = Math.max(1, 2) = 2
。
- 递推:
dp[2] = Math.max(dp[1], dp[0] + 3) = Math.max(2, 1 + 3) = 4
。dp[3] = Math.max(dp[2], dp[1] + 1) = Math.max(4, 2 + 1) = 4
。
- 结果:
4
。
- 初始化:
-
输出:
4
。
示例 2:
-
输入:
2 7 9 3 1
-
处理过程:
- 初始化:
dp[0] = 2
。dp[1] = Math.max(2, 7) = 7
。
- 递推:
dp[2] = Math.max(dp[1], dp[0] + 9) = Math.max(7, 2 + 9) = 11
。dp[3] = Math.max(dp[2], dp[1] + 3) = Math.max(11, 7 + 3) = 11
。dp[4] = Math.max(dp[3], dp[2] + 1) = Math.max(11, 11 + 1) = 12
。
- 结果:
12
。
- 初始化:
-
输出:
12
。
示例 3:
-
输入:
5 5 10 100 10 5
-
处理过程:
- 初始化:
dp[0] = 5
。dp[1] = Math.max(5, 5) = 5
。
- 递推:
dp[2] = Math.max(dp[1], dp[0] + 10) = Math.max(5, 5 + 10) = 15
。dp[3] = Math.max(dp[2], dp[1] + 100) = Math.max(15, 5 + 100) = 105
。dp[4] = Math.max(dp[3], dp[2] + 10) = Math.max(105, 15 + 10) = 105
。dp[5] = Math.max(dp[4], dp[3] + 5) = Math.max(105, 105 + 5) = 110
。
- 结果:
110
。
- 初始化:
-
输出:
110
。
总结
- 功能:从数组中选取不相邻的元素,使它们的和最大。
- 核心逻辑 :
- 使用动态规划记录每一步的最大和。
- 通过递推公式计算每个位置的最大和。
- 返回最终结果。
- 适用场景:需要从数组中选取不相邻元素并求最大和的场景。
- 注意事项 :
- 数组中的元素可以为负数,但动态规划的逻辑仍然适用。
- 时间复杂度为
O(n)
,空间复杂度为O(n)
。
如果有其他问题,欢迎随时提问!
四、Python算法源码
以下是 Python 代码 的详细中文注释和逻辑讲解:
Python 代码
python
# 输入获取
nums = list(map(int, input().split())) # 从控制台读取一行输入,按空格分割并转换为整数列表
# 算法入口
def getResult():
n = len(nums) # 获取数组的长度
dp = [0] * n # 创建一个长度为 n 的数组 dp,用于存储动态规划的结果
# 初始化 dp 数组
if n >= 1:
dp[0] = nums[0] # 如果数组长度 >= 1,dp[0] 为第一个元素
if n >= 2:
dp[1] = max(nums[0], nums[1]) # 如果数组长度 >= 2,dp[1] 为前两个元素中的最大值
# 动态规划递推
for i in range(2, n):
# dp[i] 的值取决于两种情况:
# 1. 不选择当前元素,则 dp[i] = dp[i - 1]
# 2. 选择当前元素,则 dp[i] = dp[i - 2] + nums[i]
# 取两者中的最大值
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
# 返回 dp 数组的最后一个值,即最大和
return dp[n - 1]
# 算法调用
print(getResult()) # 调用算法函数并输出结果
代码逻辑讲解
1. 输入处理
- 使用
input().split()
从控制台读取一行输入,按空格分割成字符串列表。 - 使用
map(int, ...)
将字符串列表转换为整数列表nums
。
2. 算法逻辑
- 动态规划定义 :
dp[i]
表示从数组nums
的前i
个元素中选取不相邻元素的最大和。
- 初始化 :
- 如果数组长度为 1,
dp[0] = nums[0]
。 - 如果数组长度为 2,
dp[1] = max(nums[0], nums[1])
。
- 如果数组长度为 1,
- 递推公式 :
- 对于每个位置
i
,有两种选择:- 不选择当前元素,则最大和为
dp[i - 1]
。 - 选择当前元素,则最大和为
dp[i - 2] + nums[i]
。
- 不选择当前元素,则最大和为
- 取两者中的最大值作为
dp[i]
。
- 对于每个位置
- 结果 :
dp[n - 1]
即为从整个数组中选取不相邻元素的最大和。
3. 示例验证
示例 1:
-
输入:
1 2 3 1
-
处理过程:
- 初始化:
dp[0] = 1
。dp[1] = max(1, 2) = 2
。
- 递推:
dp[2] = max(dp[1], dp[0] + 3) = max(2, 1 + 3) = 4
。dp[3] = max(dp[2], dp[1] + 1) = max(4, 2 + 1) = 4
。
- 结果:
4
。
- 初始化:
-
输出:
4
。
示例 2:
-
输入:
2 7 9 3 1
-
处理过程:
- 初始化:
dp[0] = 2
。dp[1] = max(2, 7) = 7
。
- 递推:
dp[2] = max(dp[1], dp[0] + 9) = max(7, 2 + 9) = 11
。dp[3] = max(dp[2], dp[1] + 3) = max(11, 7 + 3) = 11
。dp[4] = max(dp[3], dp[2] + 1) = max(11, 11 + 1) = 12
。
- 结果:
12
。
- 初始化:
-
输出:
12
。
示例 3:
-
输入:
5 5 10 100 10 5
-
处理过程:
- 初始化:
dp[0] = 5
。dp[1] = max(5, 5) = 5
。
- 递推:
dp[2] = max(dp[1], dp[0] + 10) = max(5, 5 + 10) = 15
。dp[3] = max(dp[2], dp[1] + 100) = max(15, 5 + 100) = 105
。dp[4] = max(dp[3], dp[2] + 10) = max(105, 15 + 10) = 105
。dp[5] = max(dp[4], dp[3] + 5) = max(105, 105 + 5) = 110
。
- 结果:
110
。
- 初始化:
-
输出:
110
。
总结
- 功能:从数组中选取不相邻的元素,使它们的和最大。
- 核心逻辑 :
- 使用动态规划记录每一步的最大和。
- 通过递推公式计算每个位置的最大和。
- 返回最终结果。
- 适用场景:需要从数组中选取不相邻元素并求最大和的场景。
- 注意事项 :
- 数组中的元素可以为负数,但动态规划的逻辑仍然适用。
- 时间复杂度为
O(n)
,空间复杂度为O(n)
。
如果有其他问题,欢迎随时提问!
五、C/C++算法源码:
以下是 C 语言代码 和 C++ 代码 的详细中文注释和逻辑讲解:
C 语言代码
c
#include <stdio.h>
#define MAX_SIZE 100 // 定义数组的最大长度
#define MAX(a, b) a > b ? a : b // 定义宏,用于求两个数的最大值
// 算法函数
int getResult(int* nums, int nums_size);
int main() {
int nums[MAX_SIZE]; // 定义数组,用于存储输入的数字
int nums_size = 0; // 记录数组的实际长度
// 从控制台读取输入,直到遇到换行符
while (scanf("%d", &nums[nums_size++])) {
if (getchar() != ' ') break; // 如果下一个字符不是空格,则结束输入
}
// 调用算法函数并输出结果
printf("%d\n", getResult(nums, nums_size));
return 0;
}
// 算法实现
int getResult(int* nums, int nums_size) {
int dp[MAX_SIZE] = {0}; // 定义 dp 数组,用于存储动态规划的结果
// 初始化 dp 数组
if (nums_size >= 1) {
dp[0] = nums[0]; // 如果数组长度 >= 1,dp[0] 为第一个元素
}
if (nums_size >= 2) {
dp[1] = MAX(nums[0], nums[1]); // 如果数组长度 >= 2,dp[1] 为前两个元素中的最大值
}
// 动态规划递推
for (int i = 2; i < nums_size; i++) {
// dp[i] 的值取决于两种情况:
// 1. 不选择当前元素,则 dp[i] = dp[i - 1]
// 2. 选择当前元素,则 dp[i] = dp[i - 2] + nums[i]
// 取两者中的最大值
dp[i] = MAX(dp[i - 1], dp[i - 2] + nums[i]);
}
// 返回 dp 数组的最后一个值,即最大和
return dp[nums_size - 1];
}
C++ 代码
cpp
#include <iostream>
#include <vector>
#include <algorithm> // 包含 max 函数
using namespace std;
// 算法函数
int getResult(vector<int>& nums);
int main() {
vector<int> nums; // 定义动态数组,用于存储输入的数字
int num;
// 从控制台读取输入,直到遇到换行符
while (cin >> num) {
nums.push_back(num); // 将输入的数字添加到数组中
if (cin.get() != ' ') break; // 如果下一个字符不是空格,则结束输入
}
// 调用算法函数并输出结果
cout << getResult(nums) << endl;
return 0;
}
// 算法实现
int getResult(vector<int>& nums) {
int n = nums.size(); // 获取数组的长度
vector<int> dp(n, 0); // 定义 dp 数组,初始化为 0
// 初始化 dp 数组
if (n >= 1) {
dp[0] = nums[0]; // 如果数组长度 >= 1,dp[0] 为第一个元素
}
if (n >= 2) {
dp[1] = max(nums[0], nums[1]); // 如果数组长度 >= 2,dp[1] 为前两个元素中的最大值
}
// 动态规划递推
for (int i = 2; i < n; i++) {
// dp[i] 的值取决于两种情况:
// 1. 不选择当前元素,则 dp[i] = dp[i - 1]
// 2. 选择当前元素,则 dp[i] = dp[i - 2] + nums[i]
// 取两者中的最大值
dp[i] = max(dp[i - 1], dp[i - 2] + nums[i]);
}
// 返回 dp 数组的最后一个值,即最大和
return dp[n - 1];
}
代码逻辑讲解
1. 输入处理
- C 语言 :
- 使用
scanf
从控制台读取输入,直到遇到换行符。 - 将输入的数字存储到数组
nums
中,并记录数组的实际长度nums_size
。
- 使用
- C++ :
- 使用
cin
从控制台读取输入,直到遇到换行符。 - 将输入的数字存储到动态数组
nums
中。
- 使用
2. 算法逻辑
- 动态规划定义 :
dp[i]
表示从数组nums
的前i
个元素中选取不相邻元素的最大和。
- 初始化 :
- 如果数组长度为 1,
dp[0] = nums[0]
。 - 如果数组长度为 2,
dp[1] = max(nums[0], nums[1])
。
- 如果数组长度为 1,
- 递推公式 :
- 对于每个位置
i
,有两种选择:- 不选择当前元素,则最大和为
dp[i - 1]
。 - 选择当前元素,则最大和为
dp[i - 2] + nums[i]
。
- 不选择当前元素,则最大和为
- 取两者中的最大值作为
dp[i]
。
- 对于每个位置
- 结果 :
dp[n - 1]
即为从整个数组中选取不相邻元素的最大和。
3. 示例验证
示例 1:
-
输入:
1 2 3 1
-
处理过程:
- 初始化:
dp[0] = 1
。dp[1] = max(1, 2) = 2
。
- 递推:
dp[2] = max(dp[1], dp[0] + 3) = max(2, 1 + 3) = 4
。dp[3] = max(dp[2], dp[1] + 1) = max(4, 2 + 1) = 4
。
- 结果:
4
。
- 初始化:
-
输出:
4
。
示例 2:
-
输入:
2 7 9 3 1
-
处理过程:
- 初始化:
dp[0] = 2
。dp[1] = max(2, 7) = 7
。
- 递推:
dp[2] = max(dp[1], dp[0] + 9) = max(7, 2 + 9) = 11
。dp[3] = max(dp[2], dp[1] + 3) = max(11, 7 + 3) = 11
。dp[4] = max(dp[3], dp[2] + 1) = max(11, 11 + 1) = 12
。
- 结果:
12
。
- 初始化:
-
输出:
12
。
示例 3:
-
输入:
5 5 10 100 10 5
-
处理过程:
- 初始化:
dp[0] = 5
。dp[1] = max(5, 5) = 5
。
- 递推:
dp[2] = max(dp[1], dp[0] + 10) = max(5, 5 + 10) = 15
。dp[3] = max(dp[2], dp[1] + 100) = max(15, 5 + 100) = 105
。dp[4] = max(dp[3], dp[2] + 10) = max(105, 15 + 10) = 105
。dp[5] = max(dp[4], dp[3] + 5) = max(105, 105 + 5) = 110
。
- 结果:
110
。
- 初始化:
-
输出:
110
。
总结
- 功能:从数组中选取不相邻的元素,使它们的和最大。
- 核心逻辑 :
- 使用动态规划记录每一步的最大和。
- 通过递推公式计算每个位置的最大和。
- 返回最终结果。
- 适用场景:需要从数组中选取不相邻元素并求最大和的场景。
- 注意事项 :
- 数组中的元素可以为负数,但动态规划的逻辑仍然适用。
- 时间复杂度为
O(n)
,空间复杂度为O(n)
。
如果有其他问题,欢迎随时提问!