Skip to content

Commit d52dbe7

Browse files
committed
word ladder done
1 parent 1783470 commit d52dbe7

File tree

3 files changed

+282
-5
lines changed

3 files changed

+282
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.leetcode.design;
2+
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.Map;
6+
import java.util.Set;
7+
8+
import static org.junit.jupiter.api.Assertions.assertEquals;
9+
10+
/**
11+
* Level: Hard
12+
* Link: https://leetcode.com/problems/all-oone-data-structure/
13+
* Description:
14+
* Implement a data structure supporting the following operations:
15+
* Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty
16+
* string.
17+
* Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If
18+
* the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string.
19+
* GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string "".
20+
* GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string "".
21+
* <p>
22+
* Challenge: Perform all these in O(1) time complexity.
23+
*
24+
* @author rampatra
25+
* @since 2019-08-11
26+
*/
27+
public class AllOne {
28+
29+
30+
31+
Map<String, Integer> keyToValMap;
32+
Map<Integer, Set<String>> valToKeyMap;
33+
34+
/**
35+
* Initialize your data structure here.
36+
*/
37+
public AllOne() {
38+
keyToValMap = new HashMap<>();
39+
valToKeyMap = new HashMap<>();
40+
}
41+
42+
/**
43+
* Inserts a new key <Key> with value 1. Or increments an existing key by 1.
44+
*/
45+
public void inc(String key) {
46+
47+
}
48+
49+
/**
50+
* Decrements an existing key by 1. If Key's value is 1, remove it from the data structure.
51+
*/
52+
public void dec(String key) {
53+
54+
}
55+
56+
/**
57+
* Returns one of the keys with maximal value.
58+
*/
59+
public String getMaxKey() {
60+
return null;
61+
}
62+
63+
/**
64+
* Returns one of the keys with Minimal value.
65+
*/
66+
public String getMinKey() {
67+
return null;
68+
}
69+
70+
public static void main(String[] args) {
71+
AllOne allOne = new AllOne();
72+
allOne.inc("r");
73+
allOne.inc("r");
74+
allOne.dec("r");
75+
allOne.inc("a");
76+
allOne.inc("b");
77+
allOne.inc("b");
78+
assertEquals("b", allOne.getMaxKey());
79+
assertEquals("a", allOne.getMinKey());
80+
81+
allOne = new AllOne();
82+
allOne.dec("hello");
83+
assertEquals("", allOne.getMaxKey());
84+
85+
allOne = new AllOne();
86+
allOne.inc("a");
87+
allOne.inc("b");
88+
allOne.inc("b");
89+
allOne.inc("b");
90+
allOne.inc("b");
91+
allOne.dec("b");
92+
allOne.dec("b");
93+
assertEquals("b", allOne.getMaxKey());
94+
assertEquals("a", allOne.getMinKey());
95+
96+
allOne = new AllOne();
97+
allOne.inc("hello");
98+
allOne.inc("hello");
99+
assertEquals("hello", allOne.getMaxKey());
100+
assertEquals("hello", allOne.getMinKey());
101+
allOne.inc("leet");
102+
assertEquals("hello", allOne.getMaxKey());
103+
assertEquals("leet", allOne.getMinKey());
104+
105+
allOne = new AllOne();
106+
allOne.inc("a");
107+
allOne.inc("b");
108+
allOne.inc("b");
109+
allOne.inc("c");
110+
allOne.inc("c");
111+
allOne.inc("c");
112+
allOne.dec("b");
113+
allOne.dec("b");
114+
assertEquals("a", allOne.getMinKey());
115+
allOne.dec("a");
116+
assertEquals("c", allOne.getMaxKey());
117+
//assertEquals("c", allOne.getMinKey());
118+
119+
allOne = new AllOne();
120+
allOne.inc("hello");
121+
allOne.dec("hello");
122+
assertEquals("", allOne.getMaxKey());
123+
assertEquals("", allOne.getMinKey());
124+
}
125+
}

