From c756576a550e3959cc15070985aafd23ae0e201c Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Sat, 24 Oct 2026 11:25:19 +0800 Subject: [PATCH] test: migrate LeetCode 2351 to new directory structure with tests and docs Move "First Letter to Appear Twice" from the legacy Hash Table directory to problems/easy/first_letter_to_appear_twice_2351/, add parametrized tests, document the solution with time and space complexity analysis, and update README.md and docs/EASY.md (62 easy / 90 total). --- .../2351. First Letter to Appear Twice.py | 8 ---- README.md | 4 +- docs/EASY.md | 3 +- .../__init__.py | 0 .../solution.py | 45 +++++++++++++++++++ .../test_solution.py | 14 ++++++ 6 files changed, 63 insertions(+), 11 deletions(-) delete mode 100644 Hash Table/2351. First Letter to Appear Twice.py create mode 100644 problems/easy/first_letter_to_appear_twice_2351/__init__.py create mode 100644 problems/easy/first_letter_to_appear_twice_2351/solution.py create mode 100644 problems/easy/first_letter_to_appear_twice_2351/test_solution.py diff --git a/Hash Table/2351. First Letter to Appear Twice.py b/Hash Table/2351. First Letter to Appear Twice.py deleted file mode 100644 index 555f6a0..0000000 --- a/Hash Table/2351. First Letter to Appear Twice.py +++ /dev/null @@ -1,8 +0,0 @@ -class Solution: - def repeatedCharacter(self, s: str) -> str: - hash_set = set() - for c in s: - if c not in hash_set: - hash_set.add(c) - else: - return c diff --git a/README.md b/README.md index 094c437..c9bd39f 100644 --- a/README.md +++ b/README.md @@ -41,11 +41,11 @@ Each problem follows this structure: ## Solutions -📊 **Statistics**: 89 problems solved (migrated to new structure) +📊 **Statistics**: 90 problems solved (migrated to new structure) | Difficulty | Count | |------------|-------| -| Easy | 61 | +| Easy | 62 | | Medium | 26 | | Hard | 2 | diff --git a/docs/EASY.md b/docs/EASY.md index 954794e..1b627a3 100644 --- a/docs/EASY.md +++ b/docs/EASY.md @@ -1,6 +1,6 @@ # Easy Problems -Total: 61 problems solved +Total: 62 problems solved ## Solutions @@ -60,6 +60,7 @@ Total: 61 problems solved | 2185 | [Counting Words With a Given Prefix](https://leetcode.com/problems/counting-words-with-a-given-prefix/) | [solution.py](../problems/easy/counting_words_with_a_given_prefix_2185/solution.py) | [test_solution.py](../problems/easy/counting_words_with_a_given_prefix_2185/test_solution.py) | | 2215 | [Find the Difference of Two Arrays](https://leetcode.com/problems/find-the-difference-of-two-arrays/) | [solution.py](../problems/easy/find_the_difference_of_two_arrays_2215/solution.py) | [test_solution.py](../problems/easy/find_the_difference_of_two_arrays_2215/test_solution.py) | | 2315 | [Count Asterisks](https://leetcode.com/problems/count-asterisks/) | [solution.py](../problems/easy/count_asterisks_2315/solution.py) | [test_solution.py](../problems/easy/count_asterisks_2315/test_solution.py) | +| 2351 | [First Letter to Appear Twice](https://leetcode.com/problems/first-letter-to-appear-twice/) | [solution.py](../problems/easy/first_letter_to_appear_twice_2351/solution.py) | [test_solution.py](../problems/easy/first_letter_to_appear_twice_2351/test_solution.py) | | 2469 | [Convert the Temperature](https://leetcode.com/problems/convert-the-temperature/) | [solution.py](../problems/easy/convert_the_temperature_2469/solution.py) | [test_solution.py](../problems/easy/convert_the_temperature_2469/test_solution.py) | | 2710 | [Remove Trailing Zeros From a String](https://leetcode.com/problems/remove-trailing-zeros-from-a-string/) | [solution.py](../problems/easy/remove_trailing_zeros_from_a_string_2710/solution.py) | [test_solution.py](../problems/easy/remove_trailing_zeros_from_a_string_2710/test_solution.py) | | 2798 | [Number of Employees Who Met the Target](https://leetcode.com/problems/number-of-employees-who-met-the-target/) | [solution.py](../problems/easy/number_of_employees_who_met_the_target_2798/solution.py) | [test_solution.py](../problems/easy/number_of_employees_who_met_the_target_2798/test_solution.py) | diff --git a/problems/easy/first_letter_to_appear_twice_2351/__init__.py b/problems/easy/first_letter_to_appear_twice_2351/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/problems/easy/first_letter_to_appear_twice_2351/solution.py b/problems/easy/first_letter_to_appear_twice_2351/solution.py new file mode 100644 index 0000000..9020376 --- /dev/null +++ b/problems/easy/first_letter_to_appear_twice_2351/solution.py @@ -0,0 +1,45 @@ +# Tags: Hash Table, String +class Solution: + def repeated_character(self, s: str) -> str: + """ + Return the first letter whose second occurrence appears earliest in s. + + Args: + s: Input string of lowercase English letters in which at least one + letter appears twice. + + Returns: + The first letter to appear twice, i.e. the letter whose second + occurrence has the smallest index. + + Time complexity: O(n) + - n is the length of s, k is the number of distinct letters (k <= n) + - The for loop visits each character at most once, so at most n iterations + - Each iteration does one set membership test (`c in seen`) and at most + one set insertion (`seen.add(c)`), both O(1) on average + - Cost per iteration is O(1), so the total is O(n) * O(1) = O(n) + - Best case: the first repeat is found early (e.g. "aa") and the loop + returns after 2 iterations: O(1) + - Worst case: the repeat is at the very end, so the loop runs through + all n characters: O(n) + - Hash collisions could degrade set operations to O(k) in theory, but + with single-character keys this is not a practical concern + - Under the problem constraints (lowercase letters only), the loop runs + at most 27 iterations (26 distinct letters + 1 repeat), because by the + pigeonhole principle the 27th character must repeat an earlier one, + so the time is effectively O(1) + + Space complexity: O(k) + - The set `seen` stores each distinct letter at most once: O(k) + - Because the loop returns on the first repeat, `seen` never holds more + than min(n, alphabet size) letters + - No recursion, slicing or copying, so there is no extra call stack or + temporary storage; the returned single character is O(1) + - With a fixed alphabet of 26 lowercase letters, k <= 26, so the + auxiliary space is O(1) + """ + seen = set() + for c in s: + if c in seen: + return c + seen.add(c) diff --git a/problems/easy/first_letter_to_appear_twice_2351/test_solution.py b/problems/easy/first_letter_to_appear_twice_2351/test_solution.py new file mode 100644 index 0000000..9ac6175 --- /dev/null +++ b/problems/easy/first_letter_to_appear_twice_2351/test_solution.py @@ -0,0 +1,14 @@ +import pytest +from tests.base_test import BaseTestSolution +from .solution import Solution + + +class TestSolution(BaseTestSolution): + solution = Solution() + + @pytest.mark.parametrize("method_name, s, expected, timeout", [ + ('repeated_character', "abccbaacz", "c", BaseTestSolution.DEFAULT_TIMEOUT), + ('repeated_character', "abcdd", "d", BaseTestSolution.DEFAULT_TIMEOUT), + ]) + def test_repeated_character(self, method_name, s, expected, timeout): + self._run_test(self.solution, method_name, (s,), expected, timeout)