Skip to content

Commit 983b40d

Browse files
Solution #3606 - Kailash Senthilkumar - 09/08/2025
1 parent 4ec8fe3 commit 983b40d

File tree

4 files changed

+226
-0
lines changed

4 files changed

+226
-0
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Coupon Code Validator
2+
3+
**Difficulty:** Easy
4+
**Category:** String, Sorting, Simulation
5+
**Leetcode Link:** [Problem Link](https://leetcode.com/problems/coupon-code-validator/)
6+
7+
---
8+
9+
## 📝 Introduction
10+
11+
We are given three arrays of length `n` describing the properties of `n` coupons:
12+
- `code[i]`: A string representing the coupon identifier.
13+
- `businessLine[i]`: A string denoting the business category of the coupon.
14+
- `isActive[i]`: A boolean indicating whether the coupon is active.
15+
16+
A coupon is valid if:
17+
1. `code[i]` is non-empty and contains only **alphanumeric characters** (`a-z, A-Z, 0-9`) and underscores (`_`).
18+
2. `businessLine[i]` is one of the following: `"electronics"`, `"grocery"`, `"pharmacy"`, `"restaurant"`.
19+
3. `isActive[i] == true`.
20+
21+
We must return an array of valid coupon codes, **sorted first by businessLine** in the order:
22+
```
23+
electronics → grocery → pharmacy → restaurant
24+
```
25+
and then by `code` in lexicographical ascending order **within the same category**.
26+
27+
---
28+
29+
## 💡 Approach & Key Insights
30+
31+
1. **Validation**:
32+
- Ensure `code[i]` is not empty and contains only `[a-zA-Z0-9_]`.
33+
- Ensure `businessLine[i]` is in the allowed categories set.
34+
- Ensure `isActive[i]` is `true`.
35+
36+
2. **Sorting**:
37+
- Create a custom order mapping for categories:
38+
```
39+
electronics → 0, grocery → 1, pharmacy → 2, restaurant → 3
40+
```
41+
- Sort first by category order, then lexicographically by code.
42+
43+
3. **Output**:
44+
- Extract and return only the coupon codes from the valid list after sorting.
45+
46+
---
47+
48+
## 🛠️ Breakdown of Approaches
49+
50+
### 1️⃣ Brute Force / Naive Approach
51+
52+
- **Explanation:**
53+
Loop over all coupons, validate each one, and store valid ones in a list. Sort using default string sorting and then reorder by category.
54+
- **Time Complexity:** O(n log n) — due to sorting.
55+
- **Space Complexity:** O(n) — storing valid coupons.
56+
57+
---
58+
59+
### 2️⃣ Optimized Approach
60+
61+
- **Explanation:**
62+
While validating, store valid coupons as pairs `(businessLine, code)`.
63+
Sort using a custom comparator that compares category order first, then `code`.
64+
- **Time Complexity:** O(n log n) — sorting dominates.
65+
- **Space Complexity:** O(n) — storing valid coupons.
66+
67+
Example:
68+
```
69+
code = ["SAVE20", "", "PHARMA5", "SAVE@20"]
70+
businessLine = ["restaurant", "grocery", "pharmacy", "restaurant"]
71+
isActive = [true, true, true, true]
72+
73+
Valid coupons after filtering:
74+
[("restaurant", "SAVE20"), ("pharmacy", "PHARMA5")]
75+
76+
After sorting by category order then code:
77+
[("pharmacy", "PHARMA5"), ("restaurant", "SAVE20")]
78+
79+
Output: ["PHARMA5", "SAVE20"]
80+
```
81+
82+
---
83+
84+
## 📊 Complexity Analysis
85+
86+
| Approach | Time Complexity | Space Complexity |
87+
| ---------- | --------------- | ---------------- |
88+
| Validation | O(n) | O(n) |
89+
| Sorting | O(n log n) | O(n) |
90+
91+
---
92+
93+
## 📌 Example Walkthroughs & Dry Runs
94+
95+
Example 1:
96+
```
97+
Input:
98+
code = ["SAVE20", "", "PHARMA5", "SAVE@20"]
99+
businessLine = ["restaurant", "grocery", "pharmacy", "restaurant"]
100+
isActive = [true, true, true, true]
101+
102+
Valid after filtering:
103+
[("restaurant", "SAVE20"), ("pharmacy", "PHARMA5")]
104+
105+
Sorted:
106+
[("pharmacy", "PHARMA5"), ("restaurant", "SAVE20")]
107+
108+
Output:
109+
["PHARMA5", "SAVE20"]
110+
```
111+
112+
Example 2:
113+
```
114+
Input:
115+
code = ["GROCERY15", "ELECTRONICS_50", "DISCOUNT10"]
116+
businessLine = ["grocery", "electronics", "invalid"]
117+
isActive = [false, true, true]
118+
119+
Valid after filtering:
120+
[("electronics", "ELECTRONICS_50")]
121+
122+
Output:
123+
["ELECTRONICS_50"]
124+
```
125+
126+
---
127+
128+
## 🔗 Additional Resources
129+
130+
- [Regular Expressions in Java](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html)
131+
- [Python: all() function](https://docs.python.org/3/library/functions.html#all)
132+
- [C++ isalnum function](https://www.cplusplus.com/reference/cctype/isalnum/)
133+
134+
---
135+
136+
Author: Kailash Senthilkumar
137+
Date: 09/08/2025
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include <bits/stdc++.h>
2+
using namespace std;
3+
4+
class Solution {
5+
public:
6+
vector<string> validCoupons(vector<string>& code, vector<string>& businessLine, vector<bool>& isActive) {
7+
unordered_set<string> validCategories = {"electronics", "grocery", "pharmacy", "restaurant"};
8+
unordered_map<string, int> categoryOrder = {
9+
{"electronics", 0},
10+
{"grocery", 1},
11+
{"pharmacy", 2},
12+
{"restaurant", 3}
13+
};
14+
15+
vector<pair<string, string>> validList;
16+
for (int i = 0; i < code.size(); i++) {
17+
bool validCode = !code[i].empty() && all_of(code[i].begin(), code[i].end(),
18+
[](char ch) { return isalnum(ch) || ch == '_'; });
19+
20+
if (isActive[i] && validCategories.count(businessLine[i]) && validCode) {
21+
validList.push_back({businessLine[i], code[i]});
22+
}
23+
}
24+
25+
sort(validList.begin(), validList.end(), [&](auto &a, auto &b) {
26+
if (categoryOrder[a.first] != categoryOrder[b.first])
27+
return categoryOrder[a.first] < categoryOrder[b.first];
28+
return a.second < b.second;
29+
});
30+
31+
vector<string> result;
32+
for (auto &p : validList) result.push_back(p.second);
33+
return result;
34+
}
35+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class Solution {
2+
public List<String> validateCoupons(String[] code, String[] businessLine, boolean[] isActive) {
3+
Set<String> validCategories = new HashSet<>(Arrays.asList("electronics", "grocery", "pharmacy", "restaurant"));
4+
Map<String, Integer> categoryOrder = Map.of(
5+
"electronics", 0,
6+
"grocery", 1,
7+
"pharmacy", 2,
8+
"restaurant", 3
9+
);
10+
11+
List<String[]> validList = new ArrayList<>();
12+
for (int i = 0; i < code.length; i++) {
13+
if (isActive[i] &&
14+
validCategories.contains(businessLine[i]) &&
15+
code[i] != null && !code[i].isEmpty() &&
16+
code[i].matches("[a-zA-Z0-9_]+")) {
17+
validList.add(new String[]{businessLine[i], code[i]});
18+
}
19+
}
20+
21+
validList.sort((a, b) -> {
22+
int cmp = Integer.compare(categoryOrder.get(a[0]), categoryOrder.get(b[0]));
23+
if (cmp != 0) return cmp;
24+
return a[1].compareTo(b[1]);
25+
});
26+
27+
List<String> result = new ArrayList<>();
28+
for (String[] item : validList) {
29+
result.add(item[1]);
30+
}
31+
32+
return result;
33+
}
34+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
class Solution:
2+
def validCoupons(self, code, businessLine, isActive):
3+
valid_categories = {"electronics", "grocery", "pharmacy", "restaurant"}
4+
category_order = {
5+
"electronics": 0,
6+
"grocery": 1,
7+
"pharmacy": 2,
8+
"restaurant": 3
9+
}
10+
11+
valid_list = []
12+
for c, b, active in zip(code, businessLine, isActive):
13+
if (active and
14+
b in valid_categories and
15+
len(c) > 0 and
16+
all(ch.isalnum() or ch == '_' for ch in c)):
17+
valid_list.append((b, c))
18+
19+
valid_list.sort(key=lambda x: (category_order[x[0]], x[1]))
20+
return [c for _, c in valid_list]

0 commit comments

Comments
 (0)