Design a category hierarchy system that stores categories, subcategories, and products. A category may contain both products and any number of subcategories.
The system must retrieve all products from a selected category and its descendant categories while applying optional filters. The filter design must allow new filter types to be added later without changing the public product-search method.
CategoryHierarchySystem
public CategoryHierarchySystem()
public boolean addCategory( String categoryId, String categoryName, String parentCategoryId)
parentCategoryId creates a root category.parentCategoryId places the new category directly under the specified existing category.true when the category is added successfully.false when the category ID or name is blank, the category ID already exists, or the specified parent category does not exist.public boolean addProduct( String productId, String categoryId, String productName, long priceInCents)
true when the product is added successfully.false when the product ID, category ID, or product name is blank, the product ID already exists, the category does not exist, or priceInCents is negative.public List<String> getProducts( String categoryId, List<String> filters)
Each filter is represented by one string in one of these formats:
"nameEquals=<text>" requires the complete product name to equal the supplied text."nameContains=<text>" requires the product name to contain the supplied text as a contiguous substring."minPriceInCents=<value>" requires the product price to be greater than or equal to the supplied value."maxPriceInCents=<value>" requires the product price to be less than or equal to the supplied value.A-Z are treated the same as their corresponding letters from a-z.minPriceInCents is greater than maxPriceInCents.getProducts, category traversal logic, or existing filter implementations."productId,productName,categoryId,priceInCents".productId in ascending case-sensitive lexicographical order using Java's String.compareTo behavior.filters are non-null.String.isBlank() method returns true.1 and 100 letters, digits, underscores, or hyphens.1 and 200 letters, digits, spaces, underscores, or hyphens.0 ≤ priceInCents ≤ 1,000,000,000 for every stored product.0 ≤ filters.size() ≤ 41,000.100,000 categories and 100,000 products are stored in one system instance.100,000 public method calls are made on one system instance.getProducts calls, at most 200,000 product rows are returned.Parameter names are shown in the calls for readability.
CategoryHierarchySystem catalog = new CategoryHierarchySystem()
catalog.addCategory( categoryId = "store", categoryName = "Store", parentCategoryId = "")
Output: true
catalog.addCategory( categoryId = "electronics", categoryName = "Electronics", parentCategoryId = "store")
Output: true
catalog.addCategory( categoryId = "computers", categoryName = "Computers", parentCategoryId = "electronics")
Output: true
catalog.addCategory( categoryId = "accessories", categoryName = "Accessories", parentCategoryId = "electronics")
Output: true
catalog.addProduct( productId = "p40", categoryId = "electronics", productName = "Travel Charger", priceInCents = 2499)
Output: true
catalog.addProduct( productId = "p10", categoryId = "computers", productName = "Orbit Laptop", priceInCents = 85000)
Output: true
catalog.addProduct( productId = "p20", categoryId = "accessories", productName = "Laptop Sleeve", priceInCents = 1999)
Output: true
catalog.addProduct( productId = "p30", categoryId = "computers", productName = "Mini Desktop", priceInCents = 55000)
Output: true
catalog.getProducts( categoryId = "store", filters = List.of("nameContains=laptop"))
Output: ["p10,Orbit Laptop,computers,85000", "p20,Laptop Sleeve,accessories,1999"]
Both products match the case-insensitive name filter and belong to descendants of store.
catalog.getProducts( categoryId = "electronics", filters = List.of( "minPriceInCents=2000", "maxPriceInCents=60000"))
Output: ["p30,Mini Desktop,computers,55000", "p40,Travel Charger,electronics,2499"]
The result includes a product stored directly in electronics and another stored in its computers subcategory.
CategoryHierarchySystem catalog = new CategoryHierarchySystem()
catalog.addCategory( categoryId = "home", categoryName = "Home", parentCategoryId = "")
Output: true
catalog.addCategory( categoryId = "kitchen", categoryName = "Kitchen", parentCategoryId = "home")
Output: true
catalog.addProduct( productId = "p7", categoryId = "kitchen", productName = "Steel Kettle", priceInCents = 3200)
Output: true
catalog.addProduct( productId = "p2", categoryId = "kitchen", productName = "Glass Kettle", priceInCents = 2800)
Output: true
catalog.addProduct( productId = "p5", categoryId = "kitchen", productName = "Coffee Grinder", priceInCents = 4100)
Output: true
catalog.getProducts( categoryId = "kitchen", filters = List.of("nameEquals=glass kettle"))
Output: ["p2,Glass Kettle,kitchen,2800"]
catalog.getProducts( categoryId = "home", filters = List.of())
Output: ["p2,Glass Kettle,kitchen,2800", "p5,Coffee Grinder,kitchen,4100", "p7,Steel Kettle,kitchen,3200"]
catalog.addProduct( productId = "p2", categoryId = "home", productName = "Replacement Kettle", priceInCents = 3500)
Output: false
The product ID already exists, so the original product remains unchanged.
catalog.getProducts( categoryId = "home", filters = List.of("brand=Nova"))
Output: []
The filter type is not currently supported, so the complete filter list is invalid.