Talentd
FleetCode
Make and follow sheets.Sign in

Plates Between Candles solution and explanation

MediumArrayBinary SearchPrefix SumString6 min read47.4% acceptanceUpdated 9 Apr 2026
2055. Plates Between Candles | LEETCODE BIWEEKLY CONTEST 64 | LEETCODE | CODE EXPLAINERcode Explainer · 11:48 · 5K viewsWatch on YouTube
9 more videos on this problem
  1. 2055. Plates Between Candles | LEETCODE BIWEEKLY CONTEST 64 | LEETCODE | CODE EXPLAINERcode Explainer · 11:48 · 5K views
  2. LeetCode 2055. Plates Between Candles - O(n + q)Kacy Codes · 16:31 · 5K views
  3. 2055. Plates Between Candles (Leetcode Medium)Programming Live with Larry · 11:56 · 3K views
  4. 【每日一题】LeetCode 2055. Plates Between CandlesHuifeng Guan · 12:24 · 1K views
  5. Leetcode 2055: Plates Between CandlesNail the Tech Interview · 21:41 · 1K views
  6. 5900 | Plates Between Candles | LeetCode Biweekly Contest 64Gaurav Agrawal · 13:56 · 1K views
  7. Plates between candles - leetcode 2055Algorhythm · 18:41 · 663 views
  8. Leetcode 2055DailyLeetcode · 13:53 · 599 views
  9. Plates Between Candles solution leetcodepreetam chatterjee · 0:13 · 64 views
  10. LeetCode 2055: Plates Between CandlesAlitaCode · 34:02 · 17 views

The problem

There is a long table with a line of plates and candles arranged on top of it. You are given a 0-indexed string s consisting of characters '*' and '|' only, where a '*' represents a plate and a '|' represents a candle.

You are also given a 0-indexed 2D integer array queries where queries[i] = [lefti, righti] denotes the substring s[lefti...righti] (inclusive). For each query, you need to find the number of plates between candles that are in the substring. A plate is considered between candles if there is at least one candle to its left and at least one candle to its right in the substring.

  • For example, s = "||**||**|*", and a query [3, 8] denotes the substring "*||**|". The number of plates between candles in this substring is 2, as each of the two plates has at least one candle in the substring to its left and right.

Return an integer array answer where answer[i] is the answer to the ith query.

Example 1:

ex-1
Input: s = "**|**|***|", queries = [[2,5],[5,9]]
Output: [2,3]
Explanation:
- queries[0] has two plates between candles.
- queries[1] has three plates between candles.

Example 2:

ex-2
Input: s = "***|**|*****|**||**|*", queries = [[1,17],[4,5],[14,17],[5,11],[15,16]]
Output: [9,0,0,0,0]
Explanation:
- queries[0] has nine plates between candles.
- The other queries have zero plates between candles.

Constraints:

  • 3 <= s.length <= 105
  • s consists of '*' and '|' characters.
  • 1 <= queries.length <= 105
  • queries[i].length == 2
  • 0 <= lefti <= righti < s.length

Approach overview

Problem Overview: You get a string containing plates (*) and candles (|). For each query [l, r], count how many plates lie strictly between two candles inside that range. Plates that are not enclosed by candles do not count.

Approach 1: Prefix Sum with Two-Pass Preprocessing (O(n + q) time, O(n) space)

This is the optimal approach for most implementations. First build a prefix sum array where prefix[i] stores how many plates appear up to index i. Then preprocess two helper arrays: leftCandle[i] (nearest candle to the left) and rightCandle[i] (nearest candle to the right). For a query [l, r], move l to the nearest candle on the right and r to the nearest candle on the left. If valid candles exist, the answer is prefix[r] - prefix[l]. Each query becomes constant time after preprocessing, which makes this approach ideal when the query count is large.

Approach 2: Binary Search with Precomputed Candles (O(n + q log n) time, O(n) space)

Instead of storing nearest candles for every index, store the indices of all candles in a list while scanning the string once. For each query, use binary search to find the first candle index greater than or equal to l and the last candle index less than or equal to r. These two candles form the valid boundary. Once the boundaries are known, compute plates between them using a prefix plate count. Binary search keeps the query logic clean and works well when you already maintain sorted candle positions.

