I made a program today that solves the following problem on a programming competition site (open.kattis.com): Check if all statements with the following format X is Y or X not Y are consistent. X and Y are words of the length 1-20 and a-z.
The catch is that every word that rhymes with X in any provided statement is said to be equivalent to X. For simplicity it is said that two words rhyme if the last min(3, |X|, |Y|) character are the same, so for example foo and boo would be the same word but not skoo and troo). Also words which do not appear in any statement do not exist, and should not be considered rhyming with anything. For example, the two words foo and moo do not rhyme with each other, unless the word oo or o exists in the input.
So to break it down, here are the rules:
- Check if all statements of the form "X is Y" or "X not Y" is consistent.
- Two words rhyme if the last min(3, |X|, |Y|) characters are the same. So if this condition holds for two words X and Y that are in the list of statements, it is equivalent to having a statement "X is Y".
- Words which do not appear in any statement do not exist, and should not be considered rhyming with anything
The first line consists of an integer 0≤N≤100000, the number of statements. The next N lines consists of statements of the two given forms.
Output should the string "yes", if the statements are consistent with each other or if there is a contradiction the output should be "wait what?".
The problem provides 4 sample inputs and corresponding outputs:
4
herp is derp
derp is herp
herp is herp
derp is derp
Output to the input above should be yes
.
3
oskar not lukas
oskar is poptart
lukas is smart
… should output wait what?
1
moo not foo
… should output yes
2
moo not foo
oo is blah
… should output wait what?
Here is my program that should hopefully be commented well enough to understand:
import sys
# read all input
indata = sys.stdin.readlines()
inlen = int(indata[0])
# return yes if the first line was 0
if inlen == 0:
print("yes")
exit(0)
Xs = []
Ys = []
equivalent = {}
words = []
# build lists of words in data
for i in range(inlen):
item = indata[i+1]
parts = item.split(" ")
word1 = parts[0].strip()
word2 = parts[2].strip()
Xs.append(word1)
Ys.append(word2)
words.append(word1)
words.append(word2)
# add word in equivalent list if not present
if word1 not in equivalent:
equivalent[word1] = [word1]
if word2 not in equivalent:
equivalent[word2] = [word2]
# check which words rhyme and add to equivalent list
for i in range(len(words)):
word1 = words[i].strip()
for j in range(len(words)):
word2 = words[j]
if word1 == word2:
continue
endinglen = min(3, len(word1), len(word2)) # min(3, |X|, |Y|)
ending1 = word1[-endinglen:]
ending2 = word2[-endinglen:]
if ending1 == ending2:
equivalent[word1].append(word2)
equivalent[word2].append(word1)
# check if any word in eq1 matches any word in eq2
def any_equals(eq1, eq2):
for i in eq1:
for j in eq2:
if i == j:
return True
return False
# build the statements data structure
statements = {}
for i in range(inlen):
item = indata[i+1]
parts = item.split(" ")
X = parts[0].strip()
b = True if parts[1] == "is" else False
Y = parts[2].strip()
if X not in statements:
statements[X] = []
# this tuiple is of the format (boolean, word) where boolean means if X is equal to or not equal to Y
statements[X].append((b, Y))
# check consistency of statements
for i in range(inlen):
item = indata[i+1]
parts = item.split(" ")
X = parts[0].strip()
Y = parts[2].strip()
for eq1 in equivalent[X]:
if eq1 not in statements:
continue
for key in statements[eq1]:
equals = any_equals(equivalent[X], equivalent[Y])
# we check if the statement is true for all words that rhyme with X
if (key[0] and equals) or (not key[0] and not equals):
continue
else:
print("wait what?") # the statement was not consistent
sys.exit(0)
print("yes") # all statements were consistent
I think due to the fact I have two nested loops the time complexity is O(n^2) but I think there is a O(n) algorithm but I can't figure it out. Any tips on how to improve my code to run faster would be much appreciated!