方法一:模拟+贪心
思路与算法:
我们从字符串左边第一位开始依次遍历,如果是 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();
}
};