├── .gitignore ├── 0005. Longest Palindromic Substring ├── go.mod └── manachers.go ├── README.md ├── 0226. Invert Binary Tree └── Approach 1: Recursion ├── 0001. Two Sum ├── Approach 3: One-pass Hash Table └── Approach 1: Brute Force ├── 0014. Longest Common Prefix └── Approach 2: Vertical scanning ├── 0027. Remove Element └── Approach 2: Two Pointers ├── 0009. Palindrome Number └── Approach 1: Revert half of the number ├── 0013. Roman to Integer └── Approach 1: Lookahead ├── _def └── TreeNode.cr ├── 0104. Maximum Depth of Binary Tree └── Approach 1: Recursion ├── 0004. Median of Two Sorted Arrays └── Approach 1: Binary Search ├── LICENSE ├── 0020. Valid Parentheses └── Approach 1: Two-pointers ├── 0003. Longest Substring Without Repeating Characters └── Approach 1: Brute Force └── 0002. Add Two Numbers └── Approach 1: Elementary Math /.gitignore: -------------------------------------------------------------------------------- 1 | /eclectic-leetcode.code-workspace 2 | -------------------------------------------------------------------------------- /0005. Longest Palindromic Substring/go.mod: -------------------------------------------------------------------------------- 1 | module approach 2 | 3 | go 1.17 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Links to get started: 2 | - LeetCode: 3 | - https://leetcode.com/problemset/all/ 4 | - Cup ☕ 5 | - https://github.com/cup-lang 6 | - https://cup-lang.org/ 7 | - Crystal 🔮 8 | - https://github.com/crystal-lang/crystal#crystal 9 | - https://crystal-lang.org/reference/1.2/ 10 | -------------------------------------------------------------------------------- /0226. Invert Binary Tree/Approach 1: Recursion: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/invert-binary-tree/ <> 3 | # .............................................................................. 4 | require "../_def/TreeNode.cr" 5 | 6 | def invert_tree(root) 7 | root.left, root.right = invert_tree(root.right), invert_tree(root.left) if root 8 | root 9 | end 10 | # .............................................................................. 11 | p! invert_tree(TreeNode[4,2,7,1,3,6,9]) 12 | p! invert_tree(TreeNode[2,1,3]) 13 | p! invert_tree(TreeNode[]) 14 | -------------------------------------------------------------------------------- /0001. Two Sum/Approach 3: One-pass Hash Table: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/two-sum/ <> 3 | # .............................................................................. 4 | def two_sum(nums, target) 5 | compliment_indices = {} of Int32 => Int32 6 | 7 | nums.each_with_index do |num, index| 8 | if compliment_indices.has_key?(num) 9 | return compliment_indices[num], index 10 | end 11 | 12 | compliment_indices[target - num] = index 13 | end 14 | end 15 | # .............................................................................. 16 | p! two_sum([2, 7, 11, 15], 9) 17 | p! two_sum([3, 2, 4], 6) 18 | p! two_sum([3, 3], 6) 19 | -------------------------------------------------------------------------------- /0005. Longest Palindromic Substring/manachers.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func main() { 8 | fmt.Println(longestPalindrome("babad")) 9 | fmt.Println(longestPalindrome("cbbd")) 10 | } 11 | 12 | func longestPalindrome(s string) (z string) { 13 | z = s[0:1] 14 | for i := 0; i < len(s); i++ { 15 | indices := [2][2]int{{0, 1}, {0, 0}} 16 | for n := 0; n < len(indices); n++ { 17 | h, l := indices[n][0], indices[n][1] 18 | for { 19 | j, k := i-h, i+l 20 | if j < 0 || k >= len(s) { 21 | break 22 | } 23 | a, b := s[j], s[k] 24 | if a != b { 25 | break 26 | } 27 | q := s[j : k+1] 28 | if len(q) > len(z) { 29 | z = q 30 | } 31 | h++ 32 | l++ 33 | } 34 | } 35 | } 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /0001. Two Sum/Approach 1: Brute Force: -------------------------------------------------------------------------------- 1 | sub main () { 2 | arr nums = arr:new_with_len(4); 3 | nums[0] = 2; 4 | nums[1] = 7; 5 | nums[2] = 11; 6 | nums[3] = 15; 7 | 8 | u8 target = 9; 9 | 10 | arr result = two_sum(nums, target); 11 | 12 | for i = 0, i < result.len, i += 1 { 13 | fmt:print("%i\n", result[i]); 14 | }; 15 | }; 16 | 17 | arr two_sum(arr nums, u8 target) { 18 | arr indices = arr:new_with_len(2); 19 | 20 | for i = 0, i < nums.len, i += 1 { 21 | for j = i, j < nums.len, j += 1 { 22 | if nums[i] + nums[j] == target { 23 | indices[0] = i; 24 | indices[1] = j; 25 | 26 | ret indices; 27 | }; 28 | }; 29 | }; 30 | }; 31 | 32 | #bind("printf") sub fmt:print (); 33 | -------------------------------------------------------------------------------- /0014. Longest Common Prefix/Approach 2: Vertical scanning: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/longest-common-prefix/ <> 3 | # .............................................................................. 4 | def longest_common_prefix(strs) 5 | i = 0 6 | c = strs[0][0] 7 | loop do 8 | i += 1 9 | break if i == strs.size 10 | return "" if c != strs[i][0] 11 | end 12 | 13 | j = 1 14 | loop do 15 | i = 0 16 | c = strs[0][j] 17 | return strs[0][...j] if c.nil? 18 | loop do 19 | i += 1 20 | break if i == strs.size 21 | return strs[0][...j] if c != strs[i][j] 22 | end 23 | j += 1 24 | end 25 | end 26 | # .............................................................................. 27 | p! longest_common_prefix ["flower","flow","flight"] 28 | p! longest_common_prefix ["dog","racecar","car"] 29 | -------------------------------------------------------------------------------- /0027. Remove Element/Approach 2: Two Pointers: -------------------------------------------------------------------------------- 1 | sub main() { 2 | arr nums = arr:new_with_len(4); 3 | nums[0] = 3; 4 | nums[1] = 2; 5 | nums[2] = 2; 6 | nums[3] = 3; 7 | 8 | u8 val = 3; 9 | 10 | u8 k = remove_element(nums, val); 11 | fmt:print("k:%i\n", k); 12 | 13 | for i = 0, i < k, i += 1 { 14 | fmt:print("%i\n", nums[i]); 15 | }; 16 | }; 17 | 18 | u8 remove_element(arr nums, u8 val) { 19 | u8 i = 0; 20 | u8 j = nums.len; 21 | while true { 22 | u8 k = j; 23 | 24 | if i == k { 25 | ret k; 26 | }; 27 | 28 | if nums[i] == val { 29 | j -= 1; 30 | u8 swp = nums[i]; 31 | nums[i] = nums[j]; 32 | nums[j] = swp; 33 | } else { 34 | i += 1; 35 | }; 36 | } 37 | }; 38 | 39 | #bind("printf") sub fmt:print (); 40 | -------------------------------------------------------------------------------- /0009. Palindrome Number/Approach 1: Revert half of the number: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/palindrome-number/ <> 3 | # .............................................................................. 4 | def is_palindrome(x) 5 | return false if x < 0 6 | return true if -1 < x && x < 10 7 | 8 | size = (Math.log10(x.abs) + 1).to_i 9 | 10 | if size.odd? 11 | right_index = (size // 2) + 1 12 | 13 | left_index = right_index - 2 14 | else 15 | right_index = (size // 2) 16 | left_index = right_index - 1 17 | end 18 | 19 | (0..left_index).each do |offset| 20 | if x // (10**(left_index - offset)) % 10 != x // (10**(right_index + offset)) % 10 21 | return false 22 | end 23 | end 24 | 25 | return true 26 | end 27 | # .............................................................................. 28 | p! is_palindrome(121) 29 | p! is_palindrome(-121) 30 | p! is_palindrome(10) 31 | -------------------------------------------------------------------------------- /0013. Roman to Integer/Approach 1: Lookahead: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/roman-to-integer/ <> 3 | # .............................................................................. 4 | SYMBOLS = ['I', 'V', 'X', 'L', 'C', 'D', 'M'] 5 | VALUES = [ 1, 5, 10, 50, 100, 500, 1000] 6 | MAP = SYMBOLS.zip(VALUES).to_h 7 | 8 | def roman_to_int(s) 9 | int = 0 10 | 11 | i = 0 12 | loop do 13 | c = s[i] 14 | i += 1 15 | 16 | if i < s.size && ( 17 | d = s[i] 18 | k = SYMBOLS.index(c).not_nil! + 1 19 | d == (SYMBOLS[k] if k < SYMBOLS.size) || 20 | d == (SYMBOLS[k+1] if k+1 < SYMBOLS.size) 21 | ) 22 | int += MAP[d] - MAP[c] 23 | i += 1 24 | else 25 | int += MAP[c] 26 | end 27 | 28 | return int if i == s.size 29 | end 30 | end 31 | # .............................................................................. 32 | p! roman_to_int("III") 33 | p! roman_to_int("LVIII") 34 | p! roman_to_int("MCMXCIV") 35 | -------------------------------------------------------------------------------- /_def/TreeNode.cr: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # REQ: Defines the TreeNode class for tree problems. 3 | # .............................................................................. 4 | class TreeNode 5 | property value : Int32? 6 | property left : TreeNode? 7 | property right : TreeNode? 8 | 9 | def initialize(values : Array(Int32?)) 10 | return if values.size == 0 11 | @value = values[0] 12 | return if values.size == 1 13 | 14 | left_values = [values[1]] 15 | right_values = [values[2]] 16 | values[3..].each_with_index do |value, index| 17 | sub_index = index % 4 18 | 19 | if [0,1].includes?(sub_index) 20 | left_values.push(value) 21 | else 22 | right_values.push(value) 23 | end 24 | end 25 | 26 | @left = TreeNode.new(left_values) 27 | @right = TreeNode.new(right_values) 28 | end 29 | 30 | def self.[](*values) 31 | self.new(values.to_a) 32 | end 33 | 34 | def self.[] 35 | self.new([] of Int32) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /0104. Maximum Depth of Binary Tree/Approach 1: Recursion: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/maximum-depth-of-binary-tree/ <> 3 | # .............................................................................. 4 | require "../_def/TreeNode.cr" 5 | 6 | def max_depth(root) 7 | return root.nil? ? 0 : _max_depth(root, 1) 8 | end 9 | 10 | def _max_depth(node, node_depth) 11 | leaf_depth = node_depth + 1 12 | 13 | if node.left.nil? 14 | if node.right.nil? 15 | return node_depth 16 | else 17 | return _max_depth(node.right.not_nil!, leaf_depth) 18 | end 19 | 20 | elsif node.right.nil? 21 | 22 | return _max_depth(node.left.not_nil!, leaf_depth) 23 | 24 | else 25 | return [ 26 | _max_depth(node.left.not_nil!, leaf_depth), 27 | _max_depth(node.right.not_nil!, leaf_depth) 28 | ].max 29 | end 30 | end 31 | # .............................................................................. 32 | p! max_depth TreeNode[3,9,20,nil,nil,15,7] 33 | p! max_depth TreeNode[1,nil,2] 34 | -------------------------------------------------------------------------------- /0004. Median of Two Sorted Arrays/Approach 1: Binary Search: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/median-of-two-sorted-arrays/ <> 3 | # .............................................................................. 4 | def find_median_sorted_arrays(nums1, nums2) 5 | nums1, nums2 = nums2, nums1 if nums1.size > nums2.size 6 | 7 | size = nums1.size + nums2.size 8 | half = size // 2 9 | 10 | l, u = 0, nums1.size 11 | loop do 12 | j = (l + u) // 2 13 | i = j - 1 14 | 15 | k = half - j 16 | h = k - 1 17 | 18 | a = i > -1 ? nums1[i] : Int32::MIN 19 | b = j < nums1.size ? nums1[j] : Int32::MAX 20 | c = h > -1 ? nums2[h] : Int32::MIN 21 | d = k < nums2.size ? nums2[k] : Int32::MAX 22 | 23 | if a <= d 24 | if b >= c 25 | if size.odd? 26 | return [b, d].min.to_f 27 | else 28 | return ([a, c].max + [b, d].min).to_f / 2 29 | end 30 | end 31 | l = j + 1 32 | else 33 | u = j 34 | end 35 | end 36 | end 37 | # .............................................................................. 38 | p! find_median_sorted_arrays([1, 3], [2]) 39 | p! find_median_sorted_arrays([1, 2], [3, 4]) 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /0020. Valid Parentheses/Approach 1: Two-pointers: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/valid-parentheses/ <> 3 | # .............................................................................. 4 | def is_valid(s) 5 | return false if s.size.odd? 6 | 7 | l_index = 0 8 | r_index = -1 9 | 10 | o_brackets = Set{'{','(','['} 11 | c_brackets = Set{'}', ')', ']'} 12 | 13 | o_map = c_brackets.zip(o_brackets).to_h 14 | c_map = o_brackets.zip(c_brackets).to_h 15 | 16 | o_stack = [] of Char 17 | c_stack = [] of Char 18 | 19 | (0...(s.size/2)).each do |offset| 20 | 21 | l_value = s[l_index + offset] 22 | if o_brackets.includes?(l_value) 23 | o_stack.push(l_value) 24 | else 25 | return false unless o_stack.pop == o_map[l_value] 26 | end 27 | 28 | r_value = s[r_index - offset] 29 | if c_brackets.includes?(r_value) 30 | c_stack.push(r_value) 31 | else 32 | return false unless c_stack.pop == c_map[r_value] 33 | end 34 | end 35 | 36 | return false unless o_stack.size == c_stack.size 37 | 38 | (0...o_stack.size).each do |index| 39 | return false unless c_map[o_stack.pop] == c_stack.pop 40 | end 41 | 42 | return true 43 | end 44 | # .............................................................................. 45 | p! is_valid("()") 46 | p! is_valid("()[]{}") 47 | p! is_valid("(]") 48 | -------------------------------------------------------------------------------- /0003. Longest Substring Without Repeating Characters/Approach 1: Brute Force: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/longest-substring-without-repeating-characters/ <> 3 | # .............................................................................. 4 | def length_of_longest_substring(s) 5 | return 0 if s.empty? 6 | 7 | longest_charset = [] of Char 8 | 9 | char_indices = {} of Char => Int32 10 | index = 0 11 | loop do 12 | char = s[index] 13 | 14 | if char_indices.has_key?(char) 15 | handle_charset!(char_indices, longest_charset) 16 | 17 | index = char_indices[char] + 1 18 | char_indices = {} of Char => Int32 19 | 20 | next 21 | end 22 | 23 | char_indices[char] = index 24 | index += 1 25 | 26 | if index >= s.size 27 | handle_charset!(char_indices, longest_charset) 28 | break 29 | end 30 | end 31 | 32 | return longest_charset.size 33 | end 34 | 35 | def handle_charset!(char_indices, longest_charset) 36 | charset = char_indices.keys 37 | 38 | if charset.size > longest_charset.size 39 | longest_charset.clear 40 | 41 | index = 0 42 | loop do 43 | longest_charset << charset[index] 44 | 45 | index += 1 46 | break if index >= charset.size 47 | end 48 | end 49 | end 50 | # .............................................................................. 51 | p! length_of_longest_substring("abcabcbb") 52 | p! length_of_longest_substring("bbbbb") 53 | p! length_of_longest_substring("pwwkew") 54 | -------------------------------------------------------------------------------- /0002. Add Two Numbers/Approach 1: Elementary Math: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env crystal 2 | # SEE: https://leetcode.com/problems/add-two-numbers/ <> 3 | # .............................................................................. 4 | class ListNode 5 | property val : Int32 6 | property next : ListNode? 7 | 8 | def initialize(val, _next = nil) 9 | @val = val 10 | @next = _next 11 | end 12 | end 13 | 14 | def make_list(digits) 15 | node = ListNode.new(digits[-1]) 16 | index = -2 17 | 18 | while index >= -digits.size 19 | node = ListNode.new(digits[index], node) 20 | index -= 1 21 | end 22 | 23 | return node 24 | end 25 | 26 | def add_two_numbers(l1, l2) 27 | result = [0] 28 | 29 | l1_node = make_list(l1) 30 | l2_node = make_list(l2) 31 | 32 | loop do 33 | sum = l1_node.val + l2_node.val 34 | 35 | carry!(result) if sum > 9 36 | result.unshift(sum % 10) 37 | 38 | l1_node = l1_node.next 39 | l2_node = l2_node.next 40 | 41 | if l1_node.nil? 42 | if l2_node.nil? 43 | break 44 | else 45 | loop do 46 | result.unshift(l2_node.val) 47 | 48 | l2_node = l2_node.next 49 | break if l2_node.nil? 50 | end 51 | 52 | break 53 | end 54 | elsif l2_node.nil? 55 | loop do 56 | result.unshift(l1_node.val) 57 | 58 | l1_node = l1_node.next 59 | break if l1_node.nil? 60 | end 61 | 62 | break 63 | end 64 | end 65 | 66 | if result[-1] == 0 67 | result = result[0..-2] 68 | end 69 | 70 | return result 71 | end 72 | 73 | def carry!(result, index = 0) 74 | if result[index] == 9 75 | result[index] = 0 76 | carry!(result, index + 1) 77 | end 78 | 79 | result[index] += 1 80 | end 81 | 82 | # .............................................................................. 83 | p! add_two_numbers([2, 4, 3], [5, 6, 4]) 84 | p! add_two_numbers([0], [0]) 85 | p! add_two_numbers([9, 9, 9, 9, 9, 9, 9], [9, 9, 9, 9]) 86 | --------------------------------------------------------------------------------