题目## 题目## 题目## 题目
题目链接
题目描述
在一个3*3的棋盘上,小红和小紫正在玩"夹吃棋"。所谓"夹吃棋",即如果存在一个白子,它的两侧(横向或者纵向)相邻都是黑子,则这个棋子将被"夹吃";对于黑棋亦然。如果一个棋盘的局面没有一方被夹吃,或者黑白双方都被对面夹吃,则认为是平局。如果只有一方夹吃了另一方,则认为夹吃方赢,被夹吃方输。
小红执黑棋,小紫执白棋,现在给定一个局面,请你判断当前棋局是谁获胜。
输入:
- 第一行输入一个正整数,代表询问的次数
- 接下来每组询问输入三行,每行是一个长度为3的字符串,字符串仅由’o’、‘*’、'.'组成
- 其中’o’代表白棋,'*‘代表黑棋,’.'代表未放置棋子
输出:
- 对于每个棋局,输出一行字符串表示答案
- 小红获胜输出"kou",小紫获胜输出"yukari",平局输出"draw"
解题思路
这是一个模拟问题,可以通过以下步骤解决:
-
关键发现:
- 需要检查每个棋子是否被夹吃
- 只需要检查横向和纵向
- 需要分别统计黑白双方被夹吃的情况
-
模拟策略:
- 遍历棋盘上的每个位置
- 对每个棋子检查横向和纵向是否被夹吃
- 根据双方被夹吃情况判断胜负
-
具体步骤:
- 读入棋盘状态
- 检查每个白子是否被黑子夹吃
- 检查每个黑子是否被白子夹吃
- 根据规则判断胜负
代码
#include <bits/stdc++.h>
using namespace std;
// 检查位置(i,j)的棋子是否被夹吃
bool isEaten(vector<string>& board, int i, int j, char target, char enemy) {
// 检查横向
if(j > 0 && j < 2 && board[i][j] == target &&
board[i][j-1] == enemy && board[i][j+1] == enemy) {
return true;
}
// 检查纵向
if(i > 0 && i < 2 && board[i][j] == target &&
board[i-1][j] == enemy && board[i+1][j] == enemy) {
return true;
}
return false;
}
string solve(vector<string>& board) {
bool white_eaten = false; // 白子是否被夹吃
bool black_eaten = false; // 黑子是否被夹吃
// 检查每个位置
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(board[i][j] == 'o' && isEaten(board, i, j, 'o', '*')) {
white_eaten = true;
}
if(board[i][j] == '*' && isEaten(board, i, j, '*', 'o')) {
black_eaten = true;
}
}
}
// 判断胜负
if(white_eaten && !black_eaten) return "kou"; // 小红赢
if(!white_eaten && black_eaten) return "yukari"; // 小紫赢
return "draw"; // 平局
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while(T--) {
vector<string> board(3);
for(int i = 0; i < 3; i++) {
cin >> board[i];
}
cout << solve(board) << '\n';
}
return 0;
}
import java.util.*;
public class Main {
// 检查位置(i,j)的棋子是否被夹吃
static boolean isEaten(char[][] board, int i, int j, char target, char enemy) {
// 检查横向
if(j > 0 && j < 2 && board[i][j] == target &&
board[i][j-1] == enemy && board[i][j+1] == enemy) {
return true;
}
// 检查纵向
if(i > 0 && i < 2 && board[i][j] == target &&
board[i-1][j] == enemy && board[i+1][j] == enemy) {
return true;
}
return false;
}
static String solve(char[][] board) {
boolean whiteEaten = false; // 白子是否被夹吃
boolean blackEaten = false; // 黑子是否被夹吃
// 检查每个位置
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 3; j++) {
if(board[i][j] == 'o' && isEaten(board, i, j, 'o', '*')) {
whiteEaten = true;
}
if(board[i][j] == '*' && isEaten(board, i, j, '*', 'o')) {
blackEaten = true;
}
}
}
// 判断胜负
if(whiteEaten && !blackEaten) return "kou"; // 小红赢
if(!whiteEaten && blackEaten) return "yukari"; // 小紫赢
return "draw"; // 平局
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int T = sc.nextInt();
while(T-- > 0) {
char[][] board = new char[3][3];
for(int i = 0; i < 3; i++) {
board[i] = sc.next().toCharArray();
}
System.out.println(solve(board));
}
}
}
def is_eaten(board, i, j, target, enemy):
# 检查横向
if j > 0 and j < 2 and board[i][j] == target and \
board[i][j-1] == enemy and board[i][j+1] == enemy:
return True
# 检查纵向
if i > 0 and i < 2 and board[i][j] == target and \
board[i-1][j] == enemy and board[i+1][j] == enemy:
return True
return False
def solve(board):
white_eaten = False # 白子是否被夹吃
black_eaten = False # 黑子是否被夹吃
# 检查每个位置
for i in range(3):
for j in range(3):
if board[i][j] == 'o' and is_eaten(board, i, j, 'o', '*'):
white_eaten = True
if board[i][j] == '*' and is_eaten(board, i, j, '*', 'o'):
black_eaten = True
# 判断胜负
if white_eaten and not black_eaten:
return "kou" # 小红赢
if not white_eaten and black_eaten:
return "yukari" # 小紫赢
return "draw" # 平局
T = int(input())
for _ in range(T):
board = [input() for _ in range(3)]
print(solve(board))
算法及复杂度
- 算法:模拟
- 时间复杂度: O ( T ) \mathcal{O}(T) O(T) - 每个棋局只需要常数时间检查
- 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要常数空间存储棋盘
题目链接
题目描述
小红喜欢吃多彩糖葫芦,多彩糖葫芦上的每一个糖葫芦都有一种颜色。但小红有非常严重的强迫症,她绝对不会连续吃两个相同颜色的糖葫芦。一串糖葫芦只能从上往下吃,一旦小红发现下一颗糖葫芦和她刚吃过的糖葫芦颜色相同时,小红就会把整串多彩糖葫芦丢掉。小红想知道她吃一串多彩糖葫芦时可以吃到几颗糖葫芦。
输入:
- 一个字符串,表示多彩糖葫芦串上从上到下每一颗糖葫芦的颜色
输出:
- 一个整数,表示小红最多能吃到的糖葫芦数量
解题思路
这是一个模拟问题,可以通过以下步骤解决:
-
关键发现:
- 小红只能从上往下吃
- 遇到相同颜色就会停止
- 需要记录上一个吃的糖葫芦的颜色
-
模拟策略:
- 从第一个糖葫芦开始吃
- 记录上一个吃的糖葫芦颜色
- 如果下一个糖葫芦颜色相同,就停止
- 否则继续吃并更新上一个颜色
-
具体步骤:
- 遍历字符串
- 维护上一个颜色和已吃数量
- 遇到相同颜色就退出循环
代码
#include <bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
int ans = 1; // 第一个糖葫芦一定能吃
char last = s[0]; // 记录上一个颜色
for(int i = 1; i < s.length(); i++) {
if(s[i] == last) { // 遇到相同颜色就停止
break;
}
last = s[i]; // 更新上一个颜色
ans++; // 可以吃这个糖葫芦
}
cout << ans << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String s = sc.next();
int ans = 1; // 第一个糖葫芦一定能吃
char last = s.charAt(0); // 记录上一个颜色
for(int i = 1; i < s.length(); i++) {
if(s.charAt(i) == last) { // 遇到相同颜色就停止
break;
}
last = s.charAt(i); // 更新上一个颜色
ans++; // 可以吃这个糖葫芦
}
System.out.println(ans);
}
}
s = input()
ans = 1 # 第一个糖葫芦一定能吃
last = s[0] # 记录上一个颜色
for i in range(1, len(s)):
if s[i] == last: # 遇到相同颜色就停止
break
last = s[i] # 更新上一个颜色
ans += 1 # 可以吃这个糖葫芦
print(ans)
算法及复杂度
- 算法:模拟
- 时间复杂度: O ( n ) \mathcal{O}(n) O(n) - 最多需要遍历整个字符串
- 空间复杂度: O ( 1 ) \mathcal{O}(1) O(1) - 只需要常数空间存储变量
题目链接
题目描述
小红有 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) - 只需要常数空间存储变量
6313

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



