Leetcode 刷题 day02 华为面试题

方法一:模拟+贪心

思路与算法:

我们从字符串左边第一位开始依次遍历,如果是 1 则不用改变,如果是 0,我们则想办法将其变成 1。我们会找到下一位出现的 0,利用操作 2 我们可以使得这两个 0 相邻,再使用操作 1 使得 00 变成 10。我们依次执行这个操作,直到字符串中没有第二个 0,或者达到字符串结尾。

代码:

//模拟+贪心算法 (找到最好的解)
class Solution {
public:
    string maximumBinaryString(string binary) {
        int n = binary.size();
        int j = 0;
        for(int i=0;i<n;i++){
            if(binary[i]=='0'){
                while(j<=i || (j<n && binary[j]=='1')){
                    j++;
                }
                if(j<n){
                    binary[j]='1';
                    binary[i]='1';
                    binary[i+1]='0';
                }
            }
        }
    return binary;
    }
};

 方法二:直接构造

思路与算法:

我们注意到最终结果,至多有一个 0。如果输入字符串中没有 0,则直接返回结果。如果有 0,结果中 0 的位置取决于字符串第一个 0 的位置,之后每多一个 0 便可以向后移动一位。

所以我们只需要求出字符串中第一个 0 的下标,以及 0 的出现的个数,即可直接构造结果。(这就是鼎鼎大名的靠智商的观察法么)

class Solution {
public:
    string maximumBinaryString(string binary) {
        int n = binary.size(),i=binary.find('0');
        if(i==string::npos){
            return binary;
        }
        int zeros = count(binary.begin(),binary.end(),'0');
        string s(n,'1');
        s[i+zeros-1]='0';
        return s;
    }
};

 

方法一:维护每一行及每一列的优先队列

对于每个滑动窗口,可以使用O(k)的时间遍历其中的每一个元素来找出其中的最大值。对于长度为n的数组nums而言,窗口的数量为n-k+1,因此该算法的时间复杂度为O((n-k+1)k) = O(nk),会超出时间限制,因此我们需要进行一些优化。

我们可以想到,对于两个相邻(只差了一个位置)的滑动窗口,它们共用着 k−1 个元素,而只有 1 个元素是变化的。我们可以根据这个特点进行优化。

方法一:优先队列

思路与算法:

对于「最大值」,我们可以想到一种非常合适的数据结构,那就是优先队列(堆),其中的大根堆可以帮助我们实时维护一系列元素中的最大值。

对于本题而言,初始时,我们将数组 nums 的前 k 个元素放入优先队列中。每当我们向右移动窗口时,我们就可以把一个新的元素放入优先队列中,此时堆顶的元素就是堆中所有元素的最大值。然而这个最大值可能并不在滑动窗口中,在这种情况下,这个值在数组 nums 中的位置出现在滑动窗口左边界的左侧。因此,当我们后续继续向右移动窗口时,这个值就永远不可能出现在滑动窗口中了,我们可以将其永久地从优先队列中移除。

我们不断地移除堆顶的元素,直到其确实出现在滑动窗口中。此时,堆顶元素就是滑动窗口中的最大值。为了方便判断堆顶元素与滑动窗口的位置关系,我们可以在优先队列中存储二元组 (num,index),表示元素 num 在数组中的下标为 index。

//滑动窗口最大值
//方法一:优先队列
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        priority_queue<pair<int,int>> q;  //priority_queue是优先队列
        for(int i=0;i<k;i++){
            q.emplace(nums[i],i); //emplace直接在容器内部构造元素,更高效
        }
        vector<int> ans = {q.top().first};
        for(int i=k;i<n;++i){
            q.emplace(nums[i],i);
            while(q.top().second<=i-k){
                q.pop();
            }
            ans.push_back(q.top().first);
        }
        return ans;
    }
};

 我又找了个可以用优先队列解决的题目,以此来练习下

