Problem Β· Design

Versioned Recipe System

Learn this problem
● HardTrade DeskFULLTIMEOA

Problem statement

Implement an in-memory recipe management system. The system receives a list of commands and returns one output string for each command.

Each recipe has a unique recipe_id, an owning user_id, a name, content, and a version number starting from 1.

Version Rules

  • ADD creates version v1.
  • UPDATE creates a new version only if either name or content differs from the current latest version. If both are unchanged, keep the current latest version.
  • ROLLBACK does not delete history. It copies the target historical version into a new latest version.
  • DELETE marks a recipe as deleted. Deleted recipes are hidden from ordinary GET, LIST, and SEARCH, but version-specific GET and HISTORY can still inspect history.

Permissions

Only the owning user can run UPDATE, DELETE, or ROLLBACK. If another user attempts one of these commands, return FORBIDDEN.

Commands

Each command is a string whose fields are separated by |:

ADD|recipe_id|user_id|name|content
GET|recipe_id
GET|recipe_id|version
UPDATE|recipe_id|user_id|name|content
DELETE|recipe_id|user_id
LIST
LIST|user_id
SEARCH|keyword
HISTORY|recipe_id
ROLLBACK|recipe_id|user_id|version

Output Rules

  • ADD success: OK v1
  • UPDATE success: OK vX
  • DELETE success: OK
  • ROLLBACK success: OK vX
  • GET success: recipe_id|user_id|vX|name|content
  • LIST and SEARCH success: entries joined by ;, where each entry is recipe_id:vX:name.
  • HISTORY success: all versions joined by ;, where each entry is vX:name.
  • No matching visible result: EMPTY
  • Missing recipe or invalid version: NOT_FOUND
  • Permission failure: FORBIDDEN
  • Other invalid operations, such as adding a duplicate recipe_id: ERROR

LIST and SEARCH results are sorted by recipe_id in lexicographic order. SEARCH|keyword matches active latest recipes where keyword is a case-insensitive substring of the latest name or content.

Function

processRecipeCommands(commands: String[]) β†’ String[]

Examples

Example 1

commands = ["ADD|r1|u1|Pasta|tomato", "GET|r1", "UPDATE|r1|u1|Pasta|tomato basil", "GET|r1|1", "GET|r1", "HISTORY|r1", "UPDATE|r1|u1|Pasta|tomato basil", "HISTORY|r1"]return = ["OK v1", "r1|u1|v1|Pasta|tomato", "OK v2", "r1|u1|v1|Pasta|tomato", "r1|u1|v2|Pasta|tomato basil", "v1:Pasta;v2:Pasta", "OK v2", "v1:Pasta;v2:Pasta"]

The first update changes the content, so it creates v2. The version-specific GET|r1|1 still returns the original content. The second update is identical to the latest version, so no new version is created.

Example 2

commands = ["ADD|r2|u2|Salad|greens", "UPDATE|r2|u3|Salad|greens and oil", "LIST|u2", "SEARCH|GREEN", "DELETE|r2|u2", "GET|r2", "HISTORY|r2"]return = ["OK v1", "FORBIDDEN", "r2:v1:Salad", "r2:v1:Salad", "OK", "NOT_FOUND", "v1:Salad"]

User u3 cannot update a recipe owned by u2. After deletion, ordinary GET does not expose the recipe, but HISTORY can still show its prior version.

Constraints

  • 1 <= commands.length <= 10^5
  • recipe_id, user_id, name, content, and keyword each have length at most 100.
  • Fields do not contain the character |.

More Trade Desk problems

drafts saved locally
public String[] processRecipeCommands(String[] commands) {
  // write your code here
}
commands["ADD|r1|u1|Pasta|tomato", "GET|r1", "UPDATE|r1|u1|Pasta|tomato basil", "GET|r1|1", "GET|r1", "HISTORY|r1", "UPDATE|r1|u1|Pasta|tomato basil", "HISTORY|r1"]
expected["OK v1", "r1|u1|v1|Pasta|tomato", "OK v2", "r1|u1|v1|Pasta|tomato", "r1|u1|v2|Pasta|tomato basil", "v1:Pasta;v2:Pasta", "OK v2", "v1:Pasta;v2:Pasta"]
checking account