recently I was trying out some past year AIO questions, and I couldn't solve this one.
The problem is as follows:
Safe Cracking Input File: safein.txt Output File: safeout.txt Time Limit: 1 second Over the centuries many wars have been won, not through a battle of strength but a battle of wits. Your sources have recently informed you that your mother has purchased a pre-release copy of the latest computer game, WheeZork, and is hiding it in the safe at home. To open the safe, one must enter a long sequence of numbers by rotating the circular dial to each number in the correct order.
If the correct sequence of numbers is entered into the safe, the safe opens and you can sneak your Christmas present out early. If you get the sequence wrong the alarm system is activated and you will be grounded for life! Luckily, you know that your mother has written the code down on a sheet of paper in her bedside drawer, which she likes to call the "code sheet".
She often boasts about how clever she is and explains to you that the numbers on the sheet are indeed the code to the safe, however each number in the sequence has been increased by a constant non-negative integer, k, which only she knows. Without this value the sheet is useless, and thus only she can open the safe ... or so she thinks!
In order to determine the correct code, you have spied on your mother when she unlocks the safe and you have managed to remember part of the code that she entered. You are not sure which part of the code this corresponds to, but it is definitely a consecutive sequence of numbers in the code. Armed with this knowledge, you set out to determine the full code to the safe.
Your task is, given the full list of numbers your mother has written down on her code sheet, and the shorter sequence that you know appears in the actual code, determine the entire sequence to unlock the safe.
For example, if the code to the safe was 7, 9, 4, 6, 8, 12, and your mother had incremented all numbers by 4, her code sheet would read 11, 13, 8, 10, 12, 16. This is because 7 + 4 = 11, giving the first number 11. The second number is obtained by adding 9 + 4 = 13. The third number is obtained by adding 4 + 4 = 8, and so forth. You may have caught a glimpse of her entering the numbers 4, 6, 8, in order. With this knowledge, you can determine the entire code.
Input The first line of the input file will contain two integers, a b, separated by a space. The integer a is the length of the sequence written on your mother's code sheet ( 2 <= a <= 100000). The integer b is the length of the sequence that you know is contained within the code to the safe ( 2 <= b <= 30).
Following this will be a lines, each containing a single integer between 1 and 1000000. These lines are the sequence written on your mother's code sheet, in the order they are entered into the safe.
Following this will be b lines, each containing a single integer, also between 1 and 1000000. These lines describe the glimpse of the actual code to the safe.
You are guaranteed that there will only be one possible solution for any given input scenario.
Output Your output file should consist of a lines. Each of these lines should contain a single integer, representing the full sequence of numbers required to open the safe.
My code (that passes most test cases) is as follows:
'''program implements a function diff which is returns a list that is the difference of the current elements in the list
to solve the problem, the subset list is reduced until it consists of a single integer
the index of this integer in the original list is then found, before determining the non-negative integer
which was used to encode the numbers'''
def diff(lst):
lst2=[]
for i in range(len(lst)-1):
lst2.append(lst[i+1]-lst[i])
return lst2
infile = open("safein.txt", "r")
outfile = open("safeout.txt", "w")
a, b = map(int, infile.readline().split())
lst, sub = [], []
for i in range(a):
lst.append(int(infile.readline()))
for j in range(b):
sub.append(int(infile.readline()))
temp_sub=sub
temp_lst=lst
k = 0
while len(temp_sub) != 1:
temp_sub=diff(temp_sub)
k+=1
for x in range(k):
temp_lst=diff(temp_lst)
n = temp_lst.index(temp_sub[0])
m = lst[n]-sub[0]
lst=[x-m for x in lst]
for i in lst:
outfile.write(str(i) + "\n")
As this code passes most test cases, with the exception of some cases that give an error (I do not know what error it is), I was wondering if anyone could suggest some corner cases that would lead to this algorithm creating an error. So far all the cases that I have thought of have passed.
EDIT: as niemmi has pointed out below, there are some side cases which my above algorithm cannot handle. As such, I have rewritten another algorithm to solve it. This algorithm passes most test cases, and there are no errors, except that the execution takes longer than 1s. Could anyone help reduce the time complexity of this solution?
def subset(lst1, lst2):
if lst2[0] in lst1:
idx = lst1.index(lst2[0])
for i in range(len(lst2)):
if lst2[i]==lst1[idx+i]:
continue
else:
return False
else:
return False
return True
infile = open("safein.txt", "r")
outfile = open("safeout.txt", "w")
a, b = map(int, infile.readline().split())
lst, sub = [], []
for x in range(a):
lst.append(int(infile.readline()))
for y in range(b):
sub.append(int(infile.readline()))
if subset(lst, sub):
for i in range(a):
outfile.write(str(int(lst[i])) + "\n")
infile.close()
outfile.close()
exit()
i=1
while True:
temp_sub = [x+i for x in sub]
if subset(lst, temp_sub):
lst = [x-i for x in lst]
for j in range(a):
outfile.write(str(int(lst[j])) + "\n")
infile.close()
outfile.close()
exit()
i+=1
EDIT: Thanks to niemmi, who provided a solution below that I edited slightly to pass a test case returning an error.
def diff(seq):
return (seq[i - 1] - seq[i] for i in range(1, len(seq)))
with open('safein.txt') as in_file:
a, b = (int(x) for x in in_file.readline().split())
code = [int(in_file.readline()) for _ in range(a)]
plain = [int(in_file.readline()) for _ in range(b)]
code_diff = tuple(diff(code))
plain_diff = tuple(diff(plain))
k = 0
def index(plain_diff, code_diff, plain, code, a, b, k):
for i in range(k, a - b):
for j, x in enumerate(plain_diff, i):
if code_diff[j] != x:
break
else:
k = code[i] - plain[0]
break # found match, break outer loop
return k
k = index(plain_diff, code_diff, plain, code, a, b, k)
with open('safeout.txt', 'w') as out_file:
out_file.write('\n'.join(str(x - k) for x in code))
Thanks!