LeetCode 第232场周赛 2021年3月14日

LeetCode 第232场周赛 2021年3月14日

  大家好,我叫亓官劼(qí guān jié ),在CSDN中记录学习的点滴历程,时光荏苒,未来可期,加油~博主目前仅在CSDN中写博客,唯一博客更新的地址为:亓官劼的博客 ,同时正在尝试在B站中做一些内容分享,B站主页为: 亓官劼的B站主页


由于学习工作的需要,算法刷题将会逐渐由C++向Python3过度,正在过度中,如实现的不太优美,请见谅。

本文原创为亓官劼,请大家支持原创,部分平台一直在恶意盗取博主的文章!!!
若需联系博主,可以联系本人微信:qiguanjie2015


5701. 仅执行一次字符串交换能否使两个字符串相等

题目

给你长度相等的两个字符串 s1s2 。一次 字符串交换 操作的步骤如下:选出某个字符串中的两个下标(不必不同),并交换这两个下标所对应的字符。

如果对 其中一个字符串 执行 最多一次字符串交换 就可以使两个字符串相等,返回 true ;否则,返回 false

示例 1:

输入:s1 = "bank", s2 = "kanb"
输出:true
解释:例如,交换 s2 中的第一个和最后一个字符可以得到 "bank"

示例 2:

输入:s1 = "attack", s2 = "defend"
输出:false
解释:一次字符串交换无法使两个字符串相等

示例 3:

输入:s1 = "kelb", s2 = "kelb"
输出:true
解释:两个字符串已经相等,所以不需要进行字符串交换

示例 4:

输入:s1 = "abcd", s2 = "dcba"
输出:false

提示:

  • 1 <= s1.length, s2.length <= 100
  • s1.length == s2.length
  • s1s2 仅由小写英文字母组成

解题思路

模拟交换S1中的各个元素,如果交换后的S1和S2相同,则return true 否则换回,继续下一次模拟,如果全部模拟完后还没返回,则false

算法实现一 C++

class Solution {
public:
    bool areAlmostEqual(string s1, string s2) {
        int len1 = s1.length(), len2 = s2.length();
        if(len1 != len2)
            return false;
        for(int i = 0 ; i < len1; i++){
            for(int j = i; j < len1; j++){
                swap(s1[i],s1[j]);
                if(s1 == s2)
                    return true;
                swap(s1[i],s1[j]);
            }
        }
        return false;
    }
};

算法实现二 Python

正在转python中,目前实现方法可能不是太好,在改进中

class Solution:
    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        if len(s1) != len(s2):
            return False
        s1 = list(s1)
        s2 = list(s2)
        i = 0
        while i < len(s1):
            j = i
            while j < len(s1):
                s1[i],s1[j] = s1[j], s1[i]
                if s1 == s2:
                    return True
                s1[i],s1[j] = s1[j], s1[i]
                j += 1
            i += 1
        return False

算法实现三 python

class Solution:
    def areAlmostEqual(self, s1: str, s2: str) -> bool:
        # 存S1和S2不同的字符
        res = []
        if len(s1) != len(s2):
            return False
        for i in range(len(s1)):
            if s1[i] != s2[i]:
                res.append([s1[i],s2[i]])
        # 如果res中为空,即全部相同,则可以
        if len(res) == 0:
            return True
        # res中的个数不为2时,一定不可以通过一次交换后相同
        if len(res) != 2:
            return False
        # 交换后相同
        if res[0][1] == res[1][0] and res[0][0] == res[1][1]:
            return True
        return False

5702. 找出星型图的中心节点

有一个无向的 星型 图,由 n 个编号从 1n 的节点组成。星型图有一个 中心 节点,并且恰有 n - 1 条边将中心节点与其他每个节点连接起来。

给你一个二维整数数组 edges ,其中 edges[i] = [ui, vi] 表示在节点 uivi 之间存在一条边。请你找出并返回 edges 所表示星型图的中心节点。

示例 1:

img

输入:edges = [[1,2],[2,3],[4,2]]
输出:2
解释:如上图所示,节点 2 与其他每个节点都相连,所以节点 2 是中心节点。

示例 2:

输入:edges = [[1,2],[5,1],[1,3],[1,4]]
输出:1

提示:

  • 3 <= n <= 105
  • edges.length == n - 1
  • edges[i].length == 2
  • 1 <= ui, vi <= n
  • ui != vi
  • 题目数据给出的 edges 表示一个有效的星型图

解题思路

这里给的是无向图,保证存在中心节点。那我们只需要找到在所有边集中,出现len次的点即可。

算法实现一 python

class Solution:
    def findCenter(self, edges: List[List[int]]) -> int:
        len1 = len(edges)
        mp = {}
        for edge in edges:
            for item in edge:
                if item not in mp.keys():
                    mp[item] = 1
                else:
                    mp[item] += 1
                if mp[item] == len1:
                    return item
        return 0

算法实现二 C++

class Solution {
public:
    int findCenter(vector<vector<int>>& edges) {
        unordered_map<int,int> hash;
        for(int i = 0; i < edges.size(); i++){
            for(int j = 0 ; j < edges[i].size(); j++){
                hash[edges[i][j]]++;
                if (hash[edges[i][j]] == edges.size())
                    return edges[i][j];
            }
        }
        return 0;
    }
};

5703. 最大平均通过率

一所学校里有一些班级,每个班级里有一些学生,现在每个班都会进行一场期末考试。给你一个二维数组 classes ,其中 classes[i] = [passi, totali] ,表示你提前知道了第 i 个班级总共有 totali 个学生,其中只有 passi 个学生可以通过考试。