Approach 3: Direct Range Scan (Brute Force) (O(n * q) time, O(1) space)

For every query, iterate from l to r, track the first and last candles, and count plates between them. This approach uses simple iteration over the array/string characters. The logic is straightforward but inefficient because the same range segments are repeatedly scanned for different queries.

Recommended for interviews: The prefix sum with two-pass preprocessing is the expected solution. It shows you can combine prefix aggregation with boundary preprocessing to reduce per-query work to O(1). Mentioning the brute-force approach demonstrates baseline reasoning, but implementing the prefix-sum optimization signals strong problem-solving and scalability awareness.

Approach 1: Prefix Sum with Two-Pass Preprocessing

This approach involves preprocessing the input string with two arrays, one for prefix sums of plates and two others to find the nearest left and right candles from any position. This preprocessing enables efficient query execution.

def platesBetweenCandles(s, queries):
    n = len(s)
    prefix_sum = [0] * n
    left_candle = [-1] * n
    right_candle = [-1] * n
    
    # Compute prefix sums of plates
    plate_count = 0
    for i in range(n):
        if s[i] == '*':
            plate_count += 1
        prefix_sum[i] = plate_count
        if s[i] == '|':
            left_candle[i] = i
        elif i > 0:
            left_candle[i] = left_candle[i - 1]

    # Compute right candle positions
    for i in range(n - 1, -1, -1):
        if s[i] == '|':
            right_candle[i] = i
        elif i < n - 1:
            right_candle[i] = right_candle[i + 1]

    # Answer each query
    results = []
    for left, right in queries:
        left = right_candle[left]
        right = left_candle[right]
        if left == -1 or right == -1 or left >= right:
            results.append(0)
        else:
            results.append(prefix_sum[right] - prefix_sum[left])

    return results
function platesBetweenCandles(s, queries) {
    const n = s.length;
    const prefixSum = Array(n).fill(0);
    const leftCandle = Array(n).fill(-1);
    const rightCandle = Array(n).fill(-1);

    let plateCount = 0;
    for (let i = 0; i < n; i++) {
        if (s[i] === '*') {
            plateCount += 1;
        }
        prefixSum[i] = plateCount;
        leftCandle[i] = (s[i] === '|') ? i : (i > 0 ? leftCandle[i - 1] : -1);
    }

    for (let i = n - 1; i >= 0; i--) {
        rightCandle[i] = (s[i] === '|') ? i : (i < n - 1 ? rightCandle[i + 1] : -1);
    }

    const results = [];
    for (const [left, right] of queries) {
        const l = rightCandle[left];
        const r = leftCandle[right];
        if (l === -1 || r === -1 || l >= r) {
            results.push(0);
        } else {
            results.push(prefixSum[r] - prefixSum[l]);
        }
    }

    return results;
}
#include <stdlib.h>
#include <string.h>

int* platesBetweenCandles(char *s, int** queries, int queriesSize, int* queriesColSize, int* returnSize){
    int n = strlen(s);
    int* prefixSum = (int*)calloc(n, sizeof(int));
    int* leftCandle = (int*)calloc(n, sizeof(int));
    int* rightCandle = (int*)calloc(n, sizeof(int));
    
    int plateCount = 0;
    for (int i = 0; i < n; i++) {
        plateCount += (s[i] == '*');
        prefixSum[i] = plateCount;
        leftCandle[i] = (s[i] == '|') ? i : (i > 0 ? leftCandle[i - 1] : -1);
    }

    for (int i = n - 1; i >= 0; i--) {
        rightCandle[i] = (s[i] == '|') ? i : (i < n - 1 ? rightCandle[i + 1] : -1);
    }

    int* result = (int*)malloc(queriesSize * sizeof(int));
    *returnSize = queriesSize;

    for (int i = 0; i < queriesSize; i++) {
        int left = queries[i][0];
        int right = queries[i][1];
        left = rightCandle[left];
        right = leftCandle[right];
        if (left == -1 || right == -1 || left >= right) {
            result[i] = 0;
        } else {
            result[i] = prefixSum[right] - prefixSum[left];
        }
    }
    
    free(prefixSum);
    free(leftCandle);
    free(rightCandle);

    return result;
}

