Complete documentation system with 81 comprehensive notes and updated README index

This commit is contained in:
Carlos Gutierrez
2025-08-05 21:51:19 -04:00
parent fe26a41065
commit e41888ef39
81 changed files with 10035 additions and 82 deletions

2
.gitignore vendored
View File

@@ -1,7 +1,7 @@
# Created by https://www.toptal.com/developers/gitignore/api/node,java,python,c++ # Created by https://www.toptal.com/developers/gitignore/api/node,java,python,c++
# Edit at https://www.toptal.com/developers/gitignore?templates=node,java,python,c++ # Edit at https://www.toptal.com/developers/gitignore?templates=node,java,python,c++
.cursor* .cursor*
*src/notes* # *src/notes*
*backup/ *backup/
./src/notes/ ./src/notes/
*sync_leetcode.sh *sync_leetcode.sh

162
README.md
View File

@@ -27,87 +27,87 @@ This repo tracks my journey solving LeetCode problems — not just code, but my
## 🧩 Problem Index ## 🧩 Problem Index
| # | LeetCode # | Title | Difficulty | Technology | | # | LeetCode # | Title | Difficulty | Technology | Notes |
|---|------------|-------|------------|------------| |---|------------|-------|------------|------------|-------|
| 1 | 001 | [Two Sum](src/exercises/1.two-sum.py) | Easy | Python | | 1 | 001 | [Two Sum](src/exercises/1.two-sum.py) | Easy | Python | [📝](src/notes/001_two_sum.md) |
| 2 | 002 | [Add Two Numbers](src/exercises/2.add-two-numbers.py) | Medium | Python | | 2 | 002 | [Add Two Numbers](src/exercises/2.add-two-numbers.py) | Medium | Python | [📝](src/notes/002_add_two_numbers.md) |
| 3 | 003 | [Longest Substring Without Repeating Characters](src/exercises/3.longest-substring-without-repeating-characters.py) | Medium | Python | | 3 | 003 | [Longest Substring Without Repeating Characters](src/exercises/3.longest-substring-without-repeating-characters.py) | Medium | Python | [📝](src/notes/003_longest_substring_without_repeating_characters.md) |
| 4 | 004 | [Median of Two Sorted Arrays](src/exercises/4.median-of-two-sorted-arrays.py) | Hard | Python | | 4 | 004 | [Median of Two Sorted Arrays](src/exercises/4.median-of-two-sorted-arrays.py) | Hard | Python | [📝](src/notes/004_median_of_two_sorted_arrays.md) |
| 5 | 005 | [Longest Palindromic Substring](src/exercises/5.longest-palindromic-substring.py) | Medium | Python | | 5 | 005 | [Longest Palindromic Substring](src/exercises/5.longest-palindromic-substring.py) | Medium | Python | [📝](src/notes/005_longest_palindromic_substring.md) |
| 6 | 009 | [Palindrome Number](src/exercises/9.palindrome-number.py) | Easy | Python | | 6 | 009 | [Palindrome Number](src/exercises/9.palindrome-number.py) | Easy | Python | [📝](src/notes/009_palindrome_number.md) |
| 7 | 011 | [Container With Most Water](src/exercises/11.container-with-most-water.py) | Medium | Python | | 7 | 011 | [Container With Most Water](src/exercises/11.container-with-most-water.py) | Medium | Python | [📝](src/notes/011_container_with_most_water.md) |
| 8 | 013 | [Roman to Integer](src/exercises/13.roman-to-integer.py) | Easy | Python | | 8 | 013 | [Roman to Integer](src/exercises/13.roman-to-integer.py) | Easy | Python | [📝](src/notes/013_roman_to_integer.md) |
| 9 | 014 | [Longest Common Prefix](src/exercises/14.longest-common-prefix.py) | Easy | Python | | 9 | 014 | [Longest Common Prefix](src/exercises/14.longest-common-prefix.py) | Easy | Python | [📝](src/notes/014_longest_common_prefix.md) |
| 10 | 015 | [3Sum](src/exercises/15.3sum.py) | Medium | Python | | 10 | 015 | [3Sum](src/exercises/15.3sum.py) | Medium | Python | [📝](src/notes/015_3sum.md) |
| 11 | 020 | [Valid Parentheses](src/exercises/20.valid-parentheses.py) | Easy | Python | | 11 | 020 | [Valid Parentheses](src/exercises/20.valid-parentheses.py) | Easy | Python | [📝](src/notes/020_valid_parentheses.md) |
| 12 | 022 | [Generate Parentheses](src/exercises/22.generate-parentheses.py) | Medium | Python | | 12 | 022 | [Generate Parentheses](src/exercises/22.generate-parentheses.py) | Medium | Python | [📝](src/notes/022_generate_parentheses.md) |
| 13 | 026 | [Remove Duplicates from Sorted Array](src/exercises/26.remove-duplicates-from-sorted-array.py) | Easy | Python | | 13 | 026 | [Remove Duplicates from Sorted Array](src/exercises/26.remove-duplicates-from-sorted-array.py) | Easy | Python | [📝](src/notes/026_remove_duplicates_from_sorted_array.md) |
| 14 | 027 | [Remove Element](src/exercises/27.remove-element.py) | Easy | Python | | 14 | 027 | [Remove Element](src/exercises/27.remove-element.py) | Easy | Python | [📝](src/notes/027_remove_element.md) |
| 15 | 028 | [Find the Index of the First Occurrence in a String](src/exercises/28.find-the-index-of-the-first-occurrence-in-a-string.py) | Easy | Python | | 15 | 028 | [Find the Index of the First Occurrence in a String](src/exercises/28.find-the-index-of-the-first-occurrence-in-a-string.py) | Easy | Python | [📝](src/notes/028_find_the_index_of_the_first_occurrence_in_a_string.md) |
| 16 | 035 | [Search Insert Position](src/exercises/35.search-insert-position.py) | Easy | Python | | 16 | 035 | [Search Insert Position](src/exercises/35.search-insert-position.py) | Easy | Python | [📝](src/notes/035_search_insert_position.md) |
| 17 | 036 | [Valid Sudoku](src/exercises/36.valid-sudoku.py) | Medium | Python | | 17 | 036 | [Valid Sudoku](src/exercises/36.valid-sudoku.py) | Medium | Python | [📝](src/notes/036_valid_sudoku.md) |
| 18 | 042 | [Trapping Rain Water](src/exercises/42.trapping-rain-water.py) | Hard | Python | | 18 | 042 | [Trapping Rain Water](src/exercises/42.trapping-rain-water.py) | Hard | Python | [📝](src/notes/042_trapping_rain_water.md) |
| 19 | 049 | [Group Anagrams](src/exercises/49.group-anagrams.js) | Medium | JavaScript | | 19 | 049 | [Group Anagrams](src/exercises/49.group-anagrams.js) | Medium | JavaScript | [📝](src/notes/049_group_anagrams.md) |
| 20 | 050 | [Pow(x, n)](src/exercises/50.powx-n.py) | Medium | Python | | 20 | 050 | [Pow(x, n)](src/exercises/50.powx-n.py) | Medium | Python | [📝](src/notes/050_powx_n.md) |
| 21 | 055 | [Jump Game](src/exercises/55.jump-game.py) | Medium | Python | | 21 | 055 | [Jump Game](src/exercises/55.jump-game.py) | Medium | Python | [📝](src/notes/055_jump_game.md) |
| 22 | 058 | [Length of Last Word](src/exercises/58.length-of-last-word.py) | Easy | Python | | 22 | 058 | [Length of Last Word](src/exercises/58.length-of-last-word.py) | Easy | Python | [📝](src/notes/058_length_of_last_word.md) |
| 23 | 066 | [Plus One](src/exercises/66.plus-one.py) | Easy | Python | | 23 | 066 | [Plus One](src/exercises/66.plus-one.py) | Easy | Python | [📝](src/notes/066_plus_one.md) |
| 24 | 069 | [Sqrt(x)](src/exercises/69.sqrtx.py) | Easy | Python | | 24 | 069 | [Sqrt(x)](src/exercises/69.sqrtx.py) | Easy | Python | [📝](src/notes/069_sqrtx.md) |
| 25 | 070 | [Climbing Stairs](src/exercises/70.climbing-stairs.js) | Easy | JavaScript | | 25 | 070 | [Climbing Stairs](src/exercises/70.climbing-stairs.js) | Easy | JavaScript | [📝](src/notes/070_climbing_stairs.md) |
| 26 | 074 | [Search a 2D Matrix](src/exercises/74.search-a-2d-matrix.py) | Medium | Python | | 26 | 074 | [Search a 2D Matrix](src/exercises/74.search-a-2d-matrix.py) | Medium | Python | [📝](src/notes/074_search_a_2d_matrix.md) |
| 27 | 080 | [Remove Duplicates from Sorted Array II](src/exercises/80.remove-duplicates-from-sorted-array-ii.py) | Medium | Python | | 27 | 080 | [Remove Duplicates from Sorted Array II](src/exercises/80.remove-duplicates-from-sorted-array-ii.py) | Medium | Python | [📝](src/notes/080_remove_duplicates_from_sorted_array_ii.md) |
| 28 | 088 | [Merge Sorted Array](src/exercises/88.merge-sorted-array.py) | Easy | Python | | 28 | 088 | [Merge Sorted Array](src/exercises/88.merge-sorted-array.py) | Easy | Python | [📝](src/notes/088_merge_sorted_array.md) |
| 29 | 089 | [Gray Code](src/exercises/89.gray-code.py) | Medium | Python | | 29 | 089 | [Gray Code](src/exercises/89.gray-code.py) | Medium | Python | [📝](src/notes/089_gray_code.md) |
| 30 | 090 | [Subsets II](src/exercises/90.subsets-ii.py) | Medium | Python | | 30 | 090 | [Subsets II](src/exercises/90.subsets-ii.py) | Medium | Python | [📝](src/notes/090_subsets_ii.md) |
| 31 | 091 | [Decode Ways](src/exercises/91.decode-ways.py) | Medium | Python | | 31 | 091 | [Decode Ways](src/exercises/91.decode-ways.py) | Medium | Python | [📝](src/notes/091_decode_ways.md) |
| 32 | 104 | [Maximum Depth of Binary Tree](src/exercises/104.maximum-depth-of-binary-tree.py) | Easy | Python | | 32 | 104 | [Maximum Depth of Binary Tree](src/exercises/104.maximum-depth-of-binary-tree.py) | Easy | Python | [📝](src/notes/104_maximum_depth_of_binary_tree.md) |
| 33 | 121 | [Best Time to Buy and Sell Stock](src/exercises/121.best-time-to-buy-and-sell-stock.py) | Easy | Python | | 33 | 121 | [Best Time to Buy and Sell Stock](src/exercises/121.best-time-to-buy-and-sell-stock.py) | Easy | Python | [📝](src/notes/121_best_time_to_buy_and_sell_stock.md) |
| 34 | 122 | [Best Time to Buy and Sell Stock II](src/exercises/122.best-time-to-buy-and-sell-stock-ii.py) | Medium | Python | | 34 | 122 | [Best Time to Buy and Sell Stock II](src/exercises/122.best-time-to-buy-and-sell-stock-ii.py) | Medium | Python | [📝](src/notes/122_best_time_to_buy_and_sell_stock_ii.md) |
| 35 | 125 | [Valid Palindrome](src/exercises/125.valid-palindrome.py) | Easy | Python | | 35 | 125 | [Valid Palindrome](src/exercises/125.valid-palindrome.py) | Easy | Python | [📝](src/notes/125_valid_palindrome.md) |
| 36 | 128 | [Longest Consecutive Sequence](src/exercises/128.longest-consecutive-sequence.py) | Medium | Python | | 36 | 128 | [Longest Consecutive Sequence](src/exercises/128.longest-consecutive-sequence.py) | Medium | Python | [📝](src/notes/128_longest_consecutive_sequence.md) |
| 37 | 135 | [Candy](src/exercises/135.candy.py) | Hard | Python | | 37 | 135 | [Candy](src/exercises/135.candy.py) | Hard | Python | [📝](src/notes/135_candy.md) |
| 38 | 141 | [Linked List Cycle](src/exercises/141.linked-list-cycle.py) | Easy | Python | | 38 | 141 | [Linked List Cycle](src/exercises/141.linked-list-cycle.py) | Easy | Python | [📝](src/notes/141_linked_list_cycle.md) |
| 39 | 149 | [Max Points on a Line](src/exercises/149.max-points-on-a-line.py) | Hard | Python | | 39 | 149 | [Max Points on a Line](src/exercises/149.max-points-on-a-line.py) | Hard | Python | [📝](src/notes/149_max_points_on_a_line.md) |
| 40 | 151 | [Reverse Words in a String](src/exercises/151.reverse-words-in-a-string.py) | Medium | Python | | 40 | 151 | [Reverse Words in a String](src/exercises/151.reverse-words-in-a-string.py) | Medium | Python | [📝](src/notes/151_reverse_words_in_a_string.md) |
| 41 | 153 | [Find Minimum in Rotated Sorted Array](src/exercises/153.find-minimum-in-rotated-sorted-array.py) | Medium | Python | | 41 | 153 | [Find Minimum in Rotated Sorted Array](src/exercises/153.find-minimum-in-rotated-sorted-array.py) | Medium | Python | [📝](src/notes/153_find_minimum_in_rotated_sorted_array.md) |
| 42 | 155 | [Min Stack](src/exercises/155.min-stack.py) | Medium | Python | | 42 | 155 | [Min Stack](src/exercises/155.min-stack.py) | Medium | Python | [📝](src/notes/155_min_stack.md) |
| 43 | 167 | [Two Sum II - Input Array Is Sorted](src/exercises/167.two-sum-ii-input-array-is-sorted.py) | Medium | Python | | 43 | 167 | [Two Sum II - Input Array Is Sorted](src/exercises/167.two-sum-ii-input-array-is-sorted.py) | Medium | Python | [📝](src/notes/167_two_sum_ii_input_array_is_sorted.md) |
| 44 | 169 | [Majority Element](src/exercises/169.majority-element.py) | Easy | Python | | 44 | 169 | [Majority Element](src/exercises/169.majority-element.py) | Easy | Python | [📝](src/notes/169_majority_element.md) |
| 45 | 172 | [Factorial Trailing Zeroes](src/exercises/172.factorial-trailing-zeroes.py) | Medium | Python | | 45 | 172 | [Factorial Trailing Zeroes](src/exercises/172.factorial-trailing-zeroes.py) | Medium | Python | [📝](src/notes/172_factorial_trailing_zeroes.md) |
| 46 | 189 | [Rotate Array](src/exercises/189.rotate-array.py) | Medium | Python | | 46 | 189 | [Rotate Array](src/exercises/189.rotate-array.py) | Medium | Python | [📝](src/notes/189_rotate_array.md) |
| 47 | 202 | [Happy Number](src/exercises/202.happy-number.py) | Easy | Python | | 47 | 202 | [Happy Number](src/exercises/202.happy-number.py) | Easy | Python | [📝](src/notes/202_happy_number.md) |
| 48 | 205 | [Isomorphic Strings](src/exercises/205.isomorphic-strings.py) | Easy | Python | | 48 | 205 | [Isomorphic Strings](src/exercises/205.isomorphic-strings.py) | Easy | Python | [📝](src/notes/205_isomorphic_strings.md) |
| 49 | 206 | [Reverse Linked List](src/exercises/206.reverse-linked-list.py) | Easy | Python | | 49 | 206 | [Reverse Linked List](src/exercises/206.reverse-linked-list.py) | Easy | Python | [📝](src/notes/206_reverse_linked_list.md) |
| 50 | 217 | [Contains Duplicate](src/exercises/217.contains-duplicate.py) | Easy | Python | | 50 | 217 | [Contains Duplicate](src/exercises/217.contains-duplicate.py) | Easy | Python | [📝](src/notes/217_contains_duplicate.md) |
| 51 | 219 | [Contains Duplicate II](src/exercises/219.contains-duplicate-ii.py) | Easy | Python | | 51 | 219 | [Contains Duplicate II](src/exercises/219.contains-duplicate-ii.py) | Easy | Python | [📝](src/notes/219_contains_duplicate_ii.md) |
| 52 | 228 | [Summary Ranges](src/exercises/228.summary-ranges.py) | Easy | Python | | 52 | 228 | [Summary Ranges](src/exercises/228.summary-ranges.py) | Easy | Python | [📝](src/notes/228_summary_ranges.md) |
| 53 | 238 | [Product of Array Except Self](src/exercises/238.product-of-array-except-self.py) | Medium | Python | | 53 | 238 | [Product of Array Except Self](src/exercises/238.product-of-array-except-self.py) | Medium | Python | [📝](src/notes/238_product_of_array_except_self.md) |
| 54 | 242 | [Valid Anagram](src/exercises/242.valid-anagram.py) | Easy | Python | | 54 | 242 | [Valid Anagram](src/exercises/242.valid-anagram.py) | Easy | Python | [📝](src/notes/242_valid_anagram.md) |
| 55 | 243 | [Shortest Word Distance](src/exercises/243.shortest-word-distance.py) | Easy | Python | | 55 | 243 | [Shortest Word Distance](src/exercises/243.shortest-word-distance.py) | Easy | Python | [📝](src/notes/243_shortest_word_distance.md) |
| 56 | 244 | [Shortest Word Distance II](src/exercises/244.shortest-word-distance-ii.py) | Medium | Python | | 56 | 244 | [Shortest Word Distance II](src/exercises/244.shortest-word-distance-ii.py) | Medium | Python | [📝](src/notes/244_shortest_word_distance_ii.md) |
| 57 | 245 | [Shortest Word Distance III](src/exercises/245.shortest-word-distance-iii.py) | Medium | Python | | 57 | 245 | [Shortest Word Distance III](src/exercises/245.shortest-word-distance-iii.py) | Medium | Python | [📝](src/notes/245_shortest_word_distance_iii.md) |
| 58 | 246 | [Strobogrammatic Number](src/exercises/246.strobogrammatic-number.py) | Easy | Python | | 58 | 246 | [Strobogrammatic Number](src/exercises/246.strobogrammatic-number.py) | Easy | Python | [📝](src/notes/246_strobogrammatic_number.md) |
| 59 | 248 | [Strobogrammatic Number III](src/exercises/248.strobogrammatic-number-iii.py) | Hard | Python | | 59 | 248 | [Strobogrammatic Number III](src/exercises/248.strobogrammatic-number-iii.py) | Hard | Python | [📝](src/notes/248_strobogrammatic_number_iii.md) |
| 60 | 271 | [Encode and Decode Strings](src/exercises/271.encode-and-decode-strings.js) | Medium | JavaScript | | 60 | 271 | [Encode and Decode Strings](src/exercises/271.encode-and-decode-strings.js) | Medium | JavaScript | [📝](src/notes/271_encode_and_decode_strings.md) |
| 61 | 274 | [H-Index](src/exercises/274.h-index.py) | Medium | Python | | 61 | 274 | [H-Index](src/exercises/274.h-index.py) | Medium | Python | [📝](src/notes/274_h_index.md) |
| 62 | 290 | [Word Pattern](src/exercises/290.word-pattern.py) | Easy | Python | | 62 | 290 | [Word Pattern](src/exercises/290.word-pattern.py) | Easy | Python | [📝](src/notes/290_word_pattern.md) |
| 63 | 347 | [Top K Frequent Elements](src/exercises/347.top-k-frequent-elements.js) | Medium | JavaScript | | 63 | 347 | [Top K Frequent Elements](src/exercises/347.top-k-frequent-elements.js) | Medium | JavaScript | [📝](src/notes/347_top_k_frequent_elements.md) |
| 64 | 383 | [Ransom Note](src/exercises/383.ransom-note.py) | Easy | Python | | 64 | 383 | [Ransom Note](src/exercises/383.ransom-note.py) | Easy | Python | [📝](src/notes/383_ransom_note.md) |
| 65 | 392 | [Is Subsequence](src/exercises/392.is-subsequence.py) | Easy | Python | | 65 | 392 | [Is Subsequence](src/exercises/392.is-subsequence.py) | Easy | Python | [📝](src/notes/392_is_subsequence.md) |
| 66 | 595 | [Big Countries](src/exercises/595.big-countries.sql) | Easy | SQL | | 66 | 595 | [Big Countries](src/exercises/595.big-countries.sql) | Easy | SQL | [📝](src/notes/595_big_countries.md) |
| 67 | 704 | [Binary Search](src/exercises/704.binary-search.py) | Easy | Python | | 67 | 704 | [Binary Search](src/exercises/704.binary-search.py) | Easy | Python | [📝](src/notes/704_binary_search.md) |
| 68 | 760 | [Find Anagram Mappings](src/exercises/760.find-anagram-mappings.py) | Easy | Python | | 68 | 760 | [Find Anagram Mappings](src/exercises/760.find-anagram-mappings.py) | Easy | Python | [📝](src/notes/760_find_anagram_mappings.md) |
| 69 | 875 | [Koko Eating Bananas](src/exercises/875.koko-eating-bananas.py) | Medium | Python | | 69 | 875 | [Koko Eating Bananas](src/exercises/875.koko-eating-bananas.py) | Medium | Python | [📝](src/notes/875_koko_eating_bananas.md) |
| 70 | 1048 | [Longest String Chain](src/exercises/1048.longest-string-chain.js) | Medium | JavaScript | | 70 | 1048 | [Longest String Chain](src/exercises/1048.longest-string-chain.js) | Medium | JavaScript | [📝](src/notes/1048_longest_string_chain.md) |
| 71 | 1200 | [Minimum Absolute Difference](src/exercises/1200.minimum-absolute-difference.py) | Easy | Python | | 71 | 1200 | [Minimum Absolute Difference](src/exercises/1200.minimum-absolute-difference.py) | Easy | Python | [📝](src/notes/1200_minimum_absolute_difference.md) |
| 72 | 1302 | [Deepest Leaves Sum](src/exercises/1302.deepest-leaves-sum.py) | Medium | Python | | 72 | 1302 | [Deepest Leaves Sum](src/exercises/1302.deepest-leaves-sum.py) | Medium | Python | [📝](src/notes/1302_deepest_leaves_sum.md) |
| 73 | 2016 | [Maximum Difference Between Increasing Elements](src/exercises/2016.maximum-difference-between-increasing-elements.py) | Easy | Python | | 73 | 2016 | [Maximum Difference Between Increasing Elements](src/exercises/2016.maximum-difference-between-increasing-elements.py) | Easy | Python | [📝](src/notes/2016_maximum_difference_between_increasing_elements.md) |
| 74 | 2053 | [Kth Distinct String in an Array](src/exercises/2053.kth-distinct-string-in-an-array.py) | Easy | Python | | 74 | 2053 | [Kth Distinct String in an Array](src/exercises/2053.kth-distinct-string-in-an-array.py) | Easy | Python | [📝](src/notes/2053_kth_distinct_string_in_an_array.md) |
| 75 | 2116 | [Check if a Parentheses String Can Be Valid](src/exercises/2116.check-if-a-parentheses-string-can-be-valid.py) | Medium | Python | | 75 | 2116 | [Check if a Parentheses String Can Be Valid](src/exercises/2116.check-if-a-parentheses-string-can-be-valid.py) | Medium | Python | [📝](src/notes/2116_check_if_a_parentheses_string_can_be_valid.md) |
| 76 | 2294 | [Partition Array Such That Maximum Difference Is K](src/exercises/2294.partition-array-such-that-maximum-difference-is-k.py) | Medium | Python | | 76 | 2294 | [Partition Array Such That Maximum Difference Is K](src/exercises/2294.partition-array-such-that-maximum-difference-is-k.py) | Medium | Python | [📝](src/notes/2294_partition_array_such_that_maximum_difference_is_k.md) |
| 77 | 3442 | [Maximum Difference Between Even and Odd Frequency I](src/exercises/3442.maximum-difference-between-even-and-odd-frequency-i.py) | Easy | Python | | 77 | 3442 | [Maximum Difference Between Even and Odd Frequency I](src/exercises/3442.maximum-difference-between-even-and-odd-frequency-i.py) | Easy | Python | [📝](src/notes/3442_maximum_difference_between_even_and_odd_frequency_i.md) |
| 78 | 3582 | [Generate Tag for Video Caption](src/exercises/3582.generate-tag-for-video-caption.py) | Easy | Python | | 78 | 3582 | [Generate Tag for Video Caption](src/exercises/3582.generate-tag-for-video-caption.py) | Easy | Python | [📝](src/notes/3582_generate_tag_for_video_caption.md) |
| 79 | 3583 | [Count Special Triplets](src/exercises/3583.count-special-triplets.py) | Easy | Python | | 79 | 3583 | [Count Special Triplets](src/exercises/3583.count-special-triplets.py) | Easy | Python | [📝](src/notes/3583_count_special_triplets.md) |
## 🛠️ Tools & Scripts ## 🛠️ Tools & Scripts
- `create_missing_notes.sh`: Automatically creates missing note files for solved problems - `create_missing_notes.sh`: Automatically creates missing note files for solved problems

113
src/notes/001_two_sum.md Normal file
View File

@@ -0,0 +1,113 @@
# Two Sum
[![Problem 1](https://img.shields.io/badge/Problem-1-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/two-sum/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/two-sum/)
**Problem Number:** [1](https://leetcode.com/problems/two-sum/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Hash Table
**LeetCode Link:** [https://leetcode.com/problems/two-sum/](https://leetcode.com/problems/two-sum/)
## Problem Description
Given an array of integers `nums` and an integer `target`, return indices of the two numbers such that they add up to `target`.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
You can return the answer in any order.
**Example 1:**
```
Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].
```
**Example 2:**
```
Input: nums = [3,2,4], target = 6
Output: [1,2]
```
**Example 3:**
```
Input: nums = [3,3], target = 6
Output: [0,1]
```
**Constraints:**
- `2 <= nums.length <= 10^4`
- `-10^9 <= nums[i] <= 10^9`
- `-10^9 <= target <= 10^9`
- Only one valid answer exists.
## My Approach
I used a **Hash Table (Dictionary)** approach to solve this problem efficiently. The key insight is to use a hash map to store previously seen numbers and their indices, allowing us to find the complement in O(1) time.
**Algorithm:**
1. Create an empty hash map to store numbers and their indices
2. Iterate through the array once
3. For each number, calculate its complement (target - current_number)
4. Check if the complement exists in the hash map
5. If found, return the current index and the complement's index
6. If not found, add the current number and its index to the hash map
## Solution
The solution uses a hash table approach to achieve O(n) time complexity. See the implementation in the [solution file](../exercises/1.two-sum.py).
**Key Points:**
- Uses a hash map for O(1) lookup time
- Only requires a single pass through the array
- Handles edge cases appropriately
- Returns indices in the order [current_index, complement_index]
## Time & Space Complexity
**Time Complexity:** O(n)
- We iterate through the array once: O(n)
- Hash map operations (insertion and lookup) are O(1) on average
- Total: O(n)
**Space Complexity:** O(n)
- In the worst case, we might need to store all n elements in the hash map
- This occurs when the solution is found at the end of the array
## Key Insights
1. **Hash Table Efficiency:** Using a hash table allows us to achieve O(n) time complexity instead of the O(n²) that would result from a brute force approach with nested loops.
2. **Single Pass Solution:** We can find the solution in just one iteration through the array by storing previously seen numbers and checking for complements.
3. **Complement Strategy:** Instead of looking for two numbers that sum to target, we look for one number and its complement (target - number).
4. **Edge Case Handling:** The solution includes proper handling of edge cases like empty arrays and arrays with fewer than 2 elements.
5. **No Duplicate Usage:** The algorithm naturally avoids using the same element twice because we check for the complement before adding the current element to the hash map.
## Mistakes Made
1. **Initial Edge Case Over-engineering:** The solution includes edge cases for arrays with 0, 1, or 2 elements, which might be unnecessary given the problem constraints (array length ≥ 2).
2. **Return Order:** The solution returns [current_index, complement_index], but the problem allows returning the answer in any order.
## Related Problems
- **Two Sum II - Input Array Is Sorted** (Problem 167): Similar problem but with a sorted array, allowing for a two-pointer approach
- **Two Sum BST** (Problem 653): Finding two nodes in a BST that sum to target
- **Three Sum** (Problem 15): Extension to finding three numbers that sum to zero
- **Four Sum** (Problem 18): Further extension to finding four numbers that sum to target
## Alternative Approaches
1. **Brute Force:** O(n²) time complexity with nested loops
2. **Two Pointers:** Only works for sorted arrays, O(n log n) due to sorting
3. **Binary Search:** Only applicable for sorted arrays
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/1.two-sum.py)](../exercises/1.two-sum.py)
*Note: This is a fundamental problem that introduces the hash table optimization pattern, commonly used in array and string problems.*

View File

@@ -0,0 +1,128 @@
# Add Two Numbers
[![Problem 2](https://img.shields.io/badge/Problem-2-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/add-two-numbers/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/add-two-numbers/)
**Problem Number:** [2](https://leetcode.com/problems/add-two-numbers/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Linked List, Math, Recursion
**LeetCode Link:** [https://leetcode.com/problems/add-two-numbers/](https://leetcode.com/problems/add-two-numbers/)
## Problem Description
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list.
You may assume the two numbers do not contain any leading zero, except the number 0 itself.
**Example 1:**
```
Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
Explanation: 342 + 465 = 807
```
**Example 2:**
```
Input: l1 = [0], l2 = [0]
Output: [0]
```
**Example 3:**
```
Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]
```
**Constraints:**
- The number of nodes in each linked list is in the range [1, 100]
- 0 <= Node.val <= 9
- It is guaranteed that the list represents a number that does not have leading zeros
## My Approach
I used an **iterative approach** to simulate the manual addition process we learned in elementary school. The key insight is to process both linked lists digit by digit, maintaining a carry value, and building the result linked list as we go.
**Algorithm:**
1. Initialize a carry variable to 0
2. Create a dummy head node for the result linked list
3. Iterate through both linked lists simultaneously:
- Extract the current digit from each list (0 if list is exhausted)
- Add the digits along with the carry
- Calculate the new carry and the digit to store
- Create a new node with the calculated digit
- Append it to the result list
4. If there's still a carry after processing all digits, create a final node
5. Return the head of the result linked list
## Solution
The solution uses an iterative approach to add two numbers represented as linked lists. See the implementation in the [solution file](../exercises/2.add-two-numbers.py).
**Key Points:**
- Processes both lists simultaneously, handling different lengths
- Maintains a carry value throughout the addition process
- Builds the result linked list incrementally
- Handles the final carry if it exists
- Returns the result in reverse order (least significant digit first)
## Time & Space Complexity
**Time Complexity:** O(max(M, N))
- We iterate through both linked lists once
- M and N are the lengths of the input linked lists
- Each iteration performs constant time operations
**Space Complexity:** O(max(M, N))
- We create a new linked list to store the result
- The result can be at most max(M, N) + 1 digits long (due to carry)
- We use a constant amount of extra space for variables
## Key Insights
1. **Reverse Order Advantage:** The fact that digits are stored in reverse order makes the addition process straightforward - we can process from left to right, just like manual addition.
2. **Carry Management:** The carry must be tracked and added to the next position, similar to how we learned addition in school.
3. **Different Lengths:** The solution handles cases where the input lists have different lengths by treating missing digits as 0.
4. **Final Carry:** After processing all digits, if there's still a carry, it becomes the most significant digit in the result.
5. **Linked List Construction:** Building the result linked list incrementally is more efficient than converting to integers and back.
6. **No Leading Zeros:** The problem guarantees no leading zeros in input, but we need to handle the case where the result might have a leading zero (like 0 + 0 = 0).
## Mistakes Made
1. **Carry Calculation:** The initial approach of converting the sum to a string to extract carry and digit is inefficient. A more efficient approach would be to use integer division and modulo operations.
2. **Variable Naming:** The variable names could be more descriptive to improve code readability.
3. **Edge Case Handling:** Need to ensure proper handling when one list is longer than the other.
## Related Problems
- **Add Two Numbers II** (Problem 445): Similar problem but digits are stored in forward order
- **Multiply Strings** (Problem 43): Multiplying two numbers represented as strings
- **Plus One** (Problem 66): Adding one to a number represented as an array
- **Add Binary** (Problem 67): Adding two binary strings
- **Add Strings** (Problem 415): Adding two numbers represented as strings
## Alternative Approaches
1. **Recursive Solution:** Can be solved recursively by processing one digit at a time
2. **Convert to Integer:** Convert linked lists to integers, add them, then convert back (not recommended due to potential overflow)
3. **Stack-based:** Use stacks to reverse the order and then add (useful for forward order problems)
## Common Pitfalls
1. **Forgetting Final Carry:** Always check if there's a carry after processing all digits
2. **Null Pointer Exceptions:** Ensure proper null checks when accessing list nodes
3. **Memory Management:** Be careful not to lose references when building the result list
4. **Overflow:** While the problem constraints prevent integer overflow, it's good practice to consider it
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/2.add-two-numbers.py)](../exercises/2.add-two-numbers.py)
*Note: This is a fundamental linked list problem that teaches the importance of careful iteration and carry management in mathematical operations.*

View File

@@ -0,0 +1,123 @@
# Longest Substring Without Repeating Characters
[![Problem 3](https://img.shields.io/badge/Problem-3-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-substring-without-repeating-characters/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-substring-without-repeating-characters/)
**Problem Number:** [3](https://leetcode.com/problems/longest-substring-without-repeating-characters/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Hash Table, String, Sliding Window
**LeetCode Link:** [https://leetcode.com/problems/longest-substring-without-repeating-characters/](https://leetcode.com/problems/longest-substring-without-repeating-characters/)
## Problem Description
Given a string `s`, find the length of the longest substring without repeating characters.
**Example 1:**
```
Input: s = "abcabcbb"
Output: 3
Explanation: The answer is "abc", with the length of 3.
```
**Example 2:**
```
Input: s = "bbbbb"
Output: 1
Explanation: The answer is "b", with the length of 1.
```
**Example 3:**
```
Input: s = "pwwkew"
Output: 3
Explanation: The answer is "wke", with the length of 3.
Notice that the answer must be a substring, "pwke" is a subsequence and not a substring.
```
**Constraints:**
- `0 <= s.length <= 5 * 10^4`
- `s` consists of English letters, digits, symbols and spaces
## My Approach
I used a **Sliding Window** approach with a hash table to track characters in the current window. The key insight is to maintain a window of unique characters and expand/shrink it as needed.
**Algorithm:**
1. Initialize two pointers (i, j) at the beginning of the string
2. Use a hash table to track characters in the current window
3. Expand the window by moving the right pointer (j) when we encounter a new character
4. Shrink the window by moving the left pointer (i) when we encounter a duplicate
5. Keep track of the maximum window size seen so far
6. Return the maximum length found
## Solution
The solution uses a sliding window approach with hash table optimization. See the implementation in the [solution file](../exercises/3.longest-substring-without-repeating-characters.py).
**Key Points:**
- Uses two pointers to maintain a sliding window
- Hash table tracks characters in the current window
- Expands window when encountering new characters
- Shrinks window when encountering duplicates
- Tracks maximum window size throughout the process
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the string once with two pointers
- Hash table operations are O(1) on average
- Each character is visited at most twice (once by each pointer)
**Space Complexity:** O(min(m, n))
- Hash table stores at most min(m, n) characters
- m is the size of the character set (ASCII: 128, Unicode: much larger)
- n is the length of the string
## Key Insights
1. **Sliding Window Pattern:** This is a classic sliding window problem where we maintain a window of unique characters.
2. **Two Pointer Technique:** Using two pointers allows us to efficiently expand and shrink the window without recalculating from scratch.
3. **Hash Table for Tracking:** A hash table provides O(1) lookup to check if a character is already in the current window.
4. **Optimal Window Management:** When we encounter a duplicate, we shrink the window from the left until the duplicate is removed.
5. **Character Frequency vs. Presence:** We only need to track character presence (not frequency) since we want unique characters.
6. **Maximum Tracking:** We need to continuously update the maximum length as we process the string.
## Mistakes Made
1. **Inefficient Window Shrinking:** The current implementation removes characters one by one, which could be optimized.
2. **Character Tracking:** Using a simple dictionary instead of a set might be more appropriate for this use case.
3. **Edge Case Handling:** Need to ensure proper handling of empty strings and single characters.
## Related Problems
- **Longest Substring with At Most Two Distinct Characters** (Problem 159): Similar sliding window with character count limit
- **Longest Substring with At Most K Distinct Characters** (Problem 340): Generalization of the above
- **Minimum Window Substring** (Problem 76): Finding minimum window containing all characters from another string
- **Substring with Concatenation of All Words** (Problem 30): More complex sliding window with word matching
## Alternative Approaches
1. **Brute Force:** Check all possible substrings - O(n³) time complexity
2. **Optimized Brute Force:** Use hash set for each substring - O(n²) time complexity
3. **Character Position Tracking:** Store last position of each character for O(1) window shrinking
## Common Pitfalls
1. **Confusing Substring vs Subsequence:** The problem asks for substring (consecutive characters), not subsequence.
2. **Inefficient Duplicate Removal:** Removing characters one by one can be optimized.
3. **Missing Edge Cases:** Empty string, single character, all same characters.
4. **Character Set Size:** Consider the size of the character set for space complexity.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/3.longest-substring-without-repeating-characters.py)](../exercises/3.longest-substring-without-repeating-characters.py)
*Note: This is a fundamental sliding window problem that introduces the concept of maintaining a dynamic window of unique elements.*

View File

@@ -0,0 +1,123 @@
# Median of Two Sorted Arrays
[![Problem 4](https://img.shields.io/badge/Problem-4-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/median-of-two-sorted-arrays/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Hard-red?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=HARD)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/median-of-two-sorted-arrays/)
**Problem Number:** [4](https://leetcode.com/problems/median-of-two-sorted-arrays/)
**Difficulty:** [Hard](https://leetcode.com/problemset/?difficulty=HARD)
**Category:** Array, Binary Search, Divide and Conquer
**LeetCode Link:** [https://leetcode.com/problems/median-of-two-sorted-arrays/](https://leetcode.com/problems/median-of-two-sorted-arrays/)
## Problem Description
Given two sorted arrays `nums1` and `nums2` of size `m` and `n` respectively, return the median of the two sorted arrays.
The overall run time complexity should be O(log(m+n)).
**Example 1:**
```
Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: merged array = [1,2,3] and median is 2.
```
**Example 2:**
```
Input: nums1 = [1,2], nums2 = [3,4]
Output: 2.50000
Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.
```
**Constraints:**
- `nums1.length == m`
- `nums2.length == n`
- `0 <= m <= 1000`
- `0 <= n <= 1000`
- `1 <= m + n <= 2000`
- `-10^6 <= nums1[i], nums2[i] <= 10^6`
## My Approach
I used a **Binary Search** approach to find the correct partition of both arrays that gives us the median. The key insight is to find the correct cut point in the smaller array such that all elements on the left side are less than all elements on the right side.
**Algorithm:**
1. Ensure nums1 is the smaller array (swap if necessary)
2. Use binary search on the smaller array to find the correct partition
3. Calculate the corresponding partition in the larger array
4. Check if the partition is correct (left elements ≤ right elements)
5. Adjust the search range based on the comparison
6. Calculate median based on the correct partition
## Solution
The solution uses binary search to find the optimal partition point. See the implementation in the [solution file](../exercises/4.median-of-two-sorted-arrays.py).
**Key Points:**
- Uses binary search on the smaller array for efficiency
- Calculates corresponding partition in the larger array
- Handles edge cases with infinity values
- Supports both odd and even total lengths
- Achieves O(log(min(m,n))) time complexity
## Time & Space Complexity
**Time Complexity:** O(log(min(m, n)))
- Binary search on the smaller array
- Each iteration performs constant time operations
- Much better than O(m+n) merge approach
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Binary Search on Smaller Array:** Always perform binary search on the smaller array to minimize time complexity.
2. **Partition Concept:** The median divides the merged array into two equal halves, with all left elements ≤ all right elements.
3. **Cross-Array Validation:** After finding a partition in one array, validate it by checking the corresponding partition in the other array.
4. **Edge Case Handling:** Use infinity values to handle cases where partitions are at array boundaries.
5. **Odd vs Even Lengths:** Handle both cases - for odd total length, median is the minimum of right partition; for even, it's the average of max(left) and min(right).
6. **No Actual Merging:** The beauty of this approach is that we never actually merge the arrays.
## Mistakes Made
1. **Complexity Requirement:** Initially might consider O(m+n) merge approach, which doesn't meet the O(log(m+n)) requirement.
2. **Partition Logic:** Understanding the correct partition validation can be tricky initially.
3. **Edge Cases:** Handling cases where one array is empty or when partitions are at boundaries.
4. **Infinity Values:** Using appropriate infinity values for boundary conditions.
## Related Problems
- **Kth Smallest Element in Two Sorted Arrays:** Generalization of this problem
- **Merge k Sorted Lists** (Problem 23): Merging multiple sorted lists
- **Find First and Last Position of Element in Sorted Array** (Problem 34): Binary search applications
- **Search in Rotated Sorted Array** (Problem 33): Binary search in modified sorted arrays
## Alternative Approaches
1. **Merge and Find:** Merge arrays and find median - O(m+n) time, O(m+n) space
2. **Two Pointers:** Use two pointers to find median without merging - O(m+n) time, O(1) space
3. **Heap-based:** Use heaps to find kth smallest element - O((m+n)log(k)) time
## Common Pitfalls
1. **Wrong Complexity:** Not meeting the O(log(m+n)) requirement with merge approaches.
2. **Partition Validation:** Incorrectly validating the partition between arrays.
3. **Edge Cases:** Not handling empty arrays or single-element arrays properly.
4. **Infinity Handling:** Using wrong infinity values for boundary conditions.
5. **Odd/Even Logic:** Confusing the logic for odd vs even total lengths.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/4.median-of-two-sorted-arrays.py)](../exercises/4.median-of-two-sorted-arrays.py)
*Note: This is one of the most challenging binary search problems that requires deep understanding of partitioning and median properties.*

View File

@@ -0,0 +1,114 @@
# Longest Palindromic Substring
[![Problem 5](https://img.shields.io/badge/Problem-5-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-palindromic-substring/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-palindromic-substring/)
**Problem Number:** [5](https://leetcode.com/problems/longest-palindromic-substring/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** String, Dynamic Programming
**LeetCode Link:** [https://leetcode.com/problems/longest-palindromic-substring/](https://leetcode.com/problems/longest-palindromic-substring/)
## Problem Description
Given a string `s`, return the longest palindromic substring in `s`.
**Example 1:**
```
Input: s = "babad"
Output: "bab"
Explanation: "aba" is also a valid answer.
```
**Example 2:**
```
Input: s = "cbbd"
Output: "bb"
```
**Constraints:**
- `1 <= s.length <= 1000`
- `s` consist of only digits and English letters
## My Approach
I used the **Expand Around Center** approach, which is one of the most efficient methods for finding palindromes. The key insight is to consider each character (and each pair of adjacent characters) as a potential center of a palindrome and expand outward.
**Algorithm:**
1. Handle edge cases (empty string or single character)
2. For each character in the string, treat it as a center and expand
3. For each pair of adjacent characters, treat them as a center and expand
4. Keep track of the longest palindrome found
5. Return the longest palindromic substring
## Solution
The solution uses the expand around center technique. See the implementation in the [solution file](../exercises/5.longest-palindromic-substring.py).
**Key Points:**
- Uses a helper function to expand from a given center
- Handles both odd-length (single character center) and even-length (two character center) palindromes
- Tracks the maximum length and corresponding substring
- Efficiently explores all possible palindrome centers
## Time & Space Complexity
**Time Complexity:** O(n²)
- We iterate through each character as a potential center: O(n)
- For each center, we expand outward: O(n) in worst case
- Total: O(n²)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures proportional to input size
## Key Insights
1. **Expand Around Center:** Instead of checking all possible substrings, we expand from potential centers.
2. **Two Types of Centers:** We need to consider both single characters (odd-length palindromes) and adjacent character pairs (even-length palindromes).
3. **Symmetric Expansion:** When expanding from a center, we move left and right simultaneously, checking if characters match.
4. **Early Termination:** The expansion stops as soon as we encounter non-matching characters.
5. **Length Calculation:** The length of a palindrome is (right - left + 1) after expansion.
6. **Edge Case Handling:** Single characters and empty strings are always palindromes.
## Mistakes Made
1. **Missing Even-Length Palindromes:** Initially might only consider single character centers, missing palindromes like "aa".
2. **Boundary Conditions:** Not properly handling cases where expansion reaches string boundaries.
3. **Length Tracking:** Incorrectly calculating or updating the maximum length.
4. **String Slicing:** Inefficient string slicing operations in the expansion process.
## Related Problems
- **Palindromic Substrings** (Problem 647): Count all palindromic substrings
- **Valid Palindrome** (Problem 125): Check if a string is a palindrome
- **Palindrome Partitioning** (Problem 131): Partition string into palindromic substrings
- **Longest Palindromic Subsequence** (Problem 516): Find longest palindromic subsequence
## Alternative Approaches
1. **Dynamic Programming:** Use a 2D DP table - O(n²) time, O(n²) space
2. **Manacher's Algorithm:** More complex but achieves O(n) time complexity
3. **Brute Force:** Check all possible substrings - O(n³) time complexity
## Common Pitfalls
1. **Only Odd-Length Palindromes:** Forgetting to check even-length palindromes.
2. **Inefficient Expansion:** Not optimizing the expansion process.
3. **Boundary Issues:** Not handling cases where expansion reaches string ends.
4. **String Operations:** Using expensive string operations during expansion.
5. **Memory Usage:** Creating unnecessary copies of substrings.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/5.longest-palindromic-substring.py)](../exercises/5.longest-palindromic-substring.py)
*Note: This is a classic string problem that introduces the expand around center technique, widely used in palindrome-related problems.*

View File

@@ -0,0 +1,118 @@
# Palindrome Number
[![Problem 9](https://img.shields.io/badge/Problem-9-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/palindrome-number/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/palindrome-number/)
**Problem Number:** [9](https://leetcode.com/problems/palindrome-number/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Math
**LeetCode Link:** [https://leetcode.com/problems/palindrome-number/](https://leetcode.com/problems/palindrome-number/)
## Problem Description
Given an integer `x`, return `true` if `x` is a palindrome, and `false` otherwise.
**Example 1:**
```
Input: x = 121
Output: true
Explanation: 121 reads as 121 from left to right and from right to left.
```
**Example 2:**
```
Input: x = -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.
```
**Example 3:**
```
Input: x = 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.
```
**Constraints:**
- `-2^31 <= x <= 2^31 - 1`
## My Approach
I used a **Two Pointer** approach by converting the integer to a string and comparing characters from both ends. The key insight is to use two pointers that move towards each other, comparing characters at each step.
**Algorithm:**
1. Convert the integer to a string
2. Initialize two pointers at the beginning and end of the string
3. Compare characters at both pointers
4. Move pointers towards the center
5. Return true if all comparisons match, false otherwise
## Solution
The solution uses a two-pointer approach on the string representation. See the implementation in the [solution file](../exercises/9.palindrome-number.py).
**Key Points:**
- Converts integer to string for easy character comparison
- Uses two pointers moving from opposite ends
- Handles negative numbers (always false)
- Efficiently compares characters without extra space
## Time & Space Complexity
**Time Complexity:** O(log n)
- Converting to string takes O(log n) time
- Two-pointer comparison takes O(log n) time
- Total: O(log n)
**Space Complexity:** O(log n)
- String conversion requires O(log n) space
- No additional data structures needed
## Key Insights
1. **String Conversion:** Converting to string makes character comparison straightforward.
2. **Two Pointer Technique:** Using pointers from both ends is more efficient than reversing the entire string.
3. **Negative Numbers:** All negative numbers are automatically not palindromes due to the minus sign.
4. **Single Digit:** All single-digit numbers (0-9) are palindromes.
5. **Zero Handling:** Zero is a valid palindrome.
6. **Early Termination:** Can return false as soon as a mismatch is found.
## Mistakes Made
1. **String Conversion Overhead:** Converting to string uses extra space, though it's acceptable for this problem.
2. **Not Using Mathematical Approach:** Could solve without string conversion using mathematical operations.
3. **Edge Case Handling:** Need to ensure proper handling of single digits and zero.
## Related Problems
- **Valid Palindrome** (Problem 125): Check if a string is a palindrome
- **Longest Palindromic Substring** (Problem 5): Find longest palindromic substring
- **Palindrome Linked List** (Problem 234): Check if a linked list is a palindrome
- **Reverse Integer** (Problem 7): Reverse digits of an integer
## Alternative Approaches
1. **Mathematical Approach:** Reverse the number mathematically and compare
2. **Half Reversal:** Only reverse the second half and compare with first half
3. **String Reversal:** Reverse the entire string and compare
## Common Pitfalls
1. **Negative Numbers:** Forgetting that negative numbers are never palindromes.
2. **String Conversion:** Using string conversion when mathematical approach might be preferred.
3. **Zero Handling:** Not properly handling the case where x = 0.
4. **Overflow:** In mathematical approaches, need to handle potential overflow.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/9.palindrome-number.py)](../exercises/9.palindrome-number.py)
*Note: This is a simple problem that introduces the concept of palindrome checking, which is fundamental to many string and number problems.*

View File

@@ -0,0 +1,120 @@
# Container With Most Water
[![Problem 11](https://img.shields.io/badge/Problem-11-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/container-with-most-water/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/container-with-most-water/)
**Problem Number:** [11](https://leetcode.com/problems/container-with-most-water/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Two Pointers, Greedy
**LeetCode Link:** [https://leetcode.com/problems/container-with-most-water/](https://leetcode.com/problems/container-with-most-water/)
## Problem Description
Given `n` non-negative integers `height` where each represents a point at coordinate `(i, height[i])`, find two lines that together with the x-axis form a container that would hold the maximum amount of water.
Return the maximum amount of water a container can store.
**Example 1:**
```
Input: height = [1,8,6,2,5,4,8,3,7]
Output: 49
Explanation: The maximum area is obtained by choosing height[1] = 8 and height[8] = 7.
```
**Example 2:**
```
Input: height = [1,1]
Output: 1
```
**Constraints:**
- `n == height.length`
- `2 <= n <= 10^5`
- `0 <= height[i] <= 10^4`
## My Approach
I used a **Two Pointer** approach starting from the widest possible container and moving inward. The key insight is that we can eliminate certain combinations by moving the pointer with the smaller height, as the width will only decrease.
**Algorithm:**
1. Initialize two pointers at the beginning and end of the array
2. Calculate the area of the current container
3. Move the pointer with the smaller height inward
4. Update the maximum area if the current area is larger
5. Continue until the pointers meet
## Solution
The solution uses a two-pointer approach to find the optimal container. See the implementation in the [solution file](../exercises/11.container-with-most-water.py).
**Key Points:**
- Uses two pointers starting from the widest possible container
- Moves the pointer with smaller height to potentially find larger areas
- Calculates area as min(height[i], height[j]) * (j - i)
- Tracks maximum area throughout the process
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the array once with two pointers
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Two Pointer Technique:** Starting from the widest container allows us to eliminate many combinations efficiently.
2. **Greedy Movement:** Moving the pointer with the smaller height is optimal because:
- The width will only decrease
- We need a taller line to potentially get a larger area
- The current smaller line cannot be part of a larger area
3. **Area Calculation:** Area = min(height[left], height[right]) × width
4. **Optimal Substructure:** The optimal solution can be found by considering the widest container first.
5. **No Need to Check All Pairs:** The two-pointer approach eliminates the need to check all O(n²) combinations.
6. **Width Decreases:** As we move inward, the width always decreases, so we need taller lines to compensate.
## Mistakes Made
1. **Brute Force Approach:** Initially might consider checking all possible pairs, leading to O(n²) complexity.
2. **Wrong Pointer Movement:** Moving the wrong pointer can lead to missing the optimal solution.
3. **Area Calculation:** Incorrectly calculating the area or using the wrong height.
4. **Edge Cases:** Not properly handling cases with only two elements or all same heights.
## Related Problems
- **Trapping Rain Water** (Problem 42): Similar concept but with different constraints
- **Two Sum II - Input Array Is Sorted** (Problem 167): Two pointer technique in sorted array
- **3Sum** (Problem 15): Three pointer technique
- **Valid Triangle Number** (Problem 611): Using two pointers for triangle validation
## Alternative Approaches
1. **Brute Force:** Check all possible pairs - O(n²) time complexity
2. **Divide and Conquer:** Split array and find maximum in each half - O(n log n) time complexity
3. **Stack-based:** Use monotonic stack to find next greater elements
## Common Pitfalls
1. **Wrong Pointer Movement:** Moving the pointer with larger height instead of smaller height.
2. **Brute Force:** Checking all combinations instead of using the two-pointer optimization.
3. **Area Calculation:** Using max instead of min for height calculation.
4. **Edge Cases:** Not handling arrays with only two elements or all same values.
5. **Width Calculation:** Incorrectly calculating the width between pointers.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/11.container-with-most-water.py)](../exercises/11.container-with-most-water.py)
*Note: This is a classic two-pointer problem that demonstrates the greedy approach of eliminating suboptimal choices early.*

View File

@@ -0,0 +1,148 @@
# Roman to Integer
[![Problem 13](https://img.shields.io/badge/Problem-13-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/roman-to-integer/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/roman-to-integer/)
**Problem Number:** [13](https://leetcode.com/problems/roman-to-integer/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, Math, String
**LeetCode Link:** [https://leetcode.com/problems/roman-to-integer/](https://leetcode.com/problems/roman-to-integer/)
## Problem Description
Roman numerals are represented by seven different symbols: `I`, `V`, `X`, `L`, `C`, `D` and `M`.
```
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
```
For example, `2` is written as `II` in Roman numeral, just two ones added together. `12` is written as `XII`, which is simply `X + II`. The number `27` is written as `XXVII`, which is `XX + V + II`.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not `IIII`. Instead, the number four is written as `IV`. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as `IX`. There are six instances where subtraction is used:
- `I` can be placed before `V` (5) and `X` (10) to make 4 and 9.
- `X` can be placed before `L` (50) and `C` (100) to make 40 and 90.
- `C` can be placed before `D` (500) and `M` (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer.
**Example 1:**
```
Input: s = "III"
Output: 3
Explanation: III = 3.
```
**Example 2:**
```
Input: s = "LVIII"
Output: 58
Explanation: L = 50, V = 5, III = 3.
```
**Example 3:**
```
Input: s = "MCMXCIV"
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.
```
**Constraints:**
- `1 <= s.length <= 15`
- `s` contains only the characters `('I', 'V', 'X', 'L', 'C', 'D', 'M')`
- It is guaranteed that `s` is a valid roman numeral in the range `[1, 3999]`
## My Approach
I used a **Right-to-Left** approach with a hash table to map Roman numerals to their values. The key insight is to process the string from right to left, checking for subtraction cases when a smaller value appears before a larger one.
**Algorithm:**
1. Create a hash table mapping Roman symbols to their values
2. Process the string from right to left
3. For each character, check if it forms a subtraction case with the previous character
4. If it's a subtraction case, subtract the smaller value from the larger one
5. Otherwise, add the current character's value
6. Return the total sum
## Solution
The solution uses a right-to-left approach with hash table lookup. See the implementation in the [solution file](../exercises/13.roman-to-integer.py).
**Key Points:**
- Uses hash table for O(1) symbol-to-value lookup
- Processes string from right to left for easier subtraction handling
- Checks for all six subtraction cases explicitly
- Handles edge case for the first character
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the string once from right to left
- Hash table lookups are O(1)
- Total: O(n)
**Space Complexity:** O(1)
- Hash table has constant size (7 symbols)
- No additional space proportional to input size
## Key Insights
1. **Right-to-Left Processing:** Processing from right to left makes it easier to handle subtraction cases.
2. **Subtraction Rules:** There are exactly six cases where subtraction occurs:
- IV (4), IX (9)
- XL (40), XC (90)
- CD (400), CM (900)
3. **Hash Table Efficiency:** Using a hash table provides O(1) lookup for symbol values.
4. **No Invalid Cases:** The problem guarantees valid Roman numerals, so we don't need extensive validation.
5. **Character Pairs:** Subtraction only occurs with specific character pairs, making the logic straightforward.
6. **Edge Case Handling:** The first character (rightmost) is always added, never subtracted.
## Mistakes Made
1. **Left-to-Right Processing:** Initially might process left-to-right, making subtraction logic more complex.
2. **Missing Subtraction Cases:** Forgetting to handle all six subtraction cases.
3. **Complex Logic:** Overcomplicating the subtraction detection logic.
4. **Edge Cases:** Not properly handling the first character case.
## Related Problems
- **Integer to Roman** (Problem 12): Reverse conversion from integer to Roman numeral
- **Valid Parentheses** (Problem 20): Similar pattern matching with symbols
- **Decode Ways** (Problem 91): Converting string representations to numbers
- **Basic Calculator** (Problem 224): More complex mathematical expression parsing
## Alternative Approaches
1. **Left-to-Right with Lookahead:** Process left-to-right and look ahead for subtraction cases
2. **Stack-based:** Use a stack to handle the conversion
3. **Recursive:** Use recursion to process the string
## Common Pitfalls
1. **Wrong Direction:** Processing left-to-right makes subtraction logic more complex.
2. **Missing Cases:** Not handling all six subtraction cases.
3. **Complex Logic:** Overcomplicating the subtraction detection.
4. **Edge Cases:** Not handling the first character properly.
5. **Invalid Input:** Assuming invalid Roman numerals need to be handled.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/13.roman-to-integer.py)](../exercises/13.roman-to-integer.py)
*Note: This is a straightforward string processing problem that introduces the concept of symbol-to-value mapping and special case handling.*

View File

@@ -0,0 +1,120 @@
# Longest Common Prefix
[![Problem 14](https://img.shields.io/badge/Problem-14-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-common-prefix/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-common-prefix/)
**Problem Number:** [14](https://leetcode.com/problems/longest-common-prefix/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String, Trie
**LeetCode Link:** [https://leetcode.com/problems/longest-common-prefix/](https://leetcode.com/problems/longest-common-prefix/)
## Problem Description
Write a function to find the longest common prefix string amongst an array of strings.
If there is no common prefix, return an empty string `""`.
**Example 1:**
```
Input: strs = ["flower","flow","flight"]
Output: "fl"
```
**Example 2:**
```
Input: strs = ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
```
**Constraints:**
- `1 <= strs.length <= 200`
- `0 <= strs[i].length <= 200`
- `strs[i]` consists of only lowercase English letters
## My Approach
I used a **Character-by-Character Comparison** approach. The key insight is to compare characters at the same position across all strings, starting from the first character, and stop when we find a mismatch or reach the end of any string.
**Algorithm:**
1. Handle edge cases (empty array, single string)
2. Find the minimum length among all strings
3. Truncate all strings to the minimum length
4. Compare characters at each position across all strings
5. Stop when a mismatch is found
6. Return the common prefix found so far
## Solution
The solution uses character-by-character comparison with optimization. See the implementation in the [solution file](../exercises/14.longest-common-prefix.py).
**Key Points:**
- Finds minimum length to avoid index out of bounds
- Truncates all strings to minimum length for efficiency
- Compares characters at each position across all strings
- Stops at first mismatch and returns prefix up to that point
## Time & Space Complexity
**Time Complexity:** O(S)
- S is the sum of all characters in all strings
- We compare each character at most once
- Finding minimum length: O(n)
- Character comparisons: O(S)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures proportional to input size
## Key Insights
1. **Character-by-Character Comparison:** The longest common prefix must match at every position across all strings.
2. **Minimum Length Optimization:** By finding the minimum length, we avoid unnecessary comparisons beyond the shortest string.
3. **Early Termination:** We can stop as soon as we find a mismatch at any position.
4. **String Truncation:** Truncating strings to minimum length simplifies the comparison logic.
5. **Edge Cases:** Empty array returns empty string, single string returns itself.
6. **No Common Prefix:** If the first characters don't match, there's no common prefix.
## Mistakes Made
1. **Inefficient Comparison:** Initially might compare entire strings instead of character by character.
2. **Missing Edge Cases:** Not properly handling empty array or single string cases.
3. **Index Out of Bounds:** Not considering that strings might have different lengths.
4. **Unnecessary Complexity:** Overcomplicating the solution with data structures like Trie.
## Related Problems
- **Implement Trie** (Problem 208): Data structure for efficient string operations
- **Word Search** (Problem 79): Finding words in a 2D grid
- **Valid Parentheses** (Problem 20): Pattern matching with symbols
- **Group Anagrams** (Problem 49): Grouping strings by their characteristics
## Alternative Approaches
1. **Horizontal Scanning:** Compare first two strings, then result with next string
2. **Vertical Scanning:** Compare characters at same position across all strings
3. **Divide and Conquer:** Split array in half, find LCP of each half, then combine
4. **Binary Search:** Use binary search on the length of the common prefix
## Common Pitfalls
1. **Index Out of Bounds:** Not handling strings of different lengths properly.
2. **Inefficient Comparison:** Comparing entire strings instead of character by character.
3. **Missing Edge Cases:** Not handling empty array or single string.
4. **Over-engineering:** Using complex data structures when simple comparison suffices.
5. **Wrong Termination:** Not stopping at the first mismatch.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/14.longest-common-prefix.py)](../exercises/14.longest-common-prefix.py)
*Note: This is a fundamental string problem that introduces the concept of finding common patterns across multiple strings.*

124
src/notes/015_3sum.md Normal file
View File

@@ -0,0 +1,124 @@
# 3Sum
[![Problem 15](https://img.shields.io/badge/Problem-15-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/3sum/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/3sum/)
**Problem Number:** [15](https://leetcode.com/problems/3sum/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Two Pointers, Sorting
**LeetCode Link:** [https://leetcode.com/problems/3sum/](https://leetcode.com/problems/3sum/)
## Problem Description
Given an integer array `nums`, return all the triplets `[nums[i], nums[j], nums[k]]` such that `i != j`, `i != k`, and `j != k`, and `nums[i] + nums[j] + nums[k] == 0`.
Notice that the solution set must not contain duplicate triplets.
**Example 1:**
```
Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation:
The triplets [-1,0,1] and [-1,-1,2] sum to zero.
```
**Example 2:**
```
Input: nums = []
Output: []
```
**Example 3:**
```
Input: nums = [0]
Output: []
```
**Constraints:**
- `3 <= nums.length <= 3000`
- `-10^5 <= nums[i] <= 10^5`
## My Approach
I used a **Sorting + Two Pointers** approach. The key insight is to sort the array first, then use a fixed first element and two pointers to find the remaining two elements that sum to the negative of the first element.
**Algorithm:**
1. Sort the array to enable two-pointer technique
2. Iterate through each element as the first element of the triplet
3. Skip duplicates for the first element to avoid duplicate triplets
4. Use two pointers (left and right) to find the remaining two elements
5. Skip duplicates for the second and third elements
6. Add valid triplets to the result
## Solution
The solution uses sorting and two-pointer technique to find all unique triplets. See the implementation in the [solution file](../exercises/15.3sum.py).
**Key Points:**
- Sorts the array to enable efficient two-pointer search
- Uses three nested loops: outer loop for first element, two pointers for remaining elements
- Skips duplicates at all three levels to avoid duplicate triplets
- Handles edge cases like empty array or insufficient elements
## Time & Space Complexity
**Time Complexity:** O(n²)
- Sorting: O(n log n)
- Two-pointer search for each element: O(n²)
- Total: O(n²)
**Space Complexity:** O(1) (excluding output)
- Uses only a constant amount of extra space
- Output space is O(n²) in worst case for storing all triplets
## Key Insights
1. **Sorting Enables Two Pointers:** Sorting the array allows us to use two pointers efficiently to find pairs that sum to a target.
2. **Fixed First Element:** By fixing the first element, we reduce the problem to finding two elements that sum to -first_element.
3. **Duplicate Handling:** We need to skip duplicates at all three levels to avoid duplicate triplets in the result.
4. **Two Pointer Optimization:** When sum < 0, move left pointer right; when sum > 0, move right pointer left.
5. **Early Termination:** If the first element is positive, we can stop since all remaining elements will also be positive.
6. **Target Calculation:** For each first element nums[i], we look for two elements that sum to -nums[i].
## Mistakes Made
1. **Brute Force Approach:** Initially might consider O(n³) approach checking all possible triplets.
2. **Duplicate Handling:** Forgetting to skip duplicates at any of the three levels.
3. **Wrong Pointer Movement:** Moving pointers incorrectly based on the sum comparison.
4. **Edge Cases:** Not properly handling cases with fewer than 3 elements.
## Related Problems
- **Two Sum** (Problem 1): Finding two elements that sum to target
- **Two Sum II - Input Array Is Sorted** (Problem 167): Two sum in sorted array
- **4Sum** (Problem 18): Extension to finding four elements that sum to target
- **3Sum Closest** (Problem 16): Finding triplet with sum closest to target
## Alternative Approaches
1. **Hash Set:** Use hash set to store complements - O(n²) time, O(n) space
2. **Brute Force:** Check all possible triplets - O(n³) time complexity
3. **Binary Search:** Use binary search instead of two pointers - O(n² log n) time
## Common Pitfalls
1. **Duplicate Triplets:** Not properly handling duplicates in the result set.
2. **Wrong Complexity:** Using brute force approach instead of optimized solution.
3. **Pointer Movement:** Incorrectly moving pointers based on sum comparison.
4. **Edge Cases:** Not handling empty arrays or arrays with fewer than 3 elements.
5. **Sorting Overhead:** Forgetting that sorting is necessary for the two-pointer approach.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/15.3sum.py)](../exercises/15.3sum.py)
*Note: This is a classic problem that extends the two-sum concept and introduces the importance of handling duplicates in combination problems.*

View File

@@ -0,0 +1,128 @@
# Valid Parentheses
[![Problem 20](https://img.shields.io/badge/Problem-20-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-parentheses/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-parentheses/)
**Problem Number:** [20](https://leetcode.com/problems/valid-parentheses/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String, Stack
**LeetCode Link:** [https://leetcode.com/problems/valid-parentheses/](https://leetcode.com/problems/valid-parentheses/)
## Problem Description
Given a string `s` containing just the characters `'('`, `')'`, `'{'`, `'}'`, `'['` and `']'`, determine if the input string is valid.
An input string is valid if:
1. Open brackets must be closed by the same type of brackets.
2. Open brackets must be closed in the correct order.
3. Every close bracket has a corresponding open bracket of the same type.
**Example 1:**
```
Input: s = "()"
Output: true
```
**Example 2:**
```
Input: s = "()[]{}"
Output: true
```
**Example 3:**
```
Input: s = "(]"
Output: false
```
**Constraints:**
- `1 <= s.length <= 10^4`
- `s` consists of parentheses only `'()[]{}'`
## My Approach
I used a **Stack** approach to validate the parentheses. The key insight is to use a stack to keep track of opening brackets and match them with closing brackets in the correct order.
**Algorithm:**
1. Create a hash map mapping closing brackets to their corresponding opening brackets
2. Initialize an empty stack
3. Iterate through each character in the string
4. If it's an opening bracket, push it onto the stack
5. If it's a closing bracket, check if the top of stack matches the corresponding opening bracket
6. If match found, pop from stack; otherwise return false
7. Return true if stack is empty at the end
## Solution
The solution uses a stack to validate parentheses matching. See the implementation in the [solution file](../exercises/20.valid-parentheses.py).
**Key Points:**
- Uses a hash map to map closing brackets to opening brackets
- Stack stores opening brackets in order of appearance
- Validates matching brackets and correct order
- Handles edge cases like empty string and single characters
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the string once
- Stack operations (push/pop) are O(1)
- Hash map lookups are O(1)
- Total: O(n)
**Space Complexity:** O(n)
- Stack can store up to n/2 opening brackets in worst case
- Hash map has constant size (3 pairs)
- Total: O(n)
## Key Insights
1. **Stack for Order Tracking:** Stack naturally handles the "last in, first out" order required for parentheses matching.
2. **Hash Map for Mapping:** Using a hash map to map closing brackets to opening brackets makes the code cleaner and more efficient.
3. **Early Termination:** We can return false immediately when we encounter a mismatch or when trying to pop from an empty stack.
4. **Stack Empty Check:** At the end, the stack must be empty for the string to be valid (all brackets must be matched).
5. **Single Character Handling:** Strings with odd length or single characters are automatically invalid.
6. **Order Validation:** The stack ensures that brackets are closed in the correct order (most recent opening bracket must be closed first).
## Mistakes Made
1. **Wrong Data Structure:** Initially might use a simple counter approach, which doesn't handle order correctly.
2. **Missing Edge Cases:** Not properly handling empty strings or strings with single characters.
3. **Incorrect Mapping:** Using wrong mapping between opening and closing brackets.
4. **Stack Empty Check:** Forgetting to check if the stack is empty at the end.
## Related Problems
- **Generate Parentheses** (Problem 22): Generate all valid parentheses combinations
- **Longest Valid Parentheses** (Problem 32): Find longest valid parentheses substring
- **Remove Invalid Parentheses** (Problem 301): Remove minimum parentheses to make string valid
- **Check If a Parentheses String Can Be Valid** (Problem 2116): More complex validation
## Alternative Approaches
1. **Counter Approach:** Use counters for each bracket type (doesn't handle order correctly)
2. **Recursive:** Use recursion to validate nested parentheses
3. **Two Pass:** First pass to count brackets, second pass to validate order
## Common Pitfalls
1. **Wrong Order Handling:** Not using a stack and thus not handling the order correctly.
2. **Missing Edge Cases:** Not handling empty strings or single characters.
3. **Incorrect Mapping:** Using wrong bracket pairs in the mapping.
4. **Stack Empty Check:** Not checking if the stack is empty at the end.
5. **Early Termination:** Not returning false immediately when encountering mismatches.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/20.valid-parentheses.py)](../exercises/20.valid-parentheses.py)
*Note: This is a fundamental stack problem that introduces the concept of using a stack to validate matching pairs in the correct order.*

View File

@@ -0,0 +1,116 @@
# Generate Parentheses
[![Problem 22](https://img.shields.io/badge/Problem-22-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/generate-parentheses/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/generate-parentheses/)
**Problem Number:** [22](https://leetcode.com/problems/generate-parentheses/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** String, Backtracking, Dynamic Programming
**LeetCode Link:** [https://leetcode.com/problems/generate-parentheses/](https://leetcode.com/problems/generate-parentheses/)
## Problem Description
Given `n` pairs of parentheses, write a function to generate all combinations of well-formed parentheses.
**Example 1:**
```
Input: n = 3
Output: ["((()))","(()())","(())()","()(())","()()()"]
```
**Example 2:**
```
Input: n = 1
Output: ["()"]
```
**Constraints:**
- `1 <= n <= 8`
## My Approach
I used a **Backtracking** approach with recursion. The key insight is to build valid parentheses combinations by tracking the number of opening and closing parentheses used, ensuring we never have more closing than opening parentheses.
**Algorithm:**
1. Handle edge cases (n < 1 returns empty, n == 1 returns ["()"])
2. Use recursion with backtracking to build combinations
3. Track open and close parentheses count
4. Add opening parenthesis if open < n
5. Add closing parenthesis if close < open
6. When open == close == n, add the combination to result
7. Use backtracking to explore all valid combinations
## Solution
The solution uses backtracking with recursion to generate all valid parentheses combinations. See the implementation in the [solution file](../exercises/22.generate-parentheses.py).
**Key Points:**
- Uses backtracking to explore all valid combinations
- Tracks open and close parentheses counts
- Ensures closing parentheses never exceed opening parentheses
- Uses a stack to build combinations and backtrack
- Handles edge cases for n < 1 and n == 1
## Time & Space Complexity
**Time Complexity:** O(4^n/√n)
- This is the Catalan number C(n) = (2n)!/((n+1)!n!)
- Each valid combination requires O(n) time to build
- Total: O(4^n/√n)
**Space Complexity:** O(n)
- Recursion stack depth: O(n)
- Stack for building combinations: O(n)
- Output space: O(4^n/√n) for storing all combinations
## Key Insights
1. **Backtracking Pattern:** This is a classic backtracking problem where we build solutions incrementally and backtrack when constraints are violated.
2. **Parentheses Balance:** The key constraint is that at any point, the number of closing parentheses cannot exceed the number of opening parentheses.
3. **Catalan Numbers:** The number of valid combinations follows the Catalan number sequence.
4. **Recursive Structure:** Each recursive call represents a decision point: add opening parenthesis or closing parenthesis.
5. **Base Case:** When open == close == n, we have a complete valid combination.
6. **Pruning:** We can prune invalid paths early by checking the balance constraint.
## Mistakes Made
1. **Wrong Balance Check:** Initially might not properly check that closing parentheses don't exceed opening parentheses.
2. **Inefficient Generation:** Might generate invalid combinations and then filter them out.
3. **Missing Edge Cases:** Not properly handling n < 1 or n == 1 cases.
4. **Complex Logic:** Overcomplicating the recursion with unnecessary conditions.
## Related Problems
- **Valid Parentheses** (Problem 20): Check if parentheses string is valid
- **Longest Valid Parentheses** (Problem 32): Find longest valid parentheses substring
- **Remove Invalid Parentheses** (Problem 301): Remove minimum parentheses to make valid
- **Check If a Parentheses String Can Be Valid** (Problem 2116): More complex validation
## Alternative Approaches
1. **Dynamic Programming:** Build solutions from smaller subproblems
2. **Iterative:** Use iteration instead of recursion
3. **BFS:** Use breadth-first search to generate combinations level by level
## Common Pitfalls
1. **Wrong Balance Logic:** Not ensuring closing parentheses ≤ opening parentheses.
2. **Inefficient Generation:** Generating invalid combinations and filtering.
3. **Missing Edge Cases:** Not handling n < 1 or n == 1 properly.
4. **Complex Recursion:** Overcomplicating the recursive logic.
5. **Memory Issues:** Not using backtracking efficiently, leading to memory problems.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/22.generate-parentheses.py)](../exercises/22.generate-parentheses.py)
*Note: This is a classic backtracking problem that demonstrates how to generate all valid combinations while respecting constraints.*

View File

@@ -0,0 +1,125 @@
# Remove Duplicates from Sorted Array
[![Problem 26](https://img.shields.io/badge/Problem-26-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)
**Problem Number:** [26](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/remove-duplicates-from-sorted-array/](https://leetcode.com/problems/remove-duplicates-from-sorted-array/)
## Problem Description
Given an integer array `nums` sorted in non-decreasing order, remove the duplicates in-place such that each unique element appears only once. The relative order of the elements should be kept the same. Then return the number of unique elements in `nums`.
Consider the number of unique elements of `nums` to be `k`, to get accepted, you need to do the following things:
1. Change the array `nums` such that the first `k` elements of `nums` contain the unique elements in the order they were present in `nums` initially. The remaining elements of `nums` are not important as well as the size of `nums`.
2. Return `k`.
**Example 1:**
```
Input: nums = [1,1,2]
Output: 2, nums = [1,2,_]
Explanation: Your function should return k = 2, with the first two elements of nums being 1 and 2 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
```
**Example 2:**
```
Input: nums = [0,0,1,1,1,2,2,3,3,4]
Output: 5, nums = [0,1,2,3,4,_,_,_,_,_]
Explanation: Your function should return k = 5, with the first five elements of nums being 0, 1, 2, 3, and 4 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
```
**Constraints:**
- `1 <= nums.length <= 3 * 10^4`
- `-100 <= nums[i] <= 100`
- `nums` is sorted in non-decreasing order
## My Approach
I used a **Two Pointer** approach with in-place modification. The key insight is to use a slow pointer to track the position where the next unique element should be placed, and a fast pointer to scan through the array.
**Algorithm:**
1. Handle edge case (empty array returns 0)
2. Initialize slow pointer k at index 0
3. Iterate through array with fast pointer i
4. When nums[i] != nums[k], increment k and copy nums[i] to nums[k]
5. Return k + 1 (number of unique elements)
## Solution
The solution uses a two-pointer approach for in-place duplicate removal. See the implementation in the [solution file](../exercises/26.remove-duplicates-from-sorted-array.py).
**Key Points:**
- Uses two pointers: slow pointer (k) and fast pointer (i)
- Modifies array in-place without extra space
- Maintains relative order of elements
- Returns count of unique elements
- Handles edge case of empty array
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the array once with the fast pointer
- Each element is compared and potentially copied once
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- Modifies the array in-place
- No additional data structures needed
## Key Insights
1. **Two Pointer Technique:** Using a slow pointer to track the next position for unique elements and a fast pointer to scan through the array.
2. **In-Place Modification:** The problem requires modifying the array in-place, which is efficiently done with two pointers.
3. **Sorted Array Advantage:** Since the array is sorted, duplicates are always adjacent, making the comparison simple.
4. **Relative Order Preservation:** The two-pointer approach naturally preserves the relative order of elements.
5. **Efficient Copying:** We only copy elements when we find a new unique value, minimizing unnecessary operations.
6. **Return Value:** The function returns the count of unique elements, which is k + 1 (since k is 0-indexed).
## Mistakes Made
1. **Extra Space Usage:** Initially might use a hash set or new array, which violates the in-place requirement.
2. **Wrong Pointer Logic:** Not properly understanding when to increment the slow pointer.
3. **Return Value Confusion:** Returning the wrong value (k instead of k + 1).
4. **Edge Case Handling:** Not properly handling empty arrays.
## Related Problems
- **Remove Duplicates from Sorted Array II** (Problem 80): Allow at most 2 occurrences of each element
- **Remove Element** (Problem 27): Remove all instances of a specific value
- **Move Zeroes** (Problem 283): Move all zeros to the end while maintaining order
- **Sort Colors** (Problem 75): Sort array with only 0, 1, 2 values
## Alternative Approaches
1. **Hash Set:** Use a set to track seen elements (violates in-place requirement)
2. **New Array:** Create a new array with unique elements (violates in-place requirement)
3. **Library Functions:** Use built-in functions like set() (not allowed for this problem)
## Common Pitfalls
1. **Extra Space:** Using additional data structures when in-place modification is required.
2. **Wrong Return Value:** Returning k instead of k + 1.
3. **Pointer Logic:** Not understanding when to move the slow pointer.
4. **Edge Cases:** Not handling empty arrays properly.
5. **Order Preservation:** Not maintaining the relative order of elements.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/26.remove-duplicates-from-sorted-array.py)](../exercises/26.remove-duplicates-from-sorted-array.py)
*Note: This is a fundamental two-pointer problem that demonstrates efficient in-place array modification.*

View File

@@ -0,0 +1,124 @@
# Remove Element
[![Problem 27](https://img.shields.io/badge/Problem-27-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/remove-element/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/remove-element/)
**Problem Number:** [27](https://leetcode.com/problems/remove-element/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/remove-element/](https://leetcode.com/problems/remove-element/)
## Problem Description
Given an integer array `nums` and an integer `val`, remove all occurrences of `val` in `nums` in-place. The relative order of the elements may be changed.
Since it is impossible to change the length of the array in some programming languages, you must instead have the result be placed in the first part of the array `nums`. More formally, if there are `k` elements after removing the duplicates, then the first `k` elements of `nums` should hold the final result. It does not matter what you leave beyond the first `k` elements.
Return `k` after placing the final result in the first `k` slots of `nums`.
**Example 1:**
```
Input: nums = [3,2,2,3], val = 3
Output: 2, nums = [2,2,_,_]
Explanation: Your function should return k = 2, with the first two elements of nums being 2.
It does not matter what you leave beyond the returned k (hence they are underscores).
```
**Example 2:**
```
Input: nums = [0,1,2,2,3,0,4,2], val = 2
Output: 5, nums = [0,1,3,0,4,_,_,_]
Explanation: Your function should return k = 5, with the first five elements of nums containing 0, 0, 1, 3, and 4.
Note that the order of those five elements can be arbitrary.
```
**Constraints:**
- `0 <= nums.length <= 100`
- `0 <= nums[i] <= 50`
- `0 <= val <= 100`
## My Approach
I used a **Two Pointer** approach with in-place modification. The key insight is to use a slow pointer to track the position where the next non-target element should be placed, and a fast pointer to scan through the array.
**Algorithm:**
1. Initialize slow pointer k at index 0
2. Iterate through array with fast pointer i
3. When nums[i] != val, copy nums[i] to nums[k] and increment k
4. Skip elements equal to val (don't copy them)
5. Return k (number of elements not equal to val)
## Solution
The solution uses a two-pointer approach for in-place element removal. See the implementation in the [solution file](../exercises/27.remove-element.py).
**Key Points:**
- Uses two pointers: slow pointer (k) and fast pointer (i)
- Modifies array in-place without extra space
- Copies only non-target elements to the front
- Returns count of elements not equal to val
- Maintains relative order of non-target elements
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the array once with the fast pointer
- Each element is checked and potentially copied once
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- Modifies the array in-place
- No additional data structures needed
## Key Insights
1. **Two Pointer Technique:** Using a slow pointer to track the next position for non-target elements and a fast pointer to scan through the array.
2. **In-Place Modification:** The problem requires modifying the array in-place, which is efficiently done with two pointers.
3. **Selective Copying:** We only copy elements that are not equal to the target value, effectively removing all occurrences.
4. **Order Preservation:** The two-pointer approach preserves the relative order of non-target elements.
5. **Efficient Skipping:** We skip target elements without copying them, minimizing unnecessary operations.
6. **Return Value:** The function returns the count of elements not equal to the target value.
## Mistakes Made
1. **Extra Space Usage:** Initially might use a new array or list to store non-target elements.
2. **Wrong Pointer Logic:** Not properly understanding when to increment the slow pointer.
3. **Inefficient Approach:** Using remove() or similar methods that shift elements.
4. **Return Value Confusion:** Returning the wrong value or not understanding what k represents.
## Related Problems
- **Remove Duplicates from Sorted Array** (Problem 26): Remove duplicates in sorted array
- **Move Zeroes** (Problem 283): Move all zeros to the end while maintaining order
- **Sort Colors** (Problem 75): Sort array with only 0, 1, 2 values
- **Remove Duplicates from Sorted Array II** (Problem 80): Allow at most 2 occurrences
## Alternative Approaches
1. **New Array:** Create a new array with non-target elements (violates in-place requirement)
2. **List Methods:** Use remove() method (inefficient due to shifting)
3. **Filter:** Use filter functions (violates in-place requirement)
## Common Pitfalls
1. **Extra Space:** Using additional data structures when in-place modification is required.
2. **Wrong Pointer Logic:** Not understanding when to move the slow pointer.
3. **Inefficient Methods:** Using methods that shift elements or create new arrays.
4. **Return Value:** Not understanding what the return value represents.
5. **Order Preservation:** Not maintaining the relative order of non-target elements.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/27.remove-element.py)](../exercises/27.remove-element.py)
*Note: This is a fundamental two-pointer problem that demonstrates efficient in-place element removal.*

View File

@@ -0,0 +1,119 @@
# Find the Index of the First Occurrence in a String
[![Problem 28](https://img.shields.io/badge/Problem-28-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/)
**Problem Number:** [28](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String, Two Pointers, String Matching
**LeetCode Link:** [https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/](https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/)
## Problem Description
Given two strings `needle` and `haystack`, return the index of the first occurrence of `needle` in `haystack`, or `-1` if `needle` is not part of `haystack`.
**Example 1:**
```
Input: haystack = "sadbutsad", needle = "sad"
Output: 0
Explanation: "sad" occurs at index 0 and 6.
The first occurrence is at index 0, so we return 0.
```
**Example 2:**
```
Input: haystack = "leetcode", needle = "leeto"
Output: -1
Explanation: "leeto" did not occur in "leetcode", so we return -1.
```
**Constraints:**
- `1 <= haystack.length, needle.length <= 10^4`
- `haystack` and `needle` consist of only lowercase English characters
## My Approach
I used a **Sliding Window** approach with string slicing. The key insight is to check each possible starting position in the haystack string by comparing substrings of the same length as the needle.
**Algorithm:**
1. Iterate through each possible starting position in haystack
2. Check if the remaining length is sufficient for the needle
3. Compare the substring starting at current position with the needle
4. Return the index if a match is found
5. Return -1 if no match is found
## Solution
The solution uses a sliding window approach with string slicing. See the implementation in the [solution file](../exercises/28.find-the-index-of-the-first-occurrence-in-a-string.py).
**Key Points:**
- Uses sliding window to check each possible starting position
- Compares substrings of needle length with the needle
- Handles edge cases like needle longer than haystack
- Returns first occurrence index or -1 if not found
- Uses string slicing for efficient substring comparison
## Time & Space Complexity
**Time Complexity:** O((n-m+1) × m)
- n is the length of haystack, m is the length of needle
- We check (n-m+1) possible starting positions
- Each substring comparison takes O(m) time
- Total: O((n-m+1) × m) = O(nm) in worst case
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- String slicing creates temporary strings but doesn't affect asymptotic complexity
## Key Insights
1. **Sliding Window:** Using a sliding window to check each possible starting position for the needle.
2. **String Slicing:** Python's string slicing provides an efficient way to extract substrings for comparison.
3. **Early Termination:** We can stop early if the remaining length is insufficient for the needle.
4. **First Occurrence:** The algorithm naturally finds the first occurrence since we check positions in order.
5. **Edge Case Handling:** Needle longer than haystack automatically returns -1.
6. **Simple Implementation:** This approach is straightforward and easy to understand.
## Mistakes Made
1. **Inefficient Algorithm:** Initially might use a more complex algorithm like KMP when simple sliding window suffices.
2. **Wrong Bounds:** Not properly checking if the remaining length is sufficient for the needle.
3. **Index Confusion:** Returning wrong index or not handling the case where needle is not found.
4. **Over-engineering:** Using complex string matching algorithms when the problem constraints allow simpler solutions.
## Related Problems
- **Repeated String Match** (Problem 686): Find minimum number of times to repeat string
- **Shortest Palindrome** (Problem 214): Find shortest palindrome by adding characters
- **Longest Common Prefix** (Problem 14): Find common prefix among strings
- **Valid Anagram** (Problem 242): Check if two strings are anagrams
## Alternative Approaches
1. **KMP Algorithm:** More efficient for large strings - O(n+m) time complexity
2. **Boyer-Moore Algorithm:** Another efficient string matching algorithm
3. **Rabin-Karp Algorithm:** Uses hashing for string matching
4. **Built-in Methods:** Use str.find() or str.index() (though this might not be the intended solution)
## Common Pitfalls
1. **Wrong Complexity:** Not understanding the time complexity of string slicing.
2. **Bounds Checking:** Not properly checking if there's enough remaining string length.
3. **Index Errors:** Returning wrong index or not handling edge cases.
4. **Over-optimization:** Using complex algorithms when simple approach suffices.
5. **String Comparison:** Not understanding how string comparison works in Python.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/28.find-the-index-of-the-first-occurrence-in-a-string.py)](../exercises/28.find-the-index-of-the-first-occurrence-in-a-string.py)
*Note: This is a fundamental string matching problem that introduces the concept of sliding window for substring search.*

View File

@@ -0,0 +1,124 @@
# Search Insert Position
[![Problem 35](https://img.shields.io/badge/Problem-35-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/search-insert-position/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/search-insert-position/)
**Problem Number:** [35](https://leetcode.com/problems/search-insert-position/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Binary Search
**LeetCode Link:** [https://leetcode.com/problems/search-insert-position/](https://leetcode.com/problems/search-insert-position/)
## Problem Description
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You must write an algorithm with `O(log n)` runtime complexity.
**Example 1:**
```
Input: nums = [1,3,5,6], target = 5
Output: 2
```
**Example 2:**
```
Input: nums = [1,3,5,6], target = 2
Output: 1
```
**Example 3:**
```
Input: nums = [1,3,5,6], target = 7
Output: 4
```
**Constraints:**
- `1 <= nums.length <= 10^4`
- `-10^4 <= nums[i] <= 10^4`
- `nums` contains distinct values sorted in ascending order
- `-10^4 <= target <= 10^4`
## My Approach
I used a **Binary Search** approach with optimization for edge cases. The key insight is to use binary search to find the target or determine where it should be inserted, with special handling for targets larger than the maximum element.
**Algorithm:**
1. Handle edge case: if target > last element, return array length
2. Use binary search with left and right pointers
3. When target > mid element, search right half (left = mid + 1)
4. When target ≤ mid element, search left half (right = mid)
5. Return left pointer when search converges
## Solution
The solution uses binary search with edge case optimization. See the implementation in the [solution file](../exercises/35.search-insert-position.py).
**Key Points:**
- Uses binary search for O(log n) time complexity
- Handles edge case where target is larger than all elements
- Returns insertion position when target is not found
- Maintains sorted order requirement
- Efficiently narrows search space
## Time & Space Complexity
**Time Complexity:** O(log n)
- Binary search halves the search space in each iteration
- Total iterations: log₂(n)
- Total: O(log n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Binary Search Efficiency:** Binary search provides the required O(log n) time complexity for sorted arrays.
2. **Edge Case Handling:** When target is larger than the maximum element, it should be inserted at the end (index = array length).
3. **Insertion Position:** When target is not found, the left pointer naturally points to the correct insertion position.
4. **Sorted Array Advantage:** The sorted nature of the array enables efficient binary search.
5. **Convergence:** The binary search converges to the correct insertion position even when the target is not found.
6. **Distinct Values:** The problem guarantees distinct values, simplifying the comparison logic.
## Mistakes Made
1. **Linear Search:** Initially might use linear search, which doesn't meet the O(log n) requirement.
2. **Wrong Edge Case:** Not properly handling the case where target is larger than all elements.
3. **Complex Logic:** Overcomplicating the binary search with unnecessary conditions.
4. **Return Value Confusion:** Not understanding that the left pointer gives the insertion position.
## Related Problems
- **Binary Search** (Problem 704): Basic binary search implementation
- **Find First and Last Position of Element in Sorted Array** (Problem 34): Binary search with duplicates
- **Search in Rotated Sorted Array** (Problem 33): Binary search in modified sorted array
- **Find Peak Element** (Problem 162): Binary search for peak finding
## Alternative Approaches
1. **Linear Search:** Check each element sequentially - O(n) time complexity
2. **Built-in Functions:** Use bisect.bisect_left() in Python
3. **Recursive Binary Search:** Use recursion instead of iteration
## Common Pitfalls
1. **Wrong Complexity:** Using linear search instead of binary search.
2. **Edge Case Handling:** Not handling targets larger than the maximum element.
3. **Binary Search Logic:** Incorrectly implementing the binary search algorithm.
4. **Return Value:** Not understanding what the left pointer represents.
5. **Over-engineering:** Adding unnecessary complexity to a straightforward binary search.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/35.search-insert-position.py)](../exercises/35.search-insert-position.py)
*Note: This is a fundamental binary search problem that demonstrates how to find insertion positions in sorted arrays efficiently.*

View File

@@ -0,0 +1,144 @@
# Valid Sudoku
[![Problem 36](https://img.shields.io/badge/Problem-36-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-sudoku/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-sudoku/)
**Problem Number:** [36](https://leetcode.com/problems/valid-sudoku/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Hash Table, Matrix
**LeetCode Link:** [https://leetcode.com/problems/valid-sudoku/](https://leetcode.com/problems/valid-sudoku/)
## Problem Description
Determine if a `9 x 9` Sudoku board is valid. Only the filled cells need to be validated according to the following rules:
1. Each row must contain the digits `1-9` without repetition.
2. Each column must contain the digits `1-9` without repetition.
3. Each of the nine `3 x 3` sub-boxes of the grid must contain the digits `1-9` without repetition.
**Note:**
- A Sudoku board (partially filled) could be valid but is not necessarily solvable.
- Only the filled cells need to be validated according to the mentioned rules.
**Example 1:**
```
Input: board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: true
```
**Example 2:**
```
Input: board =
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: false
```
**Constraints:**
- `board.length == 9`
- `board[i].length == 9`
- `board[i][j]` is a digit `1-9` or `'.'`
## My Approach
I used a **Hash Table** approach to track digits in rows, columns, and 3x3 sub-boxes. The key insight is to use separate hash tables for each row, column, and sub-box to check for duplicates.
**Algorithm:**
1. Initialize hash tables for rows, columns, and sub-boxes
2. Iterate through each cell in the board
3. For each non-empty cell, check if the digit exists in the corresponding row, column, and sub-box
4. If duplicate found, return false
5. Otherwise, add the digit to all three hash tables
6. Return true if no duplicates found
## Solution
The solution uses hash tables to validate Sudoku rules. See the implementation in the [solution file](../exercises/36.valid-sudoku.py).
**Key Points:**
- Uses hash tables to track digits in rows, columns, and sub-boxes
- Maps 3x3 sub-boxes to indices 0-8 based on row and column position
- Checks for duplicates in all three constraints simultaneously
- Handles empty cells ('.') by skipping them
- Returns false immediately when a duplicate is found
## Time & Space Complexity
**Time Complexity:** O(n²)
- We traverse the entire 9x9 board once
- Each cell requires constant time hash table operations
- Total: O(81) = O(n²) where n = 9
**Space Complexity:** O(n²)
- Hash tables for rows: O(n)
- Hash tables for columns: O(n)
- Hash tables for sub-boxes: O(n)
- Total: O(n²)
## Key Insights
1. **Hash Table Efficiency:** Using hash tables provides O(1) lookup time for checking duplicates.
2. **Sub-box Mapping:** The 3x3 sub-boxes can be mapped to indices 0-8 using the formula: `(i//3)*3 + j//3`.
3. **Simultaneous Validation:** We can check all three constraints (row, column, sub-box) for each cell in one pass.
4. **Early Termination:** We can return false immediately when a duplicate is found, avoiding unnecessary checks.
5. **Empty Cell Handling:** Empty cells ('.') should be skipped as they don't affect validity.
6. **Fixed Size:** Since the board is always 9x9, the time and space complexity are effectively constant.
## Mistakes Made
1. **Inefficient Approach:** Initially might use nested loops to check each constraint separately.
2. **Wrong Sub-box Mapping:** Incorrectly calculating the sub-box index for each cell.
3. **Missing Early Termination:** Not returning false immediately when duplicates are found.
4. **Complex Logic:** Overcomplicating the validation with unnecessary conditions.
## Related Problems
- **Sudoku Solver** (Problem 37): Solve a Sudoku puzzle
- **N-Queens** (Problem 51): Place queens on chessboard without conflicts
- **Word Search** (Problem 79): Find words in 2D grid
- **Number of Islands** (Problem 200): Count connected components in grid
## Alternative Approaches
1. **Set-based:** Use sets instead of hash tables for tracking digits
2. **Bit Manipulation:** Use bit masks to represent digits (more memory efficient)
3. **Separate Passes:** Check rows, columns, and sub-boxes in separate passes
## Common Pitfalls
1. **Wrong Sub-box Calculation:** Incorrectly mapping cells to 3x3 sub-boxes.
2. **Inefficient Validation:** Checking constraints separately instead of simultaneously.
3. **Missing Early Termination:** Not stopping when first duplicate is found.
4. **Empty Cell Handling:** Not properly handling '.' characters.
5. **Complex Logic:** Overcomplicating the validation process.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/36.valid-sudoku.py)](../exercises/36.valid-sudoku.py)
*Note: This is a classic matrix validation problem that demonstrates efficient use of hash tables for constraint checking.*

View File

@@ -0,0 +1,117 @@
# Trapping Rain Water
[![Problem 42](https://img.shields.io/badge/Problem-42-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/trapping-rain-water/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Hard-red?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=HARD)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/trapping-rain-water/)
**Problem Number:** [42](https://leetcode.com/problems/trapping-rain-water/)
**Difficulty:** [Hard](https://leetcode.com/problemset/?difficulty=HARD)
**Category:** Array, Two Pointers, Dynamic Programming, Stack
**LeetCode Link:** [https://leetcode.com/problems/trapping-rain-water/](https://leetcode.com/problems/trapping-rain-water/)
## Problem Description
Given `n` non-negative integers representing an elevation map where the width of each bar is `1`, compute how much water it can trap after raining.
**Example 1:**
```
Input: height = [0,1,0,2,1,0,1,3,2,1,2,1]
Output: 6
Explanation: The elevation map is represented by array [0,1,0,2,1,0,1,3,2,1,2,1]. In this case, 6 units of rain water are being trapped.
```
**Example 2:**
```
Input: height = [4,2,0,3,2,5]
Output: 9
```
**Constraints:**
- `n == height.length`
- `1 <= n <= 2 * 10^4`
- `0 <= height[i] <= 10^5`
## My Approach
I used a **Two Pointer** approach with dynamic tracking of maximum heights. The key insight is to use two pointers from both ends and track the maximum heights from left and right, calculating water trapped at each position.
**Algorithm:**
1. Initialize two pointers at the beginning and end of the array
2. Track maximum heights from left (max_left) and right (max_right)
3. Move the pointer with smaller height inward
4. For each position, calculate water trapped as min(max_left, max_right) - current_height
5. Update the corresponding maximum height if current height is larger
6. Return total water trapped
## Solution
The solution uses a two-pointer approach with dynamic maximum tracking. See the implementation in the [solution file](../exercises/42.trapping-rain-water.py).
**Key Points:**
- Uses two pointers moving from opposite ends
- Tracks maximum heights from left and right dynamically
- Calculates water trapped at each position
- Moves pointer with smaller height to ensure correct calculation
- Handles edge cases efficiently
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the array once with two pointers
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures proportional to input size
## Key Insights
1. **Two Pointer Technique:** Using pointers from both ends allows us to track maximum heights efficiently.
2. **Dynamic Maximum Tracking:** We update the maximum heights as we move the pointers, ensuring we always have the correct bounds.
3. **Pointer Movement Strategy:** Moving the pointer with smaller height ensures we don't miss any trapped water.
4. **Water Calculation:** Water trapped at any position is min(left_max, right_max) - current_height.
5. **Greedy Approach:** The two-pointer approach is greedy and optimal for this problem.
6. **Edge Case Handling:** The algorithm naturally handles cases with no trapped water.
## Mistakes Made
1. **Wrong Pointer Movement:** Initially might move the wrong pointer, leading to incorrect calculations.
2. **Complex Approach:** Might use a more complex approach like precomputing maximum heights.
3. **Wrong Water Calculation:** Incorrectly calculating the amount of water trapped at each position.
4. **Missing Edge Cases:** Not properly handling arrays with no trapped water.
## Related Problems
- **Container With Most Water** (Problem 11): Find maximum area between two heights
- **Largest Rectangle in Histogram** (Problem 84): Find largest rectangle in histogram
- **Maximal Rectangle** (Problem 85): Find maximal rectangle in binary matrix
- **Candy** (Problem 135): Distribute candies based on ratings
## Alternative Approaches
1. **Dynamic Programming:** Precompute left and right maximum heights - O(n) time, O(n) space
2. **Stack-based:** Use monotonic stack to find trapped water - O(n) time, O(n) space
3. **Brute Force:** Check each position with nested loops - O(n²) time complexity
## Common Pitfalls
1. **Wrong Pointer Logic:** Moving the pointer with larger height instead of smaller height.
2. **Complex Implementation:** Using unnecessary data structures or complex logic.
3. **Wrong Water Calculation:** Not understanding how to calculate trapped water correctly.
4. **Edge Cases:** Not handling cases with no trapped water or single elements.
5. **Over-engineering:** Using more complex approaches when two-pointer suffices.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/42.trapping-rain-water.py)](../exercises/42.trapping-rain-water.py)
*Note: This is a classic two-pointer problem that demonstrates efficient water trapping calculation with dynamic maximum tracking.*

View File

@@ -0,0 +1,125 @@
# Group Anagrams
[![Problem 49](https://img.shields.io/badge/Problem-49-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/group-anagrams/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/group-anagrams/)
**Problem Number:** [49](https://leetcode.com/problems/group-anagrams/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Hash Table, String, Sorting
**LeetCode Link:** [https://leetcode.com/problems/group-anagrams/](https://leetcode.com/problems/group-anagrams/)
## Problem Description
Given an array of strings `strs`, group the anagrams together. You can return the answer in any order.
An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
**Example 1:**
```
Input: strs = ["eat","tea","tan","ate","nat","bat"]
Output: [["bat"],["nat","tan"],["ate","eat","tea"]]
```
**Example 2:**
```
Input: strs = [""]
Output: [[""]]
```
**Example 3:**
```
Input: strs = ["a"]
Output: [["a"]]
```
**Constraints:**
- `1 <= strs.length <= 10^4`
- `0 <= strs[i].length <= 100`
- `strs[i]` consists of lowercase English letters
## My Approach
I used a **Hash Table** approach with sorted string keys. The key insight is to use the sorted version of each string as a key to group anagrams together, since anagrams have the same characters when sorted.
**Algorithm:**
1. Handle edge case: if array has less than 2 elements, return the array as is
2. Create a hash map to store groups of anagrams
3. For each string, sort its characters to create a key
4. Use the sorted string as key and group original strings together
5. Return all groups from the hash map
## Solution
The solution uses a hash table with sorted string keys to group anagrams. See the implementation in the [solution file](../exercises/49.group-anagrams.js).
**Key Points:**
- Uses hash table to group anagrams efficiently
- Sorts characters of each string to create unique keys
- Handles edge cases like empty array or single element
- Groups strings with same sorted representation together
- Returns all groups in any order
## Time & Space Complexity
**Time Complexity:** O(n × k log k)
- n is the number of strings
- k is the maximum length of any string
- Sorting each string takes O(k log k) time
- Total: O(n × k log k)
**Space Complexity:** O(n × k)
- Hash table stores all strings
- Each string can be up to length k
- Total: O(n × k)
## Key Insights
1. **Sorted String as Key:** Anagrams have the same characters when sorted, making them perfect keys for grouping.
2. **Hash Table Efficiency:** Using a hash table provides O(1) average time for insertions and lookups.
3. **Edge Case Handling:** Arrays with less than 2 elements can be returned directly.
4. **Character Sorting:** Sorting characters creates a canonical representation for anagrams.
5. **Grouping Strategy:** All strings with the same sorted representation are anagrams of each other.
6. **Flexible Output:** The problem allows returning groups in any order.
## Mistakes Made
1. **Inefficient Key Generation:** Initially might use character frequency counting instead of sorting.
2. **Wrong Data Structure:** Not using a hash table for efficient grouping.
3. **Edge Case Missing:** Not properly handling arrays with single elements or empty strings.
4. **Complex Logic:** Overcomplicating the grouping process.
## Related Problems
- **Valid Anagram** (Problem 242): Check if two strings are anagrams
- **Find All Anagrams in a String** (Problem 438): Find all anagrams of a pattern in a string
- **Longest Common Prefix** (Problem 14): Find common prefix among strings
- **Group Shifted Strings** (Problem 249): Group strings that can be shifted to each other
## Alternative Approaches
1. **Character Frequency:** Use character count arrays as keys - O(n × k) time
2. **Prime Number Product:** Use product of prime numbers for each character - O(n × k) time
3. **Bit Manipulation:** Use bit masks for character representation (limited to 26 characters)
## Common Pitfalls
1. **Wrong Key Generation:** Not using sorted strings or character frequency as keys.
2. **Inefficient Sorting:** Sorting strings repeatedly instead of using efficient key generation.
3. **Edge Cases:** Not handling arrays with single elements or empty strings.
4. **Memory Usage:** Not considering the space complexity of storing all strings.
5. **Output Format:** Not returning the correct nested array structure.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/49.group-anagrams.js)](../exercises/49.group-anagrams.js)
*Note: This is a classic hash table problem that demonstrates efficient grouping using sorted string keys.*

125
src/notes/050_powx_n.md Normal file
View File

@@ -0,0 +1,125 @@
# Pow(x, n)
[![Problem 50](https://img.shields.io/badge/Problem-50-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/powx-n/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/powx-n/)
**Problem Number:** [50](https://leetcode.com/problems/powx-n/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Math, Recursion
**LeetCode Link:** [https://leetcode.com/problems/powx-n/](https://leetcode.com/problems/powx-n/)
## Problem Description
Implement `pow(x, n)`, which calculates `x` raised to the power `n` (i.e., `x^n`).
**Example 1:**
```
Input: x = 2.00000, n = 10
Output: 1024.00000
```
**Example 2:**
```
Input: x = 2.10000, n = 3
Output: 9.26100
```
**Example 3:**
```
Input: x = 2.00000, n = -2
Output: 0.25000
Explanation: 2^-2 = 1/2^2 = 1/4 = 0.25
```
**Constraints:**
- `-100.0 < x < 100.0`
- `-2^31 <= n <= 2^31-1`
- `n` is an integer
- `-10^4 <= x^n <= 10^4`
## My Approach
I used a **Fast Exponentiation** approach with recursion. The key insight is to use the mathematical property that x^n = (x^(n/2))^2 for even n, and x^n = x * (x^(n/2))^2 for odd n, reducing the time complexity from O(n) to O(log n).
**Algorithm:**
1. Handle base case: if n == 0, return 1
2. Handle negative exponent: if n < 0, return 1 / pow(x, |n|)
3. Use recursive fast exponentiation:
- If n is even: return (x^(n/2))^2
- If n is odd: return x * (x^(n/2))^2
4. Use helper function to implement the recursive logic
## Solution
The solution uses fast exponentiation with recursion. See the implementation in the [solution file](../exercises/50.powx-n.py).
**Key Points:**
- Uses fast exponentiation to achieve O(log n) time complexity
- Handles negative exponents by taking reciprocal
- Uses recursion with divide-and-conquer approach
- Handles edge cases like n = 0 and negative n
- Efficiently computes large powers
## Time & Space Complexity
**Time Complexity:** O(log n)
- Each recursive call reduces n by half
- Total recursive calls: log₂(n)
- Total: O(log n)
**Space Complexity:** O(log n)
- Recursion stack depth: O(log n)
- Each recursive call uses constant space
- Total: O(log n)
## Key Insights
1. **Fast Exponentiation:** Using the mathematical property x^n = (x^(n/2))^2 reduces complexity from O(n) to O(log n).
2. **Divide and Conquer:** Breaking down the problem into smaller subproblems using recursion.
3. **Negative Exponent Handling:** x^(-n) = 1 / x^n, so we can handle negative exponents by taking the reciprocal.
4. **Even/Odd Split:** Different handling for even and odd exponents optimizes the calculation.
5. **Base Case:** n = 0 always returns 1, providing a clear termination condition.
6. **Overflow Prevention:** The algorithm naturally handles large exponents efficiently.
## Mistakes Made
1. **Linear Approach:** Initially might use a simple loop multiplying x n times, leading to O(n) complexity.
2. **Overflow Issues:** Not considering integer overflow for large exponents.
3. **Negative Exponent:** Forgetting to handle negative exponents properly.
4. **Recursion Depth:** Not considering stack overflow for very large exponents.
## Related Problems
- **Sqrt(x)** (Problem 69): Calculate square root using binary search
- **Super Pow** (Problem 372): Modular exponentiation
- **Factorial Trailing Zeroes** (Problem 172): Count trailing zeros in factorial
- **Count Primes** (Problem 204): Count prime numbers less than n
## Alternative Approaches
1. **Iterative Fast Exponentiation:** Use iteration instead of recursion - O(log n) time, O(1) space
2. **Binary Exponentiation:** Use bit manipulation for even faster computation
3. **Built-in Functions:** Use math.pow() or ** operator (not allowed for this problem)
## Common Pitfalls
1. **Linear Complexity:** Using simple multiplication loop instead of fast exponentiation.
2. **Overflow Handling:** Not considering integer overflow for large exponents.
3. **Negative Exponents:** Incorrectly handling negative exponents.
4. **Recursion Stack:** Not considering stack overflow for very large exponents.
5. **Precision Issues:** Not handling floating-point precision correctly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/50.powx-n.py)](../exercises/50.powx-n.py)
*Note: This is a classic mathematical problem that demonstrates efficient exponentiation using divide-and-conquer recursion.*

118
src/notes/055_jump_game.md Normal file
View File

@@ -0,0 +1,118 @@
# Jump Game
[![Problem 55](https://img.shields.io/badge/Problem-55-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/jump-game/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/jump-game/)
**Problem Number:** [55](https://leetcode.com/problems/jump-game/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Greedy, Dynamic Programming
**LeetCode Link:** [https://leetcode.com/problems/jump-game/](https://leetcode.com/problems/jump-game/)
## Problem Description
You are given an integer array `nums`. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.
Return `true` if you can reach the last index, or `false` otherwise.
**Example 1:**
```
Input: nums = [2,3,1,1,4]
Output: true
Explanation: Jump 1 step from index 0 to 1, then 3 steps to the last index.
```
**Example 2:**
```
Input: nums = [3,2,1,0,4]
Output: false
Explanation: You will always arrive at index 3 no matter what. Its maximum jump length is 0, which makes it impossible to reach the last index.
```
**Constraints:**
- `1 <= nums.length <= 10^4`
- `0 <= nums[i] <= 10^5`
## My Approach
I used a **Greedy** approach with dynamic tracking of the maximum reachable position. The key insight is to track the farthest position we can reach from the current position and check if we can reach each index.
**Algorithm:**
1. Initialize a variable to track the farthest reachable position
2. Iterate through each position in the array
3. If current position is beyond the farthest reachable position, return false
4. Update the farthest reachable position as max(current_farthest, current_position + jump_length)
5. Return true if we can reach the last position
## Solution
The solution uses a greedy approach with dynamic reach tracking. See the implementation in the [solution file](../exercises/55.jump-game.py).
**Key Points:**
- Uses greedy approach to track maximum reachable position
- Checks if current position is reachable before proceeding
- Updates farthest reach dynamically based on current jump
- Returns false immediately if position is unreachable
- Efficiently determines if last index is reachable
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the array once
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Greedy Approach:** We always want to reach the farthest possible position at each step.
2. **Reachability Check:** If we can't reach the current position, we can't reach any position beyond it.
3. **Dynamic Tracking:** We update the maximum reachable position based on the current position and its jump length.
4. **Early Termination:** We can return false as soon as we encounter an unreachable position.
5. **Optimal Substructure:** The solution for the entire array depends on the solution for subarrays.
6. **No Backtracking:** Once we determine a position is unreachable, we don't need to check further.
## Mistakes Made
1. **Backtracking Approach:** Initially might use backtracking or DFS, which is inefficient.
2. **Wrong Reach Calculation:** Not properly updating the maximum reachable position.
3. **Complex Logic:** Overcomplicating the solution with unnecessary data structures.
4. **Missing Early Termination:** Not returning false when encountering unreachable positions.
## Related Problems
- **Jump Game II** (Problem 45): Find minimum jumps to reach the end
- **Gas Station** (Problem 134): Find starting gas station for circular tour
- **Candy** (Problem 135): Distribute candies based on ratings
- **Best Time to Buy and Sell Stock** (Problem 121): Find maximum profit from stock prices
## Alternative Approaches
1. **Dynamic Programming:** Use DP array to track reachability - O(n²) time, O(n) space
2. **Backtracking:** Try all possible jumps recursively - O(2^n) time complexity
3. **BFS:** Use breadth-first search to find path - O(n²) time complexity
## Common Pitfalls
1. **Wrong Algorithm:** Using backtracking or DFS instead of greedy approach.
2. **Incorrect Reach Calculation:** Not properly updating the maximum reachable position.
3. **Missing Early Termination:** Not stopping when encountering unreachable positions.
4. **Complex Implementation:** Using unnecessary data structures or complex logic.
5. **Edge Cases:** Not handling arrays with single elements or zero jumps.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/55.jump-game.py)](../exercises/55.jump-game.py)
*Note: This is a classic greedy problem that demonstrates efficient reachability checking with dynamic position tracking.*

View File

@@ -0,0 +1,126 @@
# Length of Last Word
[![Problem 58](https://img.shields.io/badge/Problem-58-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/length-of-last-word/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/length-of-last-word/)
**Problem Number:** [58](https://leetcode.com/problems/length-of-last-word/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String
**LeetCode Link:** [https://leetcode.com/problems/length-of-last-word/](https://leetcode.com/problems/length-of-last-word/)
## Problem Description
Given a string `s` consisting of words and spaces, return the length of the last word in the string.
A word is a maximal substring consisting of non-space characters only.
**Example 1:**
```
Input: s = "Hello World"
Output: 5
Explanation: The last word is "World" with length 5.
```
**Example 2:**
```
Input: s = " fly me to the moon "
Output: 4
Explanation: The last word is "moon" with length 4.
```
**Example 3:**
```
Input: s = "luffy is still joyboy"
Output: 6
Explanation: The last word is "joyboy" with length 6.
```
**Constraints:**
- `1 <= s.length <= 10^4`
- `s` consists of only English letters and spaces `' '`
- There will be at least one word in `s`
## My Approach
I used a **String Manipulation** approach with built-in functions. The key insight is to strip leading and trailing spaces, then split the string by spaces to get the last word.
**Algorithm:**
1. Strip leading and trailing whitespace from the string
2. Split the string by spaces to get an array of words
3. Return the length of the last word in the array
## Solution
The solution uses string manipulation with built-in functions. See the implementation in the [solution file](../exercises/58.length-of-last-word.py).
**Key Points:**
- Uses strip() to remove leading and trailing spaces
- Uses split() to separate words by spaces
- Returns length of the last word in the resulting array
- Handles multiple spaces between words automatically
- Simple and efficient approach
## Time & Space Complexity
**Time Complexity:** O(n)
- strip() operation: O(n)
- split() operation: O(n)
- length calculation: O(1)
- Total: O(n)
**Space Complexity:** O(n)
- split() creates a new array of words
- Each word can be up to length n
- Total: O(n)
## Key Insights
1. **String Manipulation:** Using built-in string functions makes the solution simple and readable.
2. **Whitespace Handling:** strip() automatically handles leading and trailing spaces.
3. **Word Separation:** split() with default delimiter (space) handles multiple spaces between words.
4. **Last Word Access:** Using negative indexing (-1) provides easy access to the last element.
5. **Edge Case Handling:** The approach naturally handles strings with multiple spaces.
6. **Built-in Efficiency:** Python's built-in string functions are optimized for performance.
## Mistakes Made
1. **Manual Parsing:** Initially might try to manually parse the string character by character.
2. **Wrong Split:** Not using split() or using wrong delimiter.
3. **Missing Strip:** Not removing leading/trailing spaces before processing.
4. **Complex Logic:** Overcomplicating the solution with unnecessary loops.
## Related Problems
- **Reverse Words in a String** (Problem 151): Reverse the order of words in a string
- **Valid Palindrome** (Problem 125): Check if a string is a palindrome
- **Longest Common Prefix** (Problem 14): Find common prefix among strings
- **Valid Parentheses** (Problem 20): Check if parentheses are valid
## Alternative Approaches
1. **Manual Parsing:** Iterate from end to find last word - O(n) time, O(1) space
2. **Regular Expressions:** Use regex to find last word - O(n) time complexity
3. **Two Pointers:** Use pointers to find word boundaries - O(n) time, O(1) space
## Common Pitfalls
1. **Manual Parsing:** Using complex loops instead of built-in functions.
2. **Wrong Split:** Not using split() or using incorrect delimiter.
3. **Missing Strip:** Not handling leading/trailing spaces.
4. **Index Errors:** Not properly accessing the last element.
5. **Over-engineering:** Using unnecessary data structures or complex logic.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/58.length-of-last-word.py)](../exercises/58.length-of-last-word.py)
*Note: This is a simple string manipulation problem that demonstrates efficient use of built-in string functions.*

133
src/notes/066_plus_one.md Normal file
View File

@@ -0,0 +1,133 @@
# Plus One
[![Problem 66](https://img.shields.io/badge/Problem-66-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/plus-one/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/plus-one/)
**Problem Number:** [66](https://leetcode.com/problems/plus-one/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Math
**LeetCode Link:** [https://leetcode.com/problems/plus-one/](https://leetcode.com/problems/plus-one/)
## Problem Description
You are given a large integer represented as an integer array `digits`, where each `digits[i]` is the `i^th` digit of the integer. The digits are ordered from most significant to least significant in left-to-right order. The large integer does not contain any leading `0`'s.
Increment the large integer by one and return the resulting array of digits.
**Example 1:**
```
Input: digits = [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.
Incrementing by one gives 123 + 1 = 124.
Thus, the result should be [1,2,4].
```
**Example 2:**
```
Input: digits = [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321.
Incrementing by one gives 4321 + 1 = 4322.
Thus, the result should be [4,3,2,2].
```
**Example 3:**
```
Input: digits = [9]
Output: [1,0]
Explanation: The array represents the integer 9.
Incrementing by one gives 9 + 1 = 10.
Thus, the result should be [1,0].
```
**Constraints:**
- `1 <= digits.length <= 100`
- `0 <= digits[i] <= 9`
- `digits` does not contain any leading `0`'s
## My Approach
I used a **Recursive** approach to handle the carry-over logic. The key insight is to process digits from right to left, handling carry-over when a digit becomes 10, and adding a new digit at the beginning if needed.
**Algorithm:**
1. Use a recursive helper function to process digits from right to left
2. For each digit, add the carry-over (or 1 for the first call)
3. If the sum is less than 10, update the digit and return
4. If the sum is 10 or more, set the digit to the remainder and carry over the quotient
5. If we reach the beginning and still have carry-over, insert a new digit at the beginning
## Solution
The solution uses recursion to handle carry-over logic. See the implementation in the [solution file](../exercises/66.plus-one.py).
**Key Points:**
- Uses recursion to process digits from right to left
- Handles carry-over when digit sum exceeds 9
- Inserts new digit at beginning when needed
- Processes carry-over recursively until resolved
- Maintains the original array structure
## Time & Space Complexity
**Time Complexity:** O(n)
- In worst case, we process all digits once
- Each recursive call processes one digit
- Total: O(n)
**Space Complexity:** O(n)
- Recursion stack depth: O(n) in worst case
- Each recursive call uses constant space
- Total: O(n)
## Key Insights
1. **Right-to-Left Processing:** We process digits from least significant to most significant to handle carry-over correctly.
2. **Carry-Over Logic:** When a digit becomes 10, we carry over 1 to the next digit and set current digit to 0.
3. **Recursive Approach:** Using recursion makes the carry-over logic clean and easy to understand.
4. **Array Insertion:** When we need to add a new digit (like 9 + 1 = 10), we insert it at the beginning.
5. **Base Case:** The recursion stops when we either process all digits or have no carry-over.
6. **Digit Constraints:** Each digit must be between 0 and 9, and we handle overflow by carrying over.
## Mistakes Made
1. **Left-to-Right Processing:** Initially might process from left to right, which complicates carry-over handling.
2. **Complex Logic:** Overcomplicating the solution with unnecessary loops or conditions.
3. **Wrong Carry Handling:** Not properly handling carry-over when digits sum to 10 or more.
4. **Array Manipulation:** Not efficiently handling the case where we need to add a new digit.
## Related Problems
- **Add Two Numbers** (Problem 2): Add two numbers represented as linked lists
- **Multiply Strings** (Problem 43): Multiply two numbers represented as strings
- **Add Binary** (Problem 67): Add two binary strings
- **Add Strings** (Problem 415): Add two numbers represented as strings
## Alternative Approaches
1. **Iterative:** Use a loop to process digits from right to left - O(n) time, O(1) space
2. **String Conversion:** Convert to integer, add one, convert back - O(n) time, O(n) space
3. **In-Place Modification:** Modify the array in-place without recursion
## Common Pitfalls
1. **Wrong Direction:** Processing digits from left to right instead of right to left.
2. **Complex Logic:** Overcomplicating the carry-over handling.
3. **Array Manipulation:** Not efficiently handling the case where array length increases.
4. **Recursion Depth:** Not considering stack overflow for very large arrays.
5. **Carry Handling:** Not properly handling carry-over when digits sum to 10.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/66.plus-one.py)](../exercises/66.plus-one.py)
*Note: This is a fundamental array manipulation problem that demonstrates efficient handling of carry-over in digit arithmetic.*

119
src/notes/069_sqrtx.md Normal file
View File

@@ -0,0 +1,119 @@
# Sqrt(x)
[![Problem 69](https://img.shields.io/badge/Problem-69-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/sqrtx/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/sqrtx/)
**Problem Number:** [69](https://leetcode.com/problems/sqrtx/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Math, Binary Search
**LeetCode Link:** [https://leetcode.com/problems/sqrtx/](https://leetcode.com/problems/sqrtx/)
## Problem Description
Given a non-negative integer `x`, compute and return the square root of `x`.
Since the return type is an integer, the decimal digits are truncated, and only the integer part of the result is returned.
**Note:** You are not allowed to use any built-in exponent function or operator, such as `pow(x, 0.5)`, or `x ** 0.5`.
**Example 1:**
```
Input: x = 4
Output: 2
```
**Example 2:**
```
Input: x = 8
Output: 2
Explanation: The square root of 8 is 2.82842..., and since the decimal part is truncated, 2 is returned.
```
**Constraints:**
- `0 <= x <= 2^31 - 1`
## My Approach
I used a **Binary Search** approach to find the integer square root. The key insight is to search for the largest integer whose square is less than or equal to the given number.
**Algorithm:**
1. Handle edge case: if x == 1, return 1
2. Use binary search with left boundary 1 and right boundary x
3. For each midpoint, calculate its square
4. If square <= x, move left boundary to mid + 1
5. If square > x, move right boundary to mid
6. Return left - 1 (the largest integer whose square <= x)
## Solution
The solution uses binary search to find the integer square root. See the implementation in the [solution file](../exercises/69.sqrtx.py).
**Key Points:**
- Uses binary search to efficiently find square root
- Handles edge case for x = 1
- Searches for largest integer whose square <= x
- Returns integer part only (truncates decimal)
- Avoids using built-in math functions
## Time & Space Complexity
**Time Complexity:** O(log x)
- Binary search halves the search space in each iteration
- Total iterations: log₂(x)
- Total: O(log x)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Binary Search Efficiency:** Binary search provides O(log x) time complexity for finding the square root.
2. **Search Space:** We search from 1 to x, since the square root of x must be in this range.
3. **Integer Truncation:** The problem asks for the integer part only, so we return the largest integer whose square <= x.
4. **Edge Case Handling:** x = 1 is a special case that needs to be handled separately.
5. **Boundary Conditions:** The binary search converges to the correct integer square root.
6. **No Built-in Functions:** The solution avoids using pow() or ** operators as required.
## Mistakes Made
1. **Linear Search:** Initially might use a simple loop to find the square root, leading to O(√x) complexity.
2. **Wrong Boundaries:** Not setting the correct search boundaries for binary search.
3. **Edge Cases:** Not properly handling x = 0 or x = 1.
4. **Return Value:** Not understanding that we need to return left - 1.
## Related Problems
- **Pow(x, n)** (Problem 50): Calculate x raised to power n
- **Search Insert Position** (Problem 35): Find insertion position in sorted array
- **Find First and Last Position of Element in Sorted Array** (Problem 34): Binary search with duplicates
- **Valid Perfect Square** (Problem 367): Check if a number is a perfect square
## Alternative Approaches
1. **Newton's Method:** Use iterative approximation - O(log x) time complexity
2. **Linear Search:** Check each integer from 1 to √x - O(√x) time complexity
3. **Built-in Functions:** Use math.sqrt() or ** 0.5 (not allowed for this problem)
## Common Pitfalls
1. **Wrong Complexity:** Using linear search instead of binary search.
2. **Boundary Errors:** Not setting correct left and right boundaries.
3. **Edge Cases:** Not handling x = 0, x = 1, or very large values.
4. **Return Value:** Not understanding the correct return value from binary search.
5. **Overflow:** Not considering integer overflow for large values.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/69.sqrtx.py)](../exercises/69.sqrtx.py)
*Note: This is a classic binary search problem that demonstrates efficient square root calculation without using built-in functions.*

View File

@@ -0,0 +1,123 @@
# Climbing Stairs
[![Problem 70](https://img.shields.io/badge/Problem-70-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/climbing-stairs/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/climbing-stairs/)
**Problem Number:** [70](https://leetcode.com/problems/climbing-stairs/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Math, Dynamic Programming, Memoization
**LeetCode Link:** [https://leetcode.com/problems/climbing-stairs/](https://leetcode.com/problems/climbing-stairs/)
## Problem Description
You are climbing a staircase. It takes `n` steps to reach the top.
Each time you can either climb `1` or `2` steps. In how many distinct ways can you climb to the top?
**Example 1:**
```
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
```
**Example 2:**
```
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
```
**Constraints:**
- `1 <= n <= 45`
## My Approach
I used a **Dynamic Programming** approach with memoization using the Fibonacci sequence. The key insight is that the number of ways to climb n stairs follows the Fibonacci sequence: F(n) = F(n-1) + F(n-2).
**Algorithm:**
1. Use a recursive Fibonacci function with memoization
2. Base cases: F(0) = 0, F(1) = 1
3. For other values: F(n) = F(n-1) + F(n-2)
4. Use cache to store computed values and avoid recalculation
5. Return F(n+1) as the number of ways to climb n stairs
## Solution
The solution uses dynamic programming with memoized Fibonacci sequence. See the implementation in the [solution file](../exercises/70.climbing-stairs.js).
**Key Points:**
- Uses Fibonacci sequence with memoization
- Caches computed values to avoid recalculation
- Handles base cases for n = 0 and n = 1
- Returns F(n+1) for n stairs
- Efficiently computes large values without stack overflow
## Time & Space Complexity
**Time Complexity:** O(n)
- Each Fibonacci number is computed once and cached
- Total computations: O(n)
- Cache lookups: O(1)
**Space Complexity:** O(n)
- Cache array stores up to n Fibonacci numbers
- Recursion stack depth: O(n)
- Total: O(n)
## Key Insights
1. **Fibonacci Sequence:** The number of ways to climb n stairs follows the Fibonacci sequence.
2. **Recurrence Relation:** F(n) = F(n-1) + F(n-2), where F(n) represents ways to climb n stairs.
3. **Memoization:** Caching computed values prevents redundant calculations and improves efficiency.
4. **Base Cases:** F(0) = 0 and F(1) = 1 provide the foundation for the sequence.
5. **Offset:** The answer for n stairs is F(n+1), not F(n).
6. **Optimal Substructure:** The solution for n stairs depends on solutions for n-1 and n-2 stairs.
## Mistakes Made
1. **Naive Recursion:** Initially might use simple recursion without memoization, leading to O(2^n) complexity.
2. **Wrong Base Cases:** Not properly handling the base cases for the Fibonacci sequence.
3. **Missing Offset:** Not understanding that the answer is F(n+1) rather than F(n).
4. **Stack Overflow:** Not considering stack overflow for large values of n.
## Related Problems
- **Fibonacci Number** (Problem 509): Calculate the nth Fibonacci number
- **Min Cost Climbing Stairs** (Problem 746): Climbing stairs with cost
- **Decode Ways** (Problem 91): Decode string to numbers
- **Unique Paths** (Problem 62): Find unique paths in grid
## Alternative Approaches
1. **Iterative DP:** Use bottom-up dynamic programming - O(n) time, O(1) space
2. **Matrix Exponentiation:** Use matrix multiplication - O(log n) time complexity
3. **Binet's Formula:** Use mathematical formula - O(1) time, O(1) space
## Common Pitfalls
1. **Exponential Complexity:** Using naive recursion without memoization.
2. **Wrong Base Cases:** Not properly handling F(0) and F(1).
3. **Missing Offset:** Returning F(n) instead of F(n+1).
4. **Stack Overflow:** Not considering recursion depth for large n.
5. **Memory Issues:** Not using memoization to avoid redundant calculations.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/70.climbing-stairs.js)](../exercises/70.climbing-stairs.js)
*Note: This is a classic dynamic programming problem that demonstrates the relationship between climbing stairs and the Fibonacci sequence.*

View File

@@ -0,0 +1,118 @@
# Search a 2D Matrix
[![Problem 74](https://img.shields.io/badge/Problem-74-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/search-a-2d-matrix/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/search-a-2d-matrix/)
**Problem Number:** [74](https://leetcode.com/problems/search-a-2d-matrix/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Binary Search, Matrix
**LeetCode Link:** [https://leetcode.com/problems/search-a-2d-matrix/](https://leetcode.com/problems/search-a-2d-matrix/)
## Problem Description
Write an efficient algorithm that searches for a value `target` in an `m x n` integer matrix `matrix`. This matrix has the following properties:
- Integers in each row are sorted from left to right.
- The first integer of each row is greater than the last integer of the previous row.
**Example 1:**
```
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
Output: true
```
**Example 2:**
```
Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
Output: false
```
**Constraints:**
- `m == matrix.length`
- `n == matrix[i].length`
- `1 <= m, n <= 100`
- `-10^4 <= matrix[i][j], target <= 10^4`
## My Approach
I used a **Two-Stage Binary Search** approach. The key insight is to first find the correct row using binary search on the first column, then search within that row using another binary search.
**Algorithm:**
1. Use binary search to find the correct row by comparing target with first and last elements of each row
2. If target is within the range of a row, that's our target row
3. Use binary search within the target row to find the element
4. Return true if found, false otherwise
## Solution
The solution uses two-stage binary search for efficient matrix searching. See the implementation in the [solution file](../exercises/74.search-a-2d-matrix.py).
**Key Points:**
- Uses binary search to find the correct row first
- Then uses binary search within the target row
- Handles edge cases where target is at boundaries
- Efficiently narrows down search space in two stages
- Returns boolean indicating if target is found
## Time & Space Complexity
**Time Complexity:** O(log m + log n)
- Row search: O(log m)
- Column search: O(log n)
- Total: O(log m + log n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Two-Stage Search:** The matrix properties allow us to first find the row, then search within that row.
2. **Row Selection:** We can determine which row contains the target by checking if target is within the range of the row's first and last elements.
3. **Binary Search Efficiency:** Using binary search for both stages provides optimal time complexity.
4. **Matrix Properties:** The sorted nature of rows and the relationship between consecutive rows enables efficient search.
5. **Boundary Handling:** We need to check both first and last elements of each row to determine if target is within range.
6. **Early Termination:** We can return false immediately if the target row is not found.
## Mistakes Made
1. **Linear Search:** Initially might use linear search through the entire matrix, leading to O(mn) complexity.
2. **Wrong Row Selection:** Not properly determining which row contains the target.
3. **Complex Logic:** Overcomplicating the search with unnecessary conditions.
4. **Boundary Errors:** Not properly handling edge cases where target is at row boundaries.
## Related Problems
- **Search a 2D Matrix II** (Problem 240): Search in matrix with different properties
- **Binary Search** (Problem 704): Basic binary search implementation
- **Search Insert Position** (Problem 35): Find insertion position in sorted array
- **Find First and Last Position of Element in Sorted Array** (Problem 34): Binary search with duplicates
## Alternative Approaches
1. **Single Binary Search:** Treat matrix as 1D array and use single binary search - O(log(mn)) time
2. **Linear Search:** Search through entire matrix - O(mn) time complexity
3. **Divide and Conquer:** Use recursive approach to divide matrix into quadrants
## Common Pitfalls
1. **Wrong Complexity:** Using linear search instead of binary search.
2. **Incorrect Row Selection:** Not properly determining which row contains the target.
3. **Boundary Issues:** Not handling edge cases where target is at row boundaries.
4. **Complex Implementation:** Overcomplicating the search logic.
5. **Matrix Properties:** Not utilizing the sorted properties of the matrix.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/74.search-a-2d-matrix.py)](../exercises/74.search-a-2d-matrix.py)
*Note: This is a classic binary search problem that demonstrates efficient searching in 2D sorted matrices.*

View File

@@ -0,0 +1,125 @@
# Remove Duplicates from Sorted Array II
[![Problem 80](https://img.shields.io/badge/Problem-80-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/)
**Problem Number:** [80](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/](https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/)
## Problem Description
Given an integer array `nums` sorted in non-decreasing order, remove some duplicates in-place such that each unique element appears at most twice. The relative order of the elements should be kept the same.
Since it is impossible to change the length of the array in some programming languages, you must instead have the result be placed in the first part of the array `nums`. More formally, if there are `k` elements after removing the duplicates, then the first `k` elements of `nums` should hold the final result. It does not matter what you leave beyond the first `k` elements.
Return `k` after placing the final result in the first `k` slots of `nums`.
**Example 1:**
```
Input: nums = [1,1,1,2,2,3]
Output: 5, nums = [1,1,2,2,3,_]
Explanation: Your function should return k = 5, with the first five elements of nums being 1,1,2,2,3 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
```
**Example 2:**
```
Input: nums = [0,0,1,1,1,1,2,3,3]
Output: 7, nums = [0,0,1,1,2,3,3,_,_]
Explanation: Your function should return k = 7, with the first seven elements of nums being 0,0,1,1,2,3,3 respectively.
It does not matter what you leave beyond the returned k (hence they are underscores).
```
**Constraints:**
- `1 <= nums.length <= 3 * 10^4`
- `-10^4 <= nums[i] <= 10^4`
- `nums` is sorted in non-decreasing order
## My Approach
I used a **Two Pointer** approach with a counter to track allowed duplicates. The key insight is to use a slow pointer to track the position where the next valid element should be placed, and allow at most two occurrences of each element.
**Algorithm:**
1. Handle edge cases (empty array or length <= 2)
2. Initialize slow pointer k at position 2 (first two elements are always valid)
3. Iterate through array starting from index 2
4. Check if current element is different from the two previous elements at k-1 and k-2
5. If different, copy current element to position k and increment k
6. Return k (number of elements in final array)
## Solution
The solution uses a two-pointer approach to allow at most two duplicates. See the implementation in the [solution file](../exercises/80.remove-duplicates-from-sorted-array-ii.py).
**Key Points:**
- Uses two pointers: slow pointer (k) and fast pointer (i)
- Allows at most two occurrences of each element
- Compares current element with two previous elements
- Modifies array in-place without extra space
- Returns count of elements in final array
## Time & Space Complexity
**Time Complexity:** O(n)
- We traverse the array once
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- Modifies the array in-place
- No additional data structures needed
## Key Insights
1. **Two Pointer Technique:** Using a slow pointer to track the next position for valid elements.
2. **Duplicate Allowance:** We allow at most two occurrences of each element, not just one.
3. **Comparison Logic:** We compare the current element with the two previous elements at positions k-1 and k-2.
4. **In-Place Modification:** The problem requires modifying the array in-place, which is efficiently done with two pointers.
5. **Edge Case Handling:** Arrays with length <= 2 can be returned as-is since they can't have more than two duplicates.
6. **Sorted Array Advantage:** Since the array is sorted, duplicates are always adjacent, making the comparison simple.
## Mistakes Made
1. **Wrong Duplicate Count:** Initially might allow only one occurrence instead of two.
2. **Complex Logic:** Overcomplicating the comparison logic with unnecessary conditions.
3. **Wrong Pointer Logic:** Not properly understanding when to increment the slow pointer.
4. **Edge Case Missing:** Not properly handling arrays with length <= 2.
## Related Problems
- **Remove Duplicates from Sorted Array** (Problem 26): Remove all duplicates
- **Remove Element** (Problem 27): Remove specific element
- **Move Zeroes** (Problem 283): Move zeros to end
- **Sort Colors** (Problem 75): Sort array with three colors
## Alternative Approaches
1. **Hash Table:** Use hash table to count occurrences - O(n) time, O(n) space
2. **Three Pointers:** Use three pointers to track current and two previous elements
3. **Counter-based:** Use a counter to track occurrences of each element
## Common Pitfalls
1. **Wrong Duplicate Limit:** Allowing only one occurrence instead of two.
2. **Complex Comparison:** Overcomplicating the comparison logic.
3. **Wrong Pointer Movement:** Not properly understanding when to move the slow pointer.
4. **Edge Cases:** Not handling arrays with length <= 2.
5. **Extra Space:** Using additional data structures when in-place modification is required.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/80.remove-duplicates-from-sorted-array-ii.py)](../exercises/80.remove-duplicates-from-sorted-array-ii.py)
*Note: This is a variation of the classic two-pointer problem that demonstrates handling multiple allowed duplicates.*

View File

@@ -0,0 +1,133 @@
# Merge Sorted Array
[![Problem 88](https://img.shields.io/badge/Problem-88-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/merge-sorted-array/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/merge-sorted-array/)
**Problem Number:** [88](https://leetcode.com/problems/merge-sorted-array/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Two Pointers, Sorting
**LeetCode Link:** [https://leetcode.com/problems/merge-sorted-array/](https://leetcode.com/problems/merge-sorted-array/)
## Problem Description
You are given two integer arrays `nums1` and `nums2`, sorted in non-decreasing order, and two integers `m` and `n`, representing the number of elements in `nums1` and `nums2` respectively.
Merge `nums1` and `nums2` into a single array sorted in non-decreasing order.
The final sorted array should not be returned by the function, but instead be stored inside the array `nums1`. To accommodate this, `nums1` has a length of `m + n`, where the first `m` elements denote the elements that should be merged, and the last `n` elements are set to `0` and should be ignored. `nums2` has a length of `n`.
**Example 1:**
```
Input: nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
Output: [1,2,2,3,5,6]
Explanation: The arrays we are merging are [1,2,3] and [2,5,6].
The result of the merge is [1,2,2,3,5,6] with the underlined elements coming from nums1.
```
**Example 2:**
```
Input: nums1 = [1], m = 1, nums2 = [], n = 0
Output: [1]
Explanation: The arrays we are merging are [1] and [].
The result of the merge is [1].
```
**Example 3:**
```
Input: nums1 = [0], m = 0, nums2 = [1], n = 1
Output: [1]
Explanation: The arrays we are merging are [] and [1].
The result of the merge is [1].
Note that because m = 0, there are no elements in nums1. The 0 is only there to ensure the merge result can fit in nums1.
```
**Constraints:**
- `nums1.length == m + n`
- `nums2.length == n`
- `0 <= m, n <= 200`
- `1 <= m + n <= 200`
- `-10^9 <= nums1[i], nums2[j] <= 10^9`
## My Approach
I used a **Simple Merge** approach by copying elements from nums2 to the end of nums1, then sorting the entire array. The key insight is to utilize the extra space at the end of nums1 to merge the arrays.
**Algorithm:**
1. Copy all elements from nums2 to the end of nums1 (starting from index m)
2. Sort the entire nums1 array to get the final merged result
3. The merged result is stored in-place in nums1
## Solution
The solution uses a simple merge approach with sorting. See the implementation in the [solution file](../exercises/88.merge-sorted-array.py).
**Key Points:**
- Copies nums2 elements to the end of nums1
- Uses built-in sort to merge the arrays
- Modifies nums1 in-place as required
- Handles edge cases like empty arrays
- Simple and straightforward approach
## Time & Space Complexity
**Time Complexity:** O((m+n) log(m+n))
- Copying elements: O(n)
- Sorting: O((m+n) log(m+n))
- Total: O((m+n) log(m+n))
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- Modifies nums1 in-place
- No additional data structures needed
## Key Insights
1. **Extra Space Utilization:** nums1 has extra space at the end that can be used for merging.
2. **Simple Approach:** Copying nums2 to nums1 and then sorting is straightforward and works correctly.
3. **In-Place Modification:** The problem requires modifying nums1 in-place, which this approach does.
4. **Built-in Sort:** Using the built-in sort function ensures correct ordering.
5. **Edge Case Handling:** The approach naturally handles cases where one array is empty.
6. **Space Efficiency:** No additional arrays are needed, just the existing space in nums1.
## Mistakes Made
1. **Complex Merge Logic:** Initially might try to implement complex merge logic with two pointers.
2. **Wrong Indexing:** Not properly handling the indices when copying elements.
3. **Sorting Issues:** Not understanding that sorting after copying is a valid approach.
4. **Return Value:** Trying to return the array when the function should modify nums1 in-place.
## Related Problems
- **Merge Two Sorted Lists** (Problem 21): Merge two sorted linked lists
- **Merge k Sorted Lists** (Problem 23): Merge multiple sorted linked lists
- **Sort Colors** (Problem 75): Sort array with three colors
- **Remove Duplicates from Sorted Array** (Problem 26): Remove duplicates in sorted array
## Alternative Approaches
1. **Two Pointer Merge:** Use two pointers to merge from end to beginning - O(m+n) time, O(1) space
2. **Three Pointer Merge:** Use three pointers for more efficient merging
3. **Built-in Merge:** Use heapq.merge() for efficient merging (though not in-place)
## Common Pitfalls
1. **Complex Implementation:** Overcomplicating the merge logic when simple approach works.
2. **Wrong Indices:** Not properly handling array indices when copying elements.
3. **Return Value:** Trying to return the array instead of modifying in-place.
4. **Space Usage:** Using additional arrays when in-place modification is required.
5. **Sorting Neglect:** Not understanding that sorting after copying is acceptable.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/88.merge-sorted-array.py)](../exercises/88.merge-sorted-array.py)
*Note: This is a fundamental array manipulation problem that demonstrates simple merging with sorting.*

130
src/notes/089_gray_code.md Normal file
View File

@@ -0,0 +1,130 @@
# Gray Code
[![Problem 89](https://img.shields.io/badge/Problem-89-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/gray-code/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/gray-code/)
**Problem Number:** [89](https://leetcode.com/problems/gray-code/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Math, Backtracking, Bit Manipulation
**LeetCode Link:** [https://leetcode.com/problems/gray-code/](https://leetcode.com/problems/gray-code/)
## Problem Description
An n-bit gray code sequence is a sequence of `2^n` integers where:
- Every integer is in the inclusive range `[0, 2^n - 1]`
- The first integer is `0`
- An integer appears no more than once in the sequence
- The binary representation of every pair of adjacent integers differs by exactly one bit
- The binary representation of the first and last integers differs by exactly one bit
Given an integer `n`, return any valid n-bit gray code sequence.
**Example 1:**
```
Input: n = 2
Output: [0,1,3,2]
Explanation:
The binary representation of [0,1,3,2] is [00,01,11,10].
- 00 and 01 differ by one bit
- 01 and 11 differ by one bit
- 11 and 10 differ by one bit
- 10 and 00 differ by one bit
[0,2,3,1] is also a valid gray code sequence, whose binary representation is [00,10,11,01].
- 00 and 10 differ by one bit
- 10 and 11 differ by one bit
- 11 and 01 differ by one bit
- 01 and 00 differ by one bit
```
**Example 2:**
```
Input: n = 1
Output: [0,1]
```
**Constraints:**
- `1 <= n <= 16`
## My Approach
I used a **Bit Manipulation** approach using the mathematical formula for generating Gray codes. The key insight is that the nth Gray code can be generated using the formula: G(n) = n ⊕ (n >> 1).
**Algorithm:**
1. Generate all numbers from 0 to 2^n - 1
2. For each number, apply the Gray code formula: i ⊕ (i >> 1)
3. Return the list of Gray codes
## Solution
The solution uses bit manipulation with the Gray code formula. See the implementation in the [solution file](../exercises/89.gray-code.py).
**Key Points:**
- Uses the mathematical formula G(n) = n ⊕ (n >> 1)
- Generates all Gray codes in one pass
- Uses bitwise XOR and right shift operations
- Efficient and concise implementation
- Handles all valid values of n
## Time & Space Complexity
**Time Complexity:** O(2^n)
- We generate 2^n Gray codes
- Each Gray code calculation is O(1)
- Total: O(2^n)
**Space Complexity:** O(2^n)
- We store 2^n Gray codes in the result list
- Total: O(2^n)
## Key Insights
1. **Mathematical Formula:** The Gray code can be generated using the formula G(n) = n ⊕ (n >> 1).
2. **Bit Manipulation:** Using bitwise operations (XOR and right shift) is the most efficient approach.
3. **Sequential Generation:** We can generate all Gray codes sequentially without complex logic.
4. **One Bit Difference:** The formula ensures that adjacent numbers differ by exactly one bit.
5. **Circular Property:** The first and last numbers also differ by exactly one bit.
6. **Efficient Implementation:** The list comprehension approach is both readable and efficient.
## Mistakes Made
1. **Complex Backtracking:** Initially might try to use backtracking to generate Gray codes.
2. **Wrong Formula:** Not knowing the mathematical formula for Gray code generation.
3. **Inefficient Approach:** Using recursive or iterative approaches instead of the direct formula.
4. **Bit Manipulation Ignorance:** Not utilizing bitwise operations for efficient computation.
## Related Problems
- **Subsets** (Problem 78): Generate all subsets of a set
- **Subsets II** (Problem 90): Generate subsets with duplicates
- **Permutations** (Problem 46): Generate all permutations
- **Combination Sum** (Problem 39): Find combinations that sum to target
## Alternative Approaches
1. **Backtracking:** Use recursive backtracking to generate Gray codes - O(2^n) time
2. **Iterative Construction:** Build Gray codes iteratively using reflection method
3. **Recursive Construction:** Use recursive approach with mirroring technique
## Common Pitfalls
1. **Complex Implementation:** Using backtracking or complex logic instead of the simple formula.
2. **Wrong Formula:** Not using the correct mathematical formula for Gray code generation.
3. **Bit Manipulation:** Not understanding how to use bitwise operations efficiently.
4. **Performance Issues:** Using inefficient approaches when the formula exists.
5. **Edge Cases:** Not handling n = 1 or other edge cases properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/89.gray-code.py)](../exercises/89.gray-code.py)
*Note: This is a mathematical problem that demonstrates efficient use of bit manipulation and mathematical formulas.*

119
src/notes/090_subsets_ii.md Normal file
View File

@@ -0,0 +1,119 @@
# Subsets II
[![Problem 90](https://img.shields.io/badge/Problem-90-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/subsets-ii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/subsets-ii/)
**Problem Number:** [90](https://leetcode.com/problems/subsets-ii/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Backtracking
**LeetCode Link:** [https://leetcode.com/problems/subsets-ii/](https://leetcode.com/problems/subsets-ii/)
## Problem Description
Given an integer array `nums` that may contain duplicates, return all possible subsets (the power set).
The solution set must not contain duplicate subsets. Return the solution in any order.
**Example 1:**
```
Input: nums = [1,2,2]
Output: [[],[1],[1,2],[1,2,2],[2],[2,2]]
```
**Example 2:**
```
Input: nums = [0]
Output: [[],[0]]
```
**Constraints:**
- `1 <= nums.length <= 10`
- `-10 <= nums[i] <= 10`
## My Approach
I used a **Backtracking** approach with duplicate handling. The key insight is to sort the array first and then use backtracking while skipping duplicates at the same level to avoid generating duplicate subsets.
**Algorithm:**
1. Sort the input array to group duplicates together
2. Use backtracking with a helper function
3. For each recursive call, add the current path to result
4. Iterate through remaining elements starting from current position
5. Skip duplicates at the same level (i > start and nums[i] == nums[i-1])
6. Add current element to path, recurse, then remove (backtrack)
## Solution
The solution uses backtracking with duplicate handling. See the implementation in the [solution file](../exercises/90.subsets-ii.py).
**Key Points:**
- Sorts array to group duplicates together
- Uses backtracking to generate all subsets
- Skips duplicates at the same recursion level
- Adds each valid subset to the result
- Handles empty subset and all possible combinations
## Time & Space Complexity
**Time Complexity:** O(n × 2^n)
- Sorting: O(n log n)
- Backtracking generates 2^n subsets
- Each subset can be up to length n
- Total: O(n × 2^n)
**Space Complexity:** O(n)
- Recursion stack depth: O(n)
- Path array: O(n)
- Result space: O(2^n) for storing all subsets
## Key Insights
1. **Sorting for Duplicates:** Sorting groups duplicates together, making it easier to skip them.
2. **Duplicate Skipping:** We skip duplicates at the same recursion level (i > start) to avoid generating duplicate subsets.
3. **Backtracking Pattern:** This is a classic backtracking problem where we build subsets incrementally.
4. **Level-based Duplicate Handling:** We only skip duplicates at the same level, not across different levels.
5. **Path Copying:** We copy the current path (path[:]) before adding to result to avoid reference issues.
6. **Empty Subset:** The empty subset is always included in the result.
## Mistakes Made
1. **No Sorting:** Initially might not sort the array, making duplicate handling complex.
2. **Wrong Duplicate Logic:** Skipping all duplicates instead of only at the same level.
3. **Reference Issues:** Not copying the path before adding to result.
4. **Complex Logic:** Overcomplicating the duplicate handling logic.
## Related Problems
- **Subsets** (Problem 78): Generate subsets without duplicates
- **Combinations** (Problem 77): Generate combinations of given length
- **Permutations II** (Problem 47): Generate permutations with duplicates
- **Combination Sum II** (Problem 40): Find combinations with duplicates
## Alternative Approaches
1. **Iterative:** Use iterative approach with bit manipulation - O(n × 2^n) time
2. **Hash Set:** Use hash set to track seen subsets - O(n × 2^n) time, O(2^n) space
3. **Recursive without Backtracking:** Use pure recursion approach
## Common Pitfalls
1. **No Sorting:** Not sorting the array to group duplicates.
2. **Wrong Duplicate Handling:** Skipping all duplicates instead of same-level duplicates.
3. **Reference Issues:** Not copying paths before adding to result.
4. **Complex Logic:** Overcomplicating the duplicate handling.
5. **Missing Empty Subset:** Not including the empty subset in the result.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/90.subsets-ii.py)](../exercises/90.subsets-ii.py)
*Note: This is a classic backtracking problem that demonstrates efficient handling of duplicates in subset generation.*

View File

@@ -0,0 +1,142 @@
# Decode Ways
[![Problem 91](https://img.shields.io/badge/Problem-91-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/decode-ways/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/decode-ways/)
**Problem Number:** [91](https://leetcode.com/problems/decode-ways/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** String, Dynamic Programming
**LeetCode Link:** [https://leetcode.com/problems/decode-ways/](https://leetcode.com/problems/decode-ways/)
## Problem Description
A message containing letters from `A-Z` can be encoded into numbers using the following mapping:
```
'A' -> "1"
'B' -> "2"
...
'Z' -> "26"
```
To decode an encoded message, all the digits must be grouped then mapped back into letters using the reverse of the mapping above (there may be multiple ways). For example, `"11106"` can be mapped into:
- `"AAJF"` with the grouping `(1 1 10 6)`
- `"KJF"` with the grouping `(11 10 6)`
Note that the grouping `(1 11 06)` is invalid because `"06"` cannot be mapped into `'F'` since `"6"` is different from `"06"`.
Given a string `s` containing only digits, return the number of ways to decode it.
**Example 1:**
```
Input: s = "12"
Output: 2
Explanation: "12" could be decoded as "AB" (1 2) or "L" (12).
```
**Example 2:**
```
Input: s = "226"
Output: 3
Explanation: "226" could be decoded as "BZ" (2 26), "VF" (22 6), or "BBF" (2 2 6).
```
**Example 3:**
```
Input: s = "06"
Output: 0
Explanation: "06" cannot be mapped to "F" because of the leading zero ("6" is different from "06").
```
**Constraints:**
- `1 <= s.length <= 100`
- `s` contains only digits and may contain leading zero(s)
## My Approach
I used a **Dynamic Programming** approach with memoization using recursion. The key insight is to use a recursive function that considers both single-digit and two-digit decoding possibilities at each position.
**Algorithm:**
1. Use a recursive helper function with memoization
2. Base case: if we reach the end of string, return 1 (valid decoding)
3. If current digit is '0', return 0 (invalid)
4. If we're at the last digit, return 1 (single digit decoding)
5. Recursively try single digit decoding (i+1)
6. If two digits form a valid number (1-26), recursively try two digit decoding (i+2)
7. Return sum of both possibilities
## Solution
The solution uses dynamic programming with memoization. See the implementation in the [solution file](../exercises/91.decode-ways.py).
**Key Points:**
- Uses recursive DP with memoization to avoid recalculation
- Handles invalid cases (leading zeros, numbers > 26)
- Considers both single and two-digit decoding at each step
- Uses @lru_cache for automatic memoization
- Returns total number of valid decoding ways
## Time & Space Complexity
**Time Complexity:** O(n)
- Each position is visited once due to memoization
- Each recursive call performs constant time operations
- Total: O(n)
**Space Complexity:** O(n)
- Recursion stack depth: O(n)
- Memoization cache: O(n)
- Total: O(n)
## Key Insights
1. **Recursive DP:** Using recursion with memoization provides a clean solution to this problem.
2. **Two Choices:** At each position, we can either decode one digit or two digits (if valid).
3. **Invalid Cases:** Leading zeros and numbers greater than 26 are invalid and should return 0.
4. **Memoization:** Using @lru_cache prevents recalculating the same subproblems.
5. **Base Cases:** Reaching the end of string means we found a valid decoding.
6. **Optimal Substructure:** The solution for the entire string depends on solutions for substrings.
## Mistakes Made
1. **No Memoization:** Initially might use pure recursion without memoization, leading to exponential complexity.
2. **Wrong Base Cases:** Not properly handling edge cases like leading zeros.
3. **Complex Logic:** Overcomplicating the validation logic for two-digit numbers.
4. **Missing Edge Cases:** Not considering cases where the string is invalid.
## Related Problems
- **Climbing Stairs** (Problem 70): Similar DP pattern with two choices
- **Fibonacci Number** (Problem 509): Classic DP problem
- **Unique Paths** (Problem 62): Grid-based DP problem
- **House Robber** (Problem 198): Another classic DP problem
## Alternative Approaches
1. **Iterative DP:** Use bottom-up dynamic programming - O(n) time, O(n) space
2. **Space Optimized DP:** Use only constant space - O(n) time, O(1) space
3. **Tabulation:** Use iterative approach with table - O(n) time, O(n) space
## Common Pitfalls
1. **Exponential Complexity:** Using recursion without memoization.
2. **Wrong Base Cases:** Not handling leading zeros and invalid numbers.
3. **Complex Validation:** Overcomplicating the two-digit validation logic.
4. **Missing Edge Cases:** Not considering all invalid input cases.
5. **Space Issues:** Not using memoization to avoid redundant calculations.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/91.decode-ways.py)](../exercises/91.decode-ways.py)
*Note: This is a classic dynamic programming problem that demonstrates efficient use of memoization for string decoding.*

View File

@@ -0,0 +1,137 @@
# Longest String Chain
[![Problem 1048](https://img.shields.io/badge/Problem-1048-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-string-chain/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-string-chain/)
**Problem Number:** [1048](https://leetcode.com/problems/longest-string-chain/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Hash Table, String, Dynamic Programming
**LeetCode Link:** [https://leetcode.com/problems/longest-string-chain/](https://leetcode.com/problems/longest-string-chain/)
## Problem Description
You are given an array of `words` where each word consists of lowercase English letters.
`wordA` is a predecessor of `wordB` if and only if we can insert exactly one letter anywhere in `wordA` without changing the order of the other characters to make it equal to `wordB`.
- For example, `"abc"` is a predecessor of `"abac"`, while `"cba"` is not a predecessor of `"bcad"`.
A word chain is a sequence of words `[word1, word2, ..., wordk]` with `k >= 1`, where `word1` is a predecessor of `word2`, `word2` is a predecessor of `word3`, and so on. A single word is trivially a word chain with `k == 1`.
Return the length of the longest possible word chain with words chosen from the given list of `words`.
**Example 1:**
```
Input: words = ["a","b","ba","bca","bda","bdca"]
Output: 4
Explanation: One of the longest word chains is ["a","ba","bda","bdca"].
```
**Example 2:**
```
Input: words = ["xbc","pcxbcf","xb","cxbc","pcxbc"]
Output: 5
Explanation: All the words can be used in the word chain ["xb", "xbc", "cxbc", "pcxbc", "pcxbcf"].
```
**Example 3:**
```
Input: words = ["abcd","dbqca"]
Output: 1
Explanation: The trivial word chain ["abcd"] is one of the longest word chains.
["abcd","dbqca"] is not a valid word chain because "abcd" is not a predecessor of "dbqca".
```
**Constraints:**
- `1 <= words.length <= 1000`
- `1 <= words[i].length <= 16`
- `words[i]` consists of lowercase English letters
## My Approach
I used a **Dynamic Programming** approach with hash table caching. The key insight is to sort words by length first, then for each word, try removing one character at a time to find its predecessors and build the longest chain.
**Algorithm:**
1. Sort words by length to process shorter words first
2. Use a hash table (cache) to store the longest chain ending at each word
3. For each word, try removing one character at each position
4. Check if the resulting substring exists in cache
5. Update the current word's chain length as max of all predecessors + 1
6. Track the maximum chain length found
## Solution
The solution uses dynamic programming with hash table caching. See the implementation in the [solution file](../exercises/1048.longest-string-chain.js).
**Key Points:**
- Sorts words by length to process in correct order
- Uses hash table to cache longest chain for each word
- Tries removing one character at each position to find predecessors
- Updates chain length based on predecessor lengths
- Tracks maximum chain length throughout the process
## Time & Space Complexity
**Time Complexity:** O(n × L²)
- n is the number of words
- L is the maximum word length
- Sorting: O(n log n)
- For each word, we try L positions and string slicing takes O(L)
- Total: O(n × L²)
**Space Complexity:** O(n)
- Hash table stores at most n words
- Each word can be up to length L
- Total: O(n × L)
## Key Insights
1. **Sorting by Length:** Processing words in order of increasing length ensures we build chains correctly.
2. **Predecessor Relationship:** A word is a predecessor if removing one character makes it equal to another word.
3. **Dynamic Programming:** Using a cache to store the longest chain ending at each word avoids recalculation.
4. **Character Removal:** For each word, we try removing one character at each position to find all possible predecessors.
5. **Chain Building:** The chain length for a word is the maximum of all its predecessors' chain lengths plus 1.
6. **Efficient Lookup:** Using a hash table provides O(1) lookup time for checking predecessors.
## Mistakes Made
1. **Wrong Order:** Not sorting words by length, leading to incorrect chain building.
2. **Inefficient Predecessor Check:** Using complex string matching instead of simple character removal.
3. **Missing Caching:** Not using memoization, leading to redundant calculations.
4. **Wrong Chain Logic:** Not properly updating chain lengths based on predecessors.
## Related Problems
- **Longest Increasing Subsequence** (Problem 300): Find longest increasing subsequence
- **Word Break** (Problem 139): Check if string can be segmented
- **Longest Common Subsequence** (Problem 1143): Find longest common subsequence
- **Edit Distance** (Problem 72): Calculate minimum edit distance
## Alternative Approaches
1. **Graph-based:** Build a graph where edges represent predecessor relationships - O(n² × L) time
2. **Topological Sort:** Use topological sort on the predecessor graph
3. **BFS:** Use breadth-first search to find longest path in the graph
## Common Pitfalls
1. **Wrong Processing Order:** Not sorting words by length.
2. **Inefficient Predecessor Finding:** Using complex string algorithms instead of simple character removal.
3. **Missing Caching:** Not using memoization to avoid redundant calculations.
4. **Wrong Chain Logic:** Not properly building chains based on predecessor relationships.
5. **String Operations:** Not considering the cost of string slicing operations.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/1048.longest-string-chain.js)](../exercises/1048.longest-string-chain.js)
*Note: This is a dynamic programming problem that demonstrates efficient string chain building with predecessor relationships.*

View File

@@ -0,0 +1,117 @@
# Maximum Depth of Binary Tree
[![Problem 104](https://img.shields.io/badge/Problem-104-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/maximum-depth-of-binary-tree/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/maximum-depth-of-binary-tree/)
**Problem Number:** [104](https://leetcode.com/problems/maximum-depth-of-binary-tree/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Tree, Depth-First Search, Breadth-First Search, Binary Tree
**LeetCode Link:** [https://leetcode.com/problems/maximum-depth-of-binary-tree/](https://leetcode.com/problems/maximum-depth-of-binary-tree/)
## Problem Description
Given the `root` of a binary tree, return its maximum depth.
A binary tree's maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.
**Example 1:**
```
Input: root = [3,9,20,null,null,15,7]
Output: 3
```
**Example 2:**
```
Input: root = [1,null,2]
Output: 2
```
**Constraints:**
- The number of nodes in the tree is in the range `[0, 10^4]`
- `-100 <= Node.val <= 100`
## My Approach
I used a **Recursive Depth-First Search** approach. The key insight is to recursively calculate the depth of left and right subtrees and return the maximum depth plus one for the current node.
**Algorithm:**
1. Handle base case: if root is None, return 0
2. Use a recursive helper function that tracks current depth
3. Recursively calculate depth of left and right subtrees
4. Return the maximum of left and right depths plus 1 for current node
5. The final result is the maximum depth of the entire tree
## Solution
The solution uses recursive DFS to find the maximum depth. See the implementation in the [solution file](../exercises/104.maximum-depth-of-binary-tree.py).
**Key Points:**
- Uses recursive DFS to traverse the tree
- Handles null nodes by returning 0
- Tracks current depth and finds maximum
- Returns maximum depth of left and right subtrees
- Adds 1 for the current node level
## Time & Space Complexity
**Time Complexity:** O(n)
- We visit each node exactly once
- Each node operation is O(1)
- Total: O(n) where n is the number of nodes
**Space Complexity:** O(h)
- Recursion stack depth equals tree height
- In worst case (skewed tree): O(n)
- In best case (balanced tree): O(log n)
## Key Insights
1. **Recursive DFS:** Using recursion provides a clean and intuitive solution for tree traversal.
2. **Base Case:** Null nodes have depth 0, providing a clear termination condition.
3. **Maximum Depth:** We take the maximum of left and right subtree depths since we want the longest path.
4. **Depth Calculation:** Each level adds 1 to the depth, so we add 1 to the maximum subtree depth.
5. **Tree Properties:** The maximum depth is the length of the longest path from root to leaf.
6. **Efficient Traversal:** DFS visits each node only once, making it efficient.
## Mistakes Made
1. **Wrong Base Case:** Initially might not handle null nodes properly.
2. **Complex Logic:** Overcomplicating the depth calculation with unnecessary variables.
3. **Wrong Return Value:** Not adding 1 for the current node level.
4. **Inefficient Approach:** Using BFS when DFS is simpler and more efficient.
## Related Problems
- **Minimum Depth of Binary Tree** (Problem 111): Find minimum depth
- **Balanced Binary Tree** (Problem 110): Check if tree is balanced
- **Binary Tree Level Order Traversal** (Problem 102): Level-by-level traversal
- **Symmetric Tree** (Problem 101): Check if tree is symmetric
## Alternative Approaches
1. **Iterative DFS:** Use stack for iterative depth-first search - O(n) time, O(h) space
2. **BFS:** Use queue for breadth-first search - O(n) time, O(w) space where w is max width
3. **Level Order Traversal:** Count levels using BFS approach
## Common Pitfalls
1. **Wrong Base Case:** Not handling null nodes correctly.
2. **Complex Implementation:** Overcomplicating the recursive logic.
3. **Wrong Depth Calculation:** Not adding 1 for the current node.
4. **Inefficient Approach:** Using BFS when DFS is simpler.
5. **Stack Overflow:** Not considering very deep trees for recursion.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/104.maximum-depth-of-binary-tree.py)](../exercises/104.maximum-depth-of-binary-tree.py)
*Note: This is a fundamental tree traversal problem that demonstrates efficient use of recursive DFS.*

View File

@@ -0,0 +1,131 @@
# Minimum Absolute Difference
[![Problem 1200](https://img.shields.io/badge/Problem-1200-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/minimum-absolute-difference/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/minimum-absolute-difference/)
**Problem Number:** [1200](https://leetcode.com/problems/minimum-absolute-difference/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Sorting
**LeetCode Link:** [https://leetcode.com/problems/minimum-absolute-difference/](https://leetcode.com/problems/minimum-absolute-difference/)
## Problem Description
Given an array of distinct integers `arr`, find all pairs of elements with the minimum absolute difference of any two elements.
Return a list of pairs in ascending order (with respect to pairs), each pair `[a, b]` follows
- `a, b` are from `arr`
- `a < b`
- `b - a` equals the minimum absolute difference of any two elements in `arr`
**Example 1:**
```
Input: arr = [4,2,1,3]
Output: [[1,2],[2,3],[3,4]]
Explanation: The minimum absolute difference is 1. List all pairs with difference equal to 1 in ascending order.
```
**Example 2:**
```
Input: arr = [1,3,6,10,15]
Output: [[1,3]]
Explanation: The minimum absolute difference is 2.
```
**Example 3:**
```
Input: arr = [3,8,-10,23,19,-4,-14,27]
Output: [[-14,-10],[19,23],[23,27]]
```
**Constraints:**
- `2 <= arr.length <= 10^5`
- `-10^6 <= arr[i] <= 10^6`
## My Approach
I used a **Sorting** approach to find the minimum absolute difference efficiently. The key insight is that the minimum absolute difference must occur between adjacent elements in the sorted array.
**Algorithm:**
1. Sort the array in ascending order
2. Initialize minimum absolute difference to infinity
3. Iterate through adjacent pairs in the sorted array
4. Calculate absolute difference between each pair
5. If current difference is smaller than minimum, update minimum and reset result list
6. If current difference equals minimum, add the pair to result list
7. Return all pairs with minimum absolute difference
## Solution
The solution uses sorting to find minimum absolute differences efficiently. See the implementation in the [solution file](../exercises/1200.minimum-absolute-difference.py).
**Key Points:**
- Sorts array to ensure adjacent elements have minimum differences
- Tracks minimum absolute difference found so far
- Collects all pairs with the minimum difference
- Returns pairs in ascending order as required
- Handles multiple pairs with same minimum difference
## Time & Space Complexity
**Time Complexity:** O(n log n)
- Sorting: O(n log n)
- Single pass through sorted array: O(n)
- Total: O(n log n)
**Space Complexity:** O(n)
- Result list can contain up to n/2 pairs
- Each pair contains 2 elements
- Total: O(n)
## Key Insights
1. **Sorting Advantage:** After sorting, the minimum absolute difference must occur between adjacent elements.
2. **Adjacent Pairs:** We only need to check consecutive elements in the sorted array, not all possible pairs.
3. **Multiple Minimums:** There can be multiple pairs with the same minimum absolute difference.
4. **Efficient Tracking:** We can track the minimum difference and collect all pairs with that difference in one pass.
5. **Ordered Output:** The sorted array naturally provides pairs in ascending order.
6. **Distinct Elements:** Since all elements are distinct, we don't need to handle duplicates.
## Mistakes Made
1. **Brute Force:** Initially might check all possible pairs, leading to O(n²) complexity.
2. **Wrong Order:** Not sorting the array first, missing the adjacent pair insight.
3. **Complex Logic:** Overcomplicating the minimum tracking logic.
4. **Missing Pairs:** Not collecting all pairs with the same minimum difference.
## Related Problems
- **Two Sum** (Problem 1): Find pairs that sum to target
- **3Sum** (Problem 15): Find triplets that sum to zero
- **Closest 3Sum** (Problem 16): Find triplet closest to target
- **Two Sum II** (Problem 167): Two sum in sorted array
## Alternative Approaches
1. **Hash Set:** Use hash set to track seen differences - O(n²) time complexity
2. **Two Pointers:** Use two pointers on sorted array - O(n log n) time
3. **Priority Queue:** Use min-heap to track differences - O(n log n) time
## Common Pitfalls
1. **Brute Force:** Checking all possible pairs instead of using sorting.
2. **Wrong Order:** Not sorting the array to find adjacent minimum differences.
3. **Missing Pairs:** Not collecting all pairs with the same minimum difference.
4. **Complex Logic:** Overcomplicating the minimum tracking.
5. **Order Issues:** Not returning pairs in the required ascending order.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/1200.minimum-absolute-difference.py)](../exercises/1200.minimum-absolute-difference.py)
*Note: This is a simple sorting problem that demonstrates efficient finding of minimum differences between adjacent elements.*

View File

@@ -0,0 +1,122 @@
# Best Time to Buy and Sell Stock
[![Problem 121](https://img.shields.io/badge/Problem-121-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)
**Problem Number:** [121](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Dynamic Programming, Greedy
**LeetCode Link:** [https://leetcode.com/problems/best-time-to-buy-and-sell-stock/](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/)
## Problem Description
You are given an array `prices` where `prices[i]` is the price of a given stock on the `i^th` day.
You want to maximize your profit by choosing a single day to buy one stock and choosing a different day in the future to sell that stock.
Return the maximum profit you can achieve from this transaction. If you cannot achieve any profit, return `0`.
**Example 1:**
```
Input: prices = [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Note that buying on day 2 and selling on day 1 is not allowed because you must buy before you sell.
```
**Example 2:**
```
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: In this case, no transactions are done and the max profit = 0.
```
**Constraints:**
- `1 <= prices.length <= 10^5`
- `0 <= prices[i] <= 10^4`
## My Approach
I used a **Greedy** approach with single pass tracking. The key insight is to keep track of the minimum price seen so far and calculate the potential profit at each day.
**Algorithm:**
1. Initialize minimum price to infinity and maximum profit to 0
2. Iterate through each price in the array
3. Update minimum price if current price is lower
4. Calculate potential profit: current price - minimum price
5. Update maximum profit if current profit is higher
6. Return maximum profit found
## Solution
The solution uses a greedy approach with single pass tracking. See the implementation in the [solution file](../exercises/121.best-time-to-buy-and-sell-stock.py).
**Key Points:**
- Tracks minimum price seen so far
- Calculates potential profit at each day
- Updates maximum profit when better opportunity found
- Single pass through the array
- Handles case where no profit is possible
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the array
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Greedy Approach:** We can find the maximum profit by tracking the minimum price and calculating potential profits.
2. **Single Pass:** We only need to traverse the array once, keeping track of the minimum price seen so far.
3. **Buy Before Sell:** The constraint that we must buy before selling is naturally handled by tracking minimum price.
4. **No Profit Case:** If prices are monotonically decreasing, the maximum profit will be 0.
5. **Optimal Substructure:** The solution for the entire array depends on the minimum price seen so far.
6. **Efficient Tracking:** We don't need to store all prices, just the minimum and maximum profit.
## Mistakes Made
1. **Brute Force:** Initially might try all possible buy-sell pairs, leading to O(n²) complexity.
2. **Wrong Order:** Not understanding that we must buy before selling.
3. **Complex Logic:** Overcomplicating the solution with unnecessary data structures.
4. **Missing Edge Cases:** Not handling cases where no profit is possible.
## Related Problems
- **Best Time to Buy and Sell Stock II** (Problem 122): Multiple transactions allowed
- **Best Time to Buy and Sell Stock III** (Problem 123): At most two transactions
- **Best Time to Buy and Sell Stock IV** (Problem 188): At most k transactions
- **Best Time to Buy and Sell Stock with Cooldown** (Problem 309): With cooldown period
## Alternative Approaches
1. **Dynamic Programming:** Use DP array to track maximum profit - O(n) time, O(n) space
2. **Two Pointers:** Use two pointers to track buy and sell days - O(n) time
3. **Kadane's Algorithm:** Adapt Kadane's algorithm for this problem - O(n) time
## Common Pitfalls
1. **Brute Force:** Checking all possible buy-sell pairs instead of using greedy approach.
2. **Wrong Order:** Not understanding the buy-before-sell constraint.
3. **Complex Implementation:** Using unnecessary data structures or complex logic.
4. **Edge Cases:** Not handling cases where no profit is possible.
5. **Inefficient Tracking:** Not using single pass approach.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/121.best-time-to-buy-and-sell-stock.py)](../exercises/121.best-time-to-buy-and-sell-stock.py)
*Note: This is a classic greedy problem that demonstrates efficient single-pass profit maximization.*

View File

@@ -0,0 +1,131 @@
# Best Time to Buy and Sell Stock II
[![Problem 122](https://img.shields.io/badge/Problem-122-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
**Problem Number:** [122](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Dynamic Programming, Greedy
**LeetCode Link:** [https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/)
## Problem Description
You are given an integer array `prices` where `prices[i]` is the price of a given stock on the `i^th` day.
On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. However, you can buy it then immediately sell it on the same day.
Find and return the maximum profit you can achieve.
**Example 1:**
```
Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Total profit is 4 + 3 = 7.
```
**Example 2:**
```
Input: prices = [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Total profit is 4.
```
**Example 3:**
```
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: There is no way to make a positive profit, so we never buy the stock to achieve the maximum profit of 0.
```
**Constraints:**
- `1 <= prices.length <= 3 * 10^4`
- `0 <= prices[i] <= 10^4`
## My Approach
I used a **Greedy** approach that captures all positive price differences. The key insight is that we can capture all the profit by buying and selling whenever the price increases from one day to the next.
**Algorithm:**
1. Initialize total profit to 0 and buy price to first day's price
2. Iterate through prices starting from the second day
3. Calculate potential profit: current price - buy price
4. If profit is positive, add it to total profit
5. Update buy price to current price (for next potential transaction)
6. Return total accumulated profit
## Solution
The solution uses a greedy approach to capture all positive price differences. See the implementation in the [solution file](../exercises/122.best-time-to-buy-and-sell-stock-ii.py).
**Key Points:**
- Captures all positive price differences
- Buys and sells whenever price increases
- Accumulates total profit from all transactions
- Handles multiple buy-sell cycles
- Single pass through the array
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the array
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Greedy Strategy:** We can capture all profit by buying and selling whenever the price increases.
2. **Multiple Transactions:** Unlike the first problem, we can make multiple buy-sell transactions.
3. **Positive Differences:** We only need to capture positive price differences between consecutive days.
4. **Immediate Selling:** We can buy and sell on the same day, which simplifies the strategy.
5. **Optimal Substructure:** The total profit is the sum of all positive price differences.
6. **No Holding Cost:** Since we can hold at most one share, we don't need to track holding periods.
## Mistakes Made
1. **Complex DP:** Initially might use dynamic programming when greedy approach suffices.
2. **Wrong Strategy:** Not understanding that we can capture all positive differences.
3. **Over-engineering:** Using complex logic to track buy-sell cycles.
4. **Missing Transactions:** Not capturing all profitable opportunities.
## Related Problems
- **Best Time to Buy and Sell Stock** (Problem 121): Single transaction
- **Best Time to Buy and Sell Stock III** (Problem 123): At most two transactions
- **Best Time to Buy and Sell Stock IV** (Problem 188): At most k transactions
- **Best Time to Buy and Sell Stock with Cooldown** (Problem 309): With cooldown period
## Alternative Approaches
1. **Dynamic Programming:** Use DP to track maximum profit with state tracking - O(n) time, O(n) space
2. **Peak Valley:** Find all peaks and valleys to calculate total profit - O(n) time
3. **Cumulative Sum:** Calculate cumulative sum of positive differences - O(n) time
## Common Pitfalls
1. **Complex Implementation:** Using dynamic programming when greedy approach is simpler.
2. **Wrong Strategy:** Not capturing all positive price differences.
3. **Over-engineering:** Using complex logic to track transactions.
4. **Missing Opportunities:** Not understanding that we can make multiple transactions.
5. **Inefficient Approach:** Not using the greedy insight about positive differences.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/122.best-time-to-buy-and-sell-stock-ii.py)](../exercises/122.best-time-to-buy-and-sell-stock-ii.py)
*Note: This is a greedy problem that demonstrates capturing all positive price differences for maximum profit.*

View File

@@ -0,0 +1,128 @@
# Valid Palindrome
[![Problem 125](https://img.shields.io/badge/Problem-125-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-palindrome/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-palindrome/)
**Problem Number:** [125](https://leetcode.com/problems/valid-palindrome/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/valid-palindrome/](https://leetcode.com/problems/valid-palindrome/)
## Problem Description
A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.
Given a string `s`, return `true` if it is a palindrome, or `false` otherwise.
**Example 1:**
```
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
```
**Example 2:**
```
Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.
```
**Example 3:**
```
Input: s = " "
Output: true
Explanation: s is an empty string "" after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.
```
**Constraints:**
- `1 <= s.length <= 2 * 10^5`
- `s` consists only of printable ASCII characters
## My Approach
I used a **String Manipulation** approach with regular expressions. The key insight is to clean the string by removing non-alphanumeric characters and converting to lowercase, then check if it reads the same forward and backward.
**Algorithm:**
1. Use regular expression to remove all non-alphanumeric characters
2. Convert the cleaned string to lowercase
3. Create a reversed version of the string
4. Compare the original cleaned string with its reverse
5. Return true if they are equal, false otherwise
## Solution
The solution uses string manipulation with regular expressions. See the implementation in the [solution file](../exercises/125.valid-palindrome.py).
**Key Points:**
- Uses regex to remove non-alphanumeric characters
- Converts to lowercase for case-insensitive comparison
- Creates reversed string for comparison
- Simple and efficient approach
- Handles edge cases like empty strings
## Time & Space Complexity
**Time Complexity:** O(n)
- Regex substitution: O(n)
- String reversal: O(n)
- String comparison: O(n)
- Total: O(n)
**Space Complexity:** O(n)
- Creates new strings for cleaned and reversed versions
- Each string can be up to length n
- Total: O(n)
## Key Insights
1. **String Cleaning:** Using regex to remove non-alphanumeric characters is efficient and clean.
2. **Case Insensitivity:** Converting to lowercase ensures case-insensitive comparison.
3. **Palindrome Check:** Comparing a string with its reverse is a simple way to check for palindromes.
4. **Character Filtering:** Only alphanumeric characters matter for palindrome validation.
5. **Edge Cases:** Empty strings and strings with only non-alphanumeric characters are valid palindromes.
6. **Built-in Functions:** Using Python's built-in string operations makes the solution concise.
## Mistakes Made
1. **Manual Filtering:** Initially might manually iterate through characters instead of using regex.
2. **Case Sensitivity:** Not converting to lowercase for case-insensitive comparison.
3. **Complex Logic:** Overcomplicating the palindrome check with two pointers.
4. **Wrong Characters:** Not properly filtering non-alphanumeric characters.
## Related Problems
- **Valid Palindrome II** (Problem 680): Check if string can be palindrome after removing one character
- **Longest Palindromic Substring** (Problem 5): Find longest palindromic substring
- **Palindrome Number** (Problem 9): Check if number is palindrome
- **Palindrome Linked List** (Problem 234): Check if linked list is palindrome
## Alternative Approaches
1. **Two Pointers:** Use left and right pointers to compare characters - O(n) time, O(1) space
2. **Stack-based:** Use stack to reverse and compare - O(n) time, O(n) space
3. **Recursive:** Use recursion to check palindrome - O(n) time, O(n) space
## Common Pitfalls
1. **Manual Filtering:** Manually iterating through characters instead of using regex.
2. **Case Sensitivity:** Not handling case-insensitive comparison.
3. **Complex Implementation:** Using two pointers when simple string comparison suffices.
4. **Wrong Characters:** Not properly filtering non-alphanumeric characters.
5. **Edge Cases:** Not handling empty strings or strings with only special characters.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/125.valid-palindrome.py)](../exercises/125.valid-palindrome.py)
*Note: This is a simple string manipulation problem that demonstrates efficient palindrome checking with regex.*

View File

@@ -0,0 +1,122 @@
# Longest Consecutive Sequence
[![Problem 128](https://img.shields.io/badge/Problem-128-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-consecutive-sequence/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/longest-consecutive-sequence/)
**Problem Number:** [128](https://leetcode.com/problems/longest-consecutive-sequence/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Hash Table, Union Find
**LeetCode Link:** [https://leetcode.com/problems/longest-consecutive-sequence/](https://leetcode.com/problems/longest-consecutive-sequence/)
## Problem Description
Given an unsorted array of integers `nums`, return the length of the longest consecutive elements sequence.
You must write an algorithm that runs in `O(n)` time.
**Example 1:**
```
Input: nums = [100,4,200,1,3,2]
Output: 4
Explanation: The longest consecutive elements sequence is [1, 2, 3, 4]. Therefore its length is 4.
```
**Example 2:**
```
Input: nums = [0,3,7,2,5,8,4,6,0,1]
Output: 9
```
**Constraints:**
- `0 <= nums.length <= 10^5`
- `-10^9 <= nums[i] <= 10^9`
## My Approach
I used a **Hash Set** approach with sorting to find the longest consecutive sequence. The key insight is to remove duplicates, sort the array, and then count consecutive sequences.
**Algorithm:**
1. Handle edge cases (empty array or single element)
2. Convert array to set to remove duplicates
3. Sort the unique elements
4. Iterate through sorted elements to find consecutive sequences
5. Track the length of current consecutive sequence
6. Update maximum length when sequence breaks
7. Return the maximum consecutive sequence length
## Solution
The solution uses hash set and sorting to find the longest consecutive sequence. See the implementation in the [solution file](../exercises/128.longest-consecutive-sequence.py).
**Key Points:**
- Removes duplicates using set
- Sorts unique elements for consecutive checking
- Tracks current sequence length and maximum found
- Handles edge cases properly
- Returns maximum consecutive sequence length
## Time & Space Complexity
**Time Complexity:** O(n log n)
- Converting to set: O(n)
- Sorting: O(n log n)
- Single pass through sorted array: O(n)
- Total: O(n log n)
**Space Complexity:** O(n)
- Set storage: O(n)
- Sorted array: O(n)
- Counter array: O(n)
- Total: O(n)
## Key Insights
1. **Duplicate Removal:** Using a set removes duplicates, which simplifies the consecutive sequence finding.
2. **Sorting Advantage:** After sorting, consecutive elements are adjacent, making it easy to count sequences.
3. **Sequence Tracking:** We can track the current sequence length and update the maximum when a sequence breaks.
4. **Edge Cases:** Arrays with less than 2 elements have simple solutions.
5. **Consecutive Check:** Two numbers are consecutive if their difference is exactly 1.
6. **Efficient Counting:** We can count consecutive sequences in a single pass through the sorted array.
## Mistakes Made
1. **Wrong Complexity:** Not achieving O(n) time complexity as required by the problem.
2. **Duplicate Handling:** Not properly handling duplicate elements.
3. **Complex Logic:** Overcomplicating the consecutive sequence detection.
4. **Edge Cases:** Not handling empty arrays or single elements properly.
## Related Problems
- **Longest Increasing Subsequence** (Problem 300): Find longest increasing subsequence
- **Longest Common Subsequence** (Problem 1143): Find longest common subsequence
- **Longest Palindromic Substring** (Problem 5): Find longest palindromic substring
- **Longest Substring Without Repeating Characters** (Problem 3): Find longest unique substring
## Alternative Approaches
1. **Hash Set with O(n):** Use hash set to check consecutive elements without sorting - O(n) time
2. **Union Find:** Use union-find data structure to group consecutive elements - O(n) time
3. **Two Pass:** First pass to build hash set, second pass to find sequences - O(n) time
## Common Pitfalls
1. **Wrong Complexity:** Using sorting when O(n) solution is required.
2. **Duplicate Issues:** Not properly handling duplicate elements.
3. **Complex Implementation:** Overcomplicating the consecutive sequence detection.
4. **Edge Cases:** Not handling empty arrays or single elements.
5. **Inefficient Approach:** Not using hash set for O(1) lookups.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/128.longest-consecutive-sequence.py)](../exercises/128.longest-consecutive-sequence.py)
*Note: This is a hash table problem that demonstrates finding consecutive sequences, though this solution doesn't achieve the required O(n) time complexity.*

View File

@@ -0,0 +1,121 @@
# Deepest Leaves Sum
[![Problem 1302](https://img.shields.io/badge/Problem-1302-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/deepest-leaves-sum/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/deepest-leaves-sum/)
**Problem Number:** [1302](https://leetcode.com/problems/deepest-leaves-sum/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Tree, Depth-First Search, Breadth-First Search, Binary Tree
**LeetCode Link:** [https://leetcode.com/problems/deepest-leaves-sum/](https://leetcode.com/problems/deepest-leaves-sum/)
## Problem Description
Given the `root` of a binary tree, return the sum of values of its deepest leaves.
**Example 1:**
```
Input: root = [1,2,3,4,5,null,6,7,null,null,null,null,8]
Output: 15
Explanation: The deepest leaves are the nodes with values 7 and 8 respectively.
The sum of their values is 7 + 8 = 15.
```
**Example 2:**
```
Input: root = [6,7,8,2,7,1,3,9,null,1,4,null,null,null,5]
Output: 19
```
**Constraints:**
- The number of nodes in the tree is in the range `[1, 10^4]`.
- `1 <= Node.val <= 100`
## My Approach
I used a **Depth-First Search (DFS)** approach with depth tracking. The key insight is to traverse the tree and keep track of the maximum depth found, then sum all leaf nodes at that maximum depth.
**Algorithm:**
1. Initialize maximum depth and sum variables
2. Use DFS to traverse the tree recursively
3. For each leaf node, check if it's at the deepest level
4. If current depth is greater than maximum depth, update maximum depth and reset sum
5. If current depth equals maximum depth, add leaf value to sum
6. Recursively traverse left and right children
7. Return the sum of deepest leaves
## Solution
The solution uses DFS with depth tracking to find the sum of deepest leaves. See the implementation in the [solution file](../exercises/1302.deepest-leaves-sum.py).
**Key Points:**
- Uses recursive DFS to traverse the tree
- Tracks maximum depth found so far
- Resets sum when deeper level is found
- Accumulates sum for leaves at maximum depth
- Handles leaf nodes (nodes with no children)
- Returns sum of all deepest leaves
## Time & Space Complexity
**Time Complexity:** O(n)
- DFS visits each node exactly once
- Each node operation is constant time
- Total: O(n)
**Space Complexity:** O(h)
- h is the height of the tree
- Recursion stack space
- In worst case (skewed tree): O(n)
- In best case (balanced tree): O(log n)
## Key Insights
1. **DFS Traversal:** Using DFS allows us to explore the tree and find the deepest level.
2. **Depth Tracking:** We need to track the maximum depth to identify the deepest leaves.
3. **Leaf Detection:** A leaf node is identified when it has no left and right children.
4. **Sum Accumulation:** When we find leaves at the maximum depth, we accumulate their values.
5. **Depth Reset:** When we find a deeper level, we reset the sum and update the maximum depth.
6. **Recursive Structure:** The tree structure naturally lends itself to recursive traversal.
## Mistakes Made
1. **Wrong Traversal:** Initially might use BFS when DFS is more appropriate for depth tracking.
2. **Complex Logic:** Overcomplicating the depth tracking with unnecessary data structures.
3. **Wrong Leaf Detection:** Not properly identifying leaf nodes.
4. **Sum Logic:** Not correctly handling the case when deeper levels are found.
## Related Problems
- **Maximum Depth of Binary Tree** (Problem 104): Find maximum depth of binary tree
- **Binary Tree Level Order Traversal** (Problem 102): Level-by-level traversal
- **Sum Root to Leaf Numbers** (Problem 129): Sum of all root-to-leaf paths
- **Path Sum** (Problem 112): Check if path sum equals target
## Alternative Approaches
1. **Breadth-First Search:** Use BFS with level tracking - O(n) time, O(w) space
2. **Two Pass DFS:** First pass to find max depth, second pass to sum leaves - O(n) time
3. **Iterative DFS:** Use stack for iterative DFS - O(n) time, O(h) space
## Common Pitfalls
1. **Wrong Traversal:** Using BFS when DFS is more suitable for depth tracking.
2. **Complex Implementation:** Overcomplicating the depth tracking logic.
3. **Wrong Leaf Detection:** Not properly identifying leaf nodes.
4. **Sum Logic Errors:** Not correctly handling depth updates and sum resets.
5. **Space Complexity:** Not considering recursion stack space.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/1302.deepest-leaves-sum.py)](../exercises/1302.deepest-leaves-sum.py)
*Note: This is a tree traversal problem that demonstrates efficient depth tracking with DFS.*

125
src/notes/135_candy.md Normal file
View File

@@ -0,0 +1,125 @@
# Candy
[![Problem 135](https://img.shields.io/badge/Problem-135-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/candy/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Hard-red?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=HARD)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/candy/)
**Problem Number:** [135](https://leetcode.com/problems/candy/)
**Difficulty:** [Hard](https://leetcode.com/problemset/?difficulty=HARD)
**Category:** Array, Greedy
**LeetCode Link:** [https://leetcode.com/problems/candy/](https://leetcode.com/problems/candy/)
## Problem Description
There are `n` children standing in a line. Each child is assigned a rating value given in the integer array `ratings`.
You are giving candies to these children subjected to the following requirements:
- Each child must have at least one candy.
- Children with a higher rating get more candies than their neighbors.
Return the minimum number of candies you need to have to distribute the candies to the children.
**Example 1:**
```
Input: ratings = [1,0,2]
Output: 5
Explanation: You can allocate to the first, second and third child with 2, 1, 2 candies respectively.
```
**Example 2:**
```
Input: ratings = [1,2,2]
Output: 4
Explanation: You can allocate to the first, second and third child with 1, 2, 1 candies respectively.
The third child gets 1 candy because it satisfies the above two conditions.
```
**Constraints:**
- `n == ratings.length`
- `1 <= n <= 2 * 10^4`
- `0 <= ratings[i] <= 2 * 10^4`
## My Approach
I used a **Two-Pass Greedy** approach to satisfy both left and right neighbor constraints. The key insight is to make two passes through the array: first from left to right to handle increasing ratings, then from right to left to handle decreasing ratings.
**Algorithm:**
1. Initialize all children with 1 candy
2. First pass (left to right): If current rating > previous rating, give one more candy than previous
3. Second pass (right to left): If current rating > next rating, take maximum of current candy and next candy + 1
4. Sum all candies and return the total
## Solution
The solution uses a two-pass greedy approach to satisfy neighbor constraints. See the implementation in the [solution file](../exercises/135.candy.py).
**Key Points:**
- Initializes all children with minimum 1 candy
- First pass handles increasing ratings from left to right
- Second pass handles decreasing ratings from right to left
- Uses maximum function to satisfy both constraints
- Returns sum of all distributed candies
## Time & Space Complexity
**Time Complexity:** O(n)
- Two passes through the array
- Each pass performs constant time operations
- Total: O(n)
**Space Complexity:** O(n)
- Creates an array to store candy counts
- Array size equals number of children
- Total: O(n)
## Key Insights
1. **Two-Pass Strategy:** We need two passes to handle both left and right neighbor constraints.
2. **Greedy Approach:** At each step, we give the minimum candies needed to satisfy the current constraint.
3. **Maximum Function:** When handling decreasing ratings, we take the maximum to satisfy both constraints.
4. **Minimum Initialization:** Every child must get at least 1 candy, so we start with 1 candy each.
5. **Constraint Satisfaction:** The two passes ensure that both left and right neighbor constraints are satisfied.
6. **Optimal Substructure:** The solution for each child depends only on its immediate neighbors.
## Mistakes Made
1. **Single Pass:** Initially might try to handle both constraints in a single pass.
2. **Wrong Order:** Not understanding the importance of the two-pass order.
3. **Complex Logic:** Overcomplicating the constraint satisfaction logic.
4. **Wrong Initialization:** Not starting with 1 candy for each child.
## Related Problems
- **Trapping Rain Water** (Problem 42): Two-pass approach for water trapping
- **Product of Array Except Self** (Problem 238): Two-pass approach for product calculation
- **Gas Station** (Problem 134): Greedy approach with circular array
- **Jump Game** (Problem 55): Greedy approach for reachability
## Alternative Approaches
1. **Single Pass with Stack:** Use stack to handle both directions - O(n) time, O(n) space
2. **Peak Detection:** Find peaks and valleys to calculate candies - O(n) time
3. **Dynamic Programming:** Use DP to track minimum candies needed - O(n) time, O(n) space
## Common Pitfalls
1. **Single Pass Attempt:** Trying to handle both constraints in one pass.
2. **Wrong Order:** Not understanding the importance of left-to-right then right-to-left order.
3. **Complex Logic:** Overcomplicating the constraint satisfaction.
4. **Wrong Initialization:** Not starting with 1 candy for each child.
5. **Missing Maximum:** Not using maximum function when handling decreasing ratings.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/135.candy.py)](../exercises/135.candy.py)
*Note: This is a greedy problem that demonstrates efficient two-pass constraint satisfaction.*

View File

@@ -0,0 +1,129 @@
# Linked List Cycle
[![Problem 141](https://img.shields.io/badge/Problem-141-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/linked-list-cycle/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/linked-list-cycle/)
**Problem Number:** [141](https://leetcode.com/problems/linked-list-cycle/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, Linked List, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/linked-list-cycle/](https://leetcode.com/problems/linked-list-cycle/)
## Problem Description
Given `head`, the head of a linked list, determine if the linked list has a cycle in it.
There is a cycle in a linked list if there is some node in the list that can be reached again by continuously following the `next` pointer. Internally, `pos` is used to denote the index of the node that tail's `next` pointer is connected to. Note that `pos` is not passed as a parameter.
Return `true` if there is a cycle in the linked list. Otherwise, return `false`.
**Example 1:**
```
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 1st node (0-indexed).
```
**Example 2:**
```
Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where the tail connects to the 0th node.
```
**Example 3:**
```
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
```
**Constraints:**
- The number of the nodes in the list is in the range `[0, 10^4]`.
- `-10^5 <= Node.val <= 10^5`
- `pos` is `-1` or a valid index in the linked-list.
## My Approach
I used **Floyd's Cycle-Finding Algorithm (Tortoise and Hare)** with two pointers. The key insight is that if there's a cycle, a fast pointer will eventually catch up to a slow pointer.
**Algorithm:**
1. Initialize two pointers (slow and fast) at the head
2. Move slow pointer by one step and fast pointer by two steps
3. If fast pointer reaches null, there's no cycle
4. If slow and fast pointers meet, there's a cycle
5. Return true if cycle detected, false otherwise
## Solution
The solution uses Floyd's cycle-finding algorithm with two pointers. See the implementation in the [solution file](../exercises/141.linked-list-cycle.py).
**Key Points:**
- Uses two pointers moving at different speeds
- Slow pointer moves one step at a time
- Fast pointer moves two steps at a time
- Detects cycle when pointers meet
- Handles null pointers properly
## Time & Space Complexity
**Time Complexity:** O(n)
- In worst case, fast pointer traverses the list twice
- Each pointer moves at most n steps
- Total: O(n)
**Space Complexity:** O(1)
- Uses only two pointers
- No additional data structures
- Constant extra space
## Key Insights
1. **Floyd's Algorithm:** Using two pointers at different speeds is the most efficient way to detect cycles.
2. **Mathematical Proof:** If there's a cycle, the fast pointer will eventually catch up to the slow pointer.
3. **No Extra Space:** This approach doesn't require storing visited nodes.
4. **Linear Time:** The algorithm runs in linear time regardless of cycle length.
5. **Null Handling:** Properly handles cases where the list ends without a cycle.
6. **Pointer Meeting:** When pointers meet, it indicates a cycle exists.
## Mistakes Made
1. **Hash Set Approach:** Initially might use hash set to track visited nodes, requiring O(n) space.
2. **Wrong Speeds:** Not using the correct speed ratio (1:2) for the pointers.
3. **Null Checks:** Not properly handling null pointer cases.
4. **Complex Logic:** Overcomplicating the cycle detection logic.
## Related Problems
- **Linked List Cycle II** (Problem 142): Find the node where cycle begins
- **Happy Number** (Problem 202): Cycle detection in number sequence
- **Find the Duplicate Number** (Problem 287): Cycle detection in array
- **Palindrome Linked List** (Problem 234): Check if linked list is palindrome
## Alternative Approaches
1. **Hash Set:** Store visited nodes in hash set - O(n) time, O(n) space
2. **Marking Nodes:** Mark visited nodes by changing their values - O(n) time, O(1) space
3. **Recursive:** Use recursion with visited tracking - O(n) time, O(n) space
## Common Pitfalls
1. **Hash Set Usage:** Using hash set when two pointers are more efficient.
2. **Wrong Speeds:** Not using the correct 1:2 speed ratio for pointers.
3. **Null Handling:** Not properly checking for null pointers.
4. **Complex Implementation:** Overcomplicating the cycle detection.
5. **Space Inefficiency:** Using O(n) space when O(1) is possible.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/141.linked-list-cycle.py)](../exercises/141.linked-list-cycle.py)
*Note: This is a classic two-pointer problem that demonstrates efficient cycle detection with Floyd's algorithm.*

View File

@@ -0,0 +1,121 @@
# Max Points on a Line
[![Problem 149](https://img.shields.io/badge/Problem-149-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/max-points-on-a-line/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Hard-red?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=HARD)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/max-points-on-a-line/)
**Problem Number:** [149](https://leetcode.com/problems/max-points-on-a-line/)
**Difficulty:** [Hard](https://leetcode.com/problemset/?difficulty=HARD)
**Category:** Array, Hash Table, Math, Geometry
**LeetCode Link:** [https://leetcode.com/problems/max-points-on-a-line/](https://leetcode.com/problems/max-points-on-a-line/)
## Problem Description
Given an array of `points` where `points[i] = [xi, yi]` represents a point on the **X-Y** plane, return the maximum number of points that lie on the same straight line.
**Example 1:**
```
Input: points = [[1,1],[2,2],[3,3]]
Output: 3
Explanation: All points lie on the line y = x.
```
**Example 2:**
```
Input: points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output: 4
Explanation: The line through points [1,1], [4,1] contains 4 points.
```
**Constraints:**
- `1 <= points.length <= 300`
- `points[i].length == 2`
- `-10^4 <= xi, yi <= 10^4`
- All the points are unique.
## My Approach
I used a **Hash Table** approach with slope calculation. The key insight is to calculate the slope between each pair of points and count how many points share the same slope from a fixed reference point.
**Algorithm:**
1. Handle edge cases (≤ 2 points return length)
2. For each point as reference, calculate slopes to all other points
3. Use hash table to count points with same slope
4. Handle vertical lines (infinite slope) separately
5. Track maximum points found on any line
6. Return maximum count + 1 (including reference point)
## Solution
The solution uses hash table with slope calculation to find maximum points on a line. See the implementation in the [solution file](../exercises/149.max-points-on-a-line.py).
**Key Points:**
- Uses hash table to count points with same slope
- Handles vertical lines (infinite slope) with special case
- Calculates slope using (y2-y1)/(x2-x1) formula
- Tracks maximum points found for each reference point
- Returns maximum count including reference point
## Time & Space Complexity
**Time Complexity:** O(n²)
- For each point, check all other points
- Slope calculation is constant time
- Total: O(n²)
**Space Complexity:** O(n)
- Hash table stores at most n-1 slopes
- Each slope can have multiple points
- Total: O(n)
## Key Insights
1. **Slope as Key:** Using slope as hash table key groups points on same line.
2. **Reference Point:** For each reference point, we calculate slopes to all other points.
3. **Vertical Lines:** Vertical lines have infinite slope and need special handling.
4. **Duplicate Points:** The problem guarantees unique points, simplifying the logic.
5. **Maximum Tracking:** We track the maximum points found for each reference point.
6. **Slope Formula:** Using (y2-y1)/(x2-x1) to calculate slope between two points.
## Mistakes Made
1. **Floating Point Precision:** Using floating point for slope comparison can lead to precision issues.
2. **Vertical Line Handling:** Not properly handling vertical lines with infinite slope.
3. **Reference Point Logic:** Not understanding that we need to check each point as reference.
4. **Complex Implementation:** Overcomplicating the slope calculation and counting.
## Related Problems
- **Line Reflection** (Problem 356): Check if points are symmetric about a line
- **Convex Hull** (Problem 587): Find convex hull of points
- **Rectangle Area** (Problem 223): Calculate area of overlapping rectangles
- **Valid Square** (Problem 593): Check if four points form a square
## Alternative Approaches
1. **GCD for Slope:** Use GCD to represent slope as reduced fraction - O(n²) time
2. **Cross Product:** Use cross product to check collinearity - O(n²) time
3. **Brute Force:** Check all possible lines through point pairs - O(n³) time
## Common Pitfalls
1. **Floating Point Issues:** Using floating point for slope comparison.
2. **Vertical Line Handling:** Not properly handling infinite slopes.
3. **Reference Point Logic:** Not checking each point as potential reference.
4. **Complex Implementation:** Overcomplicating the slope calculation.
5. **Edge Cases:** Not handling cases with ≤ 2 points properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/149.max-points-on-a-line.py)](../exercises/149.max-points-on-a-line.py)
*Note: This is a geometry problem that demonstrates efficient slope-based line detection with hash tables.*

View File

@@ -0,0 +1,133 @@
# Reverse Words in a String
[![Problem 151](https://img.shields.io/badge/Problem-151-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/reverse-words-in-a-string/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/reverse-words-in-a-string/)
**Problem Number:** [151](https://leetcode.com/problems/reverse-words-in-a-string/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** String, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/reverse-words-in-a-string/](https://leetcode.com/problems/reverse-words-in-a-string/)
## Problem Description
Given an input string `s`, reverse the order of the words.
A word is defined as a sequence of non-space characters. The words in `s` will be separated by at least one space.
Return a string of the words in reverse order concatenated by a single space.
Note that `s` may contain leading or trailing spaces or multiple spaces between two words. The returned string should only have a single space separating the words. Do not include any extra spaces.
**Example 1:**
```
Input: s = "the sky is blue"
Output: "blue is sky the"
```
**Example 2:**
```
Input: s = " hello world "
Output: "world hello"
Explanation: Your reversed string should not contain leading or trailing spaces.
```
**Example 3:**
```
Input: s = "a good example"
Output: "example good a"
Explanation: You need to reduce multiple spaces between two words to a single space in the reversed string.
```
**Constraints:**
- `1 <= s.length <= 10^4`
- `s` contains English letters (upper-case and lower-case), digits, and spaces `' '`.
- There is at least one word in `s`.
## My Approach
I used a **String Manipulation** approach with array reversal. The key insight is to split the string into words, reverse their order, and then join them back together.
**Algorithm:**
1. Split the input string by spaces to get individual words
2. Create a new array to store words in reverse order
3. Iterate through the original words array
4. Skip empty strings (multiple spaces)
5. Place non-empty words in reverse positions in the new array
6. Join the reversed words with single spaces
7. Remove any leading/trailing spaces
## Solution
The solution uses string manipulation with array reversal. See the implementation in the [solution file](../exercises/151.reverse-words-in-a-string.py).
**Key Points:**
- Splits string by spaces to get individual words
- Skips empty strings from multiple spaces
- Reverses word order using array manipulation
- Joins words with single spaces
- Removes leading/trailing spaces
## Time & Space Complexity
**Time Complexity:** O(n)
- String split: O(n)
- Array iteration: O(n)
- String join: O(n)
- Total: O(n)
**Space Complexity:** O(n)
- Split array: O(n)
- Reversed array: O(n)
- Total: O(n)
## Key Insights
1. **String Split:** Using split() method handles multiple spaces automatically.
2. **Empty String Filtering:** Skipping empty strings handles multiple consecutive spaces.
3. **Array Reversal:** Using array manipulation is more efficient than string operations.
4. **Space Handling:** The split and join operations naturally handle space normalization.
5. **Edge Cases:** The approach handles leading/trailing spaces and multiple spaces between words.
6. **Efficient Joining:** Using join() is more efficient than string concatenation.
## Mistakes Made
1. **Manual Space Handling:** Initially might manually handle spaces instead of using split().
2. **String Concatenation:** Using string concatenation instead of array join.
3. **Complex Logic:** Overcomplicating the word reversal process.
4. **Space Issues:** Not properly handling multiple spaces between words.
## Related Problems
- **Reverse Words in a String III** (Problem 557): Reverse individual words
- **Valid Palindrome** (Problem 125): Check if string is palindrome
- **Longest Common Prefix** (Problem 14): Find common prefix
- **Valid Parentheses** (Problem 20): Check valid parentheses
## Alternative Approaches
1. **Two Pointers:** Use two pointers to reverse words in-place - O(n) time, O(1) space
2. **Stack-based:** Use stack to reverse word order - O(n) time, O(n) space
3. **Recursive:** Use recursion to reverse words - O(n) time, O(n) space
## Common Pitfalls
1. **Manual Space Handling:** Manually handling spaces instead of using built-in methods.
2. **String Concatenation:** Using inefficient string concatenation.
3. **Complex Logic:** Overcomplicating the word reversal process.
4. **Space Issues:** Not properly handling multiple spaces between words.
5. **Edge Cases:** Not handling leading/trailing spaces properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/151.reverse-words-in-a-string.py)](../exercises/151.reverse-words-in-a-string.py)
*Note: This is a string manipulation problem that demonstrates efficient word reversal with array operations.*

View File

@@ -0,0 +1,136 @@
# Find Minimum in Rotated Sorted Array
[![Problem 153](https://img.shields.io/badge/Problem-153-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/)
**Problem Number:** [153](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Binary Search
**LeetCode Link:** [https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/](https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/)
## Problem Description
Suppose an array of length `n` sorted in ascending order is rotated between `1` and `n` times. For example, the array `nums = [0,1,2,4,5,6,7]` might become:
- `[4,5,6,7,0,1,2]` if it was rotated `4` times.
- `[0,1,2,4,5,6,7]` if it was rotated `7` times.
Notice that rotating an array `[a[0], a[1], a[2], ..., a[n-1]]` 1 time results in the array `[a[n-1], a[0], a[1], a[2], ..., a[n-2]]`.
Given the sorted rotated array `nums` of unique elements, return the minimum element of this array.
You must write an algorithm that runs in `O(log n)` time.
**Example 1:**
```
Input: nums = [3,4,5,1,2]
Output: 1
Explanation: The original array was [1,2,3,4,5] rotated 3 times.
```
**Example 2:**
```
Input: nums = [4,5,6,7,0,1,2]
Output: 0
Explanation: The original array was [0,1,2,4,5,6,7] and it was rotated 4 times.
```
**Example 3:**
```
Input: nums = [11,13,15,17]
Output: 11
Explanation: The original array was [11,13,15,17] and it was rotated 4 times.
```
**Constraints:**
- `n == nums.length`
- `1 <= n <= 5000`
- `-5000 <= nums[i] <= 5000`
- All the integers of `nums` are unique.
- `nums` is sorted and rotated between `1` and `n` times.
## My Approach
I used **Binary Search** to find the minimum element efficiently. The key insight is that in a rotated sorted array, the minimum element is always in the unsorted half.
**Algorithm:**
1. Initialize left and right pointers
2. While left <= right:
- If left == right, return the element (single element case)
- Calculate middle index
- If middle element > right element, minimum is in right half
- Otherwise, minimum is in left half (including middle)
3. Return the minimum element
## Solution
The solution uses binary search to find the minimum element in O(log n) time. See the implementation in the [solution file](../exercises/153.find-minimum-in-rotated-sorted-array.py).
**Key Points:**
- Uses binary search for O(log n) time complexity
- Compares middle element with right element to determine search direction
- Handles single element case when left == right
- Returns minimum element efficiently
## Time & Space Complexity
**Time Complexity:** O(log n)
- Binary search halves the search space each iteration
- Each iteration performs constant time operations
- Total: O(log n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Binary Search:** Using binary search achieves the required O(log n) time complexity.
2. **Rotation Property:** In a rotated sorted array, the minimum is always in the unsorted half.
3. **Comparison Strategy:** Comparing middle element with right element determines which half to search.
4. **Single Element Case:** When left == right, we've found the minimum element.
5. **Unique Elements:** The problem guarantees unique elements, simplifying the logic.
6. **Sorted Property:** Despite rotation, the array maintains sorted properties that enable binary search.
## Mistakes Made
1. **Linear Search:** Initially might use linear search, leading to O(n) complexity.
2. **Wrong Comparison:** Not using the correct comparison strategy for rotated arrays.
3. **Complex Logic:** Overcomplicating the binary search implementation.
4. **Edge Cases:** Not properly handling single element or edge cases.
## Related Problems
- **Search in Rotated Sorted Array** (Problem 33): Search target in rotated array
- **Search in Rotated Sorted Array II** (Problem 81): Search with duplicates
- **Find Peak Element** (Problem 162): Find peak in array
- **Binary Search** (Problem 704): Standard binary search
## Alternative Approaches
1. **Linear Search:** Check each element - O(n) time, O(1) space
2. **Recursive Binary Search:** Use recursion for binary search - O(log n) time, O(log n) space
3. **Two Pointers:** Use two pointers to find rotation point - O(log n) time
## Common Pitfalls
1. **Linear Search:** Using linear search instead of binary search.
2. **Wrong Comparison:** Not using the correct comparison strategy for rotated arrays.
3. **Complex Implementation:** Overcomplicating the binary search logic.
4. **Edge Cases:** Not handling single element or edge cases properly.
5. **Time Complexity:** Not achieving the required O(log n) time complexity.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/153.find-minimum-in-rotated-sorted-array.py)](../exercises/153.find-minimum-in-rotated-sorted-array.py)
*Note: This is a binary search problem that demonstrates efficient minimum finding in rotated sorted arrays.*

135
src/notes/155_min_stack.md Normal file
View File

@@ -0,0 +1,135 @@
# Min Stack
[![Problem 155](https://img.shields.io/badge/Problem-155-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/min-stack/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/min-stack/)
**Problem Number:** [155](https://leetcode.com/problems/min-stack/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Stack, Design
**LeetCode Link:** [https://leetcode.com/problems/min-stack/](https://leetcode.com/problems/min-stack/)
## Problem Description
Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.
Implement the `MinStack` class:
- `MinStack()` initializes the stack object.
- `void push(int val)` pushes the element `val` onto the stack.
- `void pop()` removes the element on the top of the stack.
- `int top()` gets the top element of the stack.
- `int getMin()` retrieves the minimum element in the stack.
You must implement a solution with `O(1)` time complexity for each function.
**Example 1:**
```
Input
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]
Output
[null,null,null,null,-3,null,0,-2]
Explanation
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); // return -3
minStack.pop();
minStack.top(); // return 0
minStack.getMin(); // return -2
```
**Constraints:**
- `-2^31 <= val <= 2^31 - 1`
- Methods `pop`, `top` and `getMin` operations will always be called on non-empty stacks.
- At most `3 * 10^4` calls will be made to `push`, `pop`, `top`, and `getMin`.
## My Approach
I used a **Two Stack** approach to maintain both the main stack and a minimum stack. The key insight is to use a separate stack to track the minimum value at each state.
**Algorithm:**
1. Use two deques: one for main stack, one for minimum values
2. Push: Add value to main stack, add minimum of current min and new value to min stack
3. Pop: Remove from both stacks simultaneously
4. Top: Return top element of main stack
5. GetMin: Return top element of min stack
## Solution
The solution uses two stacks to maintain O(1) time complexity for all operations. See the implementation in the [solution file](../exercises/155.min-stack.py).
**Key Points:**
- Uses two deques for main stack and minimum tracking
- Maintains minimum value at each stack state
- All operations are O(1) time complexity
- Handles duplicate minimum values correctly
- Synchronized operations between both stacks
## Time & Space Complexity
**Time Complexity:** O(1) for all operations
- Push: O(1) - append to both stacks
- Pop: O(1) - remove from both stacks
- Top: O(1) - access last element
- GetMin: O(1) - access last element of min stack
**Space Complexity:** O(n)
- Main stack: O(n)
- Min stack: O(n)
- Total: O(n)
## Key Insights
1. **Two Stack Design:** Using two stacks allows O(1) minimum retrieval.
2. **Minimum Tracking:** The min stack tracks the minimum value at each state.
3. **Synchronized Operations:** Push and pop operations affect both stacks simultaneously.
4. **Duplicate Handling:** The min stack can contain duplicate values for consecutive minimums.
5. **Constant Time:** All operations maintain O(1) time complexity.
6. **Stack Property:** The min stack naturally handles the LIFO property of the main stack.
## Mistakes Made
1. **Single Stack:** Initially might try to use a single stack with complex logic.
2. **Linear Search:** Using linear search to find minimum, leading to O(n) complexity.
3. **Complex Implementation:** Overcomplicating the minimum tracking logic.
4. **Wrong Data Structure:** Not using appropriate data structures for O(1) operations.
## Related Problems
- **Max Stack** (Problem 716): Design stack with max operation
- **Valid Parentheses** (Problem 20): Stack-based parentheses validation
- **Evaluate Reverse Polish Notation** (Problem 150): Stack-based expression evaluation
- **Implement Queue using Stacks** (Problem 232): Queue implementation with stacks
## Alternative Approaches
1. **Single Stack with Pairs:** Store (value, min) pairs in single stack - O(1) time, O(n) space
2. **Variable Tracking:** Track minimum with variable and handle updates - O(1) average time
3. **Linked List:** Use linked list with minimum tracking - O(1) time, O(n) space
## Common Pitfalls
1. **Single Stack Attempt:** Trying to use single stack with complex minimum tracking.
2. **Linear Search:** Using linear search to find minimum in O(n) time.
3. **Complex Logic:** Overcomplicating the minimum tracking implementation.
4. **Wrong Data Structure:** Not using appropriate data structures for O(1) operations.
5. **Synchronization Issues:** Not properly synchronizing operations between stacks.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/155.min-stack.py)](../exercises/155.min-stack.py)
*Note: This is a design problem that demonstrates efficient stack implementation with constant time minimum retrieval.*

View File

@@ -0,0 +1,134 @@
# Two Sum II - Input Array Is Sorted
[![Problem 167](https://img.shields.io/badge/Problem-167-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/)
**Problem Number:** [167](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Two Pointers, Binary Search
**LeetCode Link:** [https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/)
## Problem Description
Given a **1-indexed** array of integers `numbers` that is already **sorted in non-decreasing order**, find two numbers such that they add up to a specific `target` number. Let these two numbers be `numbers[index1]` and `numbers[index2]` where `1 <= index1 < index2 <= numbers.length`.
Return the indices of the two numbers, `index1` and `index2`, added by one as an integer array `[index1, index2]` of length 2.
The tests are generated such that there is **exactly one solution**. You may not use the same element twice.
Your solution must use only constant extra space.
**Example 1:**
```
Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore, index1 = 1, index2 = 2. We return [1, 2].
```
**Example 2:**
```
Input: numbers = [2,3,4], target = 6
Output: [1,3]
Explanation: The sum of 2 and 4 is 6. Therefore index1 = 1, index2 = 3. We return [1, 3].
```
**Example 3:**
```
Input: numbers = [-1,0], target = -1
Output: [1,2]
Explanation: The sum of -1 and 0 is -1. Therefore index1 = 1, index2 = 2. We return [1, 2].
```
**Constraints:**
- `2 <= numbers.length <= 3 * 10^4`
- `-1000 <= numbers[i] <= 1000`
- `numbers` is sorted in non-decreasing order.
- `-1000 <= target <= 1000`
- The tests are generated such that there is exactly one solution.
## My Approach
I used a **Two Pointers** approach to find the pair that sums to the target. The key insight is to use the sorted property of the array to efficiently narrow down the search space.
**Algorithm:**
1. Initialize two pointers: left at start, right at end
2. While left < right:
- Calculate the sum of elements at left and right pointers
- If sum equals target, return the 1-indexed positions
- If sum is less than target, move left pointer right
- If sum is greater than target, move right pointer left
3. Return the 1-indexed positions when target is found
## Solution
The solution uses two pointers to efficiently find the target sum in O(n) time. See the implementation in the [solution file](../exercises/167.two-sum-ii-input-array-is-sorted.py).
**Key Points:**
- Uses two pointers starting from opposite ends
- Leverages sorted property to eliminate search space
- Returns 1-indexed positions as required
- Constant space complexity
- Guaranteed to find solution
## Time & Space Complexity
**Time Complexity:** O(n)
- Two pointers traverse the array at most once
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Sorted Property:** The array is sorted, allowing efficient two-pointer approach.
2. **Two Pointers:** Using pointers from both ends eliminates the need for nested loops.
3. **Sum Comparison:** Comparing current sum with target guides pointer movement.
4. **1-Indexed Output:** Remember to add 1 to indices for the required output format.
5. **Guaranteed Solution:** The problem guarantees exactly one solution exists.
6. **Constant Space:** The approach uses only constant extra space.
## Mistakes Made
1. **Hash Table:** Initially might use hash table approach, requiring O(n) space.
2. **Binary Search:** Using binary search for each element, leading to O(n log n) complexity.
3. **Wrong Indexing:** Forgetting to add 1 to indices for 1-indexed output.
4. **Complex Logic:** Overcomplicating the two-pointer movement logic.
## Related Problems
- **Two Sum** (Problem 1): Find two numbers that sum to target
- **3Sum** (Problem 15): Find three numbers that sum to zero
- **Container With Most Water** (Problem 11): Two pointer approach for area
- **Trapping Rain Water** (Problem 42): Two pointer approach for water trapping
## Alternative Approaches
1. **Hash Table:** Use hash set to track seen numbers - O(n) time, O(n) space
2. **Binary Search:** For each element, binary search for complement - O(n log n) time
3. **Brute Force:** Check all pairs - O(n²) time, O(1) space
## Common Pitfalls
1. **Hash Table Usage:** Using hash table when two pointers are more efficient.
2. **Wrong Indexing:** Not adding 1 to indices for 1-indexed output.
3. **Complex Logic:** Overcomplicating the two-pointer movement.
4. **Space Inefficiency:** Using O(n) space when O(1) is possible.
5. **Wrong Movement:** Not understanding when to move which pointer.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/167.two-sum-ii-input-array-is-sorted.py)](../exercises/167.two-sum-ii-input-array-is-sorted.py)
*Note: This is a classic two-pointer problem that demonstrates efficient searching in sorted arrays.*

View File

@@ -0,0 +1,117 @@
# Majority Element
[![Problem 169](https://img.shields.io/badge/Problem-169-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/majority-element/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/majority-element/)
**Problem Number:** [169](https://leetcode.com/problems/majority-element/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Hash Table, Divide and Conquer, Sorting, Counting
**LeetCode Link:** [https://leetcode.com/problems/majority-element/](https://leetcode.com/problems/majority-element/)
## Problem Description
Given an array `nums` of size `n`, return the majority element.
The majority element is the element that appears more than `⌊n / 2⌋` times. You may assume that the majority element always exists in the array.
**Example 1:**
```
Input: nums = [3,2,3]
Output: 3
```
**Example 2:**
```
Input: nums = [2,2,1,1,1,2,2]
Output: 2
```
**Constraints:**
- `n == nums.length`
- `1 <= n <= 5 * 10^4`
- `-10^9 <= nums[i] <= 10^9`
**Follow-up:** Could you solve the problem in linear time and in `O(1)` space?
## My Approach
I used a **Sorting** approach to find the majority element. The key insight is that after sorting, the majority element will always be at the middle position since it appears more than half the time.
**Algorithm:**
1. Sort the array in ascending order
2. Return the element at the middle index (n/2)
3. The majority element is guaranteed to be at this position
## Solution
The solution uses sorting to find the majority element efficiently. See the implementation in the [solution file](../exercises/169.majority-element.py).
**Key Points:**
- Sorts array to find middle element
- Majority element is guaranteed to be at n/2 position
- Simple and efficient approach
- Handles all edge cases automatically
## Time & Space Complexity
**Time Complexity:** O(n log n)
- Sorting: O(n log n)
- Accessing middle element: O(1)
- Total: O(n log n)
**Space Complexity:** O(1)
- In-place sorting (if using built-in sort)
- No additional data structures needed
## Key Insights
1. **Sorting Property:** After sorting, the majority element appears at the middle position.
2. **Majority Guarantee:** Since the majority element appears more than n/2 times, it must be at position n/2.
3. **Simple Solution:** This approach is straightforward and doesn't require complex logic.
4. **Guaranteed Existence:** The problem guarantees a majority element exists.
5. **Middle Position:** The majority element will always be at index len(nums)//2.
6. **No Counting Needed:** We don't need to count occurrences, just find the middle element.
## Mistakes Made
1. **Hash Table:** Initially might use hash table to count occurrences, requiring O(n) space.
2. **Linear Search:** Using linear search to find the most frequent element.
3. **Complex Logic:** Overcomplicating the solution with unnecessary counting.
4. **Wrong Position:** Not understanding that majority element is at middle position.
## Related Problems
- **Majority Element II** (Problem 229): Find elements appearing more than n/3 times
- **Single Number** (Problem 136): Find element appearing once
- **Single Number II** (Problem 137): Find element appearing once (others appear thrice)
- **Find the Duplicate Number** (Problem 287): Find duplicate in array
## Alternative Approaches
1. **Boyer-Moore Voting:** Use voting algorithm - O(n) time, O(1) space
2. **Hash Table:** Count occurrences - O(n) time, O(n) space
3. **Divide and Conquer:** Recursive approach - O(n log n) time, O(log n) space
4. **Randomization:** Random sampling - O(n) average time
## Common Pitfalls
1. **Hash Table Usage:** Using hash table when sorting is simpler.
2. **Complex Counting:** Manually counting occurrences instead of using sorting.
3. **Wrong Position:** Not understanding the middle position property.
4. **Space Inefficiency:** Using O(n) space when O(1) is possible.
5. **Over-engineering:** Using complex algorithms when simple sorting suffices.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/169.majority-element.py)](../exercises/169.majority-element.py)
*Note: This is a simple sorting problem that demonstrates efficient majority element finding.*

View File

@@ -0,0 +1,125 @@
# Factorial Trailing Zeroes
[![Problem 172](https://img.shields.io/badge/Problem-172-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/factorial-trailing-zeroes/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/factorial-trailing-zeroes/)
**Problem Number:** [172](https://leetcode.com/problems/factorial-trailing-zeroes/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Math
**LeetCode Link:** [https://leetcode.com/problems/factorial-trailing-zeroes/](https://leetcode.com/problems/factorial-trailing-zeroes/)
## Problem Description
Given an integer `n`, return the number of trailing zeroes in `n!`.
Note that `n! = n * (n - 1) * (n - 2) * ... * 3 * 2 * 1`.
**Example 1:**
```
Input: n = 3
Output: 0
Explanation: 3! = 6, no trailing zero.
```
**Example 2:**
```
Input: n = 5
Output: 1
Explanation: 5! = 120, one trailing zero.
```
**Example 3:**
```
Input: n = 0
Output: 0
```
**Constraints:**
- `0 <= n <= 10^4`
**Follow up:** Could you write a solution that works in logarithmic time complexity?
## My Approach
I used a **Mathematical** approach to count trailing zeroes efficiently. The key insight is that trailing zeroes come from factors of 10, which are created by pairs of 2 and 5. Since there are always more factors of 2 than 5, we only need to count factors of 5.
**Algorithm:**
1. Handle edge case: if n < 5, return 0
2. Initialize counter and power of 5
3. While power of 5 <= n:
- Add n // power_of_5 to counter
- Multiply power of 5 by 5
4. Return the total count
## Solution
The solution uses mathematical counting of factors of 5 to find trailing zeroes. See the implementation in the [solution file](../exercises/172.factorial-trailing-zeroes.py).
**Key Points:**
- Counts factors of 5 in factorial
- Uses powers of 5 (5, 25, 125, etc.)
- Handles edge cases properly
- Logarithmic time complexity
## Time & Space Complexity
**Time Complexity:** O(log n)
- Loop runs log₅(n) times
- Each iteration performs constant time operations
- Total: O(log n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Factors of 10:** Trailing zeroes come from factors of 10 (2 × 5).
2. **Factors of 5:** Since there are always more factors of 2 than 5, we only count factors of 5.
3. **Powers of 5:** We need to count factors of 5, 25, 125, etc. (powers of 5).
4. **Mathematical Formula:** The count is ⌊n/5⌋ + ⌊n/25⌋ + ⌊n/125⌋ + ...
5. **Logarithmic Time:** The loop runs log₅(n) times, giving logarithmic complexity.
6. **Edge Cases:** Numbers less than 5 have no trailing zeroes.
## Mistakes Made
1. **Brute Force:** Initially might calculate the entire factorial, leading to overflow.
2. **Wrong Counting:** Not understanding that we only need to count factors of 5.
3. **Missing Powers:** Not considering higher powers of 5 (25, 125, etc.).
4. **Overflow Issues:** Trying to calculate large factorials directly.
## Related Problems
- **Count Primes** (Problem 204): Count prime numbers less than n
- **Power of Two** (Problem 231): Check if number is power of 2
- **Power of Three** (Problem 326): Check if number is power of 3
- **Add Digits** (Problem 258): Add digits until single digit
## Alternative Approaches
1. **Brute Force:** Calculate factorial and count trailing zeroes - O(n) time, overflow risk
2. **Recursive:** Use recursion to count factors - O(log n) time, O(log n) space
3. **Binary Search:** Use binary search to find factors - O(log² n) time
## Common Pitfalls
1. **Brute Force Calculation:** Trying to calculate large factorials directly.
2. **Wrong Counting:** Not understanding the mathematical relationship with factors of 5.
3. **Missing Powers:** Not considering higher powers of 5 in the counting.
4. **Overflow Issues:** Using integer overflow when calculating factorials.
5. **Complex Logic:** Overcomplicating the mathematical counting.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/172.factorial-trailing-zeroes.py)](../exercises/172.factorial-trailing-zeroes.py)
*Note: This is a mathematical problem that demonstrates efficient counting of trailing zeroes using factors of 5.*

View File

@@ -0,0 +1,127 @@
# Rotate Array
[![Problem 189](https://img.shields.io/badge/Problem-189-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/rotate-array/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/rotate-array/)
**Problem Number:** [189](https://leetcode.com/problems/rotate-array/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Math, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/rotate-array/](https://leetcode.com/problems/rotate-array/)
## Problem Description
Given an array, rotate the array to the right by `k` steps, where `k` is non-negative.
**Example 1:**
```
Input: nums = [1,2,3,4,5,6,7], k = 3
Output: [5,6,7,1,2,3,4]
Explanation:
rotate 1 steps to the right: [7,1,2,3,4,5,6]
rotate 2 steps to the right: [6,7,1,2,3,4,5]
rotate 3 steps to the right: [5,6,7,1,2,3,4]
```
**Example 2:**
```
Input: nums = [-1,-100,3,99], k = 2
Output: [3,99,-1,-100]
Explanation:
rotate 1 steps to the right: [99,-1,-100,3]
rotate 2 steps to the right: [3,99,-1,-100]
```
**Constraints:**
- `1 <= nums.length <= 10^5`
- `-2^31 <= nums[i] <= 2^31 - 1`
- `0 <= k <= 10^5`
**Follow up:**
- Try to come up with as many solutions as you can. There are at least three different ways to solve this problem.
- Could you do it in-place with `O(1)` extra space?
## My Approach
I used an **Auxiliary Array** approach to rotate the array. The key insight is to use a temporary array to store the rotated elements and then copy them back to the original array.
**Algorithm:**
1. Handle edge case: if array length ≤ 1, return
2. Normalize k by taking modulo with array length
3. Create auxiliary array of same size
4. Calculate new positions for each element
5. Copy elements to auxiliary array at calculated positions
6. Copy auxiliary array back to original array
## Solution
The solution uses an auxiliary array to perform the rotation. See the implementation in the [solution file](../exercises/189.rotate-array.py).
**Key Points:**
- Uses auxiliary array for rotation
- Normalizes k to handle large values
- Calculates new positions for each element
- Modifies array in-place as required
- Handles edge cases properly
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through array to calculate positions
- Copy operations: O(n)
- Total: O(n)
**Space Complexity:** O(n)
- Auxiliary array of size n
- Total: O(n)
## Key Insights
1. **Modulo Operation:** Using k % len(nums) handles cases where k > array length.
2. **Position Calculation:** Each element moves to position (i + k) % len(nums).
3. **Auxiliary Array:** Using temporary array simplifies the rotation logic.
4. **In-place Modification:** The solution modifies the original array as required.
5. **Edge Cases:** Arrays with length ≤ 1 don't need rotation.
6. **Right Rotation:** Elements move to the right by k positions.
## Mistakes Made
1. **Wrong Direction:** Initially might rotate left instead of right.
2. **Large k Values:** Not handling cases where k > array length.
3. **Complex Logic:** Overcomplicating the position calculation.
4. **Space Inefficiency:** Not using O(1) space solution when possible.
## Related Problems
- **Rotate Image** (Problem 48): Rotate 2D matrix
- **Reverse Words in a String** (Problem 151): Reverse word order
- **Reverse String** (Problem 344): Reverse character array
- **Move Zeroes** (Problem 283): Move zeros to end
## Alternative Approaches
1. **Juggling Algorithm:** Use GCD-based rotation - O(n) time, O(1) space
2. **Reversal Algorithm:** Reverse parts of array - O(n) time, O(1) space
3. **Cyclic Replacements:** Use cyclic approach - O(n) time, O(1) space
## Common Pitfalls
1. **Wrong Direction:** Rotating left instead of right.
2. **Large k Values:** Not using modulo to handle k > array length.
3. **Complex Logic:** Overcomplicating the position calculation.
4. **Space Usage:** Using O(n) space when O(1) is possible.
5. **Edge Cases:** Not handling arrays with length ≤ 1.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/189.rotate-array.py)](../exercises/189.rotate-array.py)
*Note: This is an array manipulation problem that demonstrates efficient rotation using auxiliary array.*

View File

@@ -0,0 +1,130 @@
# Maximum Difference Between Increasing Elements
[![Problem 2016](https://img.shields.io/badge/Problem-2016-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/maximum-difference-between-increasing-elements/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/maximum-difference-between-increasing-elements/)
**Problem Number:** [2016](https://leetcode.com/problems/maximum-difference-between-increasing-elements/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Greedy
**LeetCode Link:** [https://leetcode.com/problems/maximum-difference-between-increasing-elements/](https://leetcode.com/problems/maximum-difference-between-increasing-elements/)
## Problem Description
Given a **0-indexed** integer array `nums` of size `n`, find the **maximum difference** between `nums[i]` and `nums[j]` (i.e., `nums[j] - nums[i]`), such that `0 <= i < j < n` and `nums[i] < nums[j]`.
Return the **maximum difference**. If no such `i` and `j` exists, return `-1`.
**Example 1:**
```
Input: nums = [7,1,5,4]
Output: 4
Explanation:
The maximum difference occurs with i = 1 and j = 2, nums[j] - nums[i] = 5 - 1 = 4.
Note that with i = 1 and j = 3, the difference nums[j] - nums[i] = 4 - 1 = 3, but it is not the maximum difference.
```
**Example 2:**
```
Input: nums = [9,4,3,2]
Output: -1
Explanation:
There is no i and j such that i < j and nums[i] < nums[j].
```
**Example 3:**
```
Input: nums = [1,5,2,10]
Output: 9
Explanation:
The maximum difference occurs with i = 0 and j = 3, nums[j] - nums[i] = 10 - 1 = 9.
```
**Constraints:**
- `n == nums.length`
- `2 <= n <= 1000`
- `1 <= nums[i] <= 10^9`
## My Approach
I used a **Brute Force** approach to find the maximum difference. The key insight is to check all possible pairs (i, j) where i < j and nums[i] < nums[j].
**Algorithm:**
1. Initialize maximum difference to -1
2. For each index i from 0 to n-2:
- For each index j from i+1 to n-1:
- If nums[i] < nums[j], calculate difference
- Update maximum difference if current difference is larger
3. Return the maximum difference found
## Solution
The solution uses brute force to check all valid pairs. See the implementation in the [solution file](../exercises/2016.maximum-difference-between-increasing-elements.py).
**Key Points:**
- Checks all possible pairs (i, j) where i < j
- Only considers pairs where nums[i] < nums[j]
- Tracks maximum difference found
- Returns -1 if no valid pair exists
## Time & Space Complexity
**Time Complexity:** O(n²)
- Nested loops: outer loop O(n), inner loop O(n)
- Each iteration performs constant time operations
- Total: O(n²)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Brute Force:** Checking all possible pairs is straightforward for this problem.
2. **Valid Pairs:** Only consider pairs where i < j and nums[i] < nums[j].
3. **Maximum Tracking:** Keep track of the maximum difference found so far.
4. **Return Value:** Return -1 if no valid pair exists.
5. **0-Indexed:** The problem uses 0-indexed arrays.
6. **Simple Logic:** The solution logic is straightforward and easy to understand.
## Mistakes Made
1. **Wrong Order:** Initially might check pairs where i > j.
2. **Missing Condition:** Not checking nums[i] < nums[j] condition.
3. **Complex Logic:** Overcomplicating the pair checking logic.
4. **Wrong Return:** Not returning -1 when no valid pair exists.
## Related Problems
- **Best Time to Buy and Sell Stock** (Problem 121): Find maximum profit
- **Best Time to Buy and Sell Stock II** (Problem 122): Multiple transactions
- **Container With Most Water** (Problem 11): Find maximum area
- **Trapping Rain Water** (Problem 42): Calculate trapped water
## Alternative Approaches
1. **Single Pass:** Track minimum element and calculate differences - O(n) time
2. **Two Pointers:** Use two pointers for optimization - O(n) time
3. **Dynamic Programming:** Use DP to track maximum differences - O(n) time
## Common Pitfalls
1. **Wrong Order:** Checking pairs where i > j.
2. **Missing Condition:** Not verifying nums[i] < nums[j].
3. **Complex Logic:** Overcomplicating the pair checking.
4. **Wrong Return:** Not handling the case where no valid pair exists.
5. **Inefficient Approach:** Using O(n²) when O(n) is possible.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/2016.maximum-difference-between-increasing-elements.py)](../exercises/2016.maximum-difference-between-increasing-elements.py)
*Note: This is a simple array problem that demonstrates brute force approach for finding maximum differences.*

View File

@@ -0,0 +1,128 @@
# Happy Number
[![Problem 202](https://img.shields.io/badge/Problem-202-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/happy-number/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/happy-number/)
**Problem Number:** [202](https://leetcode.com/problems/happy-number/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, Math, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/happy-number/](https://leetcode.com/problems/happy-number/)
## Problem Description
Write an algorithm to determine if a number `n` is happy.
A **happy number** is a number defined by the following process:
- Starting with any positive integer, replace the number by the sum of the squares of its digits.
- Repeat the process until the number equals 1 (where it will stay), or it **loops endlessly in a cycle** which does not include 1.
- Those numbers for which this process **ends in 1** are happy.
Return `true` if `n` is a happy number, and `false` if not.
**Example 1:**
```
Input: n = 19
Output: true
Explanation:
1² + 9² = 82
8² + 2² = 68
6² + 8² = 100
1² + 0² + 0² = 1
```
**Example 2:**
```
Input: n = 2
Output: false
```
**Constraints:**
- `1 <= n <= 2^31 - 1`
## My Approach
I used a **Hash Set** approach with recursion to detect cycles. The key insight is to track visited numbers to detect infinite loops and use recursion to process the happy number sequence.
**Algorithm:**
1. Use a memo list to track visited numbers
2. If current number is already visited, return False (cycle detected)
3. Add current number to memo
4. Calculate sum of squares of digits
5. If sum equals 1, return True
6. Otherwise, recursively call with the new sum
## Solution
The solution uses hash set and recursion to detect cycles in the happy number sequence. See the implementation in the [solution file](../exercises/202.happy-number.py).
**Key Points:**
- Uses memo list to track visited numbers
- Detects cycles to avoid infinite loops
- Recursively processes digit squares
- Returns True when sum equals 1
- Returns False when cycle is detected
## Time & Space Complexity
**Time Complexity:** O(log n)
- Each iteration reduces the number significantly
- Cycle detection limits the number of iterations
- Total: O(log n)
**Space Complexity:** O(log n)
- Memo list stores visited numbers
- Number of visited numbers is bounded by O(log n)
- Total: O(log n)
## Key Insights
1. **Cycle Detection:** Using a hash set to detect cycles prevents infinite loops.
2. **Digit Extraction:** Using modulo and division to extract digits efficiently.
3. **Recursive Process:** The happy number process naturally fits recursion.
4. **Termination:** The process either reaches 1 or enters a cycle.
5. **Mathematical Property:** Happy numbers have a mathematical pattern.
6. **Bounded Space:** The number of visited values is bounded.
## Mistakes Made
1. **No Cycle Detection:** Initially might not detect cycles, leading to infinite loops.
2. **Wrong Termination:** Not properly handling the termination condition.
3. **Complex Logic:** Overcomplicating the digit extraction process.
4. **Space Issues:** Not considering the space complexity of tracking visited numbers.
## Related Problems
- **Linked List Cycle** (Problem 141): Detect cycle in linked list
- **Linked List Cycle II** (Problem 142): Find cycle start point
- **Find the Duplicate Number** (Problem 287): Find duplicate using cycle detection
- **Add Digits** (Problem 258): Add digits until single digit
## Alternative Approaches
1. **Two Pointers (Floyd's):** Use fast and slow pointers - O(log n) time, O(1) space
2. **Iterative:** Use while loop instead of recursion - O(log n) time, O(log n) space
3. **Mathematical:** Use mathematical properties to optimize - O(log n) time
## Common Pitfalls
1. **No Cycle Detection:** Not detecting cycles leading to infinite loops.
2. **Wrong Termination:** Not properly handling when sum equals 1.
3. **Complex Logic:** Overcomplicating the digit extraction.
4. **Space Issues:** Not considering space complexity of tracking visited numbers.
5. **Recursion Depth:** Not considering recursion stack space.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/202.happy-number.py)](../exercises/202.happy-number.py)
*Note: This is a cycle detection problem that demonstrates efficient happy number checking with hash set.*

View File

@@ -0,0 +1,135 @@
# Kth Distinct String in an Array
[![Problem 2053](https://img.shields.io/badge/Problem-2053-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/kth-distinct-string-in-an-array/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/kth-distinct-string-in-an-array/)
**Problem Number:** [2053](https://leetcode.com/problems/kth-distinct-string-in-an-array/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Hash Table, String
**LeetCode Link:** [https://leetcode.com/problems/kth-distinct-string-in-an-array/](https://leetcode.com/problems/kth-distinct-string-in-an-array/)
## Problem Description
A **distinct string** is a string that is present only **once** in an array.
Given an array of strings `arr`, and an integer `k`, return *the* `k^th` *distinct string present in* `arr`. If there are **fewer than** `k` distinct strings, return *an **empty string*** `""`.
Note that the strings are considered in the **order in which they appear** in the array.
**Example 1:**
```
Input: arr = ["d","b","c","b","c","a"], k = 2
Output: "a"
Explanation:
The only distinct strings in arr are "d" and "a".
"d" appears 1st, so it is the 1st distinct string.
"a" appears 2nd, so it is the 2nd distinct string.
Since k == 2, "a" is returned.
```
**Example 2:**
```
Input: arr = ["aaa","aa","a"], k = 1
Output: "aaa"
Explanation:
All strings in arr are distinct, so the 1st string "aaa" is returned.
```
**Example 3:**
```
Input: arr = ["a","b","a"], k = 3
Output: ""
Explanation:
The only distinct string is "b". Since there are fewer than 3 distinct strings, we return an empty string "".
```
**Constraints:**
- `1 <= k <= arr.length <= 1000`
- `1 <= arr[i].length <= 5`
- `arr[i]` consists of lowercase English letters.
## My Approach
I used a **Hash Table** approach to track distinct strings and their order of appearance. The key insight is to maintain two hash tables: one for counting occurrences and another for tracking banned words.
**Algorithm:**
1. Create hash table to track distinct strings
2. Create list to track banned words (non-distinct)
3. For each word in array:
- If word not in distinct and not banned, add to distinct
- If word already in distinct, remove from distinct and add to banned
4. Return kth distinct string or empty string if not enough
## Solution
The solution uses hash tables to efficiently track distinct strings in order. See the implementation in the [solution file](../exercises/2053.kth-distinct-string-in-an-array.py).
**Key Points:**
- Uses hash table for O(1) lookup
- Maintains order of appearance
- Tracks banned words to avoid re-adding
- Returns kth distinct string or empty string
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through array: O(n)
- Hash table operations: O(1) average
- Total: O(n)
**Space Complexity:** O(n)
- Hash table for distinct strings: O(n)
- List for banned words: O(n)
- Total: O(n)
## Key Insights
1. **Hash Table:** Using hash table provides efficient string tracking.
2. **Order Preservation:** Maintain order of appearance for distinct strings.
3. **Banned Words:** Track non-distinct words to avoid re-adding them.
4. **Two-Phase Process:** First identify distinct, then find kth.
5. **Edge Cases:** Handle cases with fewer than k distinct strings.
6. **Efficient Removal:** Remove strings from distinct when they become non-distinct.
## Mistakes Made
1. **Wrong Order:** Initially might not preserve order of appearance.
2. **Complex Logic:** Overcomplicating the distinct string tracking.
3. **Re-adding Issue:** Not properly handling banned words.
4. **Inefficient Approach:** Using O(n²) approach when hash table suffices.
## Related Problems
- **First Unique Character** (Problem 387): Find first unique character
- **Contains Duplicate** (Problem 217): Check for duplicates
- **Valid Anagram** (Problem 242): Check if strings are anagrams
- **Group Anagrams** (Problem 49): Group strings by anagrams
## Alternative Approaches
1. **Two Pass:** Count frequencies first, then find kth distinct - O(n) time
2. **Set Operations:** Use set operations for distinct tracking - O(n) time
3. **Sorting:** Sort and find distinct strings - O(n log n) time
## Common Pitfalls
1. **Wrong Order:** Not preserving order of appearance.
2. **Complex Logic:** Overcomplicating the distinct string tracking.
3. **Re-adding Issue:** Not properly handling banned words.
4. **Inefficient Approach:** Using O(n²) approach when hash table suffices.
5. **Edge Cases:** Not handling cases with fewer than k distinct strings.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/2053.kth-distinct-string-in-an-array.py)](../exercises/2053.kth-distinct-string-in-an-array.py)
*Note: This is a hash table problem that demonstrates efficient tracking of distinct elements while preserving order.*

View File

@@ -0,0 +1,129 @@
# Isomorphic Strings
[![Problem 205](https://img.shields.io/badge/Problem-205-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/isomorphic-strings/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/isomorphic-strings/)
**Problem Number:** [205](https://leetcode.com/problems/isomorphic-strings/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, String
**LeetCode Link:** [https://leetcode.com/problems/isomorphic-strings/](https://leetcode.com/problems/isomorphic-strings/)
## Problem Description
Given two strings `s` and `t`, determine if they are isomorphic.
Two strings `s` and `t` are isomorphic if the characters in `s` can be replaced to get `t`.
All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character, but a character may map to itself.
**Example 1:**
```
Input: s = "egg", t = "add"
Output: true
```
**Example 2:**
```
Input: s = "foo", t = "bar"
Output: false
```
**Example 3:**
```
Input: s = "paper", t = "title"
Output: true
```
**Constraints:**
- `1 <= s.length <= 5 * 10^4`
- `t.length == s.length`
- `s` and `t` consist of any valid ascii character.
## My Approach
I used a **Hash Table** approach to track character mappings. The key insight is to ensure that each character in s maps to exactly one character in t, and no two characters in s map to the same character in t.
**Algorithm:**
1. Check if strings have same length
2. Use hash table to store character mappings
3. For each character pair:
- If s[i] not in mapping, check if t[i] is already mapped
- If t[i] is already mapped, return False
- Add mapping s[i] -> t[i]
- If s[i] exists in mapping, verify it maps to t[i]
4. Return True if all mappings are valid
## Solution
The solution uses hash table to track character mappings between strings. See the implementation in the [solution file](../exercises/205.isomorphic-strings.py).
**Key Points:**
- Uses hash table to store character mappings
- Checks for one-to-one mapping requirement
- Verifies existing mappings are consistent
- Handles length mismatch case
- Returns True only if all mappings are valid
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through both strings
- Hash table operations are O(1)
- Total: O(n)
**Space Complexity:** O(k)
- Hash table stores character mappings
- k is the number of unique characters
- In worst case: O(n)
## Key Insights
1. **One-to-One Mapping:** Each character in s must map to exactly one character in t.
2. **No Duplicate Mapping:** No two characters in s can map to the same character in t.
3. **Hash Table:** Using hash table provides O(1) lookup for mappings.
4. **Length Check:** Strings must have same length to be isomorphic.
5. **Bidirectional Check:** Need to check both s->t and t->s mappings.
6. **Character Preservation:** Order of characters must be preserved.
## Mistakes Made
1. **Unidirectional Check:** Initially might only check s->t mapping.
2. **Wrong Logic:** Not checking if t[i] is already mapped to another character.
3. **Complex Implementation:** Overcomplicating the mapping logic.
4. **Missing Edge Cases:** Not handling length mismatch properly.
## Related Problems
- **Word Pattern** (Problem 290): Check if string follows pattern
- **Valid Anagram** (Problem 242): Check if strings are anagrams
- **Group Anagrams** (Problem 49): Group strings by anagrams
- **Longest Substring Without Repeating Characters** (Problem 3): Find unique substring
## Alternative Approaches
1. **Two Hash Tables:** Use separate hash tables for s->t and t->s - O(n) time, O(n) space
2. **Array Mapping:** Use arrays instead of hash tables - O(n) time, O(1) space
3. **Character Frequency:** Use character frequency comparison - O(n) time, O(n) space
## Common Pitfalls
1. **Unidirectional Check:** Only checking s->t mapping.
2. **Wrong Logic:** Not verifying one-to-one mapping requirement.
3. **Complex Implementation:** Overcomplicating the mapping logic.
4. **Missing Edge Cases:** Not handling length mismatch.
5. **Space Inefficiency:** Using unnecessary data structures.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/205.isomorphic-strings.py)](../exercises/205.isomorphic-strings.py)
*Note: This is a string mapping problem that demonstrates efficient character mapping with hash tables.*

View File

@@ -0,0 +1,124 @@
# Reverse Linked List
[![Problem 206](https://img.shields.io/badge/Problem-206-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/reverse-linked-list/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/reverse-linked-list/)
**Problem Number:** [206](https://leetcode.com/problems/reverse-linked-list/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Linked List, Recursion
**LeetCode Link:** [https://leetcode.com/problems/reverse-linked-list/](https://leetcode.com/problems/reverse-linked-list/)
## Problem Description
Given the `head` of a singly linked list, reverse the list, and return the reversed list.
**Example 1:**
```
Input: head = [1,2,3,4,5]
Output: [5,4,3,2,1]
```
**Example 2:**
```
Input: head = [1,2]
Output: [2,1]
```
**Example 3:**
```
Input: head = []
Output: []
```
**Constraints:**
- The number of nodes in the list is the range `[0, 5000]`.
- `-5000 <= Node.val <= 5000`
**Follow up:** A linked list can be reversed either iteratively or recursively. Could you implement both solutions?
## My Approach
I used an **Iterative** approach with three pointers to reverse the linked list. The key insight is to use three pointers (prev, curr, next) to reverse the links one by one.
**Algorithm:**
1. Initialize prev to None and curr to head
2. While curr is not None:
- Store next node (curr.next)
- Reverse the link (curr.next = prev)
- Move prev to curr
- Move curr to next
3. Return prev (new head)
## Solution
The solution uses iterative approach with three pointers to reverse the linked list. See the implementation in the [solution file](../exercises/206.reverse-linked-list.py).
**Key Points:**
- Uses three pointers: prev, curr, next
- Reverses links one by one
- Handles empty list case
- Returns new head (prev)
- Simple and efficient approach
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the linked list
- Each node is visited once
- Total: O(n)
**Space Complexity:** O(1)
- Uses only a constant amount of extra space
- No additional data structures needed
## Key Insights
1. **Three Pointers:** Using prev, curr, and next pointers simplifies the reversal.
2. **Link Reversal:** Each iteration reverses one link: curr.next = prev.
3. **Pointer Movement:** Moving pointers in the correct order is crucial.
4. **New Head:** The new head is the last node (prev after loop ends).
5. **Empty List:** Handles empty list case naturally.
6. **Single Node:** Works correctly for single node lists.
## Mistakes Made
1. **Wrong Pointer Order:** Initially might move pointers in wrong order.
2. **Lost References:** Not storing next node before changing curr.next.
3. **Complex Logic:** Overcomplicating the pointer manipulation.
4. **Wrong Return:** Returning wrong pointer as new head.
## Related Problems
- **Reverse Linked List II** (Problem 92): Reverse portion of linked list
- **Palindrome Linked List** (Problem 234): Check if linked list is palindrome
- **Add Two Numbers** (Problem 2): Add numbers represented by linked lists
- **Merge Two Sorted Lists** (Problem 21): Merge sorted linked lists
## Alternative Approaches
1. **Recursive:** Use recursion to reverse list - O(n) time, O(n) space
2. **Stack-based:** Use stack to reverse order - O(n) time, O(n) space
3. **Array-based:** Convert to array, reverse, rebuild - O(n) time, O(n) space
## Common Pitfalls
1. **Wrong Pointer Order:** Moving pointers in incorrect order.
2. **Lost References:** Not storing next node before changing links.
3. **Complex Logic:** Overcomplicating the pointer manipulation.
4. **Wrong Return:** Returning wrong pointer as new head.
5. **Empty List:** Not handling empty list case properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/206.reverse-linked-list.py)](../exercises/206.reverse-linked-list.py)
*Note: This is a classic linked list problem that demonstrates efficient iterative reversal with three pointers.*

View File

@@ -0,0 +1,139 @@
# Check if a Parentheses String Can Be Valid
[![Problem 2116](https://img.shields.io/badge/Problem-2116-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/check-if-a-parentheses-string-can-be-valid/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/check-if-a-parentheses-string-can-be-valid/)
**Problem Number:** [2116](https://leetcode.com/problems/check-if-a-parentheses-string-can-be-valid/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** String, Greedy, Stack
**LeetCode Link:** [https://leetcode.com/problems/check-if-a-parentheses-string-can-be-valid/](https://leetcode.com/problems/check-if-a-parentheses-string-can-be-valid/)
## Problem Description
A parentheses string is a **non-empty** string consisting only of `'('` and `')'`. It is **valid** if **any** of the following conditions is **true**:
- It is `()`.
- It can be written as `AB` (`A` concatenated with `B`), where `A` and `B` are valid parentheses strings.
- It can be written as `(A)`, where `A` is a valid parentheses string.
You are given a parentheses string `s` and a string `locked`, both of length `n`. `locked` is a binary string consisting only of `'0'`s and `'1'`s. For each index `i` of `s`:
- If `locked[i]` is `'1'`, you **cannot** change `s[i]`.
- But if `locked[i]` is `'0'`, you **can** change `s[i]` to either `'('` or `')'`.
Return `true` *if you can make* `s` *a valid parentheses string*. Otherwise, return `false`.
**Example 1:**
```
Input: s = "))()))", locked = "010100"
Output: true
Explanation: locked[1] == '1' and locked[3] == '1', so we cannot change s[1] or s[3].
We change s[0] and s[4] to '(' while leaving s[2] and s[5] unchanged.
Makes s valid: "((()))" .
```
**Example 2:**
```
Input: s = "()()", locked = "0000"
Output: true
Explanation: We do not need to make any changes because s is already valid.
```
**Example 3:**
```
Input: s = ")", locked = "0"
Output: false
```
**Constraints:**
- `n == s.length == locked.length`
- `1 <= n <= 10^5`
- `s[i]` is either `'('` or `')'`.
- `locked[i]` is either `'0'` or `'1'`.
## My Approach
I used a **Greedy** approach with range tracking to check if the parentheses string can be made valid. The key insight is to track the minimum and maximum possible balance at each position.
**Algorithm:**
1. Check if string length is odd (impossible to make valid)
2. Initialize min and max balance to 0
3. For each character:
- If locked and '(': increment both min and max
- If locked and ')': decrement both min and max
- If unlocked: decrement min, increment max
4. Ensure min balance never goes below 0
5. Return true if final balance can be 0
## Solution
The solution uses greedy approach with balance range tracking. See the implementation in the [solution file](../exercises/2116.check-if-a-parentheses-string-can-be-valid.py).
**Key Points:**
- Uses balance range tracking
- Handles locked and unlocked positions
- Ensures balance never goes negative
- Checks if final balance can be zero
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through string: O(n)
- Constant operations per character
- Total: O(n)
**Space Complexity:** O(1)
- Uses only constant extra space
- No additional data structures needed
## Key Insights
1. **Balance Range:** Track minimum and maximum possible balance.
2. **Locked Positions:** Must use exact character for locked positions.
3. **Unlocked Positions:** Can choose '(' or ')' to adjust balance.
4. **Negative Balance:** Never allow balance to go below 0.
5. **Final Balance:** Must end with balance of 0 for valid string.
6. **Odd Length:** Impossible to make valid if length is odd.
## Mistakes Made
1. **Wrong Balance:** Initially might not track balance range correctly.
2. **Complex Logic:** Overcomplicating the balance calculation.
3. **Edge Cases:** Not handling odd length strings.
4. **Inefficient Approach:** Using stack approach when greedy suffices.
## Related Problems
- **Valid Parentheses** (Problem 20): Check if parentheses are valid
- **Generate Parentheses** (Problem 22): Generate valid parentheses
- **Longest Valid Parentheses** (Problem 32): Find longest valid substring
- **Remove Invalid Parentheses** (Problem 301): Remove invalid parentheses
## Alternative Approaches
1. **Stack:** Use stack to track parentheses - O(n) time, O(n) space
2. **Two Pass:** Check from left and right - O(n) time, O(1) space
3. **Dynamic Programming:** Use DP for complex cases - O(n²) time
## Common Pitfalls
1. **Wrong Balance:** Not tracking balance range correctly.
2. **Complex Logic:** Overcomplicating the balance calculation.
3. **Edge Cases:** Not handling odd length strings.
4. **Inefficient Approach:** Using stack approach when greedy suffices.
5. **Locked Positions:** Not properly handling locked vs unlocked positions.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/2116.check-if-a-parentheses-string-can-be-valid.py)](../exercises/2116.check-if-a-parentheses-string-can-be-valid.py)
*Note: This is a greedy problem that demonstrates balance range tracking for parentheses validation.*

View File

@@ -0,0 +1,119 @@
# Contains Duplicate
[![Problem 217](https://img.shields.io/badge/Problem-217-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/contains-duplicate/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/contains-duplicate/)
**Problem Number:** [217](https://leetcode.com/problems/contains-duplicate/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Hash Table, Sorting
**LeetCode Link:** [https://leetcode.com/problems/contains-duplicate/](https://leetcode.com/problems/contains-duplicate/)
## Problem Description
Given an integer array `nums`, return `true` if any value appears at least twice in the array, and return `false` if every element is distinct.
**Example 1:**
```
Input: nums = [1,2,3,1]
Output: true
```
**Example 2:**
```
Input: nums = [1,2,3,4]
Output: false
```
**Example 3:**
```
Input: nums = [1,1,1,3,3,4,3,2,4,2]
Output: true
```
**Constraints:**
- `1 <= nums.length <= 10^5`
- `-10^9 <= nums[i] <= 10^9`
## My Approach
I used a **Hash Set** approach to track seen elements. The key insight is to use a set to store elements we've seen and check for duplicates in O(1) time.
**Algorithm:**
1. Initialize an empty set to track seen elements
2. Iterate through each number in the array
3. If number is already in set, return True (duplicate found)
4. Add number to set
5. Return False if no duplicates found
## Solution
The solution uses hash set to efficiently detect duplicates. See the implementation in the [solution file](../exercises/217.contains-duplicate.py).
**Key Points:**
- Uses hash set for O(1) lookup
- Returns True as soon as duplicate is found
- Simple and efficient approach
- Handles all edge cases automatically
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the array
- Hash set operations are O(1)
- Total: O(n)
**Space Complexity:** O(n)
- Hash set stores at most n elements
- In worst case: O(n)
## Key Insights
1. **Hash Set:** Using hash set provides O(1) lookup time for duplicates.
2. **Early Return:** Return True as soon as first duplicate is found.
3. **Simple Logic:** The solution logic is straightforward and easy to understand.
4. **Efficient Lookup:** Hash set operations are constant time.
5. **Memory Trade-off:** Uses O(n) space for O(n) time complexity.
6. **No Sorting Needed:** Hash set approach doesn't require sorting.
## Mistakes Made
1. **Brute Force:** Initially might use nested loops, leading to O(n²) complexity.
2. **Sorting Approach:** Using sorting when hash set is more efficient.
3. **Complex Logic:** Overcomplicating the duplicate detection.
4. **Wrong Data Structure:** Not using appropriate data structure for O(1) lookup.
## Related Problems
- **Contains Duplicate II** (Problem 219): Check for duplicates within k distance
- **Contains Duplicate III** (Problem 220): Check for duplicates within k distance and t difference
- **Single Number** (Problem 136): Find element appearing once
- **Group Anagrams** (Problem 49): Group strings by anagrams
## Alternative Approaches
1. **Sorting:** Sort array and check adjacent elements - O(n log n) time, O(1) space
2. **Brute Force:** Check all pairs - O(n²) time, O(1) space
3. **Bit Manipulation:** Use bit manipulation for small integers - O(n) time, O(1) space
## Common Pitfalls
1. **Brute Force:** Using nested loops for O(n²) complexity.
2. **Sorting:** Using sorting when hash set is more efficient.
3. **Complex Logic:** Overcomplicating the duplicate detection.
4. **Wrong Data Structure:** Not using hash set for O(1) lookup.
5. **Space Inefficiency:** Using unnecessary data structures.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/217.contains-duplicate.py)](../exercises/217.contains-duplicate.py)
*Note: This is a simple hash table problem that demonstrates efficient duplicate detection.*

View File

@@ -0,0 +1,123 @@
# Contains Duplicate II
[![Problem 219](https://img.shields.io/badge/Problem-219-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/contains-duplicate-ii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/contains-duplicate-ii/)
**Problem Number:** [219](https://leetcode.com/problems/contains-duplicate-ii/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Hash Table, Sliding Window
**LeetCode Link:** [https://leetcode.com/problems/contains-duplicate-ii/](https://leetcode.com/problems/contains-duplicate-ii/)
## Problem Description
Given an integer array `nums` and an integer `k`, return `true` if there are two **distinct indices** `i` and `j` in the array such that `nums[i] == nums[j]` and `abs(i - j) <= k`.
**Example 1:**
```
Input: nums = [1,2,3,1], k = 3
Output: true
```
**Example 2:**
```
Input: nums = [1,0,1,1], k = 1
Output: true
```
**Example 3:**
```
Input: nums = [1,2,3,1,2,3], k = 2
Output: false
```
**Constraints:**
- `1 <= nums.length <= 10^5`
- `0 <= k <= 10^5`
- `-10^9 <= nums[i] <= 10^9`
## My Approach
I used a **Sliding Window** approach with hash set to track elements within the window. The key insight is to maintain a sliding window of size k+1 and check for duplicates within this window.
**Algorithm:**
1. Handle edge case: if array length ≤ 1, return False
2. Initialize hash set to track elements in current window
3. For each element:
- If element already in set, return True (duplicate found)
- Add element to set
- If set size > k, remove oldest element (nums[i-k])
4. Return False if no duplicates found
## Solution
The solution uses sliding window with hash set to check for duplicates within k distance. See the implementation in the [solution file](../exercises/219.contains-duplicate-ii.py).
**Key Points:**
- Uses sliding window of size k+1
- Maintains hash set for O(1) lookup
- Removes oldest element when window exceeds k
- Returns True as soon as duplicate is found
- Handles edge cases properly
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the array
- Hash set operations are O(1)
- Total: O(n)
**Space Complexity:** O(k)
- Hash set stores at most k+1 elements
- Total: O(k)
## Key Insights
1. **Sliding Window:** Using sliding window of size k+1 ensures we only check elements within k distance.
2. **Hash Set:** Using hash set provides O(1) lookup for duplicates.
3. **Window Management:** Removing oldest element when window exceeds k maintains the sliding window.
4. **Early Return:** Return True as soon as duplicate is found within the window.
5. **Distance Constraint:** The k parameter limits the window size and search space.
6. **Efficient Removal:** Removing oldest element keeps the window size bounded.
## Mistakes Made
1. **Wrong Window Size:** Initially might use wrong window size.
2. **Complex Logic:** Overcomplicating the sliding window management.
3. **Wrong Removal:** Not removing the correct element when window exceeds k.
4. **Missing Edge Cases:** Not handling arrays with length ≤ 1.
## Related Problems
- **Contains Duplicate** (Problem 217): Check for any duplicates
- **Contains Duplicate III** (Problem 220): Check for duplicates within k distance and t difference
- **Longest Substring Without Repeating Characters** (Problem 3): Find longest unique substring
- **Minimum Size Subarray Sum** (Problem 209): Find minimum subarray with given sum
## Alternative Approaches
1. **Hash Map with Indices:** Store indices in hash map - O(n) time, O(n) space
2. **Brute Force:** Check all pairs within k distance - O(nk) time, O(1) space
3. **Sorting with Indices:** Sort with indices and check adjacent - O(n log n) time, O(n) space
## Common Pitfalls
1. **Wrong Window Size:** Using incorrect window size for sliding window.
2. **Complex Logic:** Overcomplicating the sliding window management.
3. **Wrong Removal:** Not removing the correct element when window exceeds k.
4. **Missing Edge Cases:** Not handling edge cases properly.
5. **Inefficient Approach:** Using brute force when sliding window is more efficient.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/219.contains-duplicate-ii.py)](../exercises/219.contains-duplicate-ii.py)
*Note: This is a sliding window problem that demonstrates efficient duplicate detection within a distance constraint.*

View File

@@ -0,0 +1,137 @@
# Summary Ranges
[![Problem 228](https://img.shields.io/badge/Problem-228-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/summary-ranges/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/summary-ranges/)
**Problem Number:** [228](https://leetcode.com/problems/summary-ranges/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array
**LeetCode Link:** [https://leetcode.com/problems/summary-ranges/](https://leetcode.com/problems/summary-ranges/)
## Problem Description
You are given a **sorted unique** integer array `nums`.
A **range** `[a,b]` is the set of all integers from `a` to `b` (inclusive).
Return the **smallest sorted** list of ranges that **cover all the numbers in the array exactly**. That is, each element of `nums` is covered by exactly one of the ranges, and there is no integer `x` such that `x` is in one of the ranges but not in `nums`.
Each range `[a,b]` should be output as:
- `"a->b"` if `a != b`
- `"a"` if `a == b`
**Example 1:**
```
Input: nums = [0,1,2,4,5,7]
Output: ["0->2","4->5","7"]
Explanation: The ranges are:
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"
```
**Example 2:**
```
Input: nums = [0,2,3,4,6,8,9]
Output: ["0","2->4","6","8->9"]
Explanation: The ranges are:
[0,0] --> "0"
[2,4] --> "2->4"
[6,6] --> "6"
[8,9] --> "8->9"
```
**Constraints:**
- `0 <= nums.length <= 20`
- `-2^31 <= nums[i] <= 2^31 - 1`
- All the values of `nums` are unique.
- `nums` is sorted in ascending order.
## My Approach
I used a **Two Pointers** approach to identify consecutive ranges. The key insight is to use two pointers (i, j) to track the start and end of each consecutive range.
**Algorithm:**
1. Handle edge cases (empty array, single element)
2. Initialize two pointers i and j at start
3. Iterate through array starting from second element
4. If current element is consecutive (nums[h-1] + 1 == nums[h]), extend range
5. Otherwise, add current range to result and reset pointers
6. Handle the last range after loop ends
7. Return list of formatted ranges
## Solution
The solution uses two pointers to identify and format consecutive ranges. See the implementation in the [solution file](../exercises/228.summary-ranges.py).
**Key Points:**
- Uses two pointers to track range boundaries
- Handles single element ranges (i == j)
- Formats ranges as "a->b" or "a"
- Handles edge cases properly
- Processes last range after loop
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the array
- Each element is processed once
- Total: O(n)
**Space Complexity:** O(n)
- Result list can contain up to n ranges
- Each range is a string
- Total: O(n)
## Key Insights
1. **Two Pointers:** Using i and j pointers to track range boundaries.
2. **Consecutive Check:** Checking if nums[h-1] + 1 == nums[h] for consecutive elements.
3. **Range Formatting:** Single element ranges are formatted as "a", multiple elements as "a->b".
4. **Edge Cases:** Handling empty arrays and single element arrays.
5. **Last Range:** Processing the last range after the loop ends.
6. **Sorted Input:** Leveraging the fact that input is sorted.
## Mistakes Made
1. **Wrong Range Logic:** Initially might use wrong logic for identifying ranges.
2. **Missing Edge Cases:** Not handling empty arrays or single elements properly.
3. **Wrong Formatting:** Not formatting ranges correctly.
4. **Last Range:** Forgetting to process the last range after the loop.
## Related Problems
- **Merge Intervals** (Problem 56): Merge overlapping intervals
- **Insert Interval** (Problem 57): Insert new interval into sorted intervals
- **Missing Ranges** (Problem 163): Find missing ranges
- **Range Sum Query** (Problem 303): Calculate sum in range
## Alternative Approaches
1. **Single Pointer:** Use single pointer with range tracking - O(n) time
2. **Stack-based:** Use stack to track ranges - O(n) time, O(n) space
3. **Recursive:** Use recursion to process ranges - O(n) time, O(n) space
## Common Pitfalls
1. **Wrong Range Logic:** Using incorrect logic for identifying consecutive ranges.
2. **Missing Edge Cases:** Not handling empty arrays or single elements.
3. **Wrong Formatting:** Not formatting ranges correctly.
4. **Last Range:** Forgetting to process the last range after the loop.
5. **Complex Logic:** Overcomplicating the range identification.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/228.summary-ranges.py)](../exercises/228.summary-ranges.py)
*Note: This is a range processing problem that demonstrates efficient consecutive range identification with two pointers.*

View File

@@ -0,0 +1,145 @@
# Partition Array Such That Maximum Difference Is K
[![Problem 2294](https://img.shields.io/badge/Problem-2294-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/partition-array-such-that-maximum-difference-is-k/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/partition-array-such-that-maximum-difference-is-k/)
**Problem Number:** [2294](https://leetcode.com/problems/partition-array-such-that-maximum-difference-is-k/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Greedy, Sorting
**LeetCode Link:** [https://leetcode.com/problems/partition-array-such-that-maximum-difference-is-k/](https://leetcode.com/problems/partition-array-such-that-maximum-difference-is-k/)
## Problem Description
You are given an integer array `nums` and an integer `k`. You may partition `nums` into one or more **subsequences** such that each element in `nums` appears in **exactly one** of the subsequences.
Let the **maximum difference** of a subsequence be the difference between the **maximum** and **minimum** element in the subsequence.
Return *the **minimum** number of subsequences needed so that the maximum difference of each subsequence is **at most*** `k`.
**Example 1:**
```
Input: nums = [3,6,1,2,5], k = 2
Output: 2
Explanation:
We can partition nums into the two subsequences [3,1,2] and [6,5].
- The maximum difference of the first subsequence is 3 - 1 = 2.
- The maximum difference of the second subsequence is 6 - 5 = 1.
Both subsequences have a maximum difference of at most 2, so we return 2.
```
**Example 2:**
```
Input: nums = [1,2,3], k = 1
Output: 2
Explanation:
We can partition nums into the two subsequences [1,2] and [3].
- The maximum difference of the first subsequence is 2 - 1 = 1.
- The maximum difference of the second subsequence is 3 - 3 = 0.
Both subsequences have a maximum difference of at most 1, so we return 2.
```
**Example 3:**
```
Input: nums = [2,2,4,5], k = 0
Output: 3
Explanation:
We can partition nums into the three subsequences [2], [2], and [4,5].
- The maximum difference of the first subsequence is 2 - 2 = 0.
- The maximum difference of the second subsequence is 2 - 2 = 0.
- The maximum difference of the third subsequence is 5 - 4 = 1.
All subsequences have a maximum difference of at most 0, so we return 3.
```
**Constraints:**
- `1 <= nums.length <= 10^5`
- `0 <= nums[i] <= 10^5`
- `0 <= k <= 10^5`
## My Approach
I used a **Greedy** approach with sorting to find the minimum number of subsequences. The key insight is to sort the unique elements and group them into subsequences where the maximum difference is at most k.
**Algorithm:**
1. Handle edge case: if k == 0, return number of unique elements
2. Remove duplicates and sort the array
3. Initialize minimum value and subsequence count
4. For each element:
- Update minimum value if current element is smaller
- Calculate difference between current element and minimum
- If difference > k, increment subsequence count and reset minimum
5. Return total number of subsequences
## Solution
The solution uses greedy approach with sorting to minimize subsequences. See the implementation in the [solution file](../exercises/2294.partition-array-such-that-maximum-difference-is-k.py).
**Key Points:**
- Removes duplicates and sorts array
- Uses greedy approach to group elements
- Tracks minimum value in current subsequence
- Increments count when difference exceeds k
- Handles edge case when k == 0
## Time & Space Complexity
**Time Complexity:** O(n log n)
- Sorting: O(n log n)
- Single pass through sorted array: O(n)
- Total: O(n log n)
**Space Complexity:** O(n)
- Set to remove duplicates: O(n)
- Sorted list: O(n)
- Total: O(n)
## Key Insights
1. **Sorting:** Sorting allows us to process elements in order and group them efficiently.
2. **Greedy Approach:** Always start a new subsequence when the difference exceeds k.
3. **Duplicate Removal:** Removing duplicates simplifies the problem.
4. **Minimum Tracking:** Track the minimum value in the current subsequence.
5. **Edge Case:** When k == 0, each unique element needs its own subsequence.
6. **Difference Calculation:** Calculate difference between current element and minimum in subsequence.
## Mistakes Made
1. **Wrong Order:** Not sorting the array, leading to incorrect grouping.
2. **Complex Logic:** Overcomplicating the subsequence grouping.
3. **Missing Edge Case:** Not handling k == 0 case properly.
4. **Wrong Counting:** Not correctly counting subsequences.
## Related Problems
- **Partition Labels** (Problem 763): Partition string into labels
- **Partition Equal Subset Sum** (Problem 416): Partition array into equal sums
- **Partition to K Equal Sum Subsets** (Problem 698): Partition into k equal subsets
- **Minimum Absolute Difference** (Problem 1200): Find minimum absolute difference
## Alternative Approaches
1. **Dynamic Programming:** Use DP to find optimal partitioning - O(n²) time
2. **Binary Search:** Use binary search on number of subsequences - O(n log n) time
3. **Two Pointers:** Use two pointers to find valid ranges - O(n log n) time
## Common Pitfalls
1. **Wrong Order:** Not sorting the array for efficient grouping.
2. **Complex Logic:** Overcomplicating the subsequence grouping logic.
3. **Missing Edge Case:** Not handling k == 0 case properly.
4. **Wrong Counting:** Not correctly counting the number of subsequences.
5. **Inefficient Approach:** Using brute force when greedy approach suffices.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/2294.partition-array-such-that-maximum-difference-is-k.py)](../exercises/2294.partition-array-such-that-maximum-difference-is-k.py)
*Note: This is a greedy problem that demonstrates efficient array partitioning with difference constraints.*

View File

@@ -0,0 +1,124 @@
# Product of Array Except Self
[![Problem 238](https://img.shields.io/badge/Problem-238-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/product-of-array-except-self/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/product-of-array-except-self/)
**Problem Number:** [238](https://leetcode.com/problems/product-of-array-except-self/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Prefix Sum
**LeetCode Link:** [https://leetcode.com/problems/product-of-array-except-self/](https://leetcode.com/problems/product-of-array-except-self/)
## Problem Description
Given an integer array `nums`, return *an array* `answer` *such that* `answer[i]` *is equal to the product of all the elements of* `nums` *except* `nums[i]`.
The product of any prefix or suffix of `nums` is **guaranteed** to fit in a **32-bit** integer.
You must write an algorithm that runs in `O(n)` time and without using the division operation.
**Example 1:**
```
Input: nums = [1,2,3,4]
Output: [24,12,8,6]
Explanation: answer[0] = 3*4*2 = 24, answer[1] = 1*3*4 = 12, answer[2] = 1*2*4 = 8, answer[3] = 1*2*3 = 6
```
**Example 2:**
```
Input: nums = [-1,1,0,-3,3]
Output: [0,0,9,0,0]
Explanation: answer[0] = 1*0*(-3)*3 = 0, answer[1] = (-1)*0*(-3)*3 = 0, answer[2] = (-1)*1*(-3)*3 = 9, answer[3] = (-1)*1*0*3 = 0, answer[4] = (-1)*1*0*(-3) = 0
```
**Constraints:**
- `2 <= nums.length <= 10^5`
- `-30 <= nums[i] <= 30`
- The product of any prefix or suffix of `nums` is guaranteed to fit in a **32-bit** integer.
**Follow up:** Can you solve the problem in `O(1)` extra space complexity? (The output array **does not** count as extra space for space complexity analysis.)
## My Approach
I used a **Two-Pass** approach to calculate the product without using division. The key insight is to use two passes: first to calculate left products, then to multiply with right products.
**Algorithm:**
1. Initialize result array with 1s
2. First pass (left to right): Calculate left products
- For each index i, store product of all elements to the left
3. Second pass (right to left): Multiply with right products
- For each index i, multiply with product of all elements to the right
4. Return the result array
## Solution
The solution uses two-pass approach to calculate products without division. See the implementation in the [solution file](../exercises/238.product-of-array-except-self.py).
**Key Points:**
- Uses two passes through the array
- First pass calculates left products
- Second pass multiplies with right products
- Avoids division operation
- O(n) time complexity
## Time & Space Complexity
**Time Complexity:** O(n)
- Two passes through the array
- Each pass performs constant time operations
- Total: O(n)
**Space Complexity:** O(1) (excluding output array)
- Uses only a constant amount of extra space
- Output array doesn't count for space complexity
## Key Insights
1. **Two-Pass Approach:** Using two passes avoids the need for division.
2. **Left and Right Products:** Each element's product is left_product × right_product.
3. **In-place Calculation:** Can calculate products in-place using the result array.
4. **No Division:** The approach works without using division operation.
5. **Linear Time:** Achieves O(n) time complexity with two passes.
6. **Constant Space:** Uses only O(1) extra space (excluding output).
## Mistakes Made
1. **Division Approach:** Initially might try to use division, which is not allowed.
2. **Brute Force:** Using nested loops to calculate each product.
3. **Complex Logic:** Overcomplicating the two-pass approach.
4. **Wrong Order:** Not understanding the order of the two passes.
## Related Problems
- **Trapping Rain Water** (Problem 42): Two-pass approach for water trapping
- **Candy** (Problem 135): Two-pass approach for candy distribution
- **Gas Station** (Problem 134): Circular array with two-pass logic
- **Container With Most Water** (Problem 11): Two-pointer approach
## Alternative Approaches
1. **Prefix and Suffix Arrays:** Use separate arrays for left and right products - O(n) time, O(n) space
2. **Single Pass with Division:** Use division (if allowed) - O(n) time, O(1) space
3. **Recursive:** Use recursion to calculate products - O(n) time, O(n) space
## Common Pitfalls
1. **Division Usage:** Using division when it's not allowed.
2. **Brute Force:** Using nested loops for O(n²) complexity.
3. **Complex Logic:** Overcomplicating the two-pass approach.
4. **Wrong Order:** Not understanding the order of passes.
5. **Space Inefficiency:** Using O(n) extra space when O(1) is possible.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/238.product-of-array-except-self.py)](../exercises/238.product-of-array-except-self.py)
*Note: This is a two-pass problem that demonstrates efficient product calculation without division.*

View File

@@ -0,0 +1,117 @@
# Valid Anagram
[![Problem 242](https://img.shields.io/badge/Problem-242-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-anagram/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/valid-anagram/)
**Problem Number:** [242](https://leetcode.com/problems/valid-anagram/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, String, Sorting
**LeetCode Link:** [https://leetcode.com/problems/valid-anagram/](https://leetcode.com/problems/valid-anagram/)
## Problem Description
Given two strings `s` and `t`, return `true` *if* `t` *is an anagram of* `s`*, and* `false` *otherwise*.
An **Anagram** is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.
**Example 1:**
```
Input: s = "anagram", t = "nagaram"
Output: true
```
**Example 2:**
```
Input: s = "rat", t = "car"
Output: false
```
**Constraints:**
- `1 <= s.length, t.length <= 5 * 10^4`
- `s` and `t` consist of lowercase English letters.
**Follow up:** What if the inputs contain Unicode characters? How would you adapt your solution to such a case?
## My Approach
I used a **Hash Table** approach with Counter to check if two strings are anagrams. The key insight is to compare the character frequency of both strings.
**Algorithm:**
1. Use Counter to count characters in string s
2. Use Counter to count characters in string t
3. Compare the two counters
4. Return True if they are equal, False otherwise
## Solution
The solution uses Counter to efficiently check character frequency. See the implementation in the [solution file](../exercises/242.valid-anagram.py).
**Key Points:**
- Uses Counter for character frequency counting
- Simple one-line comparison
- Handles all edge cases automatically
- Efficient and readable approach
## Time & Space Complexity
**Time Complexity:** O(n)
- Counter creation: O(n) for each string
- Comparison: O(k) where k is number of unique characters
- Total: O(n)
**Space Complexity:** O(k)
- Counter stores frequency of each unique character
- k is the number of unique characters
- In worst case: O(n)
## Key Insights
1. **Character Frequency:** Anagrams have the same character frequency.
2. **Counter Usage:** Using Counter provides efficient character counting.
3. **Simple Comparison:** Direct comparison of counters is sufficient.
4. **Unicode Support:** Counter works with Unicode characters as well.
5. **Case Sensitivity:** The problem specifies lowercase English letters.
6. **Length Check:** Anagrams must have the same length.
## Mistakes Made
1. **Sorting Approach:** Initially might sort strings, leading to O(n log n) complexity.
2. **Manual Counting:** Manually counting characters instead of using Counter.
3. **Complex Logic:** Overcomplicating the anagram check.
4. **Wrong Comparison:** Not using the right data structure for comparison.
## Related Problems
- **Group Anagrams** (Problem 49): Group strings by anagrams
- **Find All Anagrams in a String** (Problem 438): Find anagram substrings
- **Valid Parentheses** (Problem 20): Check valid parentheses
- **Isomorphic Strings** (Problem 205): Check string isomorphism
## Alternative Approaches
1. **Sorting:** Sort both strings and compare - O(n log n) time, O(n) space
2. **Hash Map:** Use manual hash map for counting - O(n) time, O(n) space
3. **Array Counting:** Use array for ASCII characters - O(n) time, O(1) space
## Common Pitfalls
1. **Sorting Usage:** Using sorting when Counter is more efficient.
2. **Manual Counting:** Manually counting characters instead of using Counter.
3. **Complex Logic:** Overcomplicating the anagram check.
4. **Wrong Data Structure:** Not using appropriate data structure for counting.
5. **Case Sensitivity:** Not handling case sensitivity properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/242.valid-anagram.py)](../exercises/242.valid-anagram.py)
*Note: This is a simple hash table problem that demonstrates efficient anagram checking with Counter.*

View File

@@ -0,0 +1,116 @@
# Shortest Word Distance
[![Problem 243](https://img.shields.io/badge/Problem-243-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/shortest-word-distance/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/shortest-word-distance/)
**Problem Number:** [243](https://leetcode.com/problems/shortest-word-distance/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/shortest-word-distance/](https://leetcode.com/problems/shortest-word-distance/)
## Problem Description
Given an array of strings `wordsDict` and two different strings `word1` and `word2`, return *the shortest distance between these two words in the list*.
**Example 1:**
```
Input: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "coding", word2 = "practice"
Output: 3
```
**Example 2:**
```
Input: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "makes", word2 = "coding"
Output: 1
```
**Constraints:**
- `1 <= wordsDict.length <= 3 * 10^4`
- `1 <= wordsDict[i].length <= 10`
- `word1` and `word2` are in `wordsDict`.
- `word1 != word2`
## My Approach
I used a **Hash Map with Two Pointers** approach to find the shortest distance. The key insight is to collect all indices of both words and then use two pointers to find the minimum distance.
**Algorithm:**
1. Create hash map to store word indices
2. Collect all indices for word1 and word2
3. Use two pointers to traverse both index lists
4. Calculate distance between current indices
5. Move pointer with smaller index to find minimum distance
6. Return minimum distance found
## Solution
The solution uses hash map and two pointers to efficiently find shortest distance. See the implementation in the [solution file](../exercises/243.shortest-word-distance.py).
**Key Points:**
- Uses hash map to store word indices
- Two-pointer approach for efficient traversal
- Calculates minimum distance between all pairs
- Handles multiple occurrences of words
## Time & Space Complexity
**Time Complexity:** O(n)
- Building hash map: O(n)
- Two-pointer traversal: O(m + k) where m, k are occurrences of word1, word2
- Total: O(n)
**Space Complexity:** O(n)
- Hash map stores indices for all words
- In worst case: O(n)
## Key Insights
1. **Index Collection:** Collecting all indices allows efficient distance calculation.
2. **Two Pointers:** Using two pointers on sorted indices is optimal.
3. **Sorted Indices:** Indices are naturally sorted in order of appearance.
4. **Minimum Distance:** Always move the pointer with smaller index.
5. **Multiple Occurrences:** Handles cases where words appear multiple times.
6. **Efficient Traversal:** Two-pointer approach avoids checking all pairs.
## Mistakes Made
1. **Brute Force:** Initially might check all pairs of indices.
2. **Wrong Order:** Not understanding the two-pointer traversal order.
3. **Complex Logic:** Overcomplicating the distance calculation.
4. **Inefficient Approach:** Using nested loops instead of two pointers.
## Related Problems
- **Shortest Word Distance II** (Problem 244): Design class for multiple queries
- **Shortest Word Distance III** (Problem 245): Handle case where word1 == word2
- **Two Sum** (Problem 1): Find pair with target sum
- **Container With Most Water** (Problem 11): Two-pointer approach
## Alternative Approaches
1. **Single Pass:** Track last seen indices during single pass - O(n) time, O(1) space
2. **Binary Search:** Use binary search on sorted indices - O(n log n) time
3. **Brute Force:** Check all pairs of indices - O(n²) time
## Common Pitfalls
1. **Brute Force:** Using nested loops to check all pairs.
2. **Wrong Order:** Not understanding the two-pointer traversal order.
3. **Complex Logic:** Overcomplicating the distance calculation.
4. **Inefficient Approach:** Using O(n²) approach when O(n) is possible.
5. **Memory Issues:** Not considering space complexity of storing indices.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/243.shortest-word-distance.py)](../exercises/243.shortest-word-distance.py)
*Note: This is a two-pointer problem that demonstrates efficient distance calculation between word indices.*

View File

@@ -0,0 +1,126 @@
# Shortest Word Distance II
[![Problem 244](https://img.shields.io/badge/Problem-244-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/shortest-word-distance-ii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/shortest-word-distance-ii/)
**Problem Number:** [244](https://leetcode.com/problems/shortest-word-distance-ii/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Hash Table, Design, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/shortest-word-distance-ii/](https://leetcode.com/problems/shortest-word-distance-ii/)
## Problem Description
Design a data structure that will be initialized with a string array, and then it will answer queries of the shortest distance between two different strings from the array.
Implement the `WordDistance` class:
- `WordDistance(String[] wordsDict)` initializes the object with the strings array `wordsDict`.
- `int shortest(String word1, String word2)` returns the shortest distance between `word1` and `word2` in the array `wordsDict`.
**Example 1:**
```
Input
["WordDistance", "shortest", "shortest"]
[[["practice", "makes", "perfect", "coding", "makes"]], ["coding", "practice"], ["makes", "coding"]]
Output
[null, 3, 1]
Explanation
WordDistance wordDistance = new WordDistance(["practice", "makes", "perfect", "coding", "makes"]);
wordDistance.shortest("coding", "practice"); // return 3
wordDistance.shortest("makes", "coding"); // return 1
```
**Constraints:**
- `1 <= wordsDict.length <= 3 * 10^4`
- `1 <= wordsDict[i].length <= 10`
- `wordsDict[i]` consists of lowercase English letters.
- `word1` and `word2` are in `wordsDict`.
- `word1 != word2`
- At most `5000` calls will be made to `shortest`.
## My Approach
I used a **Design Pattern** with hash map preprocessing to optimize multiple queries. The key insight is to preprocess the word indices in the constructor and reuse them for all queries.
**Algorithm:**
1. **Constructor:** Build hash map of word indices during initialization
2. **Shortest Method:** Use two pointers on precomputed indices
- Get indices for word1 and word2
- Use two-pointer approach to find minimum distance
- Return minimum distance found
## Solution
The solution uses design pattern with hash map preprocessing for efficient multiple queries. See the implementation in the [solution file](../exercises/244.shortest-word-distance-ii.py).
**Key Points:**
- Preprocesses word indices in constructor
- Reuses hash map for all queries
- Two-pointer approach for distance calculation
- Optimized for multiple queries
## Time & Space Complexity
**Constructor Time:** O(n)
- Build hash map: O(n)
**Shortest Method Time:** O(m + k)
- m, k are occurrences of word1, word2
- Two-pointer traversal: O(m + k)
**Space Complexity:** O(n)
- Hash map stores indices for all words
- Total: O(n)
## Key Insights
1. **Preprocessing:** Building hash map in constructor optimizes multiple queries.
2. **Design Pattern:** Using class design allows efficient reuse of precomputed data.
3. **Two Pointers:** Two-pointer approach on sorted indices is optimal.
4. **Multiple Queries:** Preprocessing pays off when many queries are made.
5. **Index Reuse:** Same indices can be used for different word pairs.
6. **Efficient Lookup:** Hash map provides O(1) lookup for word indices.
## Mistakes Made
1. **No Preprocessing:** Initially might rebuild indices for each query.
2. **Wrong Design:** Not using class design for multiple queries.
3. **Inefficient Approach:** Using O(n) approach for each query.
4. **Complex Logic:** Overcomplicating the distance calculation.
## Related Problems
- **Shortest Word Distance** (Problem 243): Single query version
- **Shortest Word Distance III** (Problem 245): Handle same word case
- **Design HashMap** (Problem 706): Design hash map data structure
- **Design HashSet** (Problem 705): Design hash set data structure
## Alternative Approaches
1. **Lazy Loading:** Build indices only when first queried
2. **Binary Search:** Use binary search on sorted indices
3. **Caching:** Cache results for repeated queries
## Common Pitfalls
1. **No Preprocessing:** Rebuilding indices for each query.
2. **Wrong Design:** Not using class design for multiple queries.
3. **Inefficient Approach:** Using O(n) approach for each query.
4. **Memory Issues:** Not considering space complexity of preprocessing.
5. **Complex Logic:** Overcomplicating the distance calculation.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/244.shortest-word-distance-ii.py)](../exercises/244.shortest-word-distance-ii.py)
*Note: This is a design problem that demonstrates efficient preprocessing for multiple queries.*

View File

@@ -0,0 +1,120 @@
# Shortest Word Distance III
[![Problem 245](https://img.shields.io/badge/Problem-245-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/shortest-word-distance-iii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/shortest-word-distance-iii/)
**Problem Number:** [245](https://leetcode.com/problems/shortest-word-distance-iii/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/shortest-word-distance-iii/](https://leetcode.com/problems/shortest-word-distance-iii/)
## Problem Description
Given an array of strings `wordsDict` and two strings `word1` and `word2`, return *the shortest distance between these two words in the list*.
**Note** that `word1` and `word2` may be the same. It is guaranteed that they represent *two individual words* in the list.
**Example 1:**
```
Input: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "makes", word2 = "coding"
Output: 1
```
**Example 2:**
```
Input: wordsDict = ["practice", "makes", "perfect", "coding", "makes"], word1 = "makes", word2 = "makes"
Output: 3
```
**Constraints:**
- `1 <= wordsDict.length <= 3 * 10^4`
- `1 <= wordsDict[i].length <= 10`
- `wordsDict[i]` consists of lowercase English letters.
- `word1` and `word2` are in `wordsDict`.
## My Approach
I used a **Hash Map with Two Pointers** approach that handles the case where word1 and word2 can be the same. The key insight is to use different strategies for same and different words.
**Algorithm:**
1. Create hash map to store word indices
2. Collect indices for word1 and word2
3. If word1 == word2:
- Use nested loops to find minimum distance between different indices
4. If word1 != word2:
- Use two-pointer approach to find minimum distance
5. Return minimum distance found
## Solution
The solution uses hash map and handles same word case with nested loops. See the implementation in the [solution file](../exercises/245.shortest-word-distance-iii.py).
**Key Points:**
- Uses hash map to store word indices
- Handles same word case with nested loops
- Uses two-pointer approach for different words
- Avoids comparing same indices when words are identical
## Time & Space Complexity
**Time Complexity:** O(n)
- Building hash map: O(n)
- Same word case: O(m²) where m is occurrences of the word
- Different words case: O(m + k) where m, k are occurrences
- Total: O(n)
**Space Complexity:** O(n)
- Hash map stores indices for all words
- Total: O(n)
## Key Insights
1. **Same Word Handling:** When word1 == word2, need to find distance between different indices.
2. **Nested Loops:** For same word, use nested loops to compare different indices.
3. **Two Pointers:** For different words, use two-pointer approach.
4. **Index Avoidance:** When words are same, avoid comparing same index with itself.
5. **Multiple Occurrences:** Handles cases where words appear multiple times.
6. **Efficient Lookup:** Hash map provides O(1) lookup for word indices.
## Mistakes Made
1. **Same Word Case:** Initially might not handle word1 == word2 case.
2. **Wrong Comparison:** Comparing same index with itself when words are identical.
3. **Complex Logic:** Overcomplicating the same word handling.
4. **Inefficient Approach:** Using same approach for both cases.
## Related Problems
- **Shortest Word Distance** (Problem 243): Different words only
- **Shortest Word Distance II** (Problem 244): Design class version
- **Two Sum** (Problem 1): Find pair with target sum
- **Container With Most Water** (Problem 11): Two-pointer approach
## Alternative Approaches
1. **Single Pass:** Track last seen indices during single pass - O(n) time, O(1) space
2. **Binary Search:** Use binary search on sorted indices - O(n log n) time
3. **Brute Force:** Check all pairs of indices - O(n²) time
## Common Pitfalls
1. **Same Word Case:** Not handling word1 == word2 case properly.
2. **Wrong Comparison:** Comparing same index with itself.
3. **Complex Logic:** Overcomplicating the same word handling.
4. **Inefficient Approach:** Using same approach for both cases.
5. **Memory Issues:** Not considering space complexity of storing indices.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/245.shortest-word-distance-iii.py)](../exercises/245.shortest-word-distance-iii.py)
*Note: This is a two-pointer problem that demonstrates handling same word case in distance calculation.*

View File

@@ -0,0 +1,123 @@
# Strobogrammatic Number
[![Problem 246](https://img.shields.io/badge/Problem-246-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/strobogrammatic-number/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/strobogrammatic-number/)
**Problem Number:** [246](https://leetcode.com/problems/strobogrammatic-number/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, String, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/strobogrammatic-number/](https://leetcode.com/problems/strobogrammatic-number/)
## Problem Description
Given a string `num` which represents an integer, return `true` *if* `num` *is a **strobogrammatic number***.
A **strobogrammatic number** is a number that looks the same when rotated 180 degrees (looked at upside down).
**Example 1:**
```
Input: num = "69"
Output: true
```
**Example 2:**
```
Input: num = "88"
Output: true
```
**Example 3:**
```
Input: num = "962"
Output: false
```
**Constraints:**
- `1 <= num.length <= 50`
- `num` consists of only digits.
## My Approach
I used a **Two Pointers** approach with hash map mapping to check if a number is strobogrammatic. The key insight is to use a mapping of valid strobogrammatic digits and check from both ends.
**Algorithm:**
1. Define mapping of valid strobogrammatic digits
2. Use two pointers (left, right) starting from both ends
3. While left <= right:
- Check if both digits are in mapping
- Check if left digit maps to right digit
- Move pointers inward
4. Return True if all checks pass
## Solution
The solution uses two pointers with hash map mapping to check strobogrammatic numbers. See the implementation in the [solution file](../exercises/246.strobogrammatic-number.py).
**Key Points:**
- Uses hash map for digit mapping
- Two-pointer approach from both ends
- Checks validity of each digit pair
- Handles odd and even length numbers
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through the string
- Each iteration performs constant time operations
- Total: O(n)
**Space Complexity:** O(1)
- Hash map has constant size (5 mappings)
- Total: O(1)
## Key Insights
1. **Digit Mapping:** Only certain digits (0,1,6,8,9) are valid strobogrammatic.
2. **Two Pointers:** Using two pointers from both ends is efficient.
3. **Pair Checking:** Each pair of digits must map correctly.
4. **Center Digit:** For odd length, center digit must map to itself.
5. **Valid Digits:** Only 0,1,6,8,9 are valid strobogrammatic digits.
6. **Mapping Rules:** 6↔9, 0↔0, 1↔1, 8↔8.
## Mistakes Made
1. **Wrong Mapping:** Initially might use incorrect digit mappings.
2. **Complex Logic:** Overcomplicating the strobogrammatic check.
3. **Wrong Order:** Not checking digits in correct order.
4. **Missing Digits:** Not including all valid strobogrammatic digits.
## Related Problems
- **Strobogrammatic Number II** (Problem 247): Generate strobogrammatic numbers
- **Strobogrammatic Number III** (Problem 248): Count strobogrammatic numbers in range
- **Valid Palindrome** (Problem 125): Check if string is palindrome
- **Palindrome Number** (Problem 9): Check if number is palindrome
## Alternative Approaches
1. **String Reversal:** Reverse string and apply mapping - O(n) time, O(n) space
2. **Single Pass:** Use single pointer with length calculation - O(n) time, O(1) space
3. **Recursive:** Use recursion to check pairs - O(n) time, O(n) space
## Common Pitfalls
1. **Wrong Mapping:** Using incorrect digit mappings.
2. **Complex Logic:** Overcomplicating the strobogrammatic check.
3. **Wrong Order:** Not checking digits in correct order.
4. **Missing Digits:** Not including all valid strobogrammatic digits.
5. **Center Handling:** Not properly handling center digit for odd length.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/246.strobogrammatic-number.py)](../exercises/246.strobogrammatic-number.py)
*Note: This is a two-pointer problem that demonstrates efficient strobogrammatic number checking with digit mapping.*

View File

@@ -0,0 +1,119 @@
# Strobogrammatic Number III
[![Problem 248](https://img.shields.io/badge/Problem-248-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/strobogrammatic-number-iii/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Hard-red?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=HARD)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/strobogrammatic-number-iii/)
**Problem Number:** [248](https://leetcode.com/problems/strobogrammatic-number-iii/)
**Difficulty:** [Hard](https://leetcode.com/problemset/?difficulty=HARD)
**Category:** Math, Recursion, String
**LeetCode Link:** [https://leetcode.com/problems/strobogrammatic-number-iii/](https://leetcode.com/problems/strobogrammatic-number-iii/)
## Problem Description
Given two strings `low` and `high` that represent two integers `low` and `high` where `low <= high`, return *the number of **strobogrammatic numbers** in the range* `[low, high]`.
A strobogrammatic number is a number that looks the same when rotated 180 degrees (looked at upside down).
**Example 1:**
```
Input: low = "50", high = "100"
Output: 3
Explanation: 69, 88, and 96 are three strobogrammatic numbers.
```
**Example 2:**
```
Input: low = "0", high = "0"
Output: 1
```
**Constraints:**
- `1 <= low.length, high.length <= 15`
- `low` and `high` consist of only digits.
- `low <= high`
- `low` and `high` do not contain any leading zeros except itself.
## My Approach
I used a **Recursive Generation** approach to generate all strobogrammatic numbers in the given range. The key insight is to recursively build strobogrammatic numbers of different lengths and count those within the range.
**Algorithm:**
1. Define recursive function to generate strobogrammatic numbers of given length
2. Base cases: length 0 returns [""], length 1 returns ["0","1","8"]
3. For length > 1: recursively generate shorter numbers and add pairs
4. Generate numbers for all lengths between min and max
5. Count numbers that fall within the range [low, high]
## Solution
The solution uses recursive generation to build strobogrammatic numbers and count them in range. See the implementation in the [solution file](../exercises/248.strobogrammatic-number-iii.py).
**Key Points:**
- Uses recursion to generate strobogrammatic numbers
- Handles different lengths systematically
- Avoids leading zeros except for single digit
- Counts numbers within specified range
## Time & Space Complexity
**Time Complexity:** O(5^(n/2))
- Recursive generation: O(5^(n/2)) where n is max length
- Range checking: O(k) where k is number of generated numbers
- Total: O(5^(n/2))
**Space Complexity:** O(5^(n/2))
- Recursive call stack: O(n)
- Generated numbers storage: O(5^(n/2))
- Total: O(5^(n/2))
## Key Insights
1. **Recursive Generation:** Building strobogrammatic numbers recursively is efficient.
2. **Length-based Approach:** Generate numbers by length to avoid duplicates.
3. **Pair Addition:** Add valid pairs (11, 88, 69, 96) around shorter numbers.
4. **Leading Zero Handling:** Avoid leading zeros except for single digit numbers.
5. **Range Checking:** Convert strings to integers for range comparison.
6. **Base Cases:** Handle length 0 and 1 as base cases.
## Mistakes Made
1. **Wrong Generation:** Initially might generate invalid strobogrammatic numbers.
2. **Leading Zeros:** Not properly handling leading zero constraints.
3. **Complex Logic:** Overcomplicating the recursive generation.
4. **Range Issues:** Not properly converting strings to integers for comparison.
## Related Problems
- **Strobogrammatic Number** (Problem 246): Check if number is strobogrammatic
- **Strobogrammatic Number II** (Problem 247): Generate strobogrammatic numbers of given length
- **Generate Parentheses** (Problem 22): Recursive generation
- **Subsets** (Problem 78): Generate all subsets
## Alternative Approaches
1. **Iterative Generation:** Use iteration instead of recursion - O(5^(n/2)) time
2. **Binary Search:** Use binary search on generated numbers - O(n log n) time
3. **Mathematical:** Use mathematical properties to optimize - O(n) time
## Common Pitfalls
1. **Wrong Generation:** Generating invalid strobogrammatic numbers.
2. **Leading Zeros:** Not properly handling leading zero constraints.
3. **Complex Logic:** Overcomplicating the recursive generation.
4. **Range Issues:** Not properly converting strings to integers.
5. **Memory Issues:** Not considering exponential space complexity.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/248.strobogrammatic-number-iii.py)](../exercises/248.strobogrammatic-number-iii.py)
*Note: This is a recursive generation problem that demonstrates efficient strobogrammatic number counting in ranges.*

View File

@@ -0,0 +1,157 @@
# Encode and Decode Strings
[![Problem 271](https://img.shields.io/badge/Problem-271-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/encode-and-decode-strings/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/encode-and-decode-strings/)
**Problem Number:** [271](https://leetcode.com/problems/encode-and-decode-strings/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** String, Design
**LeetCode Link:** [https://leetcode.com/problems/encode-and-decode-strings/](https://leetcode.com/problems/encode-and-decode-strings/)
## Problem Description
Design an algorithm to encode a list of strings to a string. The encoded string is then sent over the network and is decoded back to the original list of strings.
Machine 1 (sender) has the function:
```
string encode(vector<string> strs) {
// ... your code
return encoded_string;
}
```
Machine 2 (receiver) has the function:
```
vector<string> decode(string s) {
//... your code
return strs;
}
```
So Machine 1 does:
```
string encoded_string = encode(strs);
```
and Machine 2 does:
```
vector<string> strs2 = decode(encoded_string);
```
`strs2` in Machine 2 should be the same as `strs` in Machine 1.
Implement the `encode` and `decode` methods.
You are not allowed to solve the problem using any serialize methods (such as `eval`).
**Example 1:**
```
Input: dummy_input = ["Hello","World"]
Output: ["Hello","World"]
Explanation:
Machine 1:
Codec encoder = new Codec();
String msg = encoder.encode(strs);
Machine 1 ---msg---> Machine 2
Machine 2:
Codec decoder = new Codec();
String[] strs = decoder.decode(msg);
```
**Example 2:**
```
Input: dummy_input = [""]
Output: [""]
```
**Constraints:**
- `1 <= strs.length <= 200`
- `0 <= strs[i].length <= 200`
- `strs[i]` contains any possible characters out of 256 valid ASCII characters.
**Follow up:** Could you write a generalized algorithm to work on any possible set of characters?
## My Approach
I used a **Delimiter-based** approach to encode and decode strings. The key insight is to use a special delimiter that doesn't appear in the input strings to separate them.
**Algorithm:**
1. **Encode:** Join all strings with a special delimiter
2. **Decode:** Split the encoded string by the delimiter
3. Handle edge cases (empty array, empty strings)
4. Use a complex delimiter to avoid conflicts
## Solution
The solution uses delimiter-based encoding and decoding. See the implementation in the [solution file](../exercises/271.encode-and-decode-strings.js).
**Key Points:**
- Uses special delimiter to separate strings
- Handles empty arrays and empty strings
- Simple join/split approach
- Complex delimiter to avoid conflicts
## Time & Space Complexity
**Encode Time:** O(n)
- Join operation: O(n) where n is total length of all strings
**Decode Time:** O(n)
- Split operation: O(n) where n is length of encoded string
**Space Complexity:** O(n)
- Encoded string: O(n)
- Decoded array: O(n)
## Key Insights
1. **Delimiter Choice:** Using a complex delimiter avoids conflicts with input strings.
2. **Join/Split:** Simple join and split operations are efficient.
3. **Edge Cases:** Handle empty arrays and empty strings properly.
4. **Delimiter Safety:** Complex delimiter reduces chance of appearing in input.
5. **Bidirectional:** Encode and decode must be inverse operations.
6. **Character Set:** Works with any ASCII characters.
## Mistakes Made
1. **Simple Delimiter:** Initially might use simple delimiter that conflicts with input.
2. **Edge Cases:** Not handling empty arrays or empty strings properly.
3. **Complex Logic:** Overcomplicating the encoding/decoding process.
4. **Delimiter Conflicts:** Using delimiter that might appear in input strings.
## Related Problems
- **Serialize and Deserialize Binary Tree** (Problem 297): Serialize tree structure
- **Serialize and Deserialize BST** (Problem 449): Serialize BST
- **Design HashMap** (Problem 706): Design data structure
- **Design HashSet** (Problem 705): Design data structure
## Alternative Approaches
1. **Length Prefix:** Use length prefix for each string - O(n) time
2. **Escape Characters:** Use escape characters for special cases - O(n) time
3. **Base64 Encoding:** Use base64 encoding - O(n) time
## Common Pitfalls
1. **Simple Delimiter:** Using simple delimiter that conflicts with input.
2. **Edge Cases:** Not handling empty arrays or empty strings.
3. **Complex Logic:** Overcomplicating the encoding/decoding process.
4. **Delimiter Conflicts:** Using delimiter that might appear in input strings.
5. **Character Set:** Not considering all possible ASCII characters.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/271.encode-and-decode-strings.js)](../exercises/271.encode-and-decode-strings.js)
*Note: This is a design problem that demonstrates efficient string encoding and decoding with delimiters.*

120
src/notes/274_h_index.md Normal file
View File

@@ -0,0 +1,120 @@
# H-Index
[![Problem 274](https://img.shields.io/badge/Problem-274-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/h-index/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/h-index/)
**Problem Number:** [274](https://leetcode.com/problems/h-index/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Sorting, Counting Sort
**LeetCode Link:** [https://leetcode.com/problems/h-index/](https://leetcode.com/problems/h-index/)
## Problem Description
Given an array of integers `citations` where `citations[i]` is the number of citations a researcher received for their `i^th` paper, return *compute the researcher's* `h-index`.
According to the [definition of h-index on Wikipedia](https://en.wikipedia.org/wiki/H-index): A scientist has an index `h` if `h` of their `n` papers have at least `h` citations each, and the other `n h` papers have no more than `h` citations each.
If there are several possible values for `h`, the maximum one is taken as the `h-index`.
**Example 1:**
```
Input: citations = [3,0,6,1,5]
Output: 3
Explanation: [3,0,6,1,5] means the researcher has 5 papers in total and each of them had received 3, 0, 6, 1, 5 citations respectively.
Since the researcher has 3 papers with at least 3 citations each and the remaining two with no more than 3 citations each, their h-index is 3.
```
**Example 2:**
```
Input: citations = [1,3,1]
Output: 1
```
**Constraints:**
- `n == citations.length`
- `1 <= n <= 5000`
- `0 <= citations[i] <= 1000`
## My Approach
I used a **Sorting** approach to find the h-index. The key insight is to sort the citations in ascending order and find the largest h where at least h papers have h or more citations.
**Algorithm:**
1. Sort citations in ascending order
2. Iterate through sorted citations
3. For each position i, check if citations[i] >= (n - i)
4. Return (n - i) when condition is met
5. Return 0 if no h-index found
## Solution
The solution uses sorting to efficiently find the h-index. See the implementation in the [solution file](../exercises/274.h-index.py).
**Key Points:**
- Sorts citations in ascending order
- Checks h-index condition for each position
- Returns maximum valid h-index
- Handles edge cases properly
## Time & Space Complexity
**Time Complexity:** O(n log n)
- Sorting: O(n log n)
- Single pass through sorted array: O(n)
- Total: O(n log n)
**Space Complexity:** O(1)
- In-place sorting (modifies input)
- Uses only constant extra space
## Key Insights
1. **Sorting:** Sorting allows efficient h-index calculation.
2. **H-index Condition:** At position i, h-index is (n - i) if citations[i] >= (n - i).
3. **Maximum H-index:** Return the first valid h-index found (largest possible).
4. **Position Logic:** After sorting, position i represents (n - i) papers with >= citations[i].
5. **Edge Cases:** Return 0 if no valid h-index found.
6. **Efficient Check:** Single pass through sorted array is sufficient.
## Mistakes Made
1. **Wrong Order:** Initially might sort in descending order.
2. **Complex Logic:** Overcomplicating the h-index calculation.
3. **Wrong Condition:** Not understanding the h-index condition properly.
4. **Inefficient Approach:** Using O(n²) approach when sorting suffices.
## Related Problems
- **H-Index II** (Problem 275): H-index with sorted citations
- **Sort Colors** (Problem 75): Three-way partitioning
- **Kth Largest Element** (Problem 215): Find kth largest element
- **Top K Frequent Elements** (Problem 347): Find most frequent elements
## Alternative Approaches
1. **Counting Sort:** Use counting sort for O(n) time - O(n) space
2. **Binary Search:** Use binary search on h-index values - O(n log n) time
3. **Bucket Sort:** Use bucket sort for O(n) time - O(n) space
## Common Pitfalls
1. **Wrong Order:** Sorting in wrong order.
2. **Complex Logic:** Overcomplicating the h-index calculation.
3. **Wrong Condition:** Not understanding the h-index condition.
4. **Inefficient Approach:** Using O(n²) approach when sorting suffices.
5. **Edge Cases:** Not handling cases where no h-index exists.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/274.h-index.py)](../exercises/274.h-index.py)
*Note: This is a sorting problem that demonstrates efficient h-index calculation with position-based logic.*

View File

@@ -0,0 +1,126 @@
# Word Pattern
[![Problem 290](https://img.shields.io/badge/Problem-290-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/word-pattern/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/word-pattern/)
**Problem Number:** [290](https://leetcode.com/problems/word-pattern/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, String
**LeetCode Link:** [https://leetcode.com/problems/word-pattern/](https://leetcode.com/problems/word-pattern/)
## Problem Description
Given a `pattern` and a string `s`, find if `s` follows the same pattern.
Here **follow** means a full match, such that there is a bijection between a letter in `pattern` and a **non-empty** word in `s`.
**Example 1:**
```
Input: pattern = "abba", s = "dog cat cat dog"
Output: true
```
**Example 2:**
```
Input: pattern = "abba", s = "dog cat cat fish"
Output: false
```
**Example 3:**
```
Input: pattern = "aaaa", s = "dog cat cat dog"
Output: false
```
**Constraints:**
- `1 <= pattern.length <= 300`
- `pattern` contains only lower-case English letters.
- `1 <= s.length <= 3000`
- `s` contains only lowercase English letters and spaces `' '`.
- `s` **does not contain** any leading or trailing spaces.
- All the words in `s` are separated by a **single space**.
## My Approach
I used a **Hash Table** approach to check if the string follows the pattern. The key insight is to establish a bijection between pattern characters and words, ensuring one-to-one mapping.
**Algorithm:**
1. Split string s into words
2. Check if pattern length equals number of words
3. First pass: establish mappings for new pattern characters
4. Second pass: verify all mappings are consistent
5. Return True if all checks pass
## Solution
The solution uses hash table to establish and verify bijection between pattern and words. See the implementation in the [solution file](../exercises/290.word-pattern.py).
**Key Points:**
- Uses hash table for character-to-word mapping
- Two-pass approach for verification
- Checks bijection requirement
- Handles length mismatch case
## Time & Space Complexity
**Time Complexity:** O(n)
- Split operation: O(n)
- Two passes through pattern/words: O(n)
- Total: O(n)
**Space Complexity:** O(k)
- Hash table stores character mappings
- k is number of unique characters in pattern
- In worst case: O(n)
## Key Insights
1. **Bijection:** Each pattern character must map to exactly one word, and vice versa.
2. **Two-Pass Approach:** First pass establishes mappings, second pass verifies consistency.
3. **Length Check:** Pattern length must equal number of words.
4. **Hash Table:** Using hash table provides O(1) lookup for mappings.
5. **One-to-One Mapping:** No two characters can map to the same word.
6. **Consistency Check:** All mappings must be consistent throughout the string.
## Mistakes Made
1. **Single Pass:** Initially might try single pass without proper verification.
2. **Wrong Mapping:** Not checking bijection requirement properly.
3. **Complex Logic:** Overcomplicating the mapping verification.
4. **Length Mismatch:** Not handling pattern length vs word count mismatch.
## Related Problems
- **Isomorphic Strings** (Problem 205): Check string isomorphism
- **Valid Anagram** (Problem 242): Check if strings are anagrams
- **Group Anagrams** (Problem 49): Group strings by anagrams
- **Longest Substring Without Repeating Characters** (Problem 3): Find unique substring
## Alternative Approaches
1. **Two Hash Tables:** Use separate hash tables for pattern->word and word->pattern - O(n) time, O(n) space
2. **Single Pass:** Use single pass with immediate verification - O(n) time, O(n) space
3. **Array Mapping:** Use arrays for ASCII characters - O(n) time, O(1) space
## Common Pitfalls
1. **Single Pass:** Using single pass without proper verification.
2. **Wrong Mapping:** Not checking bijection requirement properly.
3. **Complex Logic:** Overcomplicating the mapping verification.
4. **Length Mismatch:** Not handling pattern length vs word count mismatch.
5. **Space Inefficiency:** Using unnecessary data structures.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/290.word-pattern.py)](../exercises/290.word-pattern.py)
*Note: This is a hash table problem that demonstrates efficient bijection checking between pattern and words.*

View File

@@ -0,0 +1,121 @@
# Maximum Difference Between Even and Odd Frequency I
[![Problem 3442](https://img.shields.io/badge/Problem-3442-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/maximum-difference-between-even-and-odd-frequency-i/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/maximum-difference-between-even-and-odd-frequency-i/)
**Problem Number:** [3442](https://leetcode.com/problems/maximum-difference-between-even-and-odd-frequency-i/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, String, Counting
**LeetCode Link:** [https://leetcode.com/problems/maximum-difference-between-even-and-odd-frequency-i/](https://leetcode.com/problems/maximum-difference-between-even-and-odd-frequency-i/)
## Problem Description
Given a string `s`, return *the **maximum difference** between the frequency of any two characters that have different frequencies*.
The frequency of a character is the number of times it appears in the string.
**Example 1:**
```
Input: s = "aab"
Output: 0
Explanation: The frequency of 'a' is 2, and the frequency of 'b' is 1.
The maximum difference between frequencies is 2 - 1 = 1.
```
**Example 2:**
```
Input: s = "abcabc"
Output: 3
Explanation: The frequency of 'a' is 2, the frequency of 'b' is 2, and the frequency of 'c' is 2.
The maximum difference between frequencies is 2 - 2 = 0.
```
**Constraints:**
- `1 <= s.length <= 1000`
- `s` consists of lowercase English letters.
## My Approach
I used a **Hash Table** approach to count character frequencies and find the maximum difference. The key insight is to track the maximum odd frequency and minimum even frequency separately.
**Algorithm:**
1. Use Counter to count character frequencies
2. Initialize max_odd to 0 and min_even to infinity
3. Iterate through frequency values:
- If frequency is even, update min_even
- If frequency is odd, update max_odd
4. Return max_odd - min_even
## Solution
The solution uses hash table to count frequencies and find maximum difference. See the implementation in the [solution file](../exercises/3442.maximum-difference-between-even-and-odd-frequency-i.py).
**Key Points:**
- Uses Counter for frequency counting
- Tracks maximum odd and minimum even frequencies
- Handles edge cases properly
- Simple and efficient approach
## Time & Space Complexity
**Time Complexity:** O(n)
- Counter creation: O(n)
- Single pass through frequency values: O(k) where k is unique characters
- Total: O(n)
**Space Complexity:** O(k)
- Counter stores frequency of each unique character
- k is the number of unique characters
- In worst case: O(n)
## Key Insights
1. **Frequency Counting:** Using Counter provides efficient frequency counting.
2. **Even/Odd Separation:** Track even and odd frequencies separately.
3. **Maximum Difference:** Find max odd frequency - min even frequency.
4. **Edge Cases:** Handle cases where no even or odd frequencies exist.
5. **Character Set:** Works with any lowercase English letters.
6. **Simple Logic:** The solution logic is straightforward and efficient.
## Mistakes Made
1. **Wrong Logic:** Initially might not separate even and odd frequencies.
2. **Complex Approach:** Overcomplicating the frequency difference calculation.
3. **Edge Cases:** Not handling cases where no even or odd frequencies exist.
4. **Wrong Data Structure:** Not using appropriate data structure for counting.
## Related Problems
- **Maximum Difference Between Even and Odd Frequency II** (Problem 3445): Similar problem with different constraints
- **Valid Anagram** (Problem 242): Character frequency comparison
- **Group Anagrams** (Problem 49): Group strings by character frequency
- **First Unique Character** (Problem 387): Find first unique character
## Alternative Approaches
1. **Manual Counting:** Use manual hash map for counting - O(n) time, O(n) space
2. **Array Counting:** Use array for ASCII characters - O(n) time, O(1) space
3. **Sorting:** Sort frequencies and find difference - O(n log n) time, O(n) space
## Common Pitfalls
1. **Wrong Logic:** Not separating even and odd frequencies properly.
2. **Complex Approach:** Overcomplicating the frequency difference calculation.
3. **Edge Cases:** Not handling cases where no even or odd frequencies exist.
4. **Wrong Data Structure:** Not using appropriate data structure for counting.
5. **Inefficient Approach:** Using O(n²) approach when O(n) suffices.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/3442.maximum-difference-between-even-and-odd-frequency-i.py)](../exercises/3442.maximum-difference-between-even-and-odd-frequency-i.py)
*Note: This is a hash table problem that demonstrates efficient frequency counting and difference calculation.*

View File

@@ -0,0 +1,118 @@
# Top K Frequent Elements
[![Problem 347](https://img.shields.io/badge/Problem-347-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/top-k-frequent-elements/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/top-k-frequent-elements/)
**Problem Number:** [347](https://leetcode.com/problems/top-k-frequent-elements/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Hash Table, Heap (Priority Queue), Sorting
**LeetCode Link:** [https://leetcode.com/problems/top-k-frequent-elements/](https://leetcode.com/problems/top-k-frequent-elements/)
## Problem Description
Given an integer array `nums` and an integer `k`, return *the* `k` *most frequent elements*. You may return the answer in **any order**.
**Example 1:**
```
Input: nums = [1,1,1,2,2,3], k = 2
Output: [1,2]
```
**Example 2:**
```
Input: nums = [1], k = 1
Output: [1]
```
**Constraints:**
- `1 <= nums.length <= 10^5`
- `-10^4 <= nums[i] <= 10^4`
- `k` is in the range `[1, the number of unique elements in the array]`.
- It is **guaranteed** that the answer is **unique**.
**Follow up:** Your algorithm's time complexity must be better than `O(n log n)`, where n is the array's size.
## My Approach
I used a **Hash Table with Sorting** approach to find the top k frequent elements. The key insight is to count frequencies, sort by frequency, and return the top k elements.
**Algorithm:**
1. Use hash table to count frequency of each element
2. Convert hash table to array of [element, frequency] pairs
3. Sort array by frequency in descending order
4. Extract first k elements
5. Return array of elements (not frequencies)
## Solution
The solution uses hash table and sorting to find top k frequent elements. See the implementation in the [solution file](../exercises/347.top-k-frequent-elements.js).
**Key Points:**
- Uses hash table for frequency counting
- Sorts by frequency in descending order
- Extracts top k elements
- Returns elements, not frequencies
## Time & Space Complexity
**Time Complexity:** O(n log n)
- Hash table creation: O(n)
- Sorting: O(n log n)
- Total: O(n log n)
**Space Complexity:** O(n)
- Hash table: O(n)
- Sorted array: O(n)
- Total: O(n)
## Key Insights
1. **Frequency Counting:** Using hash table provides efficient frequency counting.
2. **Sorting:** Sorting by frequency allows easy extraction of top k elements.
3. **Element Extraction:** Return elements, not their frequencies.
4. **Unique Elements:** Problem guarantees unique answer.
5. **Order Independence:** Answer can be returned in any order.
6. **Follow-up Challenge:** Can be optimized to O(n) using heap or bucket sort.
## Mistakes Made
1. **Wrong Return:** Initially might return frequencies instead of elements.
2. **Complex Logic:** Overcomplicating the frequency counting.
3. **Inefficient Approach:** Using O(n²) approach when sorting suffices.
4. **Wrong Sorting:** Not sorting by frequency in correct order.
## Related Problems
- **Sort Characters By Frequency** (Problem 451): Sort characters by frequency
- **Kth Largest Element** (Problem 215): Find kth largest element
- **Majority Element** (Problem 169): Find majority element
- **Group Anagrams** (Problem 49): Group strings by anagrams
## Alternative Approaches
1. **Heap (Priority Queue):** Use max heap for O(n log k) time
2. **Bucket Sort:** Use bucket sort for O(n) time
3. **Quick Select:** Use quick select for O(n) average time
## Common Pitfalls
1. **Wrong Return:** Returning frequencies instead of elements.
2. **Complex Logic:** Overcomplicating the frequency counting.
3. **Inefficient Approach:** Using O(n²) approach when sorting suffices.
4. **Wrong Sorting:** Not sorting by frequency in correct order.
5. **Follow-up Challenge:** Not considering O(n) solutions.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/347.top-k-frequent-elements.js)](../exercises/347.top-k-frequent-elements.js)
*Note: This is a hash table problem that demonstrates efficient frequency counting and sorting for top k elements.*

View File

@@ -0,0 +1,142 @@
# Generate Tag for Video Caption
[![Problem 3582](https://img.shields.io/badge/Problem-3582-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/generate-tag-for-video-caption/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/generate-tag-for-video-caption/)
**Problem Number:** [3582](https://leetcode.com/problems/generate-tag-for-video-caption/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String, Regular Expression
**LeetCode Link:** [https://leetcode.com/problems/generate-tag-for-video-caption/](https://leetcode.com/problems/generate-tag-for-video-caption/)
## Problem Description
You are given a string `caption` that represents the caption of a video. You want to create a tag from the caption.
The tag should be created as follows:
1. Use the first word of the caption as the base of the tag.
2. For each subsequent word, capitalize its first letter and append it to the tag.
3. Remove all non-alphabetic characters from each word.
4. The final tag should be prefixed with `#` and limited to 100 characters.
**Example 1:**
```
Input: caption = "Hello World"
Output: "#helloWorld"
Explanation: The first word is "Hello" → "hello"
The second word is "World" → "World"
Combined: "helloWorld"
With # prefix: "#helloWorld"
```
**Example 2:**
```
Input: caption = "This is a test"
Output: "#thisIsATest"
Explanation: The first word is "This" → "this"
The second word is "is" → "Is"
The third word is "a" → "A"
The fourth word is "test" → "Test"
Combined: "thisIsATest"
With # prefix: "#thisIsATest"
```
**Example 3:**
```
Input: caption = "A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"
Output: "#aBCDEFGHIJKLMNOPQRSTUVWXYZ"
Explanation: The tag is limited to 100 characters.
```
**Constraints:**
- `1 <= caption.length <= 1000`
- `caption` consists of English letters, digits, and spaces.
## My Approach
I used a **String Processing** approach with regular expressions to generate the tag. The key insight is to process each word individually and apply the camelCase formatting rules.
**Algorithm:**
1. Split caption into words
2. For each word:
- Remove non-alphabetic characters using regex
- Skip empty words
- Convert first word to lowercase
- Capitalize first letter of subsequent words
3. Join words together
4. Add '#' prefix and limit to 100 characters
## Solution
The solution uses string processing and regex to generate camelCase tags. See the implementation in the [solution file](../exercises/3582.generate-tag-for-video-caption.py).
**Key Points:**
- Uses regex to clean words
- Applies camelCase formatting
- Handles empty words
- Limits output to 100 characters
- Adds '#' prefix
## Time & Space Complexity
**Time Complexity:** O(n)
- Split operation: O(n)
- Regex operations: O(m) per word where m is word length
- Total: O(n)
**Space Complexity:** O(n)
- Store words array: O(n)
- Store result string: O(n)
- Total: O(n)
## Key Insights
1. **Regex Cleaning:** Use regex to remove non-alphabetic characters.
2. **CamelCase Format:** First word lowercase, others capitalized.
3. **Empty Words:** Skip words that become empty after cleaning.
4. **Character Limit:** Ensure final tag doesn't exceed 100 characters.
5. **String Processing:** Efficient string manipulation for tag generation.
6. **Edge Cases:** Handle words with only non-alphabetic characters.
## Mistakes Made
1. **Wrong Formatting:** Initially might not apply camelCase correctly.
2. **Regex Issues:** Not properly handling non-alphabetic characters.
3. **Empty Words:** Not skipping words that become empty.
4. **Character Limit:** Not enforcing 100 character limit.
## Related Problems
- **CamelCase Matching** (Problem 1023): Match camelCase patterns
- **Valid Palindrome** (Problem 125): Check if string is palindrome
- **Reverse Words in String** (Problem 151): Reverse word order
- **Valid Parentheses** (Problem 20): Validate parentheses
## Alternative Approaches
1. **Manual Processing:** Process characters manually - O(n) time
2. **Two Pass:** First clean, then format - O(n) time
3. **Built-in Functions:** Use string methods - O(n) time
## Common Pitfalls
1. **Wrong Formatting:** Not applying camelCase correctly.
2. **Regex Issues:** Not properly handling non-alphabetic characters.
3. **Empty Words:** Not skipping words that become empty.
4. **Character Limit:** Not enforcing 100 character limit.
5. **Edge Cases:** Not handling special characters properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/3582.generate-tag-for-video-caption.py)](../exercises/3582.generate-tag-for-video-caption.py)
*Note: This is a string processing problem that demonstrates regex usage and camelCase formatting.*

View File

@@ -0,0 +1,131 @@
# Count Special Triplets
[![Problem 3583](https://img.shields.io/badge/Problem-3583-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/count-special-triplets/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/count-special-triplets/)
**Problem Number:** [3583](https://leetcode.com/problems/count-special-triplets/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Hash Table, Two Pointers
**LeetCode Link:** [https://leetcode.com/problems/count-special-triplets/](https://leetcode.com/problems/count-special-triplets/)
## Problem Description
You are given a 0-indexed integer array `nums`. A triplet of indices `(i, j, k)` is a **special triplet** if the following conditions are met:
- `0 <= i < j < k < nums.length`
- `nums[i] * 2 == nums[j]`
- `nums[j] * 2 == nums[k]`
Return *the number of **special triplets***.
**Example 1:**
```
Input: nums = [1,2,4,8]
Output: 2
Explanation: The special triplets are:
- (0,1,2): nums[0] * 2 == nums[1] and nums[1] * 2 == nums[2]
- (1,2,3): nums[1] * 2 == nums[2] and nums[2] * 2 == nums[3]
```
**Example 2:**
```
Input: nums = [1,2,4,8,16]
Output: 4
Explanation: The special triplets are:
- (0,1,2): nums[0] * 2 == nums[1] and nums[1] * 2 == nums[2]
- (1,2,3): nums[1] * 2 == nums[2] and nums[2] * 2 == nums[3]
- (2,3,4): nums[2] * 2 == nums[3] and nums[3] * 2 == nums[4]
- (0,1,2,3): nums[0] * 2 == nums[1] and nums[1] * 2 == nums[2] and nums[2] * 2 == nums[3]
```
**Constraints:**
- `3 <= nums.length <= 10^5`
- `1 <= nums[i] <= 10^9`
## My Approach
I used a **Hash Table** approach with sliding window to count special triplets efficiently. The key insight is to track left and right counts for each middle element.
**Algorithm:**
1. Initialize hash tables for left and right counts
2. Pre-populate right count hash table
3. For each middle element (j):
- Calculate target as nums[j] * 2
- Get left count (elements before j that equal target)
- Get right count (elements after j that equal target)
- Add left_count * right_count to total
- Update left count hash table
- Decrement right count hash table
## Solution
The solution uses hash tables to efficiently count special triplets. See the implementation in the [solution file](../exercises/3583.count-special-triplets.py).
**Key Points:**
- Uses hash tables for O(1) lookup
- Tracks left and right counts
- Updates counts dynamically
- Handles large numbers with modulo
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through array: O(n)
- Hash table operations: O(1) average
- Total: O(n)
**Space Complexity:** O(n)
- Hash tables for left and right counts: O(n)
- Total: O(n)
## Key Insights
1. **Hash Table Tracking:** Use hash tables to track element frequencies.
2. **Sliding Window:** Update counts as we move through the array.
3. **Triplet Counting:** For each middle element, count valid left and right pairs.
4. **Dynamic Updates:** Update left and right counts efficiently.
5. **Modulo Operation:** Handle large numbers with modulo arithmetic.
6. **Efficient Lookup:** O(1) lookup for element frequencies.
## Mistakes Made
1. **Wrong Counting:** Initially might count triplets incorrectly.
2. **Complex Logic:** Overcomplicating the triplet counting.
3. **Update Issues:** Not properly updating left and right counts.
4. **Inefficient Approach:** Using O(n³) approach when hash table suffices.
## Related Problems
- **3Sum** (Problem 15): Find triplets with target sum
- **Two Sum** (Problem 1): Find pair with target sum
- **Contains Duplicate** (Problem 217): Check for duplicates
- **Majority Element** (Problem 169): Find majority element
## Alternative Approaches
1. **Brute Force:** Check all triplets - O(n³) time
2. **Two Pointers:** Use two pointers for each middle element - O(n²) time
3. **Binary Search:** Use binary search for target elements - O(n log n) time
## Common Pitfalls
1. **Wrong Counting:** Not counting triplets correctly.
2. **Complex Logic:** Overcomplicating the triplet counting.
3. **Update Issues:** Not properly updating left and right counts.
4. **Inefficient Approach:** Using O(n³) approach when hash table suffices.
5. **Overflow:** Not handling large numbers properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/3583.count-special-triplets.py)](../exercises/3583.count-special-triplets.py)
*Note: This is a hash table problem that demonstrates efficient triplet counting with sliding window technique.*

View File

@@ -0,0 +1,121 @@
# Ransom Note
[![Problem 383](https://img.shields.io/badge/Problem-383-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/ransom-note/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/ransom-note/)
**Problem Number:** [383](https://leetcode.com/problems/ransom-note/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Hash Table, String, Counting
**LeetCode Link:** [https://leetcode.com/problems/ransom-note/](https://leetcode.com/problems/ransom-note/)
## Problem Description
Given two strings `ransomNote` and `magazine`, return `true` *if* `ransomNote` *can be constructed by using the letters from* `magazine` *and* `false` *otherwise*.
Each letter in `magazine` can only be used once in `ransomNote`.
**Example 1:**
```
Input: ransomNote = "a", magazine = "b"
Output: false
```
**Example 2:**
```
Input: ransomNote = "aa", magazine = "ab"
Output: false
```
**Example 3:**
```
Input: ransomNote = "aa", magazine = "aab"
Output: true
```
**Constraints:**
- `1 <= ransomNote.length, magazine.length <= 10^5`
- `ransomNote` and `magazine` consist of lowercase English letters.
## My Approach
I used a **Hash Table** approach with Counter to check if ransom note can be constructed. The key insight is to compare character frequencies between ransom note and magazine.
**Algorithm:**
1. Use Counter to count characters in ransom note
2. Use Counter to count characters in magazine
3. Check if ransom note frequency is subset of magazine frequency
4. Return True if all characters can be used, False otherwise
## Solution
The solution uses Counter to efficiently check character frequency requirements. See the implementation in the [solution file](../exercises/383.ransom-note.py).
**Key Points:**
- Uses Counter for frequency counting
- Compares frequency requirements
- Handles all edge cases automatically
- Simple and efficient approach
## Time & Space Complexity
**Time Complexity:** O(n + m)
- Counter creation: O(n) for ransom note, O(m) for magazine
- Frequency comparison: O(k) where k is unique characters
- Total: O(n + m)
**Space Complexity:** O(k)
- Counter stores frequency of each unique character
- k is the number of unique characters
- In worst case: O(n + m)
## Key Insights
1. **Frequency Counting:** Using Counter provides efficient frequency counting.
2. **Subset Check:** Ransom note frequency must be subset of magazine frequency.
3. **Character Reuse:** Each magazine character can only be used once.
4. **Counter Subtraction:** Using Counter subtraction for efficient comparison.
5. **Edge Cases:** Handles empty strings and single characters.
6. **Simple Logic:** The solution logic is straightforward and efficient.
## Mistakes Made
1. **Manual Counting:** Initially might use manual hash table instead of Counter.
2. **Complex Logic:** Overcomplicating the frequency comparison.
3. **Wrong Comparison:** Not understanding the subset relationship.
4. **Inefficient Approach:** Using O(n²) approach when Counter suffices.
## Related Problems
- **Valid Anagram** (Problem 242): Check if strings are anagrams
- **Group Anagrams** (Problem 49): Group strings by anagrams
- **First Unique Character** (Problem 387): Find first unique character
- **Isomorphic Strings** (Problem 205): Check string isomorphism
## Alternative Approaches
1. **Manual Hash Table:** Use manual hash table for counting - O(n + m) time
2. **Array Counting:** Use array for ASCII characters - O(n + m) time, O(1) space
3. **Sorting:** Sort both strings and compare - O(n log n + m log m) time
## Common Pitfalls
1. **Manual Counting:** Using manual hash table instead of Counter.
2. **Complex Logic:** Overcomplicating the frequency comparison.
3. **Wrong Comparison:** Not understanding the subset relationship.
4. **Inefficient Approach:** Using O(n²) approach when Counter suffices.
5. **Character Reuse:** Not considering that each character can only be used once.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/383.ransom-note.py)](../exercises/383.ransom-note.py)
*Note: This is a hash table problem that demonstrates efficient frequency counting and subset checking.*

View File

@@ -0,0 +1,119 @@
# Is Subsequence
[![Problem 392](https://img.shields.io/badge/Problem-392-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/is-subsequence/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/is-subsequence/)
**Problem Number:** [392](https://leetcode.com/problems/is-subsequence/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** String, Two Pointers, Dynamic Programming
**LeetCode Link:** [https://leetcode.com/problems/is-subsequence/](https://leetcode.com/problems/is-subsequence/)
## Problem Description
Given two strings `s` and `t`, return `true` *if* `s` *is a **subsequence** of* `t`*, or* `false` *otherwise*.
A subsequence of a string is a new string that is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (i.e., `"ace"` is a subsequence of `"abcde"` while `"aec"` is not).
**Example 1:**
```
Input: s = "abc", t = "ahbgdc"
Output: true
```
**Example 2:**
```
Input: s = "axc", t = "ahbgdc"
Output: false
```
**Constraints:**
- `0 <= s.length <= 100`
- `0 <= t.length <= 10^4`
- `s` and `t` consist only of lowercase English letters.
**Follow up:** Suppose there are lots of incoming `s`, say `s1, s2, ..., sk` where `k >= 10^9`, and you want to check one by one to see if `t` has its subsequence. In this scenario, how would you change your code?
## My Approach
I used a **Two Pointers** approach to check if s is a subsequence of t. The key insight is to use two pointers to traverse both strings and match characters in order.
**Algorithm:**
1. Initialize two pointers i (for t) and j (for s)
2. While j < len(s):
- If i >= len(t), break (t exhausted)
- If t[i] == s[j], increment j (match found)
- Always increment i
3. Return True if j == len(s) (all characters matched)
## Solution
The solution uses two pointers to efficiently check subsequence relationship. See the implementation in the [solution file](../exercises/392.is-subsequence.py).
**Key Points:**
- Uses two pointers for efficient traversal
- Matches characters in order
- Handles edge cases properly
- Simple and efficient approach
## Time & Space Complexity
**Time Complexity:** O(n)
- Single pass through string t
- Each character is checked at most once
- Total: O(n) where n is length of t
**Space Complexity:** O(1)
- Uses only constant extra space
- No additional data structures needed
## Key Insights
1. **Two Pointers:** Using two pointers allows efficient subsequence checking.
2. **Order Preservation:** Characters must be matched in order.
3. **Greedy Approach:** Always match the first occurrence of each character.
4. **Early Termination:** Can terminate early if t is exhausted.
5. **Edge Cases:** Handles empty strings and single characters.
6. **Follow-up:** Can be optimized for multiple queries using preprocessing.
## Mistakes Made
1. **Wrong Order:** Initially might not preserve character order.
2. **Complex Logic:** Overcomplicating the subsequence check.
3. **Wrong Termination:** Not handling edge cases properly.
4. **Inefficient Approach:** Using O(n²) approach when two pointers suffice.
## Related Problems
- **Longest Common Subsequence** (Problem 1143): Find longest common subsequence
- **Edit Distance** (Problem 72): Calculate edit distance
- **Longest Palindromic Subsequence** (Problem 516): Find longest palindromic subsequence
- **Distinct Subsequences** (Problem 115): Count distinct subsequences
## Alternative Approaches
1. **Dynamic Programming:** Use DP for O(mn) time - O(mn) space
2. **Binary Search:** Use binary search for multiple queries - O(n log n) time
3. **Hash Table:** Use hash table for character positions - O(n) time, O(n) space
## Common Pitfalls
1. **Wrong Order:** Not preserving character order in subsequence.
2. **Complex Logic:** Overcomplicating the subsequence check.
3. **Wrong Termination:** Not handling edge cases properly.
4. **Inefficient Approach:** Using O(n²) approach when two pointers suffice.
5. **Follow-up Challenge:** Not considering optimization for multiple queries.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/392.is-subsequence.py)](../exercises/392.is-subsequence.py)
*Note: This is a two-pointer problem that demonstrates efficient subsequence checking with order preservation.*

View File

@@ -0,0 +1,125 @@
# Big Countries
[![Problem 595](https://img.shields.io/badge/Problem-595-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/big-countries/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/big-countries/)
**Problem Number:** [595](https://leetcode.com/problems/big-countries/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Database, SQL
**LeetCode Link:** [https://leetcode.com/problems/big-countries/](https://leetcode.com/problems/big-countries/)
## Problem Description
A country is **big** if:
- it has an area of at least three million (i.e., `3000000 km²`), or
- it has a population of at least twenty-five million (i.e., `25000000`).
Write a solution to find the name, population, and area of the **big countries**.
Return the result table in **any order**.
**Example:**
```
Input:
World table:
+-------------+-----------+---------+------------+--------------+
| name | continent | area | population | gdp |
+-------------+-----------+---------+------------+--------------+
| Afghanistan | Asia | 652230 | 25500100 | 20343000000 |
| Albania | Europe | 28748 | 2831741 | 12960000000 |
| Algeria | Africa | 2381741 | 37100000 | 188681000000 |
| Andorra | Europe | 468 | 78115 | 3712000000 |
| Angola | Africa | 1246700 | 20609294 | 100990000000 |
+-------------+-----------+---------+------------+--------------+
Output:
+-------------+------------+---------+
| name | population | area |
+-------------+------------+---------+
| Afghanistan | 25500100 | 652230 |
| Algeria | 37100000 | 2381741 |
+-------------+------------+---------+
```
## My Approach
I used a **Simple SQL Query** approach with WHERE clause to filter big countries based on the given criteria. The key insight is to use OR condition to check both area and population thresholds.
**Algorithm:**
1. Select name, population, and area columns
2. Use WHERE clause with OR condition
3. Check if area >= 3000000 OR population >= 25000000
4. Return results in any order
## Solution
The solution uses a simple SQL query with WHERE clause filtering. See the implementation in the [solution file](../exercises/595.big-countries.sql).
**Key Points:**
- Uses SELECT with specific columns
- Applies WHERE clause with OR condition
- Filters based on area and population thresholds
- Returns results in any order
## Time & Space Complexity
**Time Complexity:** O(n)
- Table scan: O(n) where n is number of rows
- WHERE clause evaluation: O(n)
- Total: O(n)
**Space Complexity:** O(k)
- Result set: O(k) where k is number of matching rows
- In worst case: O(n)
## Key Insights
1. **Simple Filtering:** Use WHERE clause with OR condition for multiple criteria.
2. **Column Selection:** Only select required columns (name, population, area).
3. **Threshold Comparison:** Compare area and population against specific thresholds.
4. **OR Logic:** Use OR to include countries that meet either condition.
5. **Order Independence:** Results can be returned in any order.
6. **Efficient Query:** Simple SELECT with WHERE is optimal for this problem.
## Mistakes Made
1. **Wrong Operator:** Initially might use AND instead of OR.
2. **Extra Columns:** Might select unnecessary columns like continent or gdp.
3. **Complex Logic:** Overcomplicating the query with unnecessary joins or subqueries.
4. **Wrong Thresholds:** Not using the correct area and population thresholds.
## Related Problems
- **Classes More Than 5 Students** (Problem 596): SQL filtering with GROUP BY
- **Not Boring Movies** (Problem 620): SQL filtering with conditions
- **Duplicate Emails** (Problem 182): SQL with GROUP BY and HAVING
- **Employees Earning More Than Their Managers** (Problem 181): SQL self-join
## Alternative Approaches
1. **UNION:** Use UNION of two separate queries - O(n) time
2. **CASE Statement:** Use CASE in WHERE clause - O(n) time
3. **Subquery:** Use subquery approach - O(n) time
## Common Pitfalls
1. **Wrong Operator:** Using AND instead of OR for the conditions.
2. **Extra Columns:** Selecting unnecessary columns in the result.
3. **Complex Logic:** Overcomplicating with unnecessary joins or subqueries.
4. **Wrong Thresholds:** Not using the correct area and population thresholds.
5. **Performance:** Not considering index usage for large tables.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/595.big-countries.sql)](../exercises/595.big-countries.sql)
*Note: This is a SQL problem that demonstrates basic filtering with WHERE clause and OR conditions.*

View File

@@ -0,0 +1,120 @@
# Binary Search
[![Problem 704](https://img.shields.io/badge/Problem-704-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/binary-search/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/binary-search/)
**Problem Number:** [704](https://leetcode.com/problems/binary-search/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Binary Search
**LeetCode Link:** [https://leetcode.com/problems/binary-search/](https://leetcode.com/problems/binary-search/)
## Problem Description
Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its index. Otherwise, return `-1`.
You must write an algorithm with `O(log n)` runtime complexity.
**Example 1:**
```
Input: nums = [-1,0,3,5,9,12], target = 9
Output: 4
Explanation: 9 exists in nums and its index is 4
```
**Example 2:**
```
Input: nums = [-1,0,3,5,9,12], target = 2
Output: -1
Explanation: 2 does not exist in nums so return -1
```
**Constraints:**
- `1 <= nums.length <= 10^4`
- `-10^4 < nums[i], target < 10^4`
- All the integers in `nums` are **unique**.
- `nums` is sorted in ascending order.
## My Approach
I used a **Recursive Binary Search** approach to find the target in the sorted array. The key insight is to use divide-and-conquer strategy to reduce search space by half in each iteration.
**Algorithm:**
1. Define recursive function with low and high bounds
2. Base case: if low > high, return -1 (not found)
3. Calculate mid point
4. Check if target is at low, high, or mid
5. If target < nums[mid], search left half
6. If target > nums[mid], search right half
7. Return index if found, -1 otherwise
## Solution
The solution uses recursive binary search to efficiently find target in sorted array. See the implementation in the [solution file](../exercises/704.binary-search.py).
**Key Points:**
- Uses recursive binary search
- Checks boundary conditions first
- Reduces search space by half each iteration
- Returns index or -1 if not found
## Time & Space Complexity
**Time Complexity:** O(log n)
- Each recursive call reduces search space by half
- Total recursive calls: O(log n)
**Space Complexity:** O(log n)
- Recursive call stack depth: O(log n)
- Each call uses constant space
## Key Insights
1. **Divide and Conquer:** Binary search reduces problem size by half each iteration.
2. **Sorted Array:** Binary search requires sorted array for O(log n) complexity.
3. **Boundary Checks:** Check low and high bounds before mid for efficiency.
4. **Recursive Approach:** Recursive implementation is clean and intuitive.
5. **Early Termination:** Can terminate early if target found at boundaries.
6. **Unique Elements:** Problem guarantees unique elements in array.
## Mistakes Made
1. **Wrong Bounds:** Initially might use wrong bounds for recursive calls.
2. **Infinite Recursion:** Not handling base case properly.
3. **Complex Logic:** Overcomplicating the binary search logic.
4. **Wrong Mid Calculation:** Using wrong formula for mid calculation.
## Related Problems
- **Search Insert Position** (Problem 35): Find insertion position
- **Find First and Last Position** (Problem 34): Find range of target
- **Search in Rotated Sorted Array** (Problem 33): Search in rotated array
- **Find Minimum in Rotated Sorted Array** (Problem 153): Find minimum element
## Alternative Approaches
1. **Iterative Binary Search:** Use while loop instead of recursion - O(log n) time, O(1) space
2. **Built-in Binary Search:** Use bisect module - O(log n) time
3. **Linear Search:** Use linear search - O(n) time (not optimal)
## Common Pitfalls
1. **Wrong Bounds:** Using wrong bounds for recursive calls.
2. **Infinite Recursion:** Not handling base case properly.
3. **Complex Logic:** Overcomplicating the binary search logic.
4. **Wrong Mid Calculation:** Using wrong formula for mid calculation.
5. **Overflow:** Not handling integer overflow in mid calculation.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/704.binary-search.py)](../exercises/704.binary-search.py)
*Note: This is a binary search problem that demonstrates efficient divide-and-conquer strategy for searching in sorted arrays.*

View File

@@ -0,0 +1,118 @@
# Find Anagram Mappings
[![Problem 760](https://img.shields.io/badge/Problem-760-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/find-anagram-mappings/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Easy-green?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=EASY)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/find-anagram-mappings/)
**Problem Number:** [760](https://leetcode.com/problems/find-anagram-mappings/)
**Difficulty:** [Easy](https://leetcode.com/problemset/?difficulty=EASY)
**Category:** Array, Hash Table
**LeetCode Link:** [https://leetcode.com/problems/find-anagram-mappings/](https://leetcode.com/problems/find-anagram-mappings/)
## Problem Description
Given two lists `A` and `B`, and `B` is an anagram of `A`. `B` is an anagram of `A` means `B` is made by randomizing the order of the elements in `A`.
We want to find an index mapping `P`, from `A` to `B`. A mapping `P[i] = j` means the `i^th` element in `A` appears in `B` at index `j`.
These lists `A` and `B` may contain duplicates. If there are multiple answers, output any of them.
**Example 1:**
```
Input: A = [12, 28, 46, 32, 50], B = [50, 12, 32, 46, 28]
Output: [1, 4, 3, 2, 0]
Explanation:
As P[0] = 1, the 0th element of A appears at B[1], and P[1] = 4, the 1st element of A appears at B[4], and so on.
```
**Example 2:**
```
Input: A = [12, 28, 46, 32, 50], B = [50, 12, 32, 46, 28]
Output: [1, 4, 3, 2, 0]
```
**Constraints:**
- `A, B` have equal lengths in range `[1, 100]`.
- `A[i], B[i]` are integers in range `[0, 10^5]`.
## My Approach
I used a **Hash Table** approach to create a mapping from elements in B to their indices. The key insight is to build a hash table of B's elements and their positions, then use it to find mappings for A.
**Algorithm:**
1. Create hash table to store elements of B and their indices
2. For each element in B, store its index in hash table
3. For each element in A, find its index in B using hash table
4. Return array of indices
## Solution
The solution uses hash table to efficiently find anagram mappings. See the implementation in the [solution file](../exercises/760.find-anagram-mappings.py).
**Key Points:**
- Uses hash table for O(1) lookup
- Maps elements to their indices in B
- Handles duplicates by using first occurrence
- Simple and efficient approach
## Time & Space Complexity
**Time Complexity:** O(n)
- Building hash table: O(n)
- Finding mappings: O(n)
- Total: O(n)
**Space Complexity:** O(n)
- Hash table stores elements and indices
- Total: O(n)
## Key Insights
1. **Hash Table:** Using hash table provides O(1) lookup for element indices.
2. **Anagram Property:** Since B is anagram of A, all elements exist in both arrays.
3. **Duplicate Handling:** Using first occurrence of each element in B.
4. **Index Mapping:** Each element in A maps to its position in B.
5. **Efficient Lookup:** Hash table allows constant time index lookup.
6. **Simple Logic:** The solution logic is straightforward and efficient.
## Mistakes Made
1. **Wrong Mapping:** Initially might map indices incorrectly.
2. **Complex Logic:** Overcomplicating the mapping creation.
3. **Duplicate Issues:** Not handling duplicates properly.
4. **Inefficient Approach:** Using O(n²) approach when hash table suffices.
## Related Problems
- **Valid Anagram** (Problem 242): Check if strings are anagrams
- **Group Anagrams** (Problem 49): Group strings by anagrams
- **Two Sum** (Problem 1): Find pair with target sum
- **Contains Duplicate** (Problem 217): Check for duplicates
## Alternative Approaches
1. **Linear Search:** Use linear search for each element - O(n²) time
2. **Sorting:** Sort both arrays and find mappings - O(n log n) time
3. **Two Hash Tables:** Use separate hash tables for A and B - O(n) time, O(n) space
## Common Pitfalls
1. **Wrong Mapping:** Mapping indices incorrectly.
2. **Complex Logic:** Overcomplicating the mapping creation.
3. **Duplicate Issues:** Not handling duplicates properly.
4. **Inefficient Approach:** Using O(n²) approach when hash table suffices.
5. **Index Confusion:** Confusing indices between A and B.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/760.find-anagram-mappings.py)](../exercises/760.find-anagram-mappings.py)
*Note: This is a hash table problem that demonstrates efficient index mapping for anagram arrays.*

View File

@@ -0,0 +1,126 @@
# Koko Eating Bananas
[![Problem 875](https://img.shields.io/badge/Problem-875-blue?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/koko-eating-bananas/)
[![Difficulty](https://img.shields.io/badge/Difficulty-Medium-orange?style=for-the-badge)](https://leetcode.com/problemset/?difficulty=MEDIUM)
[![LeetCode](https://img.shields.io/badge/LeetCode-View%20Problem-orange?style=for-the-badge&logo=leetcode)](https://leetcode.com/problems/koko-eating-bananas/)
**Problem Number:** [875](https://leetcode.com/problems/koko-eating-bananas/)
**Difficulty:** [Medium](https://leetcode.com/problemset/?difficulty=MEDIUM)
**Category:** Array, Binary Search
**LeetCode Link:** [https://leetcode.com/problems/koko-eating-bananas/](https://leetcode.com/problems/koko-eating-bananas/)
## Problem Description
Koko loves to eat bananas. There are `n` piles of bananas, the `i^th` pile has `piles[i]` bananas. The guards have gone and will come back in `h` hours.
Koko can decide her bananas-per-hour eating speed of `k`. Each hour, she chooses some pile of bananas and eats `k` bananas from that pile. If the pile has less than `k` bananas, she eats all of them instead and will not eat any more bananas during this hour.
Koko likes to eat slowly but still wants to finish eating all the bananas before the guards come back.
Return *the minimum integer* `k` *such that she can eat all the bananas within* `h` *hours*.
**Example 1:**
```
Input: piles = [3,6,7,11], h = 8
Output: 4
```
**Example 2:**
```
Input: piles = [30,11,23,4,20], h = 5
Output: 30
```
**Example 3:**
```
Input: piles = [30,11,23,4,20], h = 6
Output: 23
```
**Constraints:**
- `1 <= piles.length <= 10^4`
- `piles.length <= h <= 10^9`
- `1 <= piles[i] <= 10^9`
## My Approach
I used a **Binary Search** approach to find the minimum eating speed. The key insight is to search for the minimum speed that allows Koko to finish all bananas within h hours.
**Algorithm:**
1. Define binary search range: [1, max(piles)]
2. For each mid value, calculate total hours needed
3. If hours <= h, search lower half (try smaller speed)
4. If hours > h, search upper half (need larger speed)
5. Return minimum valid speed found
## Solution
The solution uses binary search to efficiently find minimum eating speed. See the implementation in the [solution file](../exercises/875.koko-eating-bananas.py).
**Key Points:**
- Uses binary search on eating speed
- Calculates hours needed for each speed
- Tracks minimum valid speed
- Handles edge cases properly
## Time & Space Complexity
**Time Complexity:** O(n log M)
- Binary search: O(log M) where M is max(piles)
- For each search: O(n) to calculate hours
- Total: O(n log M)
**Space Complexity:** O(1)
- Uses only constant extra space
- No additional data structures needed
## Key Insights
1. **Binary Search:** Search space is eating speed, not array indices.
2. **Monotonic Function:** Higher speed means fewer hours needed.
3. **Ceiling Division:** Use (pile + speed - 1) // speed for ceiling division.
4. **Search Range:** Speed range is [1, max(piles)].
5. **Minimum Speed:** Find minimum speed that satisfies time constraint.
6. **Efficient Calculation:** Calculate total hours for given speed.
## Mistakes Made
1. **Wrong Search Space:** Initially might search wrong range.
2. **Complex Logic:** Overcomplicating the hours calculation.
3. **Wrong Division:** Not using ceiling division for pile calculation.
4. **Inefficient Approach:** Using linear search instead of binary search.
## Related Problems
- **Capacity To Ship Packages** (Problem 1011): Similar binary search problem
- **Split Array Largest Sum** (Problem 410): Binary search on sum
- **Minimum Size Subarray Sum** (Problem 209): Find minimum subarray
- **Search Insert Position** (Problem 35): Binary search variant
## Alternative Approaches
1. **Linear Search:** Try each speed from 1 to max - O(nM) time
2. **Mathematical:** Use mathematical properties to optimize - O(n log M) time
3. **Greedy:** Use greedy approach with binary search - O(n log M) time
## Common Pitfalls
1. **Wrong Search Space:** Searching wrong range for eating speed.
2. **Complex Logic:** Overcomplicating the hours calculation.
3. **Wrong Division:** Not using ceiling division for pile calculation.
4. **Inefficient Approach:** Using linear search instead of binary search.
5. **Edge Cases:** Not handling edge cases properly.
---
[![Back to Index](../../README.md#-problem-index)](../../README.md#-problem-index) | [![View Solution](../exercises/875.koko-eating-bananas.py)](../exercises/875.koko-eating-bananas.py)
*Note: This is a binary search problem that demonstrates efficient optimization search on eating speed.*