Lazy Run-Length Decoding - Google Top Interview Questions


Problem Statement :


Implement a data structure RunLengthDecoder which implements the following methods:

RunLengthDecoder(string s) which takes a string s that is run-length encoded.

string value(int i) which returns the character at index i of the run-length decoded version of s.

string valueInRange(string c, int i, int j) which returns the first lowercase alphabet character that is greater than or equal to c from the range [i, j) of the decoded string. 

You can assume that the range contains characters that are in ascending order. If no such character exists, return "?"
Constraints

n ≤ 100,000 where n is the length of s

k ≤ 100,000 where k is the number of calls to value and valueInRange

Example 1

Input

methods = ["constructor", "value", "value", "valueInRange", "valueInRange", "valueInRange"]

arguments = [["3a3b2c1d1a"], [0], [4], ["a", 0, 9], ["b", 3, 9], ["e", 3, 9]]`

Output

[None, "a", "b", "a", "b", "?"]
Explanation

r = RunLengthDecoder("3a3b2c1d1a") # In decoded version it's "aaabbbccda"

r.value(0) == "a"

r.value(4) == "b"

r.valueInRange("a", 0, 9) == "a"

r.valueInRange("b", 3, 9) == "b"

r.valueInRange("e", 3, 9) == "?"



Solution :



title-img




                        Solution in C++ :

class RunLengthDecoder {
    public:
    map<char, vector<pair<int, int>>> charToRanges;
    vector<pair<int, int>> ranges;
    vector<char> chars;
    RunLengthDecoder(string s) {
        int curr = 0;
        int amt = 0;
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= 'a' && s[i] <= 'z') {
                charToRanges[s[i]].emplace_back(amt, amt + curr);
                ranges.emplace_back(amt, amt + curr);
                chars.push_back(s[i]);
                amt += curr;
                curr = 0;
            } else {
                curr *= 10;
                curr += s[i] - '0';
            }
        }
        assert(curr == 0);
    }

    string value(int i) {
        auto it = upper_bound(ranges.begin(), ranges.end(), make_pair(i + 1, (int)-1e9));
        it--;
        int idx = it - ranges.begin();
        return string(1, chars[idx]);
    }

    string valueInRange(string c, int i, int j) {
        for (char ch = c[0]; ch <= 'z'; ch++) {
            auto it = upper_bound(charToRanges[ch].begin(), charToRanges[ch].end(),
                                  make_pair(j, (int)-1e9));
            if (it != charToRanges[ch].begin()) it--;
            if (it == charToRanges[ch].end()) continue;
            pair<int, int> key = *it;
            if (key.second <= i || key.first >= j) continue;
            return string(1, ch);
        }
        return "?";
    }
};
                    


                        Solution in Java :

import java.util.*;

class RunLengthDecoder {
    private StringBuilder sb = new StringBuilder();
    private List<Integer> begins = new ArrayList<>();

    public RunLengthDecoder(String s) {
        for (int i = 0, end = 0; i != s.length(); i++) {
            int j = i;
            while (Character.isDigit(s.charAt(j + 1))) j++;
            begins.add(end);
            int len = Integer.parseInt(s.substring(i, j + 1));
            if (len != 0) {
                end += Integer.parseInt(s.substring(i, j + 1));
                sb.append(s.charAt(j + 1));
            }
            i = j + 1;
        }
    }

    public String value(int i) {
        int idx = Collections.binarySearch(begins, i);
        if (idx < 0)
            idx = -2 - idx;
        return sb.substring(idx, idx + 1);
    }

    public String valueInRange(String c, int i, int j) {
        int idx = Collections.binarySearch(begins, i);
        if (idx < 0)
            idx = -2 - idx;
        final char ch = c.charAt(0);
        for (int round = 0; idx != sb.length() && round != 26; round++, idx++) {
            if (begins.get(idx) >= j)
                break;
            if (sb.charAt(idx) >= ch)
                return Character.toString(sb.charAt(idx));
        }
        return "?";
    }
}
                    


                        Solution in Python : 
                            
class RunLengthDecoder:
    def __init__(self, s):
        self.chars = []
        self.indexes = [0]

        char_count = 0
        for char in s:
            if not char.isdigit():
                self.chars.append(char)
                self.indexes.append(self.indexes[-1] + char_count)
                char_count = 0
            else:
                char_count = char_count * 10 + int(char)

        self.next_indexes = [[self.indexes[-1]] * 26 for _ in range(len(s) + 1)]

        for i in range(len(self.chars) - 1, -1, -1):
            self.next_indexes[i] = self.next_indexes[i + 1][:]
            char_num = ord(self.chars[i]) - ord("a")
            self.next_indexes[i][char_num] = self.indexes[i]

    def value(self, i):
        char_index = max(0, bisect_right(self.indexes, i) - 1)
        return self.chars[char_index]

    def valueInRange(self, c, i, j):
        char_index = max(0, bisect_right(self.indexes, i) - 1)
        next_indexes = self.next_indexes[char_index]
        char_num = ord(c) - ord("a")
        for num in range(char_num, 26):
            if next_indexes[num] < j:
                return chr(num + ord("a"))
        return "?"
                    


View More Similar Problems

Array-DS

An array is a type of data structure that stores elements of the same type in a contiguous block of memory. In an array, A, of size N, each memory location has some unique index, i (where 0<=i<N), that can be referenced as A[i] or Ai. Reverse an array of integers. Note: If you've already solved our C++ domain's Arrays Introduction challenge, you may want to skip this. Example: A=[1,2,3

View Solution →

2D Array-DS

Given a 6*6 2D Array, arr: 1 1 1 0 0 0 0 1 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 An hourglass in A is a subset of values with indices falling in this pattern in arr's graphical representation: a b c d e f g There are 16 hourglasses in arr. An hourglass sum is the sum of an hourglass' values. Calculate the hourglass sum for every hourglass in arr, then print t

View Solution →

Dynamic Array

Create a list, seqList, of n empty sequences, where each sequence is indexed from 0 to n-1. The elements within each of the n sequences also use 0-indexing. Create an integer, lastAnswer, and initialize it to 0. There are 2 types of queries that can be performed on the list of sequences: 1. Query: 1 x y a. Find the sequence, seq, at index ((x xor lastAnswer)%n) in seqList.

View Solution →

Left Rotation

A left rotation operation on an array of size n shifts each of the array's elements 1 unit to the left. Given an integer, d, rotate the array that many steps left and return the result. Example: d=2 arr=[1,2,3,4,5] After 2 rotations, arr'=[3,4,5,1,2]. Function Description: Complete the rotateLeft function in the editor below. rotateLeft has the following parameters: 1. int d

View Solution →

Sparse Arrays

There is a collection of input strings and a collection of query strings. For each query string, determine how many times it occurs in the list of input strings. Return an array of the results. Example: strings=['ab', 'ab', 'abc'] queries=['ab', 'abc', 'bc'] There are instances of 'ab', 1 of 'abc' and 0 of 'bc'. For each query, add an element to the return array, results=[2,1,0]. Fun

View Solution →

Array Manipulation

Starting with a 1-indexed array of zeros and a list of operations, for each operation add a value to each of the array element between two given indices, inclusive. Once all operations have been performed, return the maximum value in the array. Example: n=10 queries=[[1,5,3], [4,8,7], [6,9,1]] Queries are interpreted as follows: a b k 1 5 3 4 8 7 6 9 1 Add the valu

View Solution →