In the Python implementation, we first calculate a prefix_sum to track the cumulative number of plates ('*') up to every position. left_candle and right_candle arrays are used to quickly find the nearest candle positions on the left and right of each index. For each query, use these precomputed arrays to determine the number of plates located strictly between the nearest candles.

Complexity

Time Complexity: O(n + q), where n is the length of the string and q is the number of queries.
Space Complexity: O(n) due to the auxiliary arrays used for preprocessing.

Try this approach in the editor

Approach 2: Binary Search with Precomputed Candles

This approach leverages a list of precomputed candle positions and uses binary search to efficiently determine the spans of plates that are bounded by candles for each query.

import java.util.ArrayList;
import java.util.List;

public class PlatesBetweenCandles {
    public int[] platesBetweenCandles(String s, int[][] queries) {
        int n = s.length();
        List<Integer> candles = new ArrayList<>();
        int[] prefixSum = new int[n];
        int plateCount = 0;

        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == '*') {
                plateCount++;
            } else if (s.charAt(i) == '|') {
                candles.add(i);
            }
            prefixSum[i] = plateCount;
        }

        int[] result = new int[queries.length];
        for (int i = 0; i < queries.length; i++) {
            int left = queries[i][0], right = queries[i][1];
            int leftIndex = binarySearch(candles, left, true);
            int rightIndex = binarySearch(candles, right, false);
            if (leftIndex == -1 || rightIndex == -1 || leftIndex >= rightIndex) {
                result[i] = 0;
            } else {
                result[i] = prefixSum[candles.get(rightIndex)] - prefixSum[candles.get(leftIndex)];
            }
        }

        return result;
    }

    private int binarySearch(List<Integer> candles, int target, boolean isLeft) {
        int start = 0, end = candles.size() - 1;
        int result = -1;
        while (start <= end) {
            int mid = start + (end - start) / 2;
            if (candles.get(mid) >= target) {
                result = mid;
                if (isLeft) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            } else {
                start = mid + 1;
            }
        }
        return isLeft ? result : (result != -1 ? end : -1);
    }
}
using System;
using System.Collections.Generic;

public class Solution {
    public int[] PlatesBetweenCandles(string s, int[][] queries) {
        int n = s.Length;
        List<int> candles = new List<int>();
        int[] prefixSum = new int[n];
        int plateCount = 0;

        for (int i = 0; i < n; i++) {
            if (s[i] == '*') plateCount++;
            else if (s[i] == '|') candles.Add(i);
            prefixSum[i] = plateCount;
        }

        int[] results = new int[queries.Length];
        for (int i = 0; i < queries.Length; i++) {
            int left = queries[i][0], right = queries[i][1];
            int l = FindPosition(candles, left, true);
            int r = FindPosition(candles, right, false);
            if (l == -1 || r == -1 || l >= r) {
                results[i] = 0;
            } else {
                results[i] = prefixSum[candles[r]] - prefixSum[candles[l]];
            }
        }

        return results;
    }

    private int FindPosition(List<int> candles, int target, bool isLeft) {
        int low = 0, high = candles.Count - 1, result = -1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (candles[mid] >= target) {
                result = mid;
                if (isLeft) high = mid - 1;
                else low = mid + 1;
            } else {
                low = mid + 1;
            }
        }
        return isLeft ? result : (result != -1 ? low : -1);
    }
}

The Java code uses a list to store the indices of the candles found in the string. It leverages binary search to swiftly pinpoint the leftmost and rightmost candle indices valid within the range of each query. The prefix sum array is used to calculate the number of plates, since it provides cumulative counts of plates up to specific indices.

Complexity

Time Complexity: O(n + q * log k), where k is the number of candles in the string.
Space Complexity: O(n), due to the prefix sums and candle caches.

Try this approach in the editor

Approach 3: Default Approach

