【数据结构-前缀和】【含代码优化过程】力扣2055. 蜡烛之间的盘子

给你一个长桌子,桌子上盘子和蜡烛排成一列。给你一个下标从 0 开始的字符串 s ,它只包含字符 ‘’ 和 ‘|’ ,其中 '’ 表示一个 盘子 ,‘|’ 表示一支 蜡烛 。

同时给你一个下标从 0 开始的二维整数数组 queries ,其中 queries[i] = [lefti, righti] 表示 子字符串 s[lefti…righti] (包含左右端点的字符)。对于每个查询,你需要找到 子字符串中 在 两支蜡烛之间 的盘子的 数目 。如果一个盘子在 子字符串中 左边和右边 都 至少有一支蜡烛,那么这个盘子满足在 两支蜡烛之间 。

比方说,s = “|||||" ,查询 [3, 8] ,表示的是子字符串 "||**|” 。子字符串中在两支蜡烛之间的盘子数目为 2 ,子字符串中右边两个盘子在它们左边和右边 都 至少有一支蜡烛。
请你返回一个整数数组 answer ,其中 answer[i] 是第 i 个查询的答案。

示例1
在这里插入图片描述

示例2
在这里插入图片描述

在这里插入图片描述

第一次尝试(12/36)

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
        vector<int> answer;
        for(const auto& query : queries){
            int count = 0;
            bool flag = false;
            int start = query[0];
            int end = query[1];
            while(s[start] != '|'){
                start++;
            }
            while(s[end] != '|'){
                end--;
            }

            for(int i = start;i <= end;i++){
                if(s[i] == '|') {
                    continue;
                }
                count++;
            }
            answer.push_back(count);
        }
        return answer;
    }
};

一开始想的代码,找到两个边界,然后遍历里面的元素,算出answer,在12/36示例的时候超时。发现计算每个queries里面的区间的时候,都要重复遍历一遍元素,考虑可以采用预处理。

第一次优化代码(22/36)

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
        vector<int> memo(s.size(), 0);
        int total = 0;
        for(int i = 0;i < s.size();i++){
            if(s[i] == '*') {
                total++;
            }   
            memo[i] = total;
        }
        vector<int> answer;
        for(const auto& query : queries){
            int first = query[0];
            int second = query[1];
            while(s[first] != '|'  && first < second){
                first++;
            }
            while(s[second] != '|' && second > first){
                second--;
            }
            if(first != second){
                int count = memo[second] - memo[first];     
                answer.push_back(count);
            }else{
                answer.push_back((int) 0);
            }
        }

        return answer;
    }
};

定义了一个memo数组,在进行对queries的遍历前,先计算出字符串在 i 之前的累积蜡烛数量。进行测试,在22/36示例的时候超时。
在这里插入图片描述

发现在测试的时候在两根’|‘中间输入了很多很多’ * ',观察代码发现,在每次计算新的query的最外边两根蜡烛位置的时候,如果一直找不到蜡烛,就会几乎遍历完整个区间,这会消耗很多内存。

第二次优化代码(通过)

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
        vector<int> memo(s.size(), 0);
        vector<int> leftCandle(s.size(), -1);
        vector<int> rightCandle(s.size(), -1);
        int total = 0;
        int lastCandle = -1;
        for(int i = 0;i < s.size();i++){
            if(s[i] == '*') {
                total++;
            }else{
                lastCandle = i;
            }   
            memo[i] = total;
            leftCandle[i] = lastCandle;
        }

        lastCandle = -1;
        for(int i = s.size()-1;i >= 0;i--){
            if(s[i] == '|'){
                lastCandle = i;
            }
            rightCandle[i] = lastCandle;
        }
        vector<int> answer;
        for(const auto& query : queries){
            int second = leftCandle[query[1]];
            int first = rightCandle[query[0]];
            if(first != -1 && second != -1 && first < second){
                answer.push_back(memo[second] - memo[first]);
            }else{
                answer.push_back(0);
            }
        }

        return answer;
    }
};

定义了两个数组

vector<int> leftCandle(s.size(), -1);	//储存左边最近的蜡烛
vector<int> rightCandle(s.size(), -1);	//储存右边最近的蜡烛

这样,就不需要在循环中再次嵌套循环来找到最外边的两根蜡烛的位置。

if(first != -1 && second != -1 && first < second){
                answer.push_back(memo[second] - memo[first]);
            }else{
                answer.push_back(0);
            }

只要两边都有蜡烛,且first < second 两根蜡烛顺序正确,就会返回memo[second] - memo[first] ,否则返回0。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值