给你一个整数 extraStudents ,表示额外有 extraStudents 个聪明的学生,他们 一定 能通过任何班级的期末考。你需要给这 extraStudents 个学生每人都安排一个班级,使得 所有 班级的 平均 通过率 最大

一个班级的 通过率 等于这个班级通过考试的学生人数除以这个班级的总人数。平均通过率 是所有班级的通过率之和除以班级数目。

请你返回在安排这 extraStudents 个学生去对应班级后的 最大 平均通过率。与标准答案误差范围在 10-5 以内的结果都会视为正确结果。

示例 1:

输入:classes = [[1,2],[3,5],[2,2]], extraStudents = 2
输出:0.78333
解释:你可以将额外的两个学生都安排到第一个班级,平均通过率为 (3/4 + 3/5 + 2/2) / 3 = 0.78333 。

示例 2:

输入:classes = [[2,4],[3,9],[4,5],[2,10]], extraStudents = 4
输出:0.53485

提示:

  • 1 <= classes.length <= 105
  • classes[i].length == 2
  • 1 <= passi <= totali <= 105
  • 1 <= extraStudents <= 105

解题思路

多路归并问题,采用贪心方法。这里每个班级为一个待归并集合,采用优先队列存储节点 ,按每次增加一个人,班级所增加的通过率的大小进行排序。每次取优先队列的队头,即加一个人,所增加的增长率最大的。然后更新优先队列。

对于每个班级来说,总人数total,通过人数pass,则增加一个人所增加的通过率为:(pass+1)/(total+1) - pass/total化简后即:(total - pass) / (total * (total+1))

算法实现 C++

class Solution {
public:
    double maxAverageRatio(vector<vector<int>>& classes, int extraStudents) {
        struct Node {
            double v; // 增加一个人,增加的通过率
            int total,pass; // 通过人数,总数 
            bool operator< (const Node& t) const {
                return v < t.v;
            }
        };
        priority_queue<Node> heap;
        double sum = 0;
        for (auto& c: classes) {
            int total = c[1], pass = c[0];
            sum += (double) pass / total;
            heap.push({(total - pass) / (total * (total + 1.0)), total, pass});
        }
        // 贪心,每次取优先队列的队头,即加一个人,所增加的增长率最大的。然后更新优先队列
        while (extraStudents -- ) {
            auto t = heap.top();
            heap.pop();
            sum += t.v;
            int total = t.total + 1, pass = t.pass + 1;
            heap.push({(total - pass) / (total * (total + 1.0)), total, pass});
        }
        return sum / classes.size();
    }
};

算法实现 Python(超时了)

在python中没找到大根堆的容器,使用sort和max都超时了

from heapq import *
class Solution:
    def maxAverageRatio(self, classes: List[List[int]], extraStudents: int) -> float:
        heap = []
        res = 0
        
        for item in classes:
            # 增加一个人所增加的通过率:(total - pass) / (total * (total+1))
            heap.append([item[0],item[1],(item[1]-item[0])/(item[1]*(item[1]+1))])
            res = res + item[0]/item[1]
        heap.sort(key = lambda item:item[2],reverse=True)
        while extraStudents:
            res = res + heap[0][2]
            heap.append([heap[0][0]+1,heap[0][1]+1,(heap[0][1]-heap[0][0])/((heap[0][1]+1)*(heap[0][1]+2))])
            heap.remove(heap[0])
            heap.sort(key = lambda item:item[2],reverse=True)
            extraStudents -= 1
        return res / len(classes)

5704. 好子数组的最大分数

给你一个整数数组 nums **(下标从 0 开始)**和一个整数 k

一个子数组 (i, j)分数 定义为 min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1) 。一个 子数组的两个端点下标需要满足 i <= k <= j

请你返回 子数组的最大可能 分数

示例 1:

输入:nums = [1,4,3,7,4,5], k = 3
输出:15
解释:最优子数组的左右端点下标是 (1, 5) ,分数为 min(4,3,7,4,5) * (5-1+1) = 3 * 5 = 15 。

示例 2:

输入:nums = [5,5,4,5,4,1,1,1], k = 0
输出:20
解释:最优子数组的左右端点下标是 (0, 4) ,分数为 min(5,5,4,5,4) * (4-0+1) = 4 * 5 = 20 。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i] <= 2 * 104
  • 0 <= k < nums.length

算法实现

这题暴力超时了,这里附一份Y总的代码,供大家参考。

class Solution {
public:
    int maximumScore(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> h(n + 2, -1), l(n + 2), r(n + 2), stk(n + 2);
        for (int i = 1; i <= n; i ++ ) h[i] = nums[i - 1];
        int tt = 0;
        stk[0] = 0;
        for (int i = 1; i <= n; i ++ ) {
            while (h[stk[tt]] >= h[i]) tt -- ;
            l[i] = stk[tt];
            stk[ ++ tt] = i;
        }
        tt = 0, stk[0] = n + 1;
        for (int i = n; i; i -- ) {
            while (h[stk[tt]] >= h[i]) tt -- ;
            r[i] = stk[tt];
            stk[ ++ tt] = i;
        }
        k ++ ;
        int res = 0;
        for (int i = 1; i <= n; i ++ )
            if (l[i] < k && r[i] > k)
                res = max(res, (r[i] - l[i] - 1) * h[i]);
        return res;
    }
};
  • 49
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

亓官劼

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

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

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

打赏作者

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

抵扣说明:

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

余额充值