Skip to content

Commit 760e7d9

Browse files
authored
2025-01-07 v. 7.7.6: added "126. Word Ladder II"
2 parents 8981045 + 410bc93 commit 760e7d9

File tree

4 files changed

+113
-1
lines changed

4 files changed

+113
-1
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -645,3 +645,4 @@ Profile on LeetCode: [fartem](https://leetcode.com/fartem/).
645645
| 32. Longest Valid Parentheses | [Link](https://leetcode.com/problems/longest-valid-parentheses/) | [Link](./lib/hard/32_longest_valid_parentheses.rb) | [Link](./test/hard/test_32_longest_valid_parentheses.rb) |
646646
| 41. First Missing Positive | [Link](https://leetcode.com/problems/first-missing-positive/) | [Link](./lib/hard/41_first_missing_positive.rb) | [Link](./test/hard/test_41_first_missing_positive.rb) |
647647
| 115. Distinct Subsequences | [Link](https://leetcode.com/problems/distinct-subsequences/) | [Link](./lib/hard/115_distinct_subsequences.rb) | [Link](./test/hard/test_115_distinct_subsequences.rb) |
648+
| 126. Word Ladder II | [Link](https://leetcode.com/problems/word-ladder-ii/) | [Link](./lib/hard/126_word_ladder_ii.rb) | [Link](./test/hard/test_126_word_ladder_ii.rb) |

leetcode-ruby.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ require 'English'
55
::Gem::Specification.new do |s|
66
s.required_ruby_version = '>= 3.0'
77
s.name = 'leetcode-ruby'
8-
s.version = '7.7.5'
8+
s.version = '7.7.6'
99
s.license = 'MIT'
1010
s.files = ::Dir['lib/**/*.rb'] + %w[README.md]
1111
s.executable = 'leetcode-ruby'

lib/hard/126_word_ladder_ii.rb

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# frozen_string_literal: true
2+
3+
# https://leetcode.com/problems/word-ladder-ii/
4+
# @param {String} begin_word
5+
# @param {String} end_word
6+
# @param {String[]} word_list
7+
# @return {String[][]}
8+
def find_ladders(begin_word, end_word, word_list)
9+
return [] unless (unvisited = word_list.to_set).include?(end_word)
10+
11+
transformations = ::Hash.new { |h, k| h[k] = ::Set.new }
12+
13+
begin_layer = ::Set[begin_word]
14+
end_layer = ::Set[end_word]
15+
unvisited.delete(end_word)
16+
transforms = Array('a'..'z').product(Array(0...begin_word.size))
17+
18+
current_levels = begin_layer
19+
previous_levels = end_layer
20+
loop do
21+
current_levels, previous_levels = previous_levels, current_levels
22+
23+
unvisited.subtract(previous_levels)
24+
25+
next_layer = ::Set.new
26+
current_levels.each do |word|
27+
transforms.each do |c, i|
28+
next if word[i] == c
29+
30+
transform = word.dup.tap { |w| w[i] = c }
31+
32+
is_neighbor = unvisited.include?(transform)
33+
34+
next_layer << transform if is_neighbor
35+
36+
if is_neighbor || previous_levels.include?(transform)
37+
if current_levels.equal?(begin_layer)
38+
transformations[word] << transform
39+
else
40+
transformations[transform] << word
41+
end
42+
end
43+
end
44+
end
45+
46+
break if next_layer.empty? || begin_layer.any? { |w| transformations[w].intersect?(end_layer) }
47+
48+
current_levels.replace(next_layer)
49+
end
50+
51+
dfs_paths(begin_word, end_word, transformations)
52+
end
53+
54+
private
55+
56+
# @param {String} begin_word
57+
# @param {String} end_word
58+
# @param {Hash} word_graph
59+
# @return {String[][]}
60+
def dfs_paths(begin_word, end_word, word_graph)
61+
paths = []
62+
path = []
63+
stack = [[begin_word, 1]]
64+
65+
until stack.empty?
66+
word, level = stack.pop
67+
68+
path.pop until path.size < level
69+
path << word
70+
71+
if word == end_word
72+
paths << path.dup
73+
else
74+
word_graph[word].each { |w| stack << [w, level + 1] }
75+
end
76+
end
77+
78+
paths
79+
end
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../test_helper'
4+
require_relative '../../lib/hard/126_word_ladder_ii'
5+
require 'minitest/autorun'
6+
7+
class WordLadderIITest < ::Minitest::Test
8+
def test_default_one
9+
assert_equal(
10+
[
11+
%w[hit hot lot log cog],
12+
%w[hit hot dot dog cog]
13+
],
14+
find_ladders(
15+
'hit',
16+
'cog',
17+
%w[hot dot dog lot log cog]
18+
)
19+
)
20+
end
21+
22+
def test_default_two
23+
assert_equal(
24+
[],
25+
find_ladders(
26+
'hit',
27+
'cog',
28+
%w[hot dot dog lot log]
29+
)
30+
)
31+
end
32+
end

0 commit comments

Comments
 (0)