LeetCode百题刷003(449周赛一二题)

遇到的问题都有解决的方案,希望我的博客可以为你提供一些帮助

一、不同字符数量最多为 K 时的最少删除数 (哈希表空间换时间)

不同字符数量最多为 K 时的最少删除数 - 力扣 (LeetCode) 竞赛https://leetcode.cn/contest/weekly-contest-449/problems/minimum-deletions-for-at-most-k-distinct-characters/

思路分析:

  • 题干要求是删除最少的元素以保证剩下的字符串中最多有k种不同的元素(每种元素可以有重复的)并返回删除的元素的个数

问题分解:

  • 问题一:如何去确定要删除哪些元素?
  • 问题二:如何去确定重复种类元素的个数呢?
  • 问题三:如何保证最多有k种元素呢?

针对问题一,我们需要保证删除最少的元素,如果需要删除某些种类元素,首先被删除的元素种类一定是出现次数最少的而不是较多的。那么,我们需要先知道每一种元素出现的次数;其次,如果需要删除某些种类的元素需要逐次删除出现次数最小的。

针对问题二,可以看成一个经典的问题:如何在一个无序序列中统计每一个元素的频率。即构建如下的映射结构 元素:出现次数,可以采用哈希表来解决。

针对问题三,将问题二中的哈希表的大小与k进行比较即可。

问题解决:

数据结构:哈希表

算法设计:

  • 利用哈希表统计每个元素的出现次数
  • 按出现次数升序排序
  • 比较k与哈希表的大小l 
  • 如果l<=k 直接返回 0
  • 如果l>k   不断移除排序后序列的队首(实际上是不断累加首位元素出现的次数),直到l=k,返回累加结果

时间复杂度:O(nlogn)

空间复杂度: O(n)

编码实现(python):

class Solution:
    def minDeletion(self, s: str, k: int) -> int:
        #记录元素出现次数的哈希表
        char_count={}
        for char in s:
            char_count[char]=char_count.get(char,0)+1
        #排序
        sorted_c=sorted(char_count.items(),key=lambda item : item[1])
        if len(sorted_c)>k:
            return sum([x[1] for x in  sorted_c[:len(sorted_c)-k]])
        else:
            return 0
            
        

提交结果(python): 

 编码实现(c++):

class Solution {
public:
    int minDeletion(string s, int k) {
        //哈希表:记录每种元素出现次数
        unordered_map<char,int> char_count;
        for(auto c :s)
        {
            char_count[c]++;
        }
        
        // 将哈希表元素存入 vector
        vector<pair<char,int>> sorted_c(char_count.begin(),char_count.end());
        
        // 按值升序排序
        sort(sorted_c.begin(),sorted_c.end(),
            [](const auto &a,const auto &b)
             {return a.second<b.second;}
            );
        //计算结果
        if (sorted_c.size()>k){
            return accumulate(sorted_c.begin(),sorted_c.end()-k,0,
                             [](int count,const auto &b)
                              {return count+b.second;} 
                             );
        }else{
            return 0;
        }
    }
};

提交结果(c++): 

二、等和矩阵分割 I

等和矩阵分割 I - 力扣 (LeetCode) 竞赛https://leetcode.cn/contest/weekly-contest-449/problems/equal-sum-grid-partition-i/

思路分析(这是我当时先想到的一个思路):

题干要求是进行一次水平或者垂直划分,使划分后的二维数组的两部分(非空)的和相等。如果相等返回True,否则返回False

问题分解:

  • 问题一:水平或者垂直划分如何实现?
  • 问题二:如何对划分后的部分进行比较?
  • 问题三:如何判断最终的返回结果?

针对问题一:二维数组有行和列,将每一行看成一个整体,对行操作就是实现水平划分;同理对列操作就是垂直划分

针对问题二和三: 题干要求划分后两部分需要相等,直接比较两部分会比较困难因为我们不知道需要在哪一行或者那一列进行划分,如果枚举出所有可能再筛选时间耗费巨大,这时候不妨思考反面,我可不可以先求出总和(遍历二维数组一次),再按行为单位或者列为单位去遍历二维数组并记录累加和,如果当前累加和等于总和的一半说明划分正确否则不正确。

问题解决:

数据结构:二维数组

算法设计:

  • 遍历数组计算总和
  • 按行为单位或者列为单位去遍历二维数组并记录累加和
  • 比较当前累加和与总和1/2的大小,如果等于则返回True否则返回False 

时间复杂度:O(n*m)

空间复杂度: O(n)

 编码实现(python):

class Solution:
    def canPartitionGrid(self, grid: List[List[int]]) -> bool:
        #计算二维数组总和
        sum_g=0
        for row in grid:
            sum_g+=sum(row)
        if sum_g%2!=0:
            return False
        #按行划分
        sum_r=0;
        for row in grid:
            sum_r+=sum(row)
            if sum_r== sum_g/2:
                return True
            if sum_r>sum_g/2:
                #剪枝
                break
        #按列划分
        sum_c=0
        list_c=[sum(row[i] for row in grid) for i in range(len(grid[0]))]
        for c in list_c:
            sum_c+=c
            if sum_c==sum_g/2:
                return True
            if sum_c>sum_g/2:
                break
        return False

提交结果(python): 

 编码实现(c++):

class Solution {
public:
    bool canPartitionGrid(vector<vector<int>>& grid) {
        //求总和
        long long  sum_g=0;
        for (auto row:grid)
        {
            sum_g+=accumulate(row.begin(),row.end(),0LL);
        }
        // cout<<sum_g<<endl;
        //剪枝
        if (sum_g%2!=0)
        {
            return false;
        }
        //行划分
        long long sum_r=0;
        for (auto row:grid)
        {
            sum_r+=accumulate(row.begin(),row.end(),0LL);
            cout<<sum_r<<endl;
            if(sum_r==sum_g/2)return true;
            if (sum_r>sum_g/2)break;
        }
        //列划分
        long long   sum_c=0;
        for(int i=0;i<grid[0].size();i++)
        {
            for(int j=0;j<grid.size();j++)
                sum_c+=grid[j][i];
            // cout<<sum_c<<endl;
            if (sum_c==sum_g/2)return true;
            if (sum_c>sum_g/2)break;
        }
        return false;
    }
};

提交结果(c++): 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

愚戏师

多谢道友

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

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

打赏作者

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

抵扣说明:

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

余额充值