你是我生命里不朽的月亮,予我清辉如霜
—— 25.6.10
一、算法描述
按照某种策略一步一步去选择,每次都是选择最优策略,不从整体最优考虑
二、实战练习
1.翻硬币
题目描述
小明正在玩一个"翻硬币"的游戏。
桌上放着排成一排的若干硬币。我们用 * 表示正面,用 o 表示反面(是小写字母,不是零)。
比如,可能情形是:**oo***oooo;
如果同时翻转左边的两个硬币,则变为:oooo***oooo。
现在小明的问题是:如果已知了初始状态和要达到的目标状态,每次只能同时翻转相邻的两个硬币,那么对特定的局面,最少要翻动多少次呢?
我们约定:把翻动相邻的两个硬币叫做一步操作。
输入描述
两行等长的字符串,分别表示初始状态和要达到的目标状态。
每行的长度<1000。
输出描述
一个整数,表示最小操作步数。
输入输出样例
示例
输入
********** o****o****
输出
5
运行限制
- 最大运行时间:1s
- 最大运行内存: 64M
思路与算法
思路
从左到右遍历字符串,一旦发现 a[i]
与 b[i]
不匹配,立即翻转 a[i]
和 a[i+1]
。这样可以保证每次操作都能解决当前位置的不匹配问题,而不会影响已经处理过的部分。
算法步骤
初始化:读取输入的字符串 a
和目标字符串 b
,并初始化操作次数 res = 0
。
遍历字符串:从左到右遍历字符串 a
的每个字符。
检查不匹配:对于每个位置 i
,如果 a[i] != b[i]
,则执行以下操作:
翻转 a[i]
和 a[i+1]
(将 'o' 变为 '','' 变为 'o')。
操作次数 res
加 1。
终止条件:遍历结束后,res
即为将 a
转换为 b
所需的最小操作次数。
import os
import sys
# 请在此输入您的代码
a = input()
b = input()
n = len(a)
a = [i for i in a]
res = 0
for i in range(n):
if a[i] != b[i]:
a[i] = '*' if a[i] == 'o' else 'o'
a[i+1] = '*' if a[i+1] == 'o' else 'o'
res += 1
print(res)
2.1键3连
问题描述
给定一个长度为 n 的整数数列 A,A 中第 i 个元素为 Ai(1≤i≤n),整数 res 初始为 0,如果一个数 a 存在于 A 且 a+1,a+2 均存在于 A 中,则 res 加 1,请输出最后 res 的值。
输入格式
输入共 2 行。
第一行包含一个整数 n,表示整数数列 A 中元素的个数。
第二行包含 n 个整数,表示整数数列 A 中各元素的值。
输出格式
输出共一行,包含一个整数,表示最后 res 的值。
样例输入
5 1 2 2 3 4
样例输出
2
评测数据规模
对于所有评测数据,3≤n≤10^5,1≤A_i≤10^5。
运行限制
语言 最大运行时间 最大运行内存 C++ 2s 256M C 2s 256M Java 3s 256M Python3 4s 256M PyPy3 4s 256M Go 4s 256M JavaScript 4s 256M
思路与算法
思路
贪心算法的核心思想是局部最优选择,即每一步都选择当前看起来最优的操作,最终达到全局最优解。在这个问题中,贪心策略的关键在于:
预处理数组:先对数组进行排序和去重,得到一个严格递增的数组。
遍历去重后的数组:对于每个元素,检查它与后续两个元素是否能构成连续递增的三元组。如果可以,则计数加 1,并继续检查后续元素。
算法步骤
输入处理与排序:读取数组长度 n
和数组 arr
。对数组进行排序,以便后续处理。
原地去重:使用双指针法原地去重,将不重复的元素移到数组前部。指针 x
记录当前不重复元素的末尾位置,指针 y
遍历原数组。
统计连续三元组:遍历去重后的数组,检查每个元素 arr[i]
是否满足 arr[i+1] == arr[i]+1
且 arr[i+2] == arr[i]+2
。如果满足条件,则计数 res
加 1。
import os
import sys
# 请在此输入您的代码
n = int(input())
arr = list(map(int, input().split()))
arr = sorted(arr)
# x代表现在已经做完处理的非重复数据个数
# y代表当前正在处理的arr列表中的元素下标
x = 1
y = 1
while y < n:
if arr[y] != arr[x-1]:
arr[x] = arr[y]
x += 1
y += 1
res = 0
for i in range(x-2):
num = arr[i]
if arr[i+1] == num+1 and arr[i+2] == num+2:
res += 1
print(res)
3.分开元音字母
问题描述
给定一串长度为 n 且只含有小写英文字母的字符串 S,请你用小括号 '(' 与 ')' 将字符串 S 分开,使得每对小括号内有且仅有一个元音字母。如果有多种分开的方式,输出各个括号内的字母数组成的数组中字典序最大的那一个。
元音字母有 a,e,i,o,u。
例如:字符串 abe,可分为 (ab)(e),与(a)(be),前者括号内的字母数组成的数组为 2,1,后者为 1,2,所以答案为 (ab)(e)。
注意:如果给定的字符串中没有元音字母,则无需增加括号,直接输出字符串即可。
输入格式
输入共一行,包含一串字符串 S。
输出格式
输出共一行,包含一串字符串,表示被小括号分开后的字符串 S。
样例输入
abcdeeko
样例输出
(abcd)(e)(ek)(o)
评测数据规模
对于所有评测数据,1≤n≤10^5。
运行限制
语言 最大运行时间 最大运行内存 C++ 2s 256M C 2s 256M Java 3s 256M Python3 4s 256M PyPy3 4s 256M Go 4s 256M JavaScript 4s 256M
思路与算法
思路
贪心策略的核心是局部最优决策:遍历字符串时,一旦遇到元音字母,立即用括号将其包裹,并确保相邻元音字母被分隔。
算法步骤
初始化:结果字符串 res
初始化为 "("
。计数器 count
初始化为 0,用于记录已处理的元音字母数量。
遍历字符串:对于每个字符 i
:
若为元音:count
加 1。若当前不是第一个元音(即 count > 1
),说明前面已有元音,需要分隔:在结果字符串中追加 ")("
,表示前一个括号结束,新括号开始。将当前元音字符追加到结果字符串。
若非元音:直接追加到结果字符串。
收尾处理:遍历结束后,在结果字符串末尾追加 ")"
,形成完整的括号结构。
特殊情况处理:若整个字符串中没有元音(即 count == 0
),直接输出原字符串。
import os
import sys
# 请在此输入您的代码
S = input()
n = len(S)
def Judge(s):
return s in ['a', 'e', 'i', 'o', 'u']
res = "("
count = 0
for i in S:
if Judge(i):
count += 1
if count > 1:
res += ")("
count += 1
res += i
res += ")"
if count == 0:
print(S)
else:
print(res)