【LeetCode周赛】LeetCode第364场周赛

目录

  • 最大二进制奇数
  • 美丽塔Ⅰ
  • 美丽塔Ⅱ

最大二进制奇数

给你一个 二进制 字符串 s ,其中至少包含一个 ‘1’ 。
你必须按某种方式 重新排列 字符串中的位,使得到的二进制数字是可以由该组合生成的 最大二进制奇数 。
以字符串形式,表示并返回可以由给定组合生成的最大二进制奇数。
注意 返回的结果字符串 可以 含前导零。
示例 1:

输入:s = “010”
输出:“001”
解释:因为字符串 s 中仅有一个 ‘1’ ,其必须出现在最后一位上。所以答案是 “001” 。

示例 2:

输入:s = “0101”
输出:“1001”
解释:其中一个 ‘1’ 必须出现在最后一位上。而由剩下的数字可以生产的最大数字是 “100”。所以答案是 “1001” 。

提示:

1 <= s.length <= 100
s 仅由 ‘0’ 和 ‘1’ 组成
s 中至少包含一个 ‘1’

分析:
不难想到,因为要求返回的是一个奇数,所以最后一位肯定是1,同时,要使得整个数最大,所以1的位置要尽可能在前面的位数上。直接模拟即可。
代码:

class Solution {
public:
    string maximumOddBinaryNumber(string s) {
        int zero=0,one=0;
        for(int i=0;i<s.size();i++){
            if(s[i]=='0')zero++;
            else one++;
        }
        string t="";
        while(one>1){
            t+="1";
            one--;
        }
        while(zero--)t+="0";
        t+="1";
        return t;
    }
};

美丽塔Ⅰ

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。
你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。
如果以下条件满足,我们称这些塔是 美丽 的:
1 <= heights[i] <= maxHeights[i]
heights 是一个 山状 数组。
如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山状 数组:
对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k]
请你返回满足 美丽塔 要求的方案中,高度和的最大值 。
示例 1:

输入:maxHeights = [5,3,4,1,1]
输出:13
解释:和最大的美丽塔方案为 heights = [5,3,3,1,1],这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 0 处。 13 是所有美丽塔方案中的最大高度和。

示例 2:

输入:maxHeights = [6,5,3,9,2,7]
输出:22
解释: 和最大的美丽塔方案为 heights =[3,3,3,9,2,2] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 3 处。 22 是所有美丽塔方案中的最大高度和。

示例 3:

输入:maxHeights = [3,2,5,5,2,3]
输出:18
解释:和最大的美丽塔方案为 heights =[2,2,5,5,2,2] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,最大值在 i = 2 处。 注意,在这个方案中,i = 3 也是一个峰值。 18 是所有美丽塔方案中的最大高度和。

提示:
1 < = n = = m a x H e i g h t s < = 1 0 3 1 <= n == maxHeights <= 10^3 1<=n==maxHeights<=103
1 < = m a x H e i g h t s [ i ] < = 1 0 9 1 <= maxHeights[i] <= 10^9 1<=maxHeights[i]<=109

分析:
根据此题n的数据范围,可以考虑暴力做法,对于一个山状数组,只要我们能够找到"山峰"这个点,山峰i的高度h[i]肯定是当前maxHeights[i]的值,然后往左边逐渐递减,左边每一个塔j的值h[j]=min(maxHeights[j],h[j+1])。同理,右边每一个塔j的值h[j]=min(maxHeights[j],h[j-1])。因此,可以暴力计算出以每个塔为"山峰"时,最大的高度和,从而计算出整体最大的高度和。
代码:

class Solution {
public:
    long long maximumSumOfHeights(vector<int>& maxHeights) {
        long long res=0;
        int n=maxHeights.size();
        vector<int>h(n+1);
        for(int i=0;i<n;i++){//取每一个为峰值
            long long ans=maxHeights[i];
            h[i]=maxHeights[i];
            for(int j=i-1;j>=0;j--){//左边递减
                int now=min(maxHeights[j],h[j+1]);
                h[j]=now;
                ans+=now;
            }
            for(int j=i+1;j<n;j++){//右边递减
                int now=min(maxHeights[j],h[j-1]);
                h[j]=now;
                ans+=now;
            }
            res=max(res,ans);
        }
        return res;
    }
};

美丽塔Ⅱ

给你一个长度为 n 下标从 0 开始的整数数组 maxHeights 。
你的任务是在坐标轴上建 n 座塔。第 i 座塔的下标为 i ,高度为 heights[i] 。
如果以下条件满足,我们称这些塔是 美丽 的:
1 <= heights[i] <= maxHeights[i]
heights 是一个 山状 数组。
如果存在下标 i 满足以下条件,那么我们称数组 heights 是一个 山状 数组:
对于所有 0 < j <= i ,都有 heights[j - 1] <= heights[j]
对于所有 i <= k < n - 1 ,都有 heights[k + 1] <= heights[k]
请你返回满足 美丽塔 要求的方案中,高度和的最大值 。
示例 1:

