@@ -98,63 +98,104 @@ python -m codegen new <leetcode_id> --with-tests
9898
9999### 1.2 Solution File Structure
100100
101- Every solution file MUST include:
101+ Every solution file MUST follow this exact structure. See [ Solution Contract] ( ../contracts/solution-contract.md ) for complete specification.
102+
103+ #### Required Elements
104+
105+ | Element | Required | Description |
106+ | ---------| ----------| -------------|
107+ | File-level docstring | ✅ | Problem description with Link, Examples, Constraints |
108+ | ` from _runner import get_solver ` | ✅ | Required import for polymorphic dispatch |
109+ | ` SOLUTIONS ` dict | ✅ | Metadata with ` "default" ` key required |
110+ | Solution class(es) | ✅ | One or more classes implementing the solution |
111+ | ` JUDGE_FUNC ` | ✅ | Custom validation (required for pattern problems) |
112+ | ` solve() ` function | ✅ | Entry point for stdin/stdout execution |
113+
114+ #### Complete Solution Template
102115
103116``` python
104117# solutions/0496_next_greater_element_i.py
105118"""
106- LeetCode 496 - Next Greater Element I
107-
108- Problem: Given two arrays nums1 and nums2, find the next greater element
109- for each element in nums1 within nums2.
119+ Problem: Next Greater Element I
120+ Link: https://leetcode.com/problems/next-greater-element-i/
121+
122+ The next greater element of some element x in an array is the first greater
123+ element that is to the right of x in the same array.
124+ You are given two distinct 0-indexed integer arrays nums1 and nums2, where
125+ nums1 is a subset of nums2.
126+
127+ Example 1:
128+ Input: nums1 = [4,1,2], nums2 = [1,3,4,2]
129+ Output: [-1,3,-1]
130+ Explanation: The next greater element for each value of nums1 is as follows:
131+ - 4 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1.
132+ - 1 is underlined in nums2 = [1,3,4,2]. The next greater element is 3.
133+ - 2 is underlined in nums2 = [1,3,4,2]. There is no next greater element, so the answer is -1.
134+
135+ Example 2:
136+ Input: nums1 = [2,4], nums2 = [1,2,3,4]
137+ Output: [3,-1]
138+
139+ Constraints:
140+ - 1 <= nums1.length <= nums2.length <= 1000
141+ - 0 <= nums1[i], nums2[i] <= 10^4
142+ - All integers in nums1 and nums2 are unique.
143+ - All the integers of nums1 also appear in nums2.
110144
111- Pattern: Monotonic Stack (Next Greater Element)
112- Complexity: O(n + m) time, O(n) space
145+ Topics: Array, Hash Table, Stack, Monotonic Stack
113146"""
147+
114148import json
115149from typing import List
150+
116151from _runner import get_solver
117152
118- # ============================================================
119- # Solution Metadata
120- # ============================================================
121153
122154SOLUTIONS = {
123155 " default" : {
124- " class" : " SolutionStack" ,
156+ " class" : " SolutionMonotonicStack" ,
157+ " method" : " nextGreaterElement" ,
158+ " complexity" : " O(n + m) time, O(n) space" ,
159+ " description" : " Monotonic decreasing stack with hash map lookup" ,
160+ },
161+ " stack" : {
162+ " class" : " SolutionMonotonicStack" ,
125163 " method" : " nextGreaterElement" ,
126164 " complexity" : " O(n + m) time, O(n) space" ,
127- " description" : " Monotonic decreasing stack with hash map" ,
165+ " description" : " Monotonic decreasing stack with hash map lookup" ,
166+ },
167+ " brute" : {
168+ " class" : " SolutionBruteForce" ,
169+ " method" : " nextGreaterElement" ,
170+ " complexity" : " O(m * n) time, O(1) space" ,
171+ " description" : " Linear scan for each query element" ,
128172 },
129- # Add variants here if needed
130173}
131174
132- # ============================================================
133- # Solution Classes
134- # ============================================================
135-
136- class SolutionStack :
137- def nextGreaterElement (self , nums1 : List[int ], nums2 : List[int ]) -> List[int ]:
138- # Implementation here
139- pass
140-
141- # ============================================================
142- # JUDGE_FUNC (Required for generated tests)
143- # ============================================================
144175
176+ # ============================================================================
177+ # JUDGE_FUNC - Required for generator support
178+ # ============================================================================
145179def judge (actual , expected , input_data : str ) -> bool :
146180 """
147- Validate solution output.
181+ Validate result: check if actual output is the correct NGE array .
148182
149183 Args:
150- actual: Solution output (may be list or string )
151- expected: Expected output from .out file (None for generated tests )
152- input_data: Raw input string from .in file
184+ actual: Program output (list as string or list )
185+ expected: Expected output (None if from generator )
186+ input_data: Raw input string (nums1 and nums2 on separate lines)
153187
154188 Returns:
155- bool: True if output is correct
189+ bool: True if correct NGE results
156190 """
157- # Parse actual (handle both list and string types)
191+ lines = input_data.strip().split(" \n " )
192+ nums1 = json.loads(lines[0 ]) if lines[0 ] else []
193+ nums2 = json.loads(lines[1 ]) if len (lines) > 1 else []
194+
195+ # Compute correct answer using reference solution
196+ correct = _reference_nge(nums1, nums2)
197+
198+ # Parse actual output (may be list or string)
158199 if isinstance (actual, list ):
159200 actual_list = actual
160201 else :
@@ -164,57 +205,232 @@ def judge(actual, expected, input_data: str) -> bool:
164205 except (ValueError , json.JSONDecodeError):
165206 return False
166207
167- # For static tests: compare with expected
168- if expected is not None :
169- if isinstance (expected, list ):
170- return actual_list == expected
171- expected_str = expected.strip()
172- try :
173- expected_list = json.loads(expected_str) if expected_str else []
174- except (ValueError , json.JSONDecodeError):
175- return False
176- return actual_list == expected_list
208+ return actual_list == correct
177209
178- # For generated tests: validate using input
179- lines = input_data.strip().split(' \n ' )
180- nums1 = json.loads(lines[0 ])
181- nums2 = json.loads(lines[1 ])
182210
183- # Add validation logic here
184- return len (actual_list) == len (nums1)
211+ def _reference_nge (nums1 : List[int ], nums2 : List[int ]) -> List[int ]:
212+ """ O(n + m) reference using monotonic stack."""
213+ nge_map: dict[int , int ] = {}
214+ stack: list[int ] = []
215+
216+ for num in nums2:
217+ while stack and stack[- 1 ] < num:
218+ nge_map[stack.pop()] = num
219+ stack.append(num)
220+
221+ return [nge_map.get(x, - 1 ) for x in nums1]
222+
185223
186224JUDGE_FUNC = judge
187225
188- # ============================================================
189- # Entry Point
190- # ============================================================
226+
227+ # ============================================================================
228+ # Solution 1: Monotonic Decreasing Stack + Hash Map
229+ # Time: O(n + m), Space: O(n)
230+ # - Precompute NGE for all elements in nums2 using monotonic stack
231+ # - Stack stores indices of candidates awaiting their next greater element
232+ # - When a larger element appears, it becomes NGE for all smaller candidates
233+ # - Hash map enables O(1) lookup for nums1 queries
234+ #
235+ # Key Insight: The stack maintains a decreasing sequence of unresolved elements.
236+ # When we encounter a larger element, it "resolves" all smaller elements on top.
237+ # ============================================================================
238+ class SolutionMonotonicStack :
239+ def nextGreaterElement (self , nums1 : List[int ], nums2 : List[int ]) -> List[int ]:
240+ next_greater_map: dict[int , int ] = {}
241+ candidate_stack: list[int ] = [] # Stores values (not indices) since unique
242+
243+ # Build NGE map: process nums2 to find next greater for each element
244+ for current_value in nums2:
245+ # Resolve all candidates that found their next greater element
246+ while candidate_stack and candidate_stack[- 1 ] < current_value:
247+ resolved_value = candidate_stack.pop()
248+ next_greater_map[resolved_value] = current_value
249+
250+ # Current element becomes a new candidate awaiting its NGE
251+ candidate_stack.append(current_value)
252+
253+ # Elements remaining in stack have no next greater element
254+ # They will return -1 via dict.get() default
255+
256+ # Look up NGE for each query element
257+ return [next_greater_map.get(query, - 1 ) for query in nums1]
258+
259+
260+ # ============================================================================
261+ # Solution 2: Brute Force Linear Scan
262+ # Time: O(m * n), Space: O(1)
263+ # - For each element in nums1, find its position in nums2
264+ # - Scan right from that position to find the first greater element
265+ # - Simple but inefficient for large inputs
266+ #
267+ # Educational Value: Establishes baseline before optimization.
268+ # ============================================================================
269+ class SolutionBruteForce :
270+ def nextGreaterElement (self , nums1 : List[int ], nums2 : List[int ]) -> List[int ]:
271+ result: list[int ] = []
272+ nums2_length = len (nums2)
273+
274+ for query in nums1:
275+ # Find position of query element in nums2
276+ position = nums2.index(query)
277+
278+ # Scan rightward for next greater element
279+ next_greater = - 1
280+ for scan_idx in range (position + 1 , nums2_length):
281+ if nums2[scan_idx] > query:
282+ next_greater = nums2[scan_idx]
283+ break
284+
285+ result.append(next_greater)
286+
287+ return result
288+
191289
192290def solve ():
291+ """
292+ Input format (JSON per line):
293+ Line 1: nums1 as JSON array
294+ Line 2: nums2 as JSON array
295+
296+ Output format:
297+ JSON array of next greater elements
298+ """
193299 import sys
194- data = sys.stdin.read().strip().split(' \n ' )
195- nums1 = json.loads(data[0 ])
196- nums2 = json.loads(data[1 ])
300+
301+ lines = sys.stdin.read().strip().split(" \n " )
302+ nums1 = json.loads(lines[0 ])
303+ nums2 = json.loads(lines[1 ])
197304
198305 solver = get_solver(SOLUTIONS )
199306 result = solver.nextGreaterElement(nums1, nums2)
200- print (json.dumps(result, separators = (' ,' , ' :' )))
307+
308+ print (json.dumps(result))
309+
201310
202311if __name__ == " __main__" :
203312 solve()
204313```
205314
206- ### 1.3 JUDGE_FUNC Requirements
315+ ### 1.3 File-Level Docstring Requirements
316+
317+ The docstring MUST include:
318+
319+ | Field | Required | Format |
320+ | -------| ----------| --------|
321+ | ` Problem: ` | ✅ | Problem title |
322+ | ` Link: ` | ✅ | ` https://leetcode.com/problems/{slug}/ ` (NO ` /description/ ` suffix) |
323+ | Description | ✅ | Problem statement |
324+ | ` Example N: ` | ✅ | At least one example with Input/Output/Explanation |
325+ | ` Constraints: ` | ✅ | All LeetCode constraints |
326+ | ` Topics: ` | Recommended | LeetCode topic tags |
327+
328+ ### 1.4 SOLUTIONS Dict Requirements
329+
330+ | Rule | Requirement |
331+ | ------| -------------|
332+ | ` "default" ` key | ✅ REQUIRED - used when no ` --method ` flag specified |
333+ | ` "class" ` field | ✅ REQUIRED - must match actual class name in file |
334+ | ` "method" ` field | ✅ REQUIRED - must match LeetCode method signature |
335+ | ` "complexity" ` field | Recommended - e.g., ` "O(n) time, O(n) space" ` |
336+ | ` "description" ` field | Recommended - brief algorithm description |
337+
338+ ### 1.5 Solution Block Comment Format
339+
340+ ** CRITICAL** : No blank line between comment block and class definition.
341+
342+ ``` python
343+ # ============================================================================
344+ # Solution N: {Approach Name}
345+ # Time: O(?), Space: O(?)
346+ # - {Key insight 1}
347+ # - {Key insight 2}
348+ # - {Implementation detail}
349+ #
350+ # {Optional extended explanation}
351+ # ============================================================================
352+ class SolutionName : # ← NO blank line here
353+ def methodName (self , ...):
354+ ...
355+ ```
356+
357+ ### 1.6 JUDGE_FUNC Requirements
207358
208359The ` JUDGE_FUNC ` is ** mandatory** for pattern problems. Key requirements:
209360
210361| Requirement | Description |
211362| -------------| -------------|
212363| Handle both types | ` actual ` may be ` list ` or ` str ` depending on context |
213364| Support ` expected=None ` | Generated tests have no expected output |
214- | Parse ` input_data ` | Use input to validate correctness |
365+ | Reference solution | Include ` _reference_{name}() ` helper to compute correct answer |
366+ | Parse ` input_data ` | Use ` json.loads() ` to parse input |
215367| Return boolean | ` True ` for pass, ` False ` for fail |
216368
217- > ** Reference** : [ Solution Contract] ( ../contracts/solution-contract.md#judge_func-specification )
369+ #### JUDGE_FUNC Template
370+
371+ ``` python
372+ def judge (actual , expected , input_data : str ) -> bool :
373+ """ Validate result."""
374+ # 1. Parse input
375+ lines = input_data.strip().split(" \n " )
376+ param1 = json.loads(lines[0 ])
377+ param2 = json.loads(lines[1 ]) if len (lines) > 1 else None
378+
379+ # 2. Compute correct answer using reference
380+ correct = _reference_solution(param1, param2)
381+
382+ # 3. Parse actual (handle both list and string)
383+ if isinstance (actual, list ):
384+ actual_list = actual
385+ else :
386+ actual_str = actual.strip()
387+ try :
388+ actual_list = json.loads(actual_str) if actual_str else []
389+ except (ValueError , json.JSONDecodeError):
390+ return False
391+
392+ # 4. Compare
393+ return actual_list == correct
394+
395+
396+ def _reference_solution (param1 , param2 ):
397+ """ Reference implementation for validation."""
398+ # Implement correct algorithm here
399+ pass
400+
401+
402+ JUDGE_FUNC = judge
403+ ```
404+
405+ ### 1.7 solve() Function Requirements
406+
407+ ``` python
408+ def solve ():
409+ """
410+ Input format (JSON per line):
411+ Line 1: {param1 description}
412+ Line 2: {param2 description}
413+
414+ Output format:
415+ {output description}
416+ """
417+ import sys
418+
419+ lines = sys.stdin.read().strip().split(" \n " )
420+ param1 = json.loads(lines[0 ])
421+ param2 = json.loads(lines[1 ])
422+
423+ solver = get_solver(SOLUTIONS )
424+ result = solver.methodName(param1, param2)
425+
426+ print (json.dumps(result)) # Use json.dumps for arrays
427+
428+
429+ if __name__ == " __main__" :
430+ solve()
431+ ```
432+
433+ > ** Reference** : [ Solution Contract] ( ../contracts/solution-contract.md )
218434
219435---
220436
0 commit comments