class Solution {
public:
    vector<int> platesBetweenCandles(string s, vector<vector<int>>& queries) {
        int n = s.size();
        vector<int> presum(n + 1);
        for (int i = 0; i < n; ++i) presum[i + 1] = presum[i] + (s[i] == '*');
        vector<int> left(n);
        vector<int> right(n);
        for (int i = 0, l = -1; i < n; ++i) {
            if (s[i] == '|') l = i;
            left[i] = l;
        }
        for (int i = n - 1, r = -1; i >= 0; --i) {
            if (s[i] == '|') r = i;
            right[i] = r;
        }
        vector<int> ans(queries.size());
        for (int k = 0; k < queries.size(); ++k) {
            int i = right[queries[k][0]];
            int j = left[queries[k][1]];
            if (i >= 0 && j >= 0 && i < j) ans[k] = presum[j] - presum[i + 1];
        }
        return ans;
    }
};
func platesBetweenCandles(s string, queries [][]int) []int {
	n := len(s)
	presum := make([]int, n+1)
	for i := range s {
		if s[i] == '*' {
			presum[i+1] = 1
		}
		presum[i+1] += presum[i]
	}
	left, right := make([]int, n), make([]int, n)
	for i, l := 0, -1; i < n; i++ {
		if s[i] == '|' {
			l = i
		}
		left[i] = l
	}
	for i, r := n-1, -1; i >= 0; i-- {
		if s[i] == '|' {
			r = i
		}
		right[i] = r
	}
	ans := make([]int, len(queries))
	for k, q := range queries {
		i, j := right[q[0]], left[q[1]]
		if i >= 0 && j >= 0 && i < j {
			ans[k] = presum[j] - presum[i+1]
		}
	}
	return ans
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Prefix Sum with Two-Pass Preprocessing

Time Complexity: O(n + q), where n is the length of the string and q is the number of queries.
Space Complexity: O(n) due to the auxiliary arrays used for preprocessing.

Binary Search with Precomputed Candles

Time Complexity: O(n + q * log k), where k is the number of candles in the string.
Space Complexity: O(n), due to the prefix sums and candle caches.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Direct Range Scan (Brute Force)O(n * q)O(1)Useful for understanding the problem or when constraints are very small
Prefix Sum with Nearest CandlesO(n + q)O(n)Best general solution when many queries must be answered efficiently
Binary Search on Candle IndicesO(n + q log n)O(n)Good when candle positions are stored separately and binary search is convenient

Frequently asked questions

Is Plates Between Candles easy or hard?

Plates Between Candles is considered a medium difficulty problem. The challenge is recognizing that repeated range queries require preprocessing with prefix sums and boundary tracking instead of scanning each query range.

How to solve Plates Between Candles in O(n)?

Precompute a prefix sum array counting plates and track the nearest candle to the left and right for every position. For a query [l, r], shift l to the nearest right candle and r to the nearest left candle. The number of plates between them is prefix[r] minus prefix[l], giving constant-time queries after O(n) preprocessing.

Plates Between Candles Python or Java solution?

Most implementations use a prefix sum array plus nearest candle preprocessing. The logic is language-independent and commonly written in Python, Java, JavaScript, C, or C#. After preprocessing, each query simply subtracts two prefix values to count plates between candle boundaries.

What is the best approach for Plates Between Candles?

The prefix sum with nearest candle preprocessing is the most efficient approach. It builds a prefix count of plates and two arrays that store the closest candle to the left and right of every index. Each query then becomes a constant-time subtraction between two prefix values, giving O(n + q) total complexity.

What data structure is used in Plates Between Candles?

The main structures are prefix sum arrays and helper arrays storing nearest candle indices. Some solutions also store candle positions in a sorted list and apply binary search to locate boundaries for each query.

What is the time complexity of Plates Between Candles?

The optimal solution runs in O(n + q) time where n is the string length and q is the number of queries. Preprocessing the prefix sums and nearest candles takes O(n), and each query is answered in O(1). A binary search alternative runs in O(n + q log n).

Is Plates Between Candles asked at Google, Amazon, or Meta?

This style of query-processing problem appears frequently in interviews at large companies such as Amazon and Google. It tests prefix sums, preprocessing techniques, and efficient range queries over arrays or strings.

Comments

Now write it yourselfClose this page and solve Plates Between Candles in the editor, without looking.
Practise Plates Between Candles