输入:maxHeights = [5,3,4,1,1]
输出:13
解释:和最大的美丽塔方案为 heights = [5,3,3,1,1],这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 0 处。 13 是所有美丽塔方案中的最大高度和。

示例 2:

输入:maxHeights = [6,5,3,9,2,7]
输出:22
解释: 和最大的美丽塔方案为 heights =[3,3,3,9,2,2] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,峰值在 i = 3 处。 22 是所有美丽塔方案中的最大高度和。

示例 3:

输入:maxHeights = [3,2,5,5,2,3]
输出:18
解释:和最大的美丽塔方案为 heights =[2,2,5,5,2,2] ,这是一个美丽塔方案,因为:

  • 1 <= heights[i] <= maxHeights[i]
  • heights 是个山状数组,最大值在 i = 2 处。 注意,在这个方案中,i = 3 也是一个峰值。 18 是所有美丽塔方案中的最大高度和。

提示:
1 < = n = = m a x H e i g h t s < = 1 0 5 1 <= n == maxHeights <= 10^5 1<=n==maxHeights<=105
1 < = m a x H e i g h t s [ i ] < = 1 0 9 1 <= maxHeights[i] <= 10^9 1<=maxHeights[i]<=109

分析:
该题比美丽塔Ⅰ相比来说,就是数据范围变大了,同样,我们美丽塔Ⅰ的暴力做法,时间复杂度为 O ( N 2 ) O(N^2) O(N2),在当前n的范围下,是会TLE的。那么,我们可以在哪个地方减少时间的开销呢?
不难想到,主要的时间开销在枚举每一个塔作为山峰,以及计算每个塔作为山峰时,整体的一个最大高度和,都需要遍历n个塔,如果整体的高度和能够很快计算出来,可以减少时间的开销。
我们分析一下这个山状数组,当塔i作为山峰时,其高度为 h i h_{i} hi,即maxHeighs[i],如果左边的塔j的maxHeights[j]比它高,那么其高度也只能是 h i h_{i} hi,那么,我们往左边一直找,只要塔的maxHeights比 h i h_{i} hi高,那么该塔的高度就是 h i h_{i} hi,直到找到 m a x H e i g h t s [ j ] < h i maxHeights[j]maxHeights[j]<hi的塔j,那么此时到塔i的最大高度和 p r e [ i ] = ( i − j ) ∗ h [ i ] + p r e [ j ] pre[i]=(i-j)*h[i]+pre[j] pre[i]=(ij)h[i]+pre[j]。如果左边没有比i低的塔,那么此时到塔i的最大高度和 p r e [ i ] = i ∗ h [ i ] pre[i]=i*h[i] pre[i]=ih[i]
因此,对于塔i左边的塔,我们只需要能够快速找到第一个比 h i h_{i} hi矮的塔,即可维护一个最大的高度和。那么这个问题又变成了单调栈的解法,有一个类似的题,找一个数右边的最近最大的数下一个更大元素 I。对于本题,利用单调栈,每次将一个数入栈,然后凡是栈中比其大的数,都出栈,然后此时栈顶的数就是离他最近的比其小的数,单调栈里从栈顶开始是一个递减序列。(为什么出栈更大的数呢,因为出栈更大的数是对后续找左边更小的数是没有影响的,留下来的数都是最近最小的数字),这样就可以在线性时间内找到左边最近最小的数。
右边的塔的处理同理,最后枚举每一个点作为峰值,即可快速得到最大的高度和。
代码:

class Solution {
public:
    //找到每一个maxHeights[i]左边最近的一个更小的值j,这一片都采用当前maxHeights[i]的值,然后再取j那边维护的值
    void cal(vector<long long>& p,vector<int>& maxHeights){
        int n=maxHeights.size();
        stack<int>st;
        for(int i=0;i<n;i++){
            while(!st.empty()&&maxHeights[st.top()]>=maxHeights[i])st.pop();
            if(st.empty())p[i]=(long long)(i+1)*maxHeights[i];//左边没有更小的值了,那么左边的高度和全是当前的maxHeights[i]
            else p[i]=(long long)(i-st.top())*maxHeights[i]+p[st.top()];//一直到左边这个比它小的值取当前的maxHeights[i],其他的值取之前维护好的
            st.push(i);
        }
    }
    long long maximumSumOfHeights(vector<int>& maxHeights) {
        int n=maxHeights.size();
        vector<long long>pre(n+1),suf(n+1);
        cal(pre,maxHeights);
        //找右边最近的最小的数 翻转一下,就是找左边最近最小的数
        reverse(maxHeights.begin(),maxHeights.end());
        cal(suf,maxHeights);
        long long ans=0;
        //枚举山峰
        for(int i=0;i<n;i++)ans=max(ans,pre[i]+suf[n-1-i]-maxHeights[n-1-i]);
        return ans;
    }
};

你可能感兴趣的:(LeetCode,leetcode,算法,数据结构)