【CSDN竞赛】42期题解(Python + Javascript)

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 解题思路

这是一道经典的最大子序列和问题,可以使用贪心算法来解决。具体思路如下:

  1. 定义两个变量result和max_result,分别表示当前的子序列和历史最大子序列。

  2. 遍历整个序列A,对于每个元素:

    a. 如果result加上当前元素大于0,则更新result为result加上当前元素;

    b. 否则,将result更新为0。

    c. 每次更新result后,将max_result更新为result和max_result中的最大值。

  3. 最后返回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 解题思路

这道题目可以采用双指针法来解决。具体思路如下:

  1. 首先将目标节点编号m减1,因为数组下标从0开始。

  2. 定义三个变量:result、left和right,分别表示最终结果、左指针和右指针。将left和right初始化为m。

  3. 定义一个变量dis,表示当前左右指针的距离。

  4. 在while循环中,如果左指针或右指针的权值满足条件,则跳出循环。否则,将dis加1,同时更新left和right。

  5. 如果left小于0,说明左边已经没有节点了,需要向右边搜索。在while循环中,如果右指针的权值满足条件,则跳出循环。否则,将dis加1,同时更新right。

  6. 如果right大于等于n,说明右边已经没有节点了,需要向左边搜索。在while循环中,如果左指针的权值满足条件,则跳出循环。否则,将dis加1,同时更新left。

  7. 返回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 解题思路

这是一道非常简单的栈的应用题。我们可以使用栈来模拟字符串的消除过程,具体思路如下:

  1. 定义一个栈st,遍历字符串str的每个字符。

  2. 如果栈st不为空,且当前字符和栈顶元素不同,则弹出栈顶元素,否则将当前字符压入栈中。

  3. 遍历完整个字符串后,将栈中的元素弹出并拼接成字符串,即为消除后的字符串。

  4. 返回消除后的字符串。

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 解题思路

这是一道背包问题,可以使用动态规划来解决。具体思路如下:

  1. 定义一个二维数组dp,其中dp[i][j]表示在前j个物品中,花费不超过i元钱所能得到的最大重要度。

  2. 对于每个物品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]

  3. 最后返回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背包问题,可以作为动态规划练习的好题目。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如果皮卡会coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值