CSDN编程题-每日一练(2023-08-25)
- 一、题目名称:影分身
- 二、题目名称:小鱼的航程(改进版)
- 三、题目名称:排查网络故障
一、题目名称:影分身
时间限制:1000ms内存限制:256M
题目描述:
已知字符串str。字符串str包含字符’x’,’y’。 如果相邻的两个字符不同,消除两个字符,优先从左边进行消除。 xyyx - > yx ->
输入描述:
输入多个字符。(1<=len<=1e5)
输出描述:
输出最后的分身
🚩 示例:
✔️ 示例1:
输入
xyyyy
输出
yyy
🔔 解题思路:
根据题目描述,我们需要对输入的字符串进行处理,消除相邻的不同字符。优先从左边开始消除。可以使用栈(Stack)数据结构来实现。
代码1如下:
s = input().strip() # 输入字符串
##函数 calc 接受一个字符串参数 s,返回一个字符串作为最后的分身
def calc(s: str) -> str:
stack = [] # 初始化一个空栈 stack,用于存储字符
for ch in s: # 遍历输入的字符串s,依次处理每个字符
if not stack or ch == stack[-1]: # 栈为空(not stack)或者当前字符 ch 与栈顶字符相同 (ch == stack[-1])
##将当前字符 ch 入栈 (stack.append(ch))
stack.append(ch)
else:
## 如果栈不为空,并且当前字符 ch 与栈顶字符不同,说明找到了一对相邻不同的字符,将栈顶字符出栈 (stack.pop())
stack.pop()
##遍历完整个字符串后,栈中剩余的字符即为最后的分身
##使用 join 函数将栈中的字符按照出栈顺序组合起来,返回结果
return ''.join(stack)
result = calc(s) # 消除相邻的不同字符
print(result) # 输出最后的分身
代码2如下:
#include <iostream>
#include <stack>
#include <string>
##定义一个名为 calc的函数,接受一个常量引用字符串作为参数,并返回一个字符串。
std::string calc(const std::string& s) {
std::stack<char> stack; #声明一个字符栈 stack,用于模拟栈结构
#使用 for 循环遍历输入字符串 s,依次处理每个字符
for (char ch : s) {
##对于每个字符 ch 进行判断:
##1、如果栈为空(stack.empty())或者当前字符 ch 与栈顶字符相同(ch == stack.top()),将当前字符 ch 入栈(stack.push(ch))。
##2、如果栈不为空,并且当前字符 ch 与栈顶字符不同,说明找到了一对相邻不同的字符,将栈顶元素出栈(stack.pop())
if (stack.empty() || ch == stack.top()) {
stack.push(ch);
} else {
stack.pop();
}
}
##使用 for 循环遍历输入字符串 s 中的每个字符 ch。对于每个字符,如果栈为空或者当前字符与栈顶字符相同,将当前字符入栈;否则,说明找到了一对相邻不同的字符,将栈顶元素出栈
std::string result; #创建一个空字符串 result,用于保存最后的分身
while (!stack.empty()) { ##使用 while 循环将栈中的字符依次出栈,并将出栈的字符加到 result 的前面
result = stack.top() + result;
stack.pop();
}
##最后返回保存最后的分身的字符串 result
return result;
}
int main() {
##声明一个字符串 s,用于存储输入的字符串
std::string s;
##使用 std::getline 函数从标准输入中获取一行字符串
std::getline(std::cin, s);
##调用 calc函数处理输入字符串,得到最后的分身,将其赋给字符串变量 result
std::string result = calc(s);
##使用 std::cout 将结果输出到标准输出流,并在末尾添加换行符
std::cout << result << std::endl;
##程序正常结束
return 0;
}
二、题目名称:小鱼的航程(改进版)
时间限制:1000ms内存限制:256M
题目描述:
有一只小鱼,它上午游泳150公里,下午游泳100公里,晚上和周末都休息(实行双休日),假设从周x(1<=x<=7)开始算起,请问这样过了n天以后,小鱼一共累计游泳了多少公里呢?
输入描述:
输入两个整数x,n(表示从周x算起,经过n天,n在long int范围内)。
输出描述:
输出一个整数,表示小鱼累计游泳了多少公里。
🚩示例:
✔️示例1
输入
3 10
输出
2000
🔔 解题思路:
根据输入的起始天数x和总天数n,计算一定天数内(包括起始天数)游泳的总公里数。
代码1如下:
# 读取输入,起始天数x和经过的天数n
x, n = map(int, input().split())
def solution(x, n):
#计算出从起始天数开始经过n天后的总天数total_days :total_days = n + x - 1
total_days = n + x - 1
#计算完整周期(一周)的游泳公里数total_km
total_km = total_days // 7 * 250 * 5
##计算额外的天数excess_days ,即不足一周的天数
excess_days = total_days % 7
##循环遍历range(excess_days)来判断每一天是否是工作日(小于5),如果是则将游泳公里数增加250米
for i in range(excess_days):
if i < 5:
total_km += 250
##循环遍历从周一到前一天(range(1, x))的天数,在工作日(小于6)中减去250米的游泳公里数
for i in range(1, x):
if i < 6:
total_km -= 250
###计算得到的游泳公里数total_km作为函数的返回值
return total_km
###调用solution(x, n)
total_km=solution(x, n)
print(total_km)
代码2如下:
#include <stdio.h>
#include <stdlib.h>
#define MAX_SIZE 100
## 注意:n在long int范围内
long int solution(long int x, long int n) {
long int total_days = n + x - 1;
long int total_km = total_days / 7 * 250 * 5;
long int excess_days = total_days % 7;
for (long int i = 0; i < excess_days; i++) {
if (i < 5) {
total_km += 250;
}
}
for (long int i = 1; i < x; i++) {
if (i < 6) {
total_km -= 250;
}
}
return total_km;
}
int main() {
long int x, n;
scanf("%ld %ld", &x, &n);
long int total_km = solution(x, n);
printf("%ld\n", total_km);
return 0;
}
三、题目名称:排查网络故障
时间限制:1000ms内存限制:256M
题目描述:
A地跟B地的网络中间有n个节点(不包括A地和B地),相邻的两个节点是通过网线连接。正常的情况下,A地和B地是可以连通的,有一天,A地和B地突然不连通了,已知只有一段网线出问题(两个相邻的节点)小明需要排查哪段网线出问题。他的排查步骤是: 1。 选择某个中间节点 2。 在这个节点上判断跟A地B地是否连通,用来判断那一边出问题 请问小明最少要排查多少次,才能保证一定可以找到故障网线。
输入描述:
一个正整数 n (n <= 10^18),表示A地和B地之间的节点数。
输出描述:
输出一个数字,代表保证一定可以找到故障网线的前提下,小明最少要排查多少次?
🚩示例:
✔️示例1
输入
2
输出
2
🔔 解题思路:
假设节点数为n,我们可以将整个网络划分为两半,即左边的节点和右边的节点。如果某个节点被选为判断节点,那么它所在的位置就决定了是哪一半出了问题。
对于一个给定的节点数n,首先找到最接近n的2的幂次方m,使得m <= n。然后,排查的次数就是最接近n的2的幂次方的对数log2(m)。
首先观察题目中的连接方式,可以发现节点数n与排查次数node_number之间存在一定的关系。
1、假设排查次数为x,那么排查的节点个数应为2^x - 1。
2、当排查的节点个数超过了n时,即2^x - 1 > n,说明排查次数为x-1时已经可以确定故障网线的位置。
3、根据以上思路,可以用循环不断将n除以2,直到n小于等于0为止,每次循环时check_number 加1。
4、最后输出check_number 即为所求的最少排查次数。
代码1如下:*
##A地和B地之间的节点数n
n = int(input())
##计数器check_number , 排查次数
check_number = 0
##当n大于0时,执行循环体
while n > 0:
##将n除以2,结果赋值给n,相当于将节点数减半,直到n小于等于0为止
n = n // 2
###每次循环时,将check_number 加1
check_number += 1
###输出check_number即为所求的最少排查次数
print(check_number)
代码2如下:*
🔔 解题思路:
首先,我们需要找到一个节点,通过判断这个节点是否与A地和B地连通,来确定故障网线是在节点的哪一边。
假设A地和B地之间有n个节点,我们可以将节点数n表示成二进制形式。例如,n=2时,二进制为10,表示有两个节点。
我们观察一下,当节点数为2的幂次方时,排查次数最少。例如,n=2时,只有节点2需要排查;n=4时,只有节点4需要排查;n=8时,只有节点8需要排查,以此类推。
因此,我们可以先找到节点数n的二进制表示中最高位的1的位置,记为highest_bit_pos。然后,我们构造一个掩码mask,将最高位1右边的所有位都置为1。再将节点数n与掩码mask进行或运算,得到masked_n。
最后,我们统计masked_n中1的个数,即为小明最少要排查的次数。
n = int(input())
# 1、找到最高位1的位置,即二进制字符串的长度减去3,
### 如: bin(2)的结果是字符串'0b10'。长度为4,这表示二进制数2的二进制表示形式为10。前缀0b表示这是一个二进制数,最高位为1
highest_bit_pos = len(bin(n)) - 3
# 2、将最高位1右边的所有位都置为1
##使用左移运算符<<将1左移highest_bit_pos个位数,然后减去1,生成一个二进制数,其中最高位1的右边都是1,其余位为0。这个二进制数被赋值给变量mask
mask = (1 << highest_bit_pos) - 1
##3、按位或运算符|将n与mask进行按位或操作
###将masked_n的最高位1右边的所有位都置为1,而其余位与n保持相同
masked_n = n | mask
# 4、计算1的个数
##将masked_n转换为二进制字符串,然后使用count()函数计算其中字符'1'的个数
count = bin(masked_n).count('1')
#5、输出count,即masked_n中1的个数
print(count)
🔔 示例输入解释:
例如,当输入为2时,输出为2。解释:
1、节点数n为2,二进制表示为10。
2、找到最高位1的位置为1,即highest_bit_pos=1。
3、构造掩码mask,将最高位1右边的所有位都置为1,即mask=1。
4、将节点数n与掩码mask进行或运算,得到masked_n=3。
5、统计masked_n中1的个数,即为小明最少要排查的次数,即count=2。