From 29fcbffb58eb324057d252b3e4e3b6574557a8d1 Mon Sep 17 00:00:00 2001 From: ivan Date: Tue, 24 Feb 2026 04:35:41 -0600 Subject: [PATCH] adding algo --- .../common_algos/two_sum_round_2.py | 24 +++ .../common_algos/valid_palindrome_round_2.py | 22 +++ .../ex_86_clone_graph.py | 41 +++++ .../ex_86_clone_graph.ts | 43 +++++ .../test_86_clone_graph_round_22.py | 165 ++++++++++++++++++ 5 files changed, 295 insertions(+) create mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_2.py create mode 100644 src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_2.py create mode 100644 src/my_project/interviews/top_150_questions_round_22/ex_86_clone_graph.py create mode 100644 src/my_project/interviews_typescript/top_150_questions_round_1/ex_86_clone_graph.ts create mode 100644 tests/test_150_questions_round_22/test_86_clone_graph_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 new file mode 100644 index 00000000..ad708f40 --- /dev/null +++ b/src/my_project/interviews/amazon_high_frequency_23/common_algos/two_sum_round_2.py @@ -0,0 +1,24 @@ +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 new file mode 100644 index 00000000..854c89ac --- /dev/null +++ b/src/my_project/interviews/amazon_high_frequency_23/common_algos/valid_palindrome_round_2.py @@ -0,0 +1,22 @@ +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_86_clone_graph.py b/src/my_project/interviews/top_150_questions_round_22/ex_86_clone_graph.py new file mode 100644 index 00000000..59b37794 --- /dev/null +++ b/src/my_project/interviews/top_150_questions_round_22/ex_86_clone_graph.py @@ -0,0 +1,41 @@ +from typing import List, Union, Collection, Mapping, Optional +from abc import ABC, abstractmethod +from collections import deque + + +# Definition for a Node. +class Node: + def __init__(self, val = 0, neighbors = None): + self.val = val + self.neighbors = neighbors if neighbors is not None else [] + + +class Solution: + def cloneGraph(self, node: Optional['Node']) -> Optional['Node']: + if not node: + return None + + # HashMap to store original node -> cloned node mapping + old_to_new = {} + + # BFS approach + queue = deque([node]) + old_to_new[node] = Node(node.val) + + while queue: + curr = queue.popleft() + + # Process all neighbors + for neighbor in curr.neighbors: + # If neighbor hasn't been cloned yet + if neighbor not in old_to_new: + # Clone the neighbor + old_to_new[neighbor] = Node(neighbor.val) + # Add to queue for processing + queue.append(neighbor) + + # Add the cloned neighbor to the current cloned node's neighbors + old_to_new[curr].neighbors.append(old_to_new[neighbor]) + + return old_to_new[node] + \ No newline at end of file diff --git a/src/my_project/interviews_typescript/top_150_questions_round_1/ex_86_clone_graph.ts b/src/my_project/interviews_typescript/top_150_questions_round_1/ex_86_clone_graph.ts new file mode 100644 index 00000000..75293ef6 --- /dev/null +++ b/src/my_project/interviews_typescript/top_150_questions_round_1/ex_86_clone_graph.ts @@ -0,0 +1,43 @@ +class _Node { + val: number + neighbors: _Node[] + + constructor(val?: number, neighbors?: _Node[]) { + this.val = (val===undefined ? 0 : val) + this.neighbors = (neighbors===undefined ? [] : neighbors) + } +} + +function cloneGraph(node: _Node | null): _Node | null { + if (!node) { + return null; + } + + // HashMap to store original node -> cloned node mapping + const oldToNew = new Map<_Node, _Node>(); + + // BFS approach + const queue: _Node[] = [node]; + oldToNew.set(node, new _Node(node.val)); + + while (queue.length > 0) { + const curr = queue.shift()!; + + // Process all neighbors + for (const neighbor of curr.neighbors) { + // If neighbor hasn't been cloned yet + if (!oldToNew.has(neighbor)) { + // Clone the neighbor + oldToNew.set(neighbor, new _Node(neighbor.val)); + // Add to queue for processing + queue.push(neighbor); + } + + // Add the cloned neighbor to the current cloned node's neighbors + oldToNew.get(curr)!.neighbors.push(oldToNew.get(neighbor)!); + } + } + + return oldToNew.get(node)!; +} + \ No newline at end of file diff --git a/tests/test_150_questions_round_22/test_86_clone_graph_round_22.py b/tests/test_150_questions_round_22/test_86_clone_graph_round_22.py new file mode 100644 index 00000000..622809a5 --- /dev/null +++ b/tests/test_150_questions_round_22/test_86_clone_graph_round_22.py @@ -0,0 +1,165 @@ +import unittest +from src.my_project.interviews.top_150_questions_round_22.ex_86_clone_graph import Solution, Node +from typing import Optional, List + + +class CloneGraphTestCase(unittest.TestCase): + + def build_graph(self, adj_list: List[List[int]]) -> Optional[Node]: + """Helper function to build a graph from adjacency list""" + if not adj_list: + return None + + # Create all nodes first + nodes = [Node(i + 1) for i in range(len(adj_list))] + + # Build connections + for i, neighbors in enumerate(adj_list): + for neighbor_val in neighbors: + nodes[i].neighbors.append(nodes[neighbor_val - 1]) + + return nodes[0] if nodes else None + + def graph_to_adj_list(self, node: Optional[Node]) -> List[List[int]]: + """Helper function to convert graph back to adjacency list for comparison""" + if not node: + return [] + + visited = {} + adj_list = [] + + def dfs(curr: Node): + if curr in visited: + return + + visited[curr] = len(visited) + adj_list.append([]) + + for neighbor in curr.neighbors: + if neighbor not in visited: + dfs(neighbor) + + # First pass: assign indices + dfs(node) + + # Second pass: build adjacency list + visited.clear() + adj_list.clear() + + def build_adj(curr: Node): + if curr in visited: + return + + visited[curr] = len(visited) + neighbors_vals = [n.val for n in curr.neighbors] + adj_list.append(sorted(neighbors_vals)) + + for neighbor in curr.neighbors: + build_adj(neighbor) + + build_adj(node) + return adj_list + + def verify_deep_copy(self, original: Optional[Node], cloned: Optional[Node]) -> bool: + """Verify that the clone is a deep copy (not sharing references)""" + if original is None and cloned is None: + return True + if original is None or cloned is None: + return False + + visited_original = set() + visited_cloned = set() + + def dfs(orig: Node, clone: Node) -> bool: + if orig is clone: # Same reference = not a deep copy + return False + + if orig.val != clone.val: + return False + + if len(orig.neighbors) != len(clone.neighbors): + return False + + visited_original.add(orig) + visited_cloned.add(clone) + + # Check neighbors + orig_neighbor_vals = sorted([n.val for n in orig.neighbors]) + clone_neighbor_vals = sorted([n.val for n in clone.neighbors]) + + if orig_neighbor_vals != clone_neighbor_vals: + return False + + # Recursively check unvisited neighbors + for orig_n, clone_n in zip( + sorted(orig.neighbors, key=lambda x: x.val), + sorted(clone.neighbors, key=lambda x: x.val) + ): + if orig_n not in visited_original: + if not dfs(orig_n, clone_n): + return False + + return True + + return dfs(original, cloned) + + def test_example_1(self): + """ + Example 1: Graph with 4 nodes + adjList = [[2,4],[1,3],[2,4],[1,3]] + """ + solution = Solution() + adj_list = [[2, 4], [1, 3], [2, 4], [1, 3]] + original = self.build_graph(adj_list) + cloned = solution.cloneGraph(original) + + # Verify it's a deep copy + self.assertTrue(self.verify_deep_copy(original, cloned)) + + # Verify structure is the same + cloned_adj_list = self.graph_to_adj_list(cloned) + expected = [[2, 4], [1, 3], [2, 4], [1, 3]] + self.assertEqual(cloned_adj_list, expected) + + def test_example_2(self): + """ + Example 2: Single node with no neighbors + adjList = [[]] + """ + solution = Solution() + adj_list = [[]] + original = self.build_graph(adj_list) + cloned = solution.cloneGraph(original) + + # Verify it's a deep copy + self.assertTrue(self.verify_deep_copy(original, cloned)) + + # Verify structure + self.assertIsNotNone(cloned) + self.assertEqual(cloned.val, 1) + self.assertEqual(len(cloned.neighbors), 0) + + def test_example_3(self): + """ + Example 3: Empty graph + adjList = [] + """ + solution = Solution() + adj_list = [] + original = self.build_graph(adj_list) + cloned = solution.cloneGraph(original) + + # Both should be None + self.assertIsNone(original) + self.assertIsNone(cloned) + + def test_two_nodes(self): + """Test simple graph with two connected nodes""" + solution = Solution() + adj_list = [[2], [1]] + original = self.build_graph(adj_list) + cloned = solution.cloneGraph(original) + + self.assertTrue(self.verify_deep_copy(original, cloned)) + self.assertEqual(self.graph_to_adj_list(cloned), [[2], [1]]) +