From f35b24c32cd8d231c3caae525861865f218e5379 Mon Sep 17 00:00:00 2001 From: ivan Date: Mon, 2 Mar 2026 04:30:18 -0600 Subject: [PATCH] adding algo --- .../common_algos/two_sum_round_2.py | 24 ---- .../common_algos/two_sum_round_3.py | 23 ---- .../common_algos/two_sum_round_4.py | 24 ---- .../common_algos/two_sum_round_5.py | 24 ---- .../common_algos/two_sum_round_6.py | 24 ---- .../common_algos/two_sum_round_7.py | 22 ---- .../common_algos/valid_palindrome_round_2.py | 22 ---- .../common_algos/valid_palindrome_round_3.py | 22 ---- .../common_algos/valid_palindrome_round_4.py | 22 ---- .../common_algos/valid_palindrome_round_5.py | 22 ---- .../common_algos/valid_palindrome_round_6.py | 22 ---- .../common_algos/valid_palindrome_round_7.py | 22 ---- .../ex_91_minimum_genetic_mutation.py | 52 ++++++++ .../ex_90_snakes_and_ladders.ts | 29 +---- .../ex_91_minimum_genetic_mutation.ts | 58 +++++++++ ...st_91_minimum_genetic_mutation_round_22.py | 123 ++++++++++++++++++ 16 files changed, 234 insertions(+), 301 deletions(-) delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_2.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_3.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_4.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_5.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_6.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_7.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_2.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_3.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_4.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_5.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_6.py delete mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_7.py create mode 100644 src/my_project/interviews/top_150_questions_round_22/ex_91_minimum_genetic_mutation.py create mode 100644 src/my_project/interviews_typescript/top_150_questions_round_1/ex_91_minimum_genetic_mutation.ts create mode 100644 tests/test_150_questions_round_22/test_91_minimum_genetic_mutation_round_22.py diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_2.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_2.py deleted file mode 100644 index ad708f40..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_2.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod - -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - - answer = dict() - - for k, v in enumerate(nums): - - if v in answer: - return [answer[v], k] - else: - answer[target - v] = k - - return [] - - - - - - - - diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_3.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_3.py deleted file mode 100644 index 2fa397c1..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_3.py +++ /dev/null @@ -1,23 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod - -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - - answer = dict() - - for k, v in enumerate(nums): - - if v in answer: - return [answer[v], k] - else: - answer[target - v] = k - - return [] - - - - - - - diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_4.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_4.py deleted file mode 100644 index abd69b23..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_4.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod - -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - - answer = dict() - - for k, v in enumerate(nums): - - if v in answer: - return [answer[v], k] - else: - answer[target - v] = k - - return [] - - - - - - - - diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_5.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_5.py deleted file mode 100644 index 7cef88a4..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_5.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod - -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - - answer = dict() - - for k, v in enumerate(nums): - - if v in answer: - return [answer[v], k] - else: - answer[target - v] = k - - return [] - - - - - - - - diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_6.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_6.py deleted file mode 100644 index 7cef88a4..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_6.py +++ /dev/null @@ -1,24 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod - -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - - answer = dict() - - for k, v in enumerate(nums): - - if v in answer: - return [answer[v], k] - else: - answer[target - v] = k - - return [] - - - - - - - - diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_7.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_7.py deleted file mode 100644 index f0ed2bb2..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_7.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod - -class Solution: - def twoSum(self, nums: List[int], target: int) -> List[int]: - - answer = dict() - - for k, v in enumerate(nums): - - if v in answer: - return [answer[v], k] - else: - answer[target - v] = k - - return [] - - - - - - diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_2.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_2.py deleted file mode 100644 index 854c89ac..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_2.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod -import re - -class Solution: - def isPalindrome(self, s: str) -> bool: - - # To lowercase - s = s.lower() - - # Remove non-alphanumeric characters - s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s) - - # Determine if s is palindrome or not - len_s = len(s) - - for i in range(len_s//2): - - if s[i] != s[len_s - 1 - i]: - return False - - return True \ No newline at end of file diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_3.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_3.py deleted file mode 100644 index cad2b1e6..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_3.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod -import re - -class Solution: - def isPalindrome(self, s: str) -> bool: - - # To lowercase - s = s.lower() - - # Remove non-alphanumeric characters - s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s) - - # Determine if s is palindrome or not - len_s = len(s) - - for i in range(len_s//2): - - if s[i] != s[len_s - 1 - i]: - return False - - return True \ No newline at end of file diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_4.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_4.py deleted file mode 100644 index 67993077..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_4.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod -import re - -class Solution: - def isPalindrome(self, s: str) -> bool: - - # To lowercase - s = s.lower() - - # Remove non-alphanumeric characters - s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s) - - # Determine if s is palindrome or not - len_s = len(s) - - for i in range(len_s//2): - - if s[i] != s[len_s - 1 - i]: - return False - - return True \ No newline at end of file diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_5.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_5.py deleted file mode 100644 index 854c89ac..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_5.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod -import re - -class Solution: - def isPalindrome(self, s: str) -> bool: - - # To lowercase - s = s.lower() - - # Remove non-alphanumeric characters - s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s) - - # Determine if s is palindrome or not - len_s = len(s) - - for i in range(len_s//2): - - if s[i] != s[len_s - 1 - i]: - return False - - return True \ No newline at end of file diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_6.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_6.py deleted file mode 100644 index 67993077..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_6.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod -import re - -class Solution: - def isPalindrome(self, s: str) -> bool: - - # To lowercase - s = s.lower() - - # Remove non-alphanumeric characters - s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s) - - # Determine if s is palindrome or not - len_s = len(s) - - for i in range(len_s//2): - - if s[i] != s[len_s - 1 - i]: - return False - - return True \ No newline at end of file diff --git a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_7.py b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_7.py deleted file mode 100644 index db19456c..00000000 --- a/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_7.py +++ /dev/null @@ -1,22 +0,0 @@ -from typing import List, Union, Collection, Mapping, Optional -from abc import ABC, abstractmethod -import re - -class Solution: - def isPalindrome(self, s: str) -> bool: - - # To lowercase - s = s.lower() - - # Remove non-alphanumeric characters - s = re.sub(pattern=r'[^a-zA-Z0-9]', repl='', string=s) - - # Determine if s is palindrome or not - len_s = len(s) - - for i in range(len_s//2): - - if s[i] != s[len_s - 1 - i]: - return False - - return True \ No newline at end of file diff --git a/src/my_project/interviews/top_150_questions_round_22/ex_91_minimum_genetic_mutation.py b/src/my_project/interviews/top_150_questions_round_22/ex_91_minimum_genetic_mutation.py new file mode 100644 index 00000000..cf1c0722 --- /dev/null +++ b/src/my_project/interviews/top_150_questions_round_22/ex_91_minimum_genetic_mutation.py @@ -0,0 +1,52 @@ +from typing import List, Union, Collection, Mapping, Optional +from abc import ABC, abstractmethod +from collections import deque, defaultdict + +class Solution: + def minMutation(self, startGene: str, endGene: str, bank: List[str]) -> int: + """ + Find minimum number of mutations from startGene to endGene. + Uses BFS to find shortest path. Each mutation changes one character, + and the resulting gene must be in the bank. + + Time Complexity: O(N * L * 4) where N is bank size, L is gene length (8) + Space Complexity: O(N) for visited set and queue + """ + # If endGene is not in bank, it's impossible + if endGene not in bank: + return -1 + + # Convert bank to set for O(1) lookup + bank_set = set(bank) + + # BFS queue: (current_gene, mutation_count) + queue = deque([(startGene, 0)]) + visited = {startGene} + + # Possible gene characters + genes = ['A', 'C', 'G', 'T'] + + while queue: + current_gene, mutations = queue.popleft() + + # If we reached the end gene, return the mutation count + if current_gene == endGene: + return mutations + + # Try all possible single character mutations + for i in range(len(current_gene)): + for gene_char in genes: + # Skip if same character + if gene_char == current_gene[i]: + continue + + # Create mutated gene + mutated = current_gene[:i] + gene_char + current_gene[i+1:] + + # If mutation is valid and not visited + if mutated in bank_set and mutated not in visited: + visited.add(mutated) + queue.append((mutated, mutations + 1)) + + # No path found + return -1 \ No newline at end of file diff --git a/src/my_project/interviews_typescript/top_150_questions_round_1/ex_90_snakes_and_ladders.ts b/src/my_project/interviews_typescript/top_150_questions_round_1/ex_90_snakes_and_ladders.ts index 26d0d0dd..b86aabe8 100644 --- a/src/my_project/interviews_typescript/top_150_questions_round_1/ex_90_snakes_and_ladders.ts +++ b/src/my_project/interviews_typescript/top_150_questions_round_1/ex_90_snakes_and_ladders.ts @@ -60,31 +60,4 @@ function snakesAndLadders(board: number[][]): number { // If we can't reach the target return -1; -} - -// Test cases -console.log("Example 1:"); -const board1 = [ - [-1,-1,-1,-1,-1,-1], - [-1,-1,-1,-1,-1,-1], - [-1,-1,-1,-1,-1,-1], - [-1,35,-1,-1,13,-1], - [-1,-1,-1,-1,-1,-1], - [-1,15,-1,-1,-1,-1] -]; -console.log(`Input: board = ${JSON.stringify(board1)}`); -console.log(`Output: ${snakesAndLadders(board1)}`); // Expected: 4 -console.log(`Explanation: In the beginning, you start at square 1 (at row 5, column 0). -You decide to move to square 2 and must take the ladder to square 15. -You then decide to move to square 17 and must take the snake to square 13. -You then decide to move to square 14 and must take the ladder to square 35. -You then decide to move to square 36, ending the game. -This is the lowest possible number of moves to reach the last square, so return 4.`); - -console.log("\nExample 2:"); -const board2 = [[-1,-1],[-1,3]]; -console.log(`Input: board = ${JSON.stringify(board2)}`); -console.log(`Output: ${snakesAndLadders(board2)}`); // Expected: 1 - -export { snakesAndLadders }; - +} \ No newline at end of file diff --git a/src/my_project/interviews_typescript/top_150_questions_round_1/ex_91_minimum_genetic_mutation.ts b/src/my_project/interviews_typescript/top_150_questions_round_1/ex_91_minimum_genetic_mutation.ts new file mode 100644 index 00000000..81f756cc --- /dev/null +++ b/src/my_project/interviews_typescript/top_150_questions_round_1/ex_91_minimum_genetic_mutation.ts @@ -0,0 +1,58 @@ +/** + * 433. Minimum Genetic Mutation + * + * A gene string can be represented by an 8-character long string, with choices from 'A', 'C', 'G', and 'T'. + * Find the minimum number of mutations needed to mutate from startGene to endGene. + * Each mutation changes one single character, and the resulting gene must be in the bank. + * + * Time Complexity: O(N * L * 4) where N is bank size, L is gene length (8) + * Space Complexity: O(N) for visited set and queue + */ + +function minMutation(startGene: string, endGene: string, bank: string[]): number { + // If endGene is not in bank, it's impossible + if (!bank.includes(endGene)) { + return -1; + } + + // Convert bank to set for O(1) lookup + const bankSet = new Set(bank); + + // BFS queue: [current_gene, mutation_count] + const queue: [string, number][] = [[startGene, 0]]; + const visited = new Set([startGene]); + + // Possible gene characters + const genes = ['A', 'C', 'G', 'T']; + + while (queue.length > 0) { + const [currentGene, mutations] = queue.shift()!; + + // If we reached the end gene, return the mutation count + if (currentGene === endGene) { + return mutations; + } + + // Try all possible single character mutations + for (let i = 0; i < currentGene.length; i++) { + for (const geneChar of genes) { + // Skip if same character + if (geneChar === currentGene[i]) { + continue; + } + + // Create mutated gene + const mutated = currentGene.substring(0, i) + geneChar + currentGene.substring(i + 1); + + // If mutation is valid and not visited + if (bankSet.has(mutated) && !visited.has(mutated)) { + visited.add(mutated); + queue.push([mutated, mutations + 1]); + } + } + } + } + + // No path found + return -1; +} \ No newline at end of file diff --git a/tests/test_150_questions_round_22/test_91_minimum_genetic_mutation_round_22.py b/tests/test_150_questions_round_22/test_91_minimum_genetic_mutation_round_22.py new file mode 100644 index 00000000..287f4edb --- /dev/null +++ b/tests/test_150_questions_round_22/test_91_minimum_genetic_mutation_round_22.py @@ -0,0 +1,123 @@ +import unittest +from src.my_project.interviews.top_150_questions_round_22\ + .ex_91_minimum_genetic_mutation import Solution +from typing import Optional, List + + +class MinimumGeneticMutationTestCase(unittest.TestCase): + + def test_example_1(self): + """ + Example 1: + Input: startGene = "AACCGGTT", endGene = "AACCGGTA", bank = ["AACCGGTA"] + Output: 1 + Explanation: One mutation from "AACCGGTT" to "AACCGGTA". + """ + solution = Solution() + startGene = "AACCGGTT" + endGene = "AACCGGTA" + bank = ["AACCGGTA"] + expected = 1 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + def test_example_2(self): + """ + Example 2: + Input: startGene = "AACCGGTT", endGene = "AAACGGTA", + bank = ["AACCGGTA","AACCGCTA","AAACGGTA"] + Output: 2 + Explanation: + "AACCGGTT" -> "AACCGGTA" -> "AAACGGTA" + """ + solution = Solution() + startGene = "AACCGGTT" + endGene = "AAACGGTA" + bank = ["AACCGGTA", "AACCGCTA", "AAACGGTA"] + expected = 2 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + def test_no_mutation_possible(self): + """ + Test case where endGene is not in bank. + Input: startGene = "AACCGGTT", endGene = "AAACGGTA", bank = ["AACCGGTA"] + Output: -1 + Explanation: endGene is not in the bank, so mutation is impossible. + """ + solution = Solution() + startGene = "AACCGGTT" + endGene = "AAACGGTA" + bank = ["AACCGGTA"] + expected = -1 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + def test_start_equals_end(self): + """ + Test case where start and end are the same. + Input: startGene = "AACCGGTT", endGene = "AACCGGTT", bank = ["AACCGGTT"] + Output: 0 + Explanation: No mutation needed as start equals end. + """ + solution = Solution() + startGene = "AACCGGTT" + endGene = "AACCGGTT" + bank = ["AACCGGTT"] + expected = 0 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + def test_empty_bank(self): + """ + Test case with empty bank. + Input: startGene = "AACCGGTT", endGene = "AACCGGTA", bank = [] + Output: -1 + Explanation: Bank is empty, so no valid mutations possible. + """ + solution = Solution() + startGene = "AACCGGTT" + endGene = "AACCGGTA" + bank = [] + expected = -1 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + def test_longer_path(self): + """ + Test case with a longer mutation path. + Input: startGene = "AAAAACCC", endGene = "AACCCCCC", + bank = ["AAAACCCC","AAACCCCC","AACCCCCC"] + Output: 3 + """ + solution = Solution() + startGene = "AAAAACCC" + endGene = "AACCCCCC" + bank = ["AAAACCCC", "AAACCCCC", "AACCCCCC"] + expected = 3 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + def test_multiple_paths(self): + """ + Test case with multiple possible paths (BFS should find shortest). + """ + solution = Solution() + startGene = "AACCGGTT" + endGene = "AAACGGTA" + bank = ["AACCGGTA", "AACCGCTA", "AAACGGTA", "AACCGCTT", "AAACGCTA"] + # Shortest path: AACCGGTT -> AACCGGTA -> AAACGGTA (2 mutations) + expected = 2 + + result = solution.minMutation(startGene, endGene, bank) + self.assertEqual(result, expected) + + +if __name__ == '__main__': + unittest.main()