Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
There is a supermarket that is frequented by many customers. The products sold at the supermarket are represented as two parallel integer arrays products and prices, where the ith product has an ID of products[i] and a price of prices[i].
When a customer is paying, their bill is represented as two parallel integer arrays product and amount, where the jth product they purchased has an ID of product[j], and amount[j] is how much of the product they bought. Their subtotal is calculated as the sum of each amount[j] * (price of the jth product).
The supermarket decided to have a sale. Every nth customer paying for their groceries will be given a percentage discount. The discount amount is given by discount, where they will be given discount percent off their subtotal. More formally, if their subtotal is bill, then they would actually pay bill * ((100 - discount) / 100).
Implement the Cashier class:
Cashier(int n, int discount, int[] products, int[] prices) Initializes the object with n, the discount, and the products and their prices.double getBill(int[] product, int[] amount) Returns the final total of the bill with the discount applied (if any). Answers within 10-5 of the actual value will be accepted.Example 1:
Input
["Cashier","getBill","getBill","getBill","getBill","getBill","getBill","getBill"]
[[3,50,[1,2,3,4,5,6,7],[100,200,300,400,300,200,100]],[[1,2],[1,2]],[[3,7],[10,10]],[[1,2,3,4,5,6,7],[1,1,1,1,1,1,1]],[[4],[10]],[[7,3],[10,10]],[[7,5,3,1,6,4,2],[10,10,10,9,9,9,7]],[[2,3,5],[5,3,2]]]
Output
[null,500.0,4000.0,800.0,4000.0,4000.0,7350.0,2500.0]
Explanation
Cashier cashier = new Cashier(3,50,[1,2,3,4,5,6,7],[100,200,300,400,300,200,100]);
cashier.getBill([1,2],[1,2]); // return 500.0. 1st customer, no discount.
// bill = 1 * 100 + 2 * 200 = 500.
cashier.getBill([3,7],[10,10]); // return 4000.0. 2nd customer, no discount.
// bill = 10 * 300 + 10 * 100 = 4000.
cashier.getBill([1,2,3,4,5,6,7],[1,1,1,1,1,1,1]); // return 800.0. 3rd customer, 50% discount.
// Original bill = 1600
// Actual bill = 1600 * ((100 - 50) / 100) = 800.
cashier.getBill([4],[10]); // return 4000.0. 4th customer, no discount.
cashier.getBill([7,3],[10,10]); // return 4000.0. 5th customer, no discount.
cashier.getBill([7,5,3,1,6,4,2],[10,10,10,9,9,9,7]); // return 7350.0. 6th customer, 50% discount.
// Original bill = 14700, but with
// Actual bill = 14700 * ((100 - 50) / 100) = 7350.
cashier.getBill([2,3,5],[5,3,2]); // return 2500.0. 7th customer, no discount.
Constraints:
1 <= n <= 1040 <= discount <= 1001 <= products.length <= 200prices.length == products.length1 <= products[i] <= 2001 <= prices[i] <= 1000products are unique.1 <= product.length <= products.lengthamount.length == product.lengthproduct[j] exists in products.1 <= amount[j] <= 1000product are unique.1000 calls will be made to getBill.10-5 of the actual value will be accepted.Problem summary: There is a supermarket that is frequented by many customers. The products sold at the supermarket are represented as two parallel integer arrays products and prices, where the ith product has an ID of products[i] and a price of prices[i]. When a customer is paying, their bill is represented as two parallel integer arrays product and amount, where the jth product they purchased has an ID of product[j], and amount[j] is how much of the product they bought. Their subtotal is calculated as the sum of each amount[j] * (price of the jth product). The supermarket decided to have a sale. Every nth customer paying for their groceries will be given a percentage discount. The discount amount is given by discount, where they will be given discount percent off their subtotal. More formally, if their subtotal is bill, then they would actually pay bill * ((100 - discount) / 100). Implement the Cashier
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Design
["Cashier","getBill","getBill","getBill","getBill","getBill","getBill","getBill"] [[3,50,[1,2,3,4,5,6,7],[100,200,300,400,300,200,100]],[[1,2],[1,2]],[[3,7],[10,10]],[[1,2,3,4,5,6,7],[1,1,1,1,1,1,1]],[[4],[10]],[[7,3],[10,10]],[[7,5,3,1,6,4,2],[10,10,10,9,9,9,7]],[[2,3,5],[5,3,2]]]
apply-discount-to-prices)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1357: Apply Discount Every n Orders
class Cashier {
private int i;
private int n;
private int discount;
private Map<Integer, Integer> d = new HashMap<>();
public Cashier(int n, int discount, int[] products, int[] prices) {
this.n = n;
this.discount = discount;
for (int j = 0; j < products.length; ++j) {
d.put(products[j], prices[j]);
}
}
public double getBill(int[] product, int[] amount) {
int dis = (++i) % n == 0 ? discount : 0;
double ans = 0;
for (int j = 0; j < product.length; ++j) {
int p = product[j], a = amount[j];
int x = d.get(p) * a;
ans += x - (dis * x) / 100.0;
}
return ans;
}
}
/**
* Your Cashier object will be instantiated and called as such:
* Cashier obj = new Cashier(n, discount, products, prices);
* double param_1 = obj.getBill(product,amount);
*/
// Accepted solution for LeetCode #1357: Apply Discount Every n Orders
type Cashier struct {
i int
n int
discount int
d map[int]int
}
func Constructor(n int, discount int, products []int, prices []int) Cashier {
d := map[int]int{}
for i, product := range products {
d[product] = prices[i]
}
return Cashier{0, n, discount, d}
}
func (this *Cashier) GetBill(product []int, amount []int) (ans float64) {
this.i++
dis := 0
if this.i%this.n == 0 {
dis = this.discount
}
for j, p := range product {
x := float64(this.d[p] * amount[j])
ans += x - (float64(dis)*x)/100.0
}
return
}
/**
* Your Cashier object will be instantiated and called as such:
* obj := Constructor(n, discount, products, prices);
* param_1 := obj.GetBill(product,amount);
*/
# Accepted solution for LeetCode #1357: Apply Discount Every n Orders
class Cashier:
def __init__(self, n: int, discount: int, products: List[int], prices: List[int]):
self.i = 0
self.n = n
self.discount = discount
self.d = {product: price for product, price in zip(products, prices)}
def getBill(self, product: List[int], amount: List[int]) -> float:
self.i += 1
discount = self.discount if self.i % self.n == 0 else 0
ans = 0
for p, a in zip(product, amount):
x = self.d[p] * a
ans += x - (discount * x) / 100
return ans
# Your Cashier object will be instantiated and called as such:
# obj = Cashier(n, discount, products, prices)
# param_1 = obj.getBill(product,amount)
// Accepted solution for LeetCode #1357: Apply Discount Every n Orders
use std::collections::HashMap;
struct Cashier {
n: usize,
index: usize,
discount: f64,
inventory: HashMap<i32, f64>,
}
impl Cashier {
fn new(n: i32, discount: i32, products: Vec<i32>, prices: Vec<i32>) -> Self {
let n = n as usize;
let index = 0;
let discount = (100 - discount) as f64 / 100.0;
let mut inventory: HashMap<i32, f64> = HashMap::new();
for (id, price) in products.into_iter().zip(prices.into_iter()) {
inventory.insert(id, price as f64);
}
Cashier {
n,
index,
discount,
inventory,
}
}
fn get_bill(&mut self, products: Vec<i32>, amount: Vec<i32>) -> f64 {
let mut res = 0.0;
for (id, amount) in products.into_iter().zip(amount.into_iter()) {
res += self.inventory[&id] * amount as f64;
}
self.index += 1;
if self.index == self.n {
self.index = 0;
res * self.discount
} else {
res
}
}
}
#[test]
fn test() {
use assert_approx_eq::assert_approx_eq;
let mut cashier = Cashier::new(
3,
50,
vec![1, 2, 3, 4, 5, 6, 7],
vec![100, 200, 300, 400, 300, 200, 100],
);
assert_approx_eq!(cashier.get_bill(vec![1, 2], vec![1, 2]), 500.0);
assert_approx_eq!(cashier.get_bill(vec![3, 7], vec![10, 10]), 4000.0);
assert_approx_eq!(
cashier.get_bill(vec![1, 2, 3, 4, 5, 6, 7], vec![1, 1, 1, 1, 1, 1, 1]),
800.0
);
assert_approx_eq!(cashier.get_bill(vec![4], vec![10]), 4000.0);
assert_approx_eq!(cashier.get_bill(vec![7, 3], vec![10, 10]), 4000.0);
assert_approx_eq!(
cashier.get_bill(vec![7, 5, 3, 1, 6, 4, 2], vec![10, 10, 10, 9, 9, 9, 7]),
7350.0
);
assert_approx_eq!(cashier.get_bill(vec![2, 3, 5], vec![5, 3, 2]), 2500.0);
}
// Accepted solution for LeetCode #1357: Apply Discount Every n Orders
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #1357: Apply Discount Every n Orders
// class Cashier {
// private int i;
// private int n;
// private int discount;
// private Map<Integer, Integer> d = new HashMap<>();
//
// public Cashier(int n, int discount, int[] products, int[] prices) {
// this.n = n;
// this.discount = discount;
// for (int j = 0; j < products.length; ++j) {
// d.put(products[j], prices[j]);
// }
// }
//
// public double getBill(int[] product, int[] amount) {
// int dis = (++i) % n == 0 ? discount : 0;
// double ans = 0;
// for (int j = 0; j < product.length; ++j) {
// int p = product[j], a = amount[j];
// int x = d.get(p) * a;
// ans += x - (dis * x) / 100.0;
// }
// return ans;
// }
// }
//
// /**
// * Your Cashier object will be instantiated and called as such:
// * Cashier obj = new Cashier(n, discount, products, prices);
// * double param_1 = obj.getBill(product,amount);
// */
Use this to step through a reusable interview workflow for this problem.
Use a simple list or array for storage. Each operation (get, put, remove) requires a linear scan to find the target element — O(n) per operation. Space is O(n) to store the data. The linear search makes this impractical for frequent operations.
Design problems target O(1) amortized per operation by combining data structures (hash map + doubly-linked list for LRU, stack + min-tracking for MinStack). Space is always at least O(n) to store the data. The challenge is achieving constant-time operations through clever structure composition.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.