Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
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 []





Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
from typing import List, Union, Collection, Mapping, Optional
from abc import ABC, abstractmethod
from collections import deque, defaultdict

class Solution:
def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int:
"""
Find the shortest transformation sequence from beginWord to endWord.
Uses BFS to find the shortest path.

Time Complexity: O(M^2 * N) where M is word length, N is wordList size
Space Complexity: O(M^2 * N) for the pattern dictionary
"""
# If beginWord equals endWord, the sequence is just the word itself
if beginWord == endWord:
return 1

# If endWord is not in wordList, no valid transformation exists
if endWord not in wordList:
return 0

# Convert wordList to set for O(1) lookup
word_set = set(wordList)

# Build a pattern dictionary to find all words that differ by one letter
# e.g., "hot" -> {"*ot": ["hot"], "h*t": ["hot"], "ho*": ["hot"]}
pattern_dict = defaultdict(list)
word_len = len(beginWord)

# Add beginWord to the set if not present
if beginWord not in word_set:
word_set.add(beginWord)

# Create patterns for all words
for word in word_set:
for i in range(word_len):
pattern = word[:i] + '*' + word[i+1:]
pattern_dict[pattern].append(word)

# BFS to find shortest path
queue = deque([(beginWord, 1)]) # (current_word, level)
visited = {beginWord}

while queue:
current_word, level = queue.popleft()

# Try all possible transformations by replacing each character
for i in range(word_len):
pattern = current_word[:i] + '*' + current_word[i+1:]

# Get all words matching this pattern
for next_word in pattern_dict[pattern]:
if next_word == endWord:
return level + 1

if next_word not in visited:
visited.add(next_word)
queue.append((next_word, level + 1))

# Clear the pattern to avoid revisiting in future iterations
pattern_dict[pattern] = []

return 0
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
function ladderLength(beginWord: string, endWord: string, wordList: string[]): number {
/**
* Find the shortest transformation sequence from beginWord to endWord.
* Uses BFS to find the shortest path.
*
* Time Complexity: O(M^2 * N) where M is word length, N is wordList size
* Space Complexity: O(M^2 * N) for the pattern dictionary
*/

// If beginWord equals endWord, the sequence is just the word itself
if (beginWord === endWord) {
return 1;
}

// If endWord is not in wordList, no valid transformation exists
if (!wordList.includes(endWord)) {
return 0;
}

// Convert wordList to set for O(1) lookup
const wordSet = new Set<string>(wordList);

// Add beginWord to the set if not present
if (!wordSet.has(beginWord)) {
wordSet.add(beginWord);
}

// Build a pattern dictionary to find all words that differ by one letter
// e.g., "hot" -> {"*ot": ["hot"], "h*t": ["hot"], "ho*": ["hot"]}
const patternDict = new Map<string, string[]>();
const wordLen = beginWord.length;

// Create patterns for all words
for (const word of wordSet) {
for (let i = 0; i < wordLen; i++) {
const pattern = word.slice(0, i) + '*' + word.slice(i + 1);
if (!patternDict.has(pattern)) {
patternDict.set(pattern, []);
}
patternDict.get(pattern)!.push(word);
}
}

// BFS to find shortest path
const queue: [string, number][] = [[beginWord, 1]]; // [current_word, level]
const visited = new Set<string>([beginWord]);

while (queue.length > 0) {
const [currentWord, level] = queue.shift()!;

// Try all possible transformations by replacing each character
for (let i = 0; i < wordLen; i++) {
const pattern = currentWord.slice(0, i) + '*' + currentWord.slice(i + 1);

// Get all words matching this pattern
const neighbors = patternDict.get(pattern) || [];
for (const nextWord of neighbors) {
if (nextWord === endWord) {
return level + 1;
}

if (!visited.has(nextWord)) {
visited.add(nextWord);
queue.push([nextWord, level + 1]);
}
}

// Clear the pattern to avoid revisiting in future iterations
patternDict.set(pattern, []);
}
}

return 0;
}

79 changes: 79 additions & 0 deletions tests/test_150_questions_round_22/test_92_word_ladder_round_22.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pytest
from src.my_project.interviews.top_150_questions_round_22.ex_92_word_ladder import Solution


class TestWordLadder:
def setup_method(self):
self.solution = Solution()

def test_example_1(self):
"""Test Example 1: Standard transformation sequence"""
beginWord = "hit"
endWord = "cog"
wordList = ["hot", "dot", "dog", "lot", "log", "cog"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 5, "Should return 5 for the sequence: hit -> hot -> dot -> dog -> cog"

def test_example_2(self):
"""Test Example 2: endWord not in wordList"""
beginWord = "hit"
endWord = "cog"
wordList = ["hot", "dot", "dog", "lot", "log"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 0, "Should return 0 when endWord is not in wordList"

def test_single_transformation(self):
"""Test single transformation"""
beginWord = "hot"
endWord = "dot"
wordList = ["hot", "dot"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 2, "Should return 2 for direct transformation"

def test_no_transformation_needed(self):
"""Test when begin and end are same"""
beginWord = "hot"
endWord = "hot"
wordList = ["hot"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 1, "Should return 1 when beginWord equals endWord"

def test_no_path_exists(self):
"""Test when no valid path exists"""
beginWord = "hit"
endWord = "cog"
wordList = ["hot", "dot", "tog"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 0, "Should return 0 when no valid transformation sequence exists"

def test_longer_words(self):
"""Test with longer words"""
beginWord = "teach"
endWord = "place"
wordList = ["teach", "peach", "peace", "place", "reach"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 4, "Should return 4 for: teach -> peach -> peace -> place"

def test_multiple_paths(self):
"""Test when multiple paths exist"""
beginWord = "red"
endWord = "tax"
wordList = ["ted", "tex", "red", "tax", "tad", "rex"]

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 4, "Should return 4 for shortest path: red -> ted -> tex -> tax"

def test_empty_word_list(self):
"""Test with empty wordList"""
beginWord = "hit"
endWord = "cog"
wordList = []

result = self.solution.ladderLength(beginWord, endWord, wordList)
assert result == 0, "Should return 0 when wordList is empty"