力扣 每日一题 2055. 蜡烛之间的盘子 我的代码+别人的代码

  1. 蜡烛之间的盘子 https://leetcode-cn.com/problems/plates-between-candles/

一个字符串,*代表盘子,|代表蜡烛,查询若干次,每次给你两个端点Left和right,查询left和right之间被蜡烛包裹的盘子最大数量。如下图:

在这里插入图片描述

我的思路:

   1.用前缀和的思想,开一个数组cont记录从0到i的盘子数量。

   2. 对于每次查询的两个端点left和right,我直接开两个while循环,找到left右侧最近的蜡烛下标和right左侧最近的蜡烛下标。

   3. cont[right左侧最近的蜡烛下标-left右侧最近的蜡烛下标] 就是结果。

结果超时了,卡在了第二步的那两个while循环上,下面是我的代码:

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
        vector<int> ans;
        int len=s.size();
        int i,j,left,right;
        vector<int> cont;
        cont.resize(len+1);

        for(i=0;i<len;i++){
            if(s.at(i)=='*'){
                if(i==0){
                    cont[i]=1;
                }else{
                    cont[i]=cont[i-1]+1;
                }
            }else{
                if(i==0){
                    cont[i]=0;
                }else{
                   cont[i]=cont[i-1]; 
                }
            }
        }
        for(i=0;i<queries.size();i++){
            left=queries[i][0];
            right=queries[i][1];
            if(left<0||right>=len){
                ans.push_back(0);
            }else{
                while(left<len&&s.at(left)=='*'){
                    left++;
                }
                while(right>=0&&s.at(right)=='*'){
                    right--;
                }
                if(left<right&&s.at(left)=='|'&&s.at(right)=='|'){
                    ans.push_back(cont[right]-cont[left]);
                }else{
                    ans.push_back(0);
                }
            }
        }
        return ans;
    }
};

然后我看了评论区,有一个思路跟我的有点像,但他没有开两个while循环,而是采用了空间换时间的思想,开了两个vector来记录Left右端最近的蜡烛下标和Right左端最近的蜡烛下标。这点我真没想到。

正确代码:

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
        vector<int> ans,Lcandle,Rcandle;
        // Lcandle和Rcandle记录 i左侧和右侧最近的蜡烛下标。
        int len=s.size();
        int i,j,left=-1,right=-1,sum=0;
        vector<int> cont;
        cont.resize(len);
        Lcandle.resize(len);
        Rcandle.resize(len);
        // 前缀和处理
        for(i=0;i<len;i++){
            if(s.at(i)=='*'){
                sum++;
            }else{
                left=i;
            }
            Lcandle[i]=left;
            cont[i]=sum;
        }
        // 找到当前i最右侧的蜡烛下标
        for(i=len-1;i>=0;i--){
            if(s.at(i)=='|'){
                right=i;
            }
            Rcandle[i]=right;
        }
        for(i=0;i<queries.size();i++){
            left=queries[i][0];
            right=queries[i][1];
            if(left<0||right>=len){
                ans.push_back(0);
            }else{
                int l=Rcandle[left];
                int r=Lcandle[right];
                if(l==-1||r==-1||l>=r){
                    ans.push_back(0);
                }else{
                    ans.push_back(cont[r]-cont[l]);
                }
                
            }
        }
        return ans;
    }
};

评论区还有大佬用前缀和+哈希的思想写的,我觉得代码挺简洁的,思路:
1.遍历一遍字符串,统计从0到i的盘子数量
如果当前是蜡烛,则往map里加一个键值对(蜡烛下标,蜡烛下标之前的盘子数量)
2. 对于给定的两个查询端点left和right,在map里找到大于等于left的键值对和小于等于right的键值对,输出这两个值得前缀和差就OK了。
具体看代码:

 public int[] platesBetweenCandles(String s, int[][] queries) {
        int n = queries.length;
        int length = s.length();
        int[] ans = new int[n];
        //将索引在"|"时的前缀和盘子数加入哈希表中
        TreeMap<Integer, Integer> map = new TreeMap<>();
        int count = 0;
        for (int i = 0; i < length; i++) {
            if (s.charAt(i) == '*'){
                if (!map.isEmpty()){
                    count++;
                }
            } else {
                map.put(i, count);
            }
        }
        for (int i = 0; i < n; i++) {
            //获取哈希表中最小 >=左边界的索引
            Integer left = map.higherKey(queries[i][0] - 1);
            //获取哈希表中最大 <=右边界的索引
            Integer right = map.lowerKey(queries[i][1] + 1);
            if (left == null || right == null || left >= right){
                ans[i] = 0;
            } else {
                ans[i] = map.get(right) - map.get(left);
            }
        }
        return ans;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值