Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

157. Read N Characters Given Read4 - Leetcode Solution

Code Implementation

"""
The read4 API is already defined for you.
def read4(buf4: List[str]) -> int:
"""

class Solution:
    def read(self, buf: List[str], n: int) -> int:
        idx = 0
        temp = [''] * 4
        while idx < n:
            count = read4(temp)
            to_read = min(count, n - idx)
            for i in range(to_read):
                buf[idx] = temp[i]
                idx += 1
            if count < 4:
                break
        return idx
      
/**
 * The read4 API is defined in the parent class Reader4.
 *     int read4(char *buf4);
 */

class Solution : public Reader4 {
public:
    int read(char *buf, int n) {
        int idx = 0;
        char temp[4];
        while (idx < n) {
            int count = read4(temp);
            int toRead = std::min(count, n - idx);
            for (int i = 0; i < toRead; ++i) {
                buf[idx++] = temp[i];
            }
            if (count < 4) break;
        }
        return idx;
    }
};
      
/**
 * The read4 API is defined in the parent class Reader4.
 *     int read4(char[] buf4);
 */

public class Solution extends Reader4 {
    public int read(char[] buf, int n) {
        int idx = 0;
        char[] temp = new char[4];
        while (idx < n) {
            int count = read4(temp);
            int toRead = Math.min(count, n - idx);
            for (int i = 0; i < toRead; i++) {
                buf[idx++] = temp[i];
            }
            if (count < 4) break;
        }
        return idx;
    }
}
      
/**
 * The read4 API is defined for you.
 *     read4 = function(buf4: character[]): number {}
 */

/**
 * @param {character[]} buf
 * @param {number} n
 * @return {number}
 */
var read = function(buf, n) {
    let idx = 0;
    let temp = new Array(4);
    while (idx < n) {
        let count = read4(temp);
        let toRead = Math.min(count, n - idx);
        for (let i = 0; i < toRead; i++) {
            buf[idx++] = temp[i];
        }
        if (count < 4) break;
    }
    return idx;
};
      

Problem Description

The problem "Read N Characters Given Read4" asks you to implement a function read(buf, n) that reads up to n characters from a file into the buffer buf. The catch is that you can only read from the file using the provided API read4(buf4), which reads up to 4 characters at a time into buf4 and returns the number of characters actually read.

  • You may need to call read4 multiple times to read enough characters.
  • If the file contains fewer than n characters, you should read as many as possible.
  • You should not read more than n characters into buf.
  • The function should return the number of characters actually read.

The key constraints are: you can only use read4 to access the file, and you must not read beyond the end of the file or beyond n characters.

Thought Process

At first glance, this problem seems straightforward: just read characters using read4 until you have read n characters or reached the end of the file. However, since read4 reads in chunks of 4, you may read more characters than needed in your last call, which you must avoid copying to buf. Also, if the file ends before n characters, you must stop.

A brute-force approach would be to keep calling read4 and copying all characters to buf, but this risks writing more than n characters. The optimized approach is to only copy as many characters as needed from the buffer returned by read4 in each iteration.

The key insight is to use a temporary buffer for each read4 call, and only copy the minimum of the number of characters read and the number of characters still needed.

Solution Approach

  • Initialize a counter idx to keep track of how many characters have been read into buf so far.
  • Create a temporary buffer (like temp in code) to store the result from each read4 call.
  • Use a loop to repeatedly call read4 until you have read n characters or read4 returns fewer than 4 (end of file).
  • In each iteration, determine how many characters you still need to read (n - idx), and copy only the minimum of that and the number returned by read4 from temp to buf.
  • After each copy, increment idx by the number of characters copied.
  • If read4 returns fewer than 4, break the loop, since the file has ended.
  • Return idx as the number of characters actually read.

This approach ensures that you never read more than n characters, and you handle files shorter than n gracefully.

Example Walkthrough

Suppose the file contains the string "LeetCode" (8 characters), and you are asked to read n = 5 characters.

  1. First call to read4(temp) reads 'L','e','e','t' (returns 4). Copy all 4 to buf (idx = 4).
  2. Second call to read4(temp) reads 'C','o','d','e' (returns 4). But you only need n - idx = 1 more character, so copy only 'C' to buf (idx = 5).
  3. Since you have now read n = 5 characters, stop and return 5.

If the file had only "abc" (3 characters) and n = 5, the first read4 would return 3, you copy all 3, and since read4 returns less than 4, you stop and return 3.

Time and Space Complexity

  • Brute-force approach: If you tried to copy all 4 characters from read4 every time, you could end up writing more than n characters, which is incorrect.
  • Optimized approach: The time complexity is O(n) because in the worst case you read up to n characters, making at most ceil(n/4) calls to read4. Each call and copy is constant time per character.
  • The space complexity is O(1) extra space, since the temporary buffer is always size 4 regardless of input size.

The optimized solution is efficient both in terms of time and space.

Summary

In this problem, the main challenge is to read up to n characters using only a limited API that reads 4 characters at a time. By carefully controlling how many characters are copied from the temporary buffer to the output buffer, we ensure correctness and efficiency. The solution is elegant because it uses a simple loop and a small temporary buffer, and works efficiently for any reasonable value of n.