//扫描线+优先队列
class Solution {
public:
    vector<vector<int>> getSkyline(vector<vector<int>>& buildings) {
    //因为buildings=[[2,9,10],[3,7,15],[5,12,12],[15,20,10],[19,24,8]],所以是vector<vector<int>>的形式,最后输出结果是:[[2,10],[3,15],[7,12],[12,0],[15,10],[20,8],[24,0]],所以也是vector<vector<int>>的形式
        auto cmp = [](const pair<int,int>& a,const pair<int,int>& b)->bool {return a.second<b.second;};
        // 
        priority_queue<pair<int,int>,vector<pair<int,int>>,decltype(cmp)> que(cmp);
        //小根堆
        vector<int> boundaries;
        for(auto& building : buildings){
            boundaries.emplace_back(building[0]);
            boundaries.emplace_back(building[1]);
        }
        sort(boundaries.begin(),boundaries.end()); //把边界点按照从小到大的顺序进行排列
        
        vector<vector<int>> ret;
        int n=buildings.size(),idx=0;
        for(auto & boundary : boundaries){
            while(idx<n && buildings[idx][0]<=boundary){
                que.emplace(buildings[idx][1],buildings[idx][2]); //最顶部值最小
                idx++;
            }
            while(!que.empty() && que.top().first<=boundary){
                que.pop();
            }
            
            int maxn = que.empty()?0:que.top().second;
            if(ret.size()==0 || maxn!=ret.back()[1]){
                ret.push_back({boundary,maxn});
            }
        }
        return ret;
    }
};

嘶,真心感觉难难的,初次用C++来写算法题,现在看这个的代码都有些一言难尽0,还是先多刷点简单点的好了。下面这道题自己写就好多了。

class Solution {
public:
    vector<string> findRelativeRanks(vector<int>& score) {
        
        priority_queue<pair<int,int>,vector<pair<int,int>>> q;
        int n = score.size(); 
        string desc[3] = {"Gold Medal","Silver Medal","Bronze Medal"};

        for(int i=0;i<n;i++){
            q.emplace(score[i],i);
        }

        vector<string> ans(n);
        for(int i=0;i<n;i++){
            if(i>=3){
                ans[q.top().second]=to_string(i+1); 
            }
            else{
                ans[q.top().second]=desc[i];
            }
            q.pop();
        }
        return ans;
    }
};

接下来还是优先队列->我死磕一下好吧

我自己写的时候写超时了,后来看了题解中关于用优先队列解决的代码时,学到了几点:

第一个是对于vector<vector<int>> & intervals中的interval排序,根据开始时间排序会议,直接用:

sort(intervals.begin(),intervals.end());

sort()可以自动根据intervals的第一个元素进行排序(默认从小到大)。

方法一:优先队列

总体算法解题思路:

1、按其开始时间对给定的会议进行排序。
2、初始化一个新的 min-heap 并将第一个会议的结束时间添加到堆中。我们只需要跟踪结束时间,因为这告诉我们什么时候一个会议室会空闲。
3、对于每个会议室,检查堆的最小元素即堆顶的房间是否空闲。
        a.如果房间是空闲的,那么我们提取最顶部的元素并加入当前正在处理的会议的结束时间。
        b.如果不是,那么我们分配一个新的房间并将其添加到堆中。
4、处理完所有的会议后,堆的大小会告诉我们分配了多少个房间。这将是容纳所有会议所需的最小房间数。

//优先队列
class Solution{
public:
    int minMeetingRooms(vector<vector<int>>& intervals){
        if(intervals.size()==0){
            return 0;
        }
        priority_queue<int,vector<int>,greater<int>> allocator;
        //根据开始时间排序会议
        sort(intervals.begin(),intervals.end());
        allocator.emplace(intervals[0][1]);//存入开始时间最早的会议的结束的时间
        for(int i=1;i<intervals.size();i++){
            if(intervals[i][0]>=allocator.top()){
                allocator.pop();
            }
            allocator.emplace(intervals[i][1]);
        }
        return allocator.size();
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值