CSDN周赛 42期 题解
前言
4.1的时候发现有些ACM模式下的题目用python真的咔咔乱杀。(相比C、C++)
虽然作为动态语言的JS也简单,但有些时候别人的编译器不认Javascript,却认python。所以打算适当用点Python解题。
这期前两题简单,不需要多高级的语法,就使用Python了。后面两题虽然也简单,但是JS两题不用,如隔三秋,便又用回JS了。
文章目录
一、鬼画符门之宗门大比
1.1 题目说明
题目描述:给定整数序列A,求在整数序列A中连续权值最大的子序列的权值。
输入格式:第一行输入整数n,表示序列A的长度。第二行输入n个整数,表示序列A中的元素。
输出格式:输出一个整数,表示整数序列A中连续权值最大的子序列的权值。
1.2 解题思路
这是一道经典的最大子序列和问题,可以使用贪心算法来解决。具体思路如下:
-
定义两个变量result和max_result,分别表示当前的子序列和历史最大子序列。
-
遍历整个序列A,对于每个元素:
a. 如果result加上当前元素大于0,则更新result为result加上当前元素;
b. 否则,将result更新为0。
c. 每次更新result后,将max_result更新为result和max_result中的最大值。
-
最后返回max_result即可。
1.3 实现代码
class Solution:
def __init__(self) -> None:
pass
def solution(self, n, arr):
result = 0
max_result = 0
for value in arr:
if (result + value) > 0:
result += value
max_result = max(result,max_result)
else:
result = 0
return max_result
if __name__ == "__main__":
n = int(input().strip())
arr = [int(item) for item in input().strip().split()]
sol = Solution()
result = sol.solution(n, arr)
print(result)
时间复杂度:O(n)
空间复杂度:O(1)
代码实现简单,容易理解,是一道不错的贪心练手题。
二、K皇把妹
2.1 题目说明
题目描述:存在n个节点,目标节点在m。每个节点有自己的权值a。在权值k内(含权值K)选择一个权值非0节点且与目标节点距离最近。节点i与节点j的距离为abs(i-j)。
输入格式:第一行输入3个整数n、m、k,分别表示节点个数、目标节点编号和权值范围。第二行输入n个整数,表示每个节点的权值。
输出格式:输出一个整数,表示在权值k内(含权值K)选择一个权值非0节点且与目标节点距离最近的节点到目标节点的距离。
2.2 解题思路
这道题目可以采用双指针法来解决。具体思路如下:
-
首先将目标节点编号m减1,因为数组下标从0开始。
-
定义三个变量:result、left和right,分别表示最终结果、左指针和右指针。将left和right初始化为m。
-
定义一个变量dis,表示当前左右指针的距离。
-
在while循环中,如果左指针或右指针的权值满足条件,则跳出循环。否则,将dis加1,同时更新left和right。
-
如果left小于0,说明左边已经没有节点了,需要向右边搜索。在while循环中,如果右指针的权值满足条件,则跳出循环。否则,将dis加1,同时更新right。
-
如果right大于等于n,说明右边已经没有节点了,需要向左边搜索。在while循环中,如果左指针的权值满足条件,则跳出循环。否则,将dis加1,同时更新left。
-
返回dis即可。
2.3 实现代码
class Solution:
def __init__(self) -> None:
pass
def solution(self, n, m, k, arr):
m = m - 1
result = None
left = m
right = m
dis = 0
while left >= 0 and right < n:
if arr[left] > 0 and arr[left] <= k:
break;
if arr[right] > 0 and arr[right] <= k:
break;
dis += 1
left = m - dis
right = m + dis
if left < 0 :
while(right < n):
if arr[right] > 0 and arr[right] <= k:
break;
dis += 1
right = m + dis
if right >= n:
while(left >=0):
if arr[left] > 0 and arr[left] <= k:
break;
dis += 1
left = m - dis
return dis
if __name__ == "__main__":
arr_temp = [int(item) for item in input().strip().split()]
n = int(arr_temp[0])
m = int(arr_temp[1])
k = int(arr_temp[2])
arr = [int(item) for item in input().strip().split()]
sol = Solution()
result = sol.solution(n, m, k, arr)
print(result)
时间复杂度:O(n)
空间复杂度:O(1)
代码实现较为简单,但需要注意边界情况的处理。这是一道比较典型的双指针问题,可以帮助我们加深对双指针的理解。
三、影分身
3.1 题目说明
题目描述:已知字符串str,字符串str包含字符’x’,‘y’。 如果相邻的两个字符不同,消除两个字符,优先从左边进行消除。例如:‘xyyx’ - > ‘yx’ -> ‘’。
输入格式:输入一个字符串str,长度不超过100000,只包含字符’x’和’y’。
输出格式:输出消除后的字符串。
3.2 解题思路
这是一道非常简单的栈的应用题。我们可以使用栈来模拟字符串的消除过程,具体思路如下:
-
定义一个栈st,遍历字符串str的每个字符。
-
如果栈st不为空,且当前字符和栈顶元素不同,则弹出栈顶元素,否则将当前字符压入栈中。
-
遍历完整个字符串后,将栈中的元素弹出并拼接成字符串,即为消除后的字符串。
-
返回消除后的字符串。
3.3 实现代码
class Solution {
solution(str) {
let result;
if(str.length <= 1) return str;
let st = [str[0]];
let n = str.length;
for(let i=1;i<n;i++){
if(st.length > 0 && str[i] != st[st.length - 1 ]){
st.pop();
}else{
st.push(str[i]);
}
}
result = st.join("");
return result;
}
}
var str_0 = readline().trim();
var str = str_0;
let sol = new Solution();
result = sol.solution(str);
print(result);
时间复杂度:O(n)
空间复杂度:O(n)
代码实现简单,容易理解,是一道不错的栈的练手题。
四、开心的金明
4.1 题目说明
题目描述:金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间他自己专用的很宽敞的房间。更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过 N 元钱就行”。今天一早金明就开始做预算,但是他想买的东西太多了,肯定会超过妈妈限定的 N 元。于是,他把每件物品规定了一个重要度,分为 5 等:用整数 1-5表示,第 5 等最重要。他还从因特网上查到了每件物品的价格(都是整数元)。他希望在不超过 N 元(可以等于 N 元)的前提下,使每件物品的价格与重要度的乘积的总和最大。设第 j 件物品的价格为 v[j],重要度为 w[j],共选中了 k 件物品,编号依次为 j1,j2,…,jk,则所求的总和为:v[j1]×w[j1]+v[j2]×w[j2]+ …+v[jk]×w[jk]。请你帮助金明设计一个满足要求的购物单。
输入格式:第一行输入两个整数N和m,分别表示金明的预算和希望购买物品的个数。接下来m行,每行输入两个整数v和w,分别表示一个物品的价格和重要度。
输出格式:输出一个整数,表示金明最多能够得到的总重要度。
4.2 解题思路
这是一道背包问题,可以使用动态规划来解决。具体思路如下:
-
定义一个二维数组
dp
,其中dp[i][j]
表示在前j
个物品中,花费不超过i
元钱所能得到的最大重要度。 -
对于每个物品
j
,遍历前i
个元素:-
如果当前花费
i
大于等于第j
个物品的价格,则可以将第j
个物品加入到前i
个物品中,此时
dp[i][j]
的值等于dp [剩余i钱 - j的钱] [剩余j-1物品]
加上第j
个物品的价值vector[j-1][0]
乘以重要度vector[j-1][1]
; -
或者不加入第
j
个物品,此时dp[i][j]
的值等于dp[i][j-1]
。
-
-
最后返回
dp[N][m]
即可。
4.3 实现代码
class Solution {
solution(N, m, vector) {
var dp = new Array(N+1).fill(0).map(()=>{
return new Array(m+1).fill(0);
});
for(let j=1;j<=m;j++){
for(let i=0;i<=N;i++){
dp[i][j] = dp[i][j-1];
if( i>= vector[j-1][0]){
dp[i][j] = Math.max(dp[i][j] , dp[i-vector[j-1][0]][j-1] + vector[j-1][1] * vector[j-1][0]);
}
}
}
return dp[N][m];
}
}
var str_0 = readline();
var line_list_0 = str_0.trim().split(" ");
var arr_temp = new Array();
for(var i = 0; i < line_list_0.length; i++){
arr_temp[i] = parseInt(line_list_0[i]);
}
var N = parseInt(arr_temp[0]);
var m = parseInt(arr_temp[1]);
var vector = new Array();
for(var i = 0; i < m; i++){
var str_2 = readline();
var line_list_2 = str_2.trim().split(" ");
var temp_2 = new Array();
for(var j = 0; j < line_list_2.length; j++){
temp_2[j] = parseInt(line_list_2[j]);
}
vector[i] = temp_2;
}
let sol = new Solution();
result = sol.solution(N, m, vector);
print(result);
时间复杂度:O(N*m)
空间复杂度:O(N*m)
代码实现较为简单,是一道典型的01背包问题,可以作为动态规划练习的好题目。