1. 找出最长的神奇数列
问题描述
小F是一个好学的中学生, 今天他学习了数列的概念。他在纸上写下了一个由0和1组成的正整数序列,长度为n。这个序列中的1和0交替出现,且至少由 3 个连续的0和1组成的部分数列称为「神奇数列」。例如,10101是一个神奇数列,而1011不是。现在,小F想知道在这个序列中,最长的「神奇数列」是哪个。你能帮他找到吗?
如果有多个神奇数列,那么输出最先出现的一个。
解题思路
我们可以使用暴力算法,通过遍历所有可能的子串,判断其是否符合神奇数列的条件,时间复杂度是。我们还可以使用动态规划算法,首先定义状态,
dp[i]表示以inp[i]结尾的最长神奇数列的长度。然后写出状态转移方程:如果inp[i] == inp[i - 1],则dp[i] = 1,因为当前字符与前一个字符相同,无法形成交替序列。如果inp[i] != inp[i - 1],则dp[i] = dp[i - 1] + 1,因为当前字符与前一个字符不同,可以形成更长的交替序列。
代码实现
def solution(inp): # 动态规划算法
n = len(inp)
if n < 3:
return ""
# 初始化dp数组
dp = [1] * n
max_length = 0
max_sequence = ""
start = 0
# 动态规划计算最长神奇数列
for i in range(1, n):
if inp[i] != inp[i - 1]:
dp[i] = dp[i - 1] + 1
else:
dp[i] = 1
# 如果当前长度大于最大长度,更新最长神奇数列
if dp[i] > max_length:
max_length = dp[i]
start = i - max_length + 1
# 如果最长的神奇数列长度小于3,返回空字符串
if max_length < 3:
return ""
return inp[start:start + max_length]
def solution(inp): # 暴力算法
max_length = 0
max_sequence = ""
# 遍历字符串,检查每个可能的子序列
for i in range(len(inp)):
for j in range(i + 3, len(inp) + 1):
subseq = inp[i:j]
# 检查子序列是否符合神奇数列的条件
if is_magical(subseq):
# 如果找到更长的神奇数列,更新记录
if len(subseq) > max_length:
max_length = len(subseq)
max_sequence = subseq
return max_sequence
# 辅助函数:检查子序列是否符合神奇数列的条件
def is_magical(subseq):
# 检查子序列是否由0和1交替组成
for k in range(1, len(subseq)):
if subseq[k] == subseq[k - 1]:
return False
return True
2. 字符串最短循环子串
问题描述
小M在研究字符串时发现了一个有趣的现象:某些字符串是由一个较短的子串反复拼接而成的。如果能够找到这个最短的子串,便可以很好地还原字符串的结构。你的任务是给定一个字符串,判断它是否是由某个子串反复拼接而成的。如果是,输出该最短的子串;否则,输出空字符串""。例如:当输入字符串为abababab时,它可以由子串ab反复拼接而成,因此输出ab;而如果输入ab,则该字符串不能通过子串的重复拼接得到,因此输出空字符串。
解题思路
我们可以遍历所有可能的子串长度,从1到字符串长度的一半。对于每个子串长度,检查是否可以通过重复该子串来构造原字符串。如果找到这样的子串,返回该子串;否则,返回空字符串。
代码实现
def solution(inp):
# 获取字符串的长度
n = len(inp)
# 遍历所有可能的子串长度
for length in range(1, n // 2 + 1):
# 检查当前长度的子串是否可以重复构成原字符串
if n % length == 0:
# 获取当前长度的子串
substring = inp[:length]
# 重复子串并检查是否等于原字符串
if substring * (n // length) == inp:
return substring
# 如果没有找到符合条件的子串,返回空字符串
return ""
3. 优秀项目组初选评比
问题描述
公司正在进行优秀项目组评比的初选工作,参赛者有小C、小U、小R、小S、小M和小F的项目组。评委会已经根据他们提交的材料完成了打分,各个项目组的得分分别是。评委们希望设定一个初选晋级的分数线,让所有得分大于的项目组晋级,其他的项目组将被淘汰。此外,评委们希望晋级的项目组数量和淘汰的项目组数量都在区间之间。
显然,这个分数线可能不存在,也可能存在多个满足条件的分数线。如果不存在满足条件的,则输出;如果存在多个满足条件的分数线,则输出满足条件的最小分数线。
解题思路
首先,我们对得分列表进行排序,这样当存在多个满足条件的分数线,我们更容易输出满足条件的最小分数线。然后,我们遍历所有可能的分数线,检查每个分数对应的晋级和淘汰的项目组数量是否满足条件,如果满足,则直接返回该分数。这题还可以用变体的二分查找。
代码实现
def solution(m: int, n: int, a: list) -> int:
# 1. 对得分列表进行排序
a.sort()
# 2. 遍历所有可能的分数线
for i in range(len(a)):
# 计算当前分数线 a[i] 对应的晋级和淘汰的项目组数量
晋级项目组数量 = len(a) - i - 1
淘汰项目组数量 = i + 1
# 3. 检查条件
if m <= 晋级项目组数量 <= n and m <= 淘汰项目组数量 <= n:
# 4. 返回结果
return a[i]
# 5. 如果没有找到满足条件的分数线,返回 -1
return -1
4. 小 C 点菜问题
问题描述
小C来到了一家餐馆,准备点一些菜。
已知该餐馆有 道菜,第 道菜的售价为 。
小C准备点一些价格相同的菜,但小C不会点单价超过 的菜。
小C想知道,自己最多可以点多少道菜?
解题思路
首先,我们过滤掉那些价格超过
m的菜品,因为小C不会点这些菜。接下来,我们使用字典统计每种价格的菜品数量。最后,我们找出数量最多的菜品,这个数量就是小C最多可以点的菜的数量。
代码实现
def solution(m: int, w: list) -> int:
# 过滤价格不超过 m 的菜品
valid_prices = [price for price in w if price <= m]
# 统计每种价格的菜品数量
price_count = {}
for price in valid_prices:
if price in price_count:
price_count[price] += 1
else:
price_count[price] = 1
# 找出数量最多的菜品
max_count = 0
for count in price_count.values():
if count > max_count:
max_count = count
return max_count
5. 小 C 的外卖超时判断
问题描述
小C点了一个外卖,并且急切地等待着骑手的送达。她想知道她的外卖是否超时了。
已知小C在时刻 t1 点了外卖,外卖平台上显示的预计送达时间为 t2,而实际送达时间为 t3。需要判断外卖是否超时。如果外卖超时,则输出 "Yes";否则输出 "No"。
t3 在 t2 之后则认定为超时。
实际送达时间与预计送达时间在 2 小时之内。
解题思路
首先,我们解析时间字符串,将时间字符串转换为分钟数,便于比较。然后计算
t2和t3距离t1的分钟数。我们需要额外处理跨天时间,如果t在t1之前,说明t是第二天的时间。最后,我们比较时间,判断t3是否在t2之后。
代码实现
def solution(t1: str, t2: str, t3: str) -> str:
# 将时间字符串转换为分钟数
def time_to_minutes(t: str) -> int:
hours, minutes = map(int, t.split(':'))
return hours * 60 + minutes
# 将 t1 转换为分钟数
t1_minutes = time_to_minutes(t1)
# 将 t2 和 t3 转换为相对于 t1 的分钟数
def relative_minutes(t: str, base: int) -> int:
t_minutes = time_to_minutes(t)
if t_minutes < base:
return t_minutes + 24 * 60 - base # 跨天处理
return t_minutes - base
t2_relative = relative_minutes(t2, t1_minutes)
t3_relative = relative_minutes(t3, t1_minutes)
# 判断 t3 是否在 t2 之后
if t3_relative > t2_relative:
return "Yes"
else:
return "No"
6. 小 C 的排列询问
问题描述
小C拿到了一个排列,她想知道在这个排列中,元素 x 和 y 是否是相邻的。排列是一个长度为 n 的数组,其中每个数字从 1 到 n 恰好出现一次。
你的任务是判断在给定的排列中,x 和 y 是否是相邻的。
解题思路
首先,我们遍历一次数组,找到数字
x的下标。然后,我们判断与x相邻的数字是否是y。如果是,返回True,否则返回False。
代码实现
def solution(n: int, a: list, x: int, y: int) -> bool:
# 找到 x 的位置
x_index = -1
for i in range(n):
if a[i] == x:
x_index = i
break
# 如果 x 不在数组中,返回 False
if x_index == -1:
return False
# 检查 y 是否与 x 相邻
if x_index > 0 and a[x_index - 1] == y:
return True
if x_index < n - 1 and a[x_index + 1] == y:
return True
# 如果没有找到相邻的 y,返回 False
return False
7. 小 C 的类二进制拼图
问题描述
小C发现了一种特殊的数字,称为类二进制数字,即仅由数字0和1组成的十进制数。例如,101和1100都是类二进制数字,而112和3001则不是。现在,小C手上有一个正整数n,他想知道最少需要多少个类二进制数字相加才能得到n。
解题思路
需要最少得类二进制数字的个数取决于正整数
n数值最大的那一位。因此,我们遍历字符串,找到数值最大的那位数字就是答案。或者我们可以使用分解方法:为了使类二进制数字相加得到n,可以考虑把n按照每个位上的1分解。例如,假设n = 231,其分解过程为:231 = 111 + 110 + 10。每一步都使用了最大的类二进制数以减少相加次数。贪心策略:对n的每一位,尽量找到该位数上的最大类二进制数,这样就可以用较少的类二进制数分解n。
代码实现
def solution(n: str) -> int:
max_digit = 0 # 用于记录最高位的数字
# 遍历数字的每一位
for digit in n:
digit = int(digit) # 将字符转换为整数
# 更新最高位的数字
if digit > max_digit:
max_digit = digit
return max_digit
def solution(n: str) -> int:
count = 0
n = int(n)
while n > 0:
max_binary_like = int(''.join(['1' if digit != '0' else '0' for digit in str(n)]))
n -= max_binary_like
count += 1
return count
8. 小 M 的奶酪问题
问题描述
小M在集市上买了一公斤奶酪回家。然而,在小M不在的时候,小F偷偷地偷走了 公斤的奶酪。现在,小M想知道他还剩下多少奶酪。要求答案以分数的形式表示,并且分数的分母必须为 。
解题思路
我们直接使用
B - A来计算剩余的奶酪量的分子,因为原本有1公斤奶酪,偷走了A/B公斤,剩下的奶酪量就是1 - A/B,可以简化为(B - A) / B。
代码实现
def solution(A: int, B: int) -> str:
# 计算剩余的奶酪量
remaining_cheese = B - A
# 将剩余的奶酪量表示为分数形式,分母为 B
return f"{remaining_cheese}/{B}"
9. 小 T 的密码变换规则
问题描述
小T设计了一套密码变换规则,将输入的字符串转换成一串数字密码。变换规则如下:
-
小写字母的映射:
a, b, c->2d, e, f->3g, h, i->4j, k, l->5m, n, o->6p, q, r, s->7t, u, v->8w, x, y, z->9
-
大写字母的处理:
- 大写字母先转为小写字母,再跳到字母表中的前一个字母,并按上述规则转换为对应的数字。
- 例如,
B转换为a,再转换为2;A特殊处理,先变为Z,再转换为9。
-
非字母字符的处理:
- 非字母字符保持不变。
解题思路
首先,我们创建一个字典来存储小写字母到数字的映射关系。对于大写字母,我们需要先将其转换为小写字母,然后跳到字母表中的前一个字母,再进行映射。非字母字符保持不变。最后,我们遍历输入字符串的每个字符,根据其类型进行相应的转换。
代码实现
def solution(s: str) -> str:
# 创建字母到数字的映射字典
letter_to_digit = {
'a': '2', 'b': '2', 'c': '2',
'd': '3', 'e': '3', 'f': '3',
'g': '4', 'h': '4', 'i': '4',
'j': '5', 'k': '5', 'l': '5',
'm': '6', 'n': '6', 'o': '6',
'p': '7', 'q': '7', 'r': '7', 's': '7',
't': '8', 'u': '8', 'v': '8',
'w': '9', 'x': '9', 'y': '9', 'z': '9'
}
# 初始化结果字符串
result = []
# 遍历输入字符串的每个字符
for char in s:
if char.islower():
# 如果是小写字母,直接映射
result.append(letter_to_digit[char])
elif char.isupper():
# 如果是大写字母,先转换为小写字母,再跳到前一个字母
if char == 'A':
# 特殊处理 'A'
result.append(letter_to_digit['z'])
else:
# 其他大写字母
prev_char = chr(ord(char.lower()) - 1)
result.append(letter_to_digit[prev_char])
else:
# 非字母字符保持不变
result.append(char)
# 将结果列表转换为字符串并返回
return ''.join(result)
10. 数值操作的期望计算问题
问题描述
小R有两个正整数 a 和 b,她将随机选择其中一个数并将其乘以 2。这个操作会进行两次,操作后的两个数之和会有所变化。小R想知道,操作结束后,两个数之和的期望值是多少?
例如:如果 和 ,那么有 的概率两数之和为 , 的概率两数之和为 。因此,期望值为 。
解题思路
-
期望值计算:
-
每次操作有
1/2的概率选择a,1/2的概率选择b。 -
操作两次后,可能的结果有:
a被乘以2两次,结果为4a + b。a被乘以2一次,b被乘以2一次,结果为2a + 2b。b被乘以2一次,a被乘以2一次,结果为2a + 2b。b被乘以2两次,结果为a + 4b。
-
每种结果的概率都是
1/4。
-
-
期望值公式:
- 期望值
E可以表示为: - 简化后:
- 期望值
代码实现
def solution(a: int, b: int) -> str:
# 计算期望值
expected_value = (9 / 4) * (a + b)
# 将结果格式化为字符串,保留两位小数
result = f"{expected_value:.2f}"
return result
11. 数组重排最小化差值
问题描述
小C 和小U 有两个数组,分别是 a 和 b,它们的长度相同。小U 想通过重新排列数组 a 的元素,来最小化 a 和 b 之间的差异。具体来说,他们要最小化所有元素差值绝对值之和,即 sum(abs(a[i] - b[i]))。 你能帮助小C 和小U 找到这个最小化的值吗?
解题思路
首先,我们可以对数组
a和b进行排序。然后,我们可以将排序后的a和b进行匹配,使得每个a[i]尽量接近b[i]。最后,计算所有元素差值的绝对值之和。留个小问题,如何严谨的证明这种排列差异最小。
代码实现
def solution(a: list, b: list) -> int:
# 1. 对数组 a 和 b 进行排序
a.sort()
b.sort()
# 2. 初始化差异总和
total_diff = 0
# 3. 计算每个元素的差异
for i in range(len(a)):
total_diff += abs(a[i] - b[i])
# 4. 返回差异总和
return total_diff
12. 选择题反选效果分析
问题描述
小U正在检查某同学的选择题答案。试卷共有 n 道题目,每道题目只有两个选项 A 和 B。当前小U手上有两组答案:
s:该同学的原始答案。t:标准答案。
小U想知道,如果将该同学的所有答案都反选(即:如果某题的答案是 A 则改成 B,如果是 B 则改成 A),那么在反选之后,正确的答案数量是否会增加?具体结果有三种可能:
- 如果反选后的正确答案数 增加,输出 "yes"。
- 如果反选后的正确答案数 不变,输出 "draw"。
- 如果反选后的正确答案数 减少,输出 "no"。
解题思路
首先,我们遍历
s和t,计算原始答案s中有多少题是正确的。然后,我们遍历s和t,计算反选后的答案s'中有多少题是正确的。最后,我们比较这两个正确答案的数量,输出相应的结果。
代码实现
def solution(n: int, s: str, t: str) -> str:
# 计算原始答案 s 中有多少题是正确的
original_correct = 0
for i in range(n):
if s[i] == t[i]:
original_correct += 1
# 计算反选后的答案 s' 中有多少题是正确的
flipped_correct = 0
for i in range(n):
if s[i] != t[i]:
flipped_correct += 1
# 比较原始正确答案数和反选后的正确答案数
if flipped_correct > original_correct:
return "yes"
elif flipped_correct == original_correct:
return "draw"
else:
return "no"
13. 二进制反码转换问题
问题描述
小C在学习二进制运算,他了解到每个非负整数都有其二进制表示。例如,整数 5 可以被表示为二进制 "101",整数 11 可以被表示为二进制 "1011",并且除了 N = 0 外,任何二进制表示中都不含前导零。
二进制的反码表示是将每个 1 变为 0,每个 0 变为 1。例如,二进制数 "101" 的二进制反码为 "010"。现在小C想知道,给定一个十进制数 N,它的二进制反码对应的十进制数是多少。
解题思路
首先,我们使用
bin()函数将十进制数转换为二进制字符串,并去掉前缀'0b'。然后,我们遍历二进制字符串,将每个字符进行反码操作。最后,我们使用int()函数将二进制字符串转换回十进制数。
代码实现
def solution(N: int) -> int:
# 将十进制数转换为二进制字符串,并去掉前缀 '0b'
binary_str = bin(N)[2:]
# 对二进制字符串进行反码操作
inverted_binary_str = ''.join('1' if bit == '0' else '0' for bit in binary_str)
# 将反码后的二进制字符串转换回十进制数
result = int(inverted_binary_str, 2)
return result
14. 充电总时间计算
问题描述
小R有n部电脑,每部电脑的电池容量分别为。她可以使用两种不同的充电方式来给电脑充电:
- 普通充电:每单位时间为电脑充电单位的电量。
- 闪充:每单位时间为电脑充电单位的电量。
现在,所有电脑的电量都为零。小R希望使用闪充给所有电脑充满电,计算她需要的总充电时间。请保留结果的小数点后两位。
解题思路
首先,我们计算每部电脑充满电所需的时间。使用闪充时,每单位时间充电
4x单位。因此,每部电脑充满电所需的时间为 。然后,我们将所有电脑充满电所需的时间求和,得到总时间。最后,我们格式化输出,将总时间保留两位小数,并转换为字符串格式。
代码实现
def solution(n: int, x: int, a: list) -> str:
# 初始化总时间为0
total_time = 0.0
# 遍历每部电脑的电池容量
for battery in a:
# 计算每部电脑充满电所需的时间,并累加到总时间
total_time += battery / (4 * x)
# 将总时间保留两位小数,并转换为字符串格式
result = f"{total_time:.2f}"
return result
15. 判断回旋镖的存在
问题描述
小M正在玩一个几何游戏,给定一个二维平面上的三个点 points,其中每个点用坐标 points[i] = [xi, yi] 表示。如果三点构成一个回旋镖,则返回 true。回旋镖的定义是三点不在一条直线上,并且这三个点互不相同。
请你帮助小M判断这些点是否构成一个回旋镖。
解题思路
首先,我们通过比较每个点的坐标来判断是否相同。然后,我们通过计算斜率来判断点是否共线。如果三个点的斜率相同,则它们在一条直线上。
代码实现
def solution(points: list) -> bool:
# 检查点是否相同
if points[0] == points[1] or points[1] == points[2] or points[0] == points[2]:
return False
# return not (((points[1][1] - points[0][1]) * (points[2][0] - points[1][0])) == ((points[2][1] - points[1][1]) * (points[1][0] - points[0][0])))
# 计算斜率
# 计算点1和点2的斜率
slope1 = (points[1][1] - points[0][1]) / (points[1][0] - points[0][0]) if points[1][0] != points[0][0] else float('inf')
# 计算点2和点3的斜率
slope2 = (points[2][1] - points[1][1]) / (points[2][0] - points[1][0]) if points[2][0] != points[1][0] else float('inf')
# 如果斜率相同,则三点共线
if slope1 == slope2:
return False
return True
16. 判断数组是否单调
问题描述
小S最近在研究一些数组的性质,她发现有一种非常有趣的数组被称为 单调数组。如果一个数组是单调递增或单调递减的,那么它就是单调的。
- 当对于所有索引
i <= j时,nums[i] <= nums[j],数组nums是单调递增的。 - 当对于所有索引
i <= j时,nums[i] >= nums[j],数组nums是单调递减的。
你需要编写一个程序来判断给定的数组nums是否为单调数组。如果是,返回true,否则返回false。
解题思路
首先,我们定义两个布尔变量来分别表示数组是否是单调递增或单调递减。然后,我们遍历数组中的每一对相邻元素,检查它们的关系。如果某对元素破坏了递增或递减性质,那么,我们就根据相邻元素的关系更新布尔变量。最后,我们返回结果,如果两个布尔变量中有一个为
True,则数组是单调的。
代码实现
def solution(nums: list) -> bool:
# 初始化标志
is_increasing = True
is_decreasing = True
# 遍历数组
for i in range(len(nums) - 1):
# 检查相邻元素的关系
if nums[i] > nums[i + 1]:
is_increasing = False
if nums[i] < nums[i + 1]:
is_decreasing = False
# 返回结果
return is_increasing or is_decreasing
今天的AI刷题题目解析就到这里,小伙伴们如果有更好的解题思路,欢迎在评论区留言一起交流。