题目## 题目
题目链接
题目描述
小红有 n n n 块地砖,小红从第一块地砖开始,要走到第 n n n 块地砖。走到第 i i i 块地砖需要消耗 a i a_i ai 的体力值,小红每次可以选择向前走一步或者向前走两步,求小红走到第 n n n 块地砖时消耗的最小体力值。
输入:
- 第一行输入一个整数 n n n,表示地砖的数量
- 第二行输入 n n n 个整数 a i a_i ai,表示走到第 i i i 块地砖需要消耗的体力值
输出:
- 输出一个整数,表示小红走到第 n n n 块地砖时消耗的最小体力值
解题思路
这是一个动态规划问题,可以通过以下步骤解决:
-
关键发现:
- 每次可以走一步或两步
- 到达每个位置的最小体力值只与前两个位置有关
- 需要累加经过的地砖的体力值
-
解题策略:
- 使用dp数组记录到达每个位置的最小体力值
- 对每个位置,考虑从前一个位置走一步或从前两个位置走两步
- 选择较小的体力值
-
具体步骤:
- 初始化dp数组,dp[i]表示到达第i个位置的最小体力值
- 状态转移:dp[i] = min(dp[i-1], dp[i-2]) + a[i]
- 最后返回dp[n-1]
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
for(int i = 0; i < n; i++) {
cin >> a[i];
}
vector<int> dp(n, INT_MAX);
dp[0] = a[0];
if(n > 1) dp[1] = a[1];
for(int i = 2; i < n; i++) {
dp[i] = min(dp[i-1], dp[i-2]) + a[i];
}
cout << dp[n-1] << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[n];
for(int i = 0; i < n; i++) {
a[i] = sc.nextInt();
}
int[] dp = new int[n];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = a[0];
if(n > 1) dp[1] = a[1];
for(int i = 2; i < n; i++) {
dp[i] = Math.min(dp[i-1], dp[i-2]) + a[i];
}
System.out.println(dp[n-1]);
}
}
n = int(input())
a = list(map(int, input().split()))
dp = [float('inf')] * n
dp[0] = a[0]
if n > 1:
dp[1] = a[1]
for i in range(2, n):
dp[i] = min(dp[i-1], dp[i-2]) + a[i]
print(dp[n-1])
算法及复杂度
- 算法:动态规划
- 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要遍历一次数组
- 空间复杂度: O ( n ) \mathcal{O}(n) O(n) - 需要dp数组存储状态
注意:
- 需要特别处理n=1和n=2的情况
- 初始化dp数组时要用最大值
- 状态转移时需要考虑前两个位置
- 最终结果是dp[n-1]而不是dp[n]
题目链接
题目描述
小红拿到了一个字符串。她想知道,该字符串有多少个长度为 k 的连续子串是回文的?
输入:
- 第一行输入两个正整数 n 和 k,分别代表字符串长度和子串长度
- 第二行输入一个长度为 n 的、仅由小写字母组成的字符串
输出:
- 输出一个整数,表示长度为 k 的回文子串数量
解题思路
这是一个字符串处理问题,可以通过以下步骤解决:
-
关键发现:
- 需要检查所有长度为 k 的连续子串
- 子串总数为 n-k+1 个
- 每个子串需要判断是否为回文串
-
解题策略:
- 使用滑动窗口遍历所有长度为 k 的子串
- 对每个子串判断是否为回文
- 统计回文子串的数量
-
具体步骤:
- 遍历字符串的每个位置 i (0 到 n-k)
- 检查从位置 i 开始的长度为 k 的子串
- 判断该子串是否为回文
- 累计回文子串的数量
代码
#include <bits/stdc++.h>
using namespace std;
// 判断字符串是否为回文
bool isPalindrome(const string& s, int start, int len) {
int left = start;
int right = start + len - 1;
while(left < right) {
if(s[left] != s[right]) return false;
left++;
right--;
}
return true;
}
int main() {
int n, k;
cin >> n >> k;
string s;
cin >> s;
int ans = 0;
// 遍历所有长度为k的子串
for(int i = 0; i <= n - k; i++) {
if(isPalindrome(s, i, k)) {
ans++;
}
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
// 判断字符串是否为回文
static boolean isPalindrome(String s, int start, int len) {
int left = start;
int right = start + len - 1;
while(left < right) {
if(s.charAt(left) != s.charAt(right)) return false;
left++;
right--;
}
return true;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
String s = sc.next();
int ans = 0;
// 遍历所有长度为k的子串
for(int i = 0; i <= n - k; i++) {
if(isPalindrome(s, i, k)) {
ans++;
}
}
System.out.println(ans);
}
}
def is_palindrome(s, start, length):
left = start
right = start + length - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
n, k = map(int, input().split())
s = input()
ans = 0
# 遍历所有长度为k的子串
for i in range(n - k + 1):
if is_palindrome(s, i, k):
ans += 1
print(ans)
算法及复杂度
- 算法:滑动窗口 + 回文判断
- 时间复杂度: O ( n ⋅ k ) \mathcal{O}(n \cdot k) O(n⋅k) - 需要检查 n − k + 1 n-k+1 n−k+1 个子串,每个子串需要 O ( k ) \mathcal{O}(k) O(k) 时间判断
- 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要常数空间存储变量

被折叠的 条评论
为什么被折叠?