src/main/java/com/leetcode/graphs/WordLadder.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
public class WordLadder {
5252

5353
/**
54-
* Runtime: <a href="https://leetcode.com/submissions/detail/251953011/">78 ms</a>.
54+
* Runtime: <a href="https://leetcode.com/submissions/detail/251960230/">79 ms</a>.
5555
*
5656
* @param beginWord
5757
* @param endWord
@@ -60,15 +60,15 @@ public class WordLadder {
6060
*/
6161
public static int ladderLength(String beginWord, String endWord, List<String> wordList) {
6262
int L = beginWord.length();
63-
Map<String, Set<String>> originalToTransformedWordMap = new HashMap<>();
63+
Map<String, Set<String>> transformedToOriginalWordMap = new HashMap<>();
6464
Queue<Pair<String, Integer>> queue = new LinkedList<>();
6565

6666
wordList.forEach(word -> {
6767
String transformedWord;
6868
for (int i = 0; i < L; i++) {
6969
transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L);
70-
originalToTransformedWordMap.putIfAbsent(transformedWord, new HashSet<>());
71-
originalToTransformedWordMap.get(transformedWord).add(word);
70+
transformedToOriginalWordMap.putIfAbsent(transformedWord, new HashSet<>());
71+
transformedToOriginalWordMap.get(transformedWord).add(word);
7272
}
7373
}
7474
);
@@ -90,7 +90,7 @@ public static int ladderLength(String beginWord, String endWord, List<String> wo
9090
for (int i = 0; i < L; i++) {
9191
transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L);
9292

93-
for (String originalWord : originalToTransformedWordMap.getOrDefault(transformedWord, Collections.emptySet())) {
93+
for (String originalWord : transformedToOriginalWordMap.getOrDefault(transformedWord, Collections.emptySet())) {
9494
if (!visited.contains(originalWord)) {
9595
queue.add(new Pair<>(originalWord, level + 1));
9696
visited.add(originalWord);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
package com.leetcode.graphs;
2+
3+
import javafx.util.Pair;
4+
5+
import java.util.*;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
9+
/**
10+
* Level: Hard
11+
* Link: https://leetcode.com/problems/word-ladder-ii/
12+
* Description:
13+
* Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s)
14+
* from beginWord to endWord, such that:
15+
* <p>
16+
* Only one letter can be changed at a time
17+
* Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
18+
* <p>
19+
* Note:
20+
* - Return an empty list if there is no such transformation sequence.
21+
* - All words have the same length.
22+
* - All words contain only lowercase alphabetic characters.
23+
* - You may assume no duplicates in the word list.
24+
* - You may assume beginWord and endWord are non-empty and are not the same.
25+
* <p>
26+
* Example 1:
27+
* Input:
28+
* beginWord = "hit",
29+
* endWord = "cog",
30+
* wordList = ["hot","dot","dog","lot","log","cog"]
31+
* <p>
32+
* Output:
33+
* [
34+
* ["hit","hot","dot","dog","cog"],
35+
* ["hit","hot","lot","log","cog"]
36+
* ]
37+
* <p>
38+
* <p>
39+
* Example 2:
40+
* Input:
41+
* beginWord = "hit"
42+
* endWord = "cog"
43+
* wordList = ["hot","dot","dog","lot","log"]
44+
* <p>
45+
* Output: []
46+
* Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
47+
*
48+
* @author rampatra
49+
* @since 2019-08-15
50+
*/
51+
public class WordLadderII {
52+
53+
/**
54+
* The approach is same as {@link WordLadder}. We calculate the {@code minDistance} from start to end word and also
55+
* keep a map of words and its adjacent words (i.e, with only character difference). After we are done calculating
56+
* the {@code mindistance}, we perform a dfs on the map upto depth {@code minDistance} and if the last word at this
57+
* depth is equal to the end word then we add all words to the result.
58+
*
59+
* @param beginWord
60+
* @param endWord
61+
* @param wordList
62+
* @return
63+
*/
64+
public static List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
65+
int L = beginWord.length();
66+
List<List<String>> ladders = new LinkedList<>();
67+
Map<String, Set<String>> transformedToOriginalWordMap = new HashMap<>();
68+
Queue<Pair<String, Integer>> queue = new LinkedList<>();
69+
70+
wordList.forEach(word -> {
71+
String transformedWord;
72+
for (int i = 0; i < L; i++) {
73+
transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L);
74+
transformedToOriginalWordMap.putIfAbsent(transformedWord, new HashSet<>());
75+
transformedToOriginalWordMap.get(transformedWord).add(word);
76+
}
77+
}
78+
);
79+
80+
int minDistance = -1;
81+
Set<String> visited = new HashSet<>();
82+
queue.add(new Pair<>(beginWord, 1));
83+
visited.add(beginWord);
84+
85+
HashMap<String, Set<String>> connectedNodes = new HashMap<>();
86+
87+
while (!queue.isEmpty()) {
88+
Pair<String, Integer> currPair = queue.poll();
89+
String word = currPair.getKey();
90+
Integer level = currPair.getValue();
91+
92+
if (word.equals(endWord) && minDistance == -1) {
93+
minDistance = level - 1;
94+
}
95+
96+
String transformedWord;
97+
for (int i = 0; i < L; i++) {
98+
transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L);
99+
100+
for (String originalWord : transformedToOriginalWordMap.getOrDefault(transformedWord, Collections.emptySet())) {
101+
if (!visited.contains(originalWord)) {
102+
queue.add(new Pair<>(originalWord, level + 1));
103+
visited.add(originalWord);
104+
}
105+
106+
if (!word.equals(originalWord)) {
107+
connectedNodes.putIfAbsent(word, new HashSet<>());
108+
connectedNodes.get(word).add(originalWord);
109+
}
110+
}
111+
}
112+
}
113+
114+
dfs(ladders, new LinkedHashSet<>(), connectedNodes, beginWord, endWord, 0, minDistance);
115+
116+
return ladders;
117+
}
118+
119+
/**
120+
* Perform dfs on the map which contains words and its adjacent words.
121+
*
122+
* @param ladders
123+
* @param ladder
124+
* @param connectedNodes
125+
* @param startNode
126+
* @param endNode
127+
* @param distance
128+
* @param minDistance
129+
*/
130+
private static void dfs(List<List<String>> ladders, Set<String> ladder, Map<String, Set<String>> connectedNodes,
131+
String startNode, String endNode, int distance, int minDistance) {
132+
if (distance == minDistance && startNode.equals(endNode)) {
133+
ladder.add(endNode);
134+
ladders.add(new ArrayList<>(ladder));
135+
return;
136+
} else if (distance > minDistance) {
137+
return;
138+
}
139+
140+
ladder.add(startNode);
141+
for (String nextNode : connectedNodes.getOrDefault(startNode, new HashSet<>())) {
142+
if (!ladder.contains(nextNode)) {
143+
dfs(ladders, new LinkedHashSet<>(ladder), connectedNodes, nextNode, endNode, distance + 1, minDistance);
144+
}
145+
}
146+
}
147+
148+
public static void main(String[] args) {
149+
assertEquals("[[hit, hot, lot, log, cog], [hit, hot, dot, dog, cog]]", findLadders("hit", "cog", Arrays.asList("hot", "dot", "dog", "lot", "log", "cog")).toString());
150+
// TODO Fix this test case System.out.println(findLadders("cet", "ism", Arrays.asList("kid", "tag", "pup", "ail", "tun", "woo", "erg", "luz", "brr", "gay", "sip", "kay", "per", "val", "mes", "ohs", "now", "boa", "cet", "pal", "bar", "die", "war", "hay", "eco", "pub", "lob", "rue", "fry", "lit", "rex", "jan", "cot", "bid", "ali", "pay", "col", "gum", "ger", "row", "won", "dan", "rum", "fad", "tut", "sag", "yip", "sui", "ark", "has", "zip", "fez", "own", "ump", "dis", "ads", "max", "jaw", "out", "btu", "ana", "gap", "cry", "led", "abe", "box", "ore", "pig", "fie", "toy", "fat", "cal", "lie", "noh", "sew", "ono", "tam", "flu", "mgm", "ply", "awe", "pry", "tit", "tie", "yet", "too", "tax", "jim", "san", "pan", "map", "ski", "ova", "wed", "non", "wac", "nut", "why", "bye", "lye", "oct", "old", "fin", "feb", "chi", "sap", "owl", "log", "tod", "dot", "bow", "fob", "for", "joe", "ivy", "fan", "age", "fax", "hip", "jib", "mel", "hus", "sob", "ifs", "tab", "ara", "dab", "jag", "jar", "arm", "lot", "tom", "sax", "tex", "yum", "pei", "wen", "wry", "ire", "irk", "far", "mew", "wit", "doe", "gas", "rte", "ian", "pot", "ask", "wag", "hag", "amy", "nag", "ron", "soy", "gin", "don", "tug", "fay", "vic", "boo", "nam", "ave", "buy", "sop", "but", "orb", "fen", "paw", "his", "sub", "bob", "yea", "oft", "inn", "rod", "yam", "pew", "web", "hod", "hun", "gyp", "wei", "wis", "rob", "gad", "pie", "mon", "dog", "bib", "rub", "ere", "dig", "era", "cat", "fox", "bee", "mod", "day", "apr", "vie", "nev", "jam", "pam", "new", "aye", "ani", "and", "ibm", "yap", "can", "pyx", "tar", "kin", "fog", "hum", "pip", "cup", "dye", "lyx", "jog", "nun", "par", "wan", "fey", "bus", "oak", "bad", "ats", "set", "qom", "vat", "eat", "pus", "rev", "axe", "ion", "six", "ila", "lao", "mom", "mas", "pro", "few", "opt", "poe", "art", "ash", "oar", "cap", "lop", "may", "shy", "rid", "bat", "sum", "rim", "fee", "bmw", "sky", "maj", "hue", "thy", "ava", "rap", "den", "fla", "auk", "cox", "ibo", "hey", "saw", "vim", "sec", "ltd", "you", "its", "tat", "dew", "eva", "tog", "ram", "let", "see", "zit", "maw", "nix", "ate", "gig", "rep", "owe", "ind", "hog", "eve", "sam", "zoo", "any", "dow", "cod", "bed", "vet", "ham", "sis", "hex", "via", "fir", "nod", "mao", "aug", "mum", "hoe", "bah", "hal", "keg", "hew", "zed", "tow", "gog", "ass", "dem", "who", "bet", "gos", "son", "ear", "spy", "kit", "boy", "due", "sen", "oaf", "mix", "hep", "fur", "ada", "bin", "nil", "mia", "ewe", "hit", "fix", "sad", "rib", "eye", "hop", "haw", "wax", "mid", "tad", "ken", "wad", "rye", "pap", "bog", "gut", "ito", "woe", "our", "ado", "sin", "mad", "ray", "hon", "roy", "dip", "hen", "iva", "lug", "asp", "hui", "yak", "bay", "poi", "yep", "bun", "try", "lad", "elm", "nat", "wyo", "gym", "dug", "toe", "dee", "wig", "sly", "rip", "geo", "cog", "pas", "zen", "odd", "nan", "lay", "pod", "fit", "hem", "joy", "bum", "rio", "yon", "dec", "leg", "put", "sue", "dim", "pet", "yaw", "nub", "bit", "bur", "sid", "sun", "oil", "red", "doc", "moe", "caw", "eel", "dix", "cub", "end", "gem", "off", "yew", "hug", "pop", "tub", "sgt", "lid", "pun", "ton", "sol", "din", "yup", "jab", "pea", "bug", "gag", "mil", "jig", "hub", "low", "did", "tin", "get", "gte", "sox", "lei", "mig", "fig", "lon", "use", "ban", "flo", "nov", "jut", "bag", "mir", "sty", "lap", "two", "ins", "con", "ant", "net", "tux", "ode", "stu", "mug", "cad", "nap", "gun", "fop", "tot", "sow", "sal", "sic", "ted", "wot", "del", "imp", "cob", "way", "ann", "tan", "mci", "job", "wet", "ism", "err", "him", "all", "pad", "hah", "hie", "aim", "ike", "jed", "ego", "mac", "baa", "min", "com", "ill", "was", "cab", "ago", "ina", "big", "ilk", "gal", "tap", "duh", "ola", "ran", "lab", "top", "gob", "hot", "ora", "tia", "kip", "han", "met", "hut", "she", "sac", "fed", "goo", "tee", "ell", "not", "act", "gil", "rut", "ala", "ape", "rig", "cid", "god", "duo", "lin", "aid", "gel", "awl", "lag", "elf", "liz", "ref", "aha", "fib", "oho", "tho", "her", "nor", "ace", "adz", "fun", "ned", "coo", "win", "tao", "coy", "van", "man", "pit", "guy", "foe", "hid", "mai", "sup", "jay", "hob", "mow", "jot", "are", "pol", "arc", "lax", "aft", "alb", "len", "air", "pug", "pox", "vow", "got", "meg", "zoe", "amp", "ale", "bud", "gee", "pin", "dun", "pat", "ten", "mob")));
151+
}
152+
}

0 commit comments

Comments
 (0)