forked from PriyankaKhire/ProgrammingPracticePython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAlienDictionary.py
More file actions
259 lines (211 loc) · 7.94 KB
/
AlienDictionary.py
File metadata and controls
259 lines (211 loc) · 7.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
#Given a sorted dictionary of an alien language, find order of characters
class graphNode(object):
def __init__(self, data):
self.data = data
self.link = []
class CreateGraph():
def __init__(self):
#key is node data and value is node object
self.nodesDictionary = {}
self.root = None
def createNode(self, data):
node = graphNode(data)
return node
def addChildNode(self, parentNode, childNode):
parentNode.link.append(childNode)
return parentNode
#Creates uni directed graph from given array
#So if array is b,a,d then graph will be
#b->a->d
def createGraph(self, array):
#Create graph nodes and fill dictionary
for letter in array:
if not letter in self.nodesDictionary:
node = self.createNode(letter)
self.nodesDictionary[letter] = node
if self.root == None:
self.root = node
#Add edges
for i in range(len(array)-1):
pnode = self.nodesDictionary[array[i]]
cnode = self.nodesDictionary[array[i+1]]
pnode = self.addChildNode(pnode, cnode)
def dfs(self, node, output):
if not node.link:
print output
return
for child in node.link:
output.append(child.data)
self.dfs(child, output)
output.pop()
def dfsTraversal(self):
self.dfs(self.root, [self.root.data])
class trieNode(object):
def __init__(self, letter):
self.letter = letter
self.childern = []
self.childCount = 0
class CreateTrie():
def __init__(self):
self.trieRoot = trieNode("")
#keeps track of all letters of all words in trie
self.letterDictionary = []
self.childCollector = []
def traverse_collectChildern(self, parentNode):
if not parentNode.childern:
return
for child in parentNode.childern:
if child.childCount > 1:
childNodeData = self.returnChildNodeData(child)
self.childCollector.append(childNodeData)
self.traverse_collectChildern(child)
#Traverses the trie and returns all the intermediate node childern
def collectChildern(self):
rootChildern = self.returnChildNodeData(self.trieRoot)
self.childCollector.append(rootChildern)
self.traverse_collectChildern(self.trieRoot)
return self.childCollector
def findWord(self, word):
parentNode = self.trieRoot
for letter in word:
childFlag, childNode = self.findChild(parentNode, letter)
if childFlag:
parentNode = childNode
else:
return False
return True
def returnChildNodeData(self, node):
if not node.childern:
return False
output = []
for child in node.childern:
output.append(child.letter)
return output
def createNode(self, letter):
node = trieNode(letter)
return node
def addChildToTrieNode(self, child, node):
node.childern.append(child)
node.childCount = node.childCount + 1
def findChild(self, node, childData):
#if Node does not have childern
if not node.childern:
return False, -1
for child in node.childern:
if(child.letter == childData):
return True, child
return False, -1
def addWordToTrie(self, word):
parentNode = self.trieRoot
for letter in word:
#Add letter to letter dictionary
if not letter in self.letterDictionary:
self.letterDictionary.append(letter)
childFlag, childNode = self.findChild(parentNode, letter)
if childFlag:
parentNode = childNode
else:
#Create child node
cnode = self.createNode(letter)
self.addChildToTrieNode(cnode, parentNode)
parentNode = cnode
class AlienDictionary(object):
def __init__(self, words):
self.graph = CreateGraph()
self.trie = CreateTrie()
#Create a trie
for word in words:
self.trie.addWordToTrie(word)
def print_order(self):
allChildern = self.trie.collectChildern()
for child in allChildern:
self.graph.createGraph(child)
self.graph.dfsTraversal()
#Leetcode solution
class LeetCodeGraphNode(object):
def __init__(self, letter):
self.letter = letter
self.next = None
#To detect cycle
self.seen = False
class Solution(object):
def __init__(self):
self.hashTable = {}
self.root = None
def createNode(self, letter):
node = LeetCodeGraphNode(letter)
return node
def addNextToNode(self, node, nextLink):
node.next = nextLink
def addToHashTable(self,letter):
if not(letter in self.hashTable):
self.hashTable[letter] = self.createNode(letter)
if(self.root == None):
print "root is ", letter
self.root = self.hashTable[letter]
#creates nodes from letters and adds edge between node1 -> node2
def connect2Letters(self, letter1, letter2):
#if the nodes are not in hash table then add them
self.addToHashTable(letter1)
self.addToHashTable(letter2)
#add edge from node1 -> node2
self.addNextToNode(self.hashTable[letter1], self.hashTable[letter2])
print "Added edge between ", letter1, " and ", letter2
#need to imporve this function, right now its only doing simple traversal, we need topo sort or dfs
def traverseLinkedList(self):
ptr = self.root
output = ""
while(ptr != None):
if(ptr.seen == True):
return ""
output = output + ptr.letter
ptr.seen = True
ptr = ptr.next
#Go through hash table, if there is no edgebetween rest of them then add it to output by alphabetical order
return output
def logic(self, words):
for i in range(1, len(words)):
if(words[i-1] == words[i]):
return ""
self.root = self.hashTable[letter]
def logic(self, words):
for i in range(1, len(words)):
letterIndex = 0
while(letterIndex < len(words[i-1]) and letterIndex < len(words[i]) and words[i-1][letterIndex] == words[i][letterIndex]):
self.addToHashTable(words[i][letterIndex])
letterIndex = letterIndex+1
if(letterIndex < len(words[i-1]) and letterIndex < len(words[i]) ):
self.connect2Letters(words[i-1][letterIndex], words[i][letterIndex])
#Traverse the created linked list
return self.traverseLinkedList()
def alienOrder(self, words):
print self.logic(words)
self.logic(words)
"""
:type words: List[str]
:rtype: str
"""
#Main program
words1 = ["baa", "abcd", "abca", "cab", "cad"]
words2 = ["caa", "aaa", "aab"]
words3 = ["wrt", "wrf", "er", "ett", "rftt"]
words4 = [ "z","x","z"]
words5 = ["z", "z"]
words6 = ["wrt","wrtkj"]
#words = ["baa", "abcd", "abca", "cab", "cad"]
#words = ["caa", "aaa", "aab"]
words = ["wrt", "wrf", "er", "ett", "rftt"]
#o = AlienDictionary(words)
#o.print_order()
obj1 = Solution()
obj1.alienOrder(words1)
obj2 = Solution()
obj2.alienOrder(words2)
obj3 = Solution()
obj3.alienOrder(words3)
obj4 = Solution()
obj4.alienOrder(words4)
obj5 = Solution()
obj5.alienOrder(words5)
obj6 = Solution()
obj6.alienOrder(words6)