The Substring Game! challenge

This is the Substring Game! challenge from HackerEarth:

Watson gives Sherlock a string (let's denote it by S). Watson calculates all the substrings of S in his favourite order.

According to the Watson's favourite order, all the substrings starting from first character of the string will occur first in the sorted order of their length, followed by all the substrings starting from the second character of the string in the sorted order of their length, and so on.

For example, suppose S = abc. Then, all the substrings of S as per Watson's favourite order are:

1. a
2. ab
3. abc
4. b
5. bc
6. c

Watson will ask Sherlock 'q' questions. In each question, Watson will give Sherlock a number and Sherlock has to speak the substring on that number. If there is no possible substring, then Sherlock has to speak -1.

Can the below code be improved to run in $o(n^2)$ complexity?

str=raw_input()
q=int(raw_input())
num=raw_input().split(' ')
substr=[]
for i,s in enumerate(str):
#print i,s
for j in range(i+1,len(str)+1):
#print j
substr.append(s+str[i+1:j])
#print substr
for i in range(0,q):
try:
print substr[int(num[i])-1]
except IndexError:
print -1


Sample Input
First line is the string - abc
Second line is the number of substrings asked- 2
Third line is the position of the substrings to return from the list of substrings- 2 5

The list of substrings would be ['a','ab','abc','b','bc','c']
Sample Output
ab
bc

• Don't name things str.
• Use a list comprehension to build substr.
• s+str[i+1:j] would be simpler as str[i:j].
• Iterate through num, rather than the range(q)
• Your can wrap your print keywords with (), so this is a bit more Python 3 compatible.

This can get:

S = raw_input()
q = int(raw_input())
nums = map(int, raw_input().split(' '))

substr = [
S[i:j+1]
for i in range(len(S))
for j in range(i, len(S))
]

for i in nums:
try:
print(substr[i-1])
except IndexError:
print(-1)


However this uses $O(S^3)$ of memory. So about $10^{15}$, or 1 petabyte of storage. So your code doesn't feasibly work. Instead work things in the reverse order.

If you have the number $5$, you know it's $5 \gt 3$, $5-3 = 2$, $2 \le 2$, and so is S[1:1+2]. And so I'd use:

S = raw_input()
q = raw_input()
nums = map(int, raw_input().split(' '))

for num in nums:
for i, s in enumerate(reversed(range(1, len(S)+1))):
if num <= s:
print(S[i:i+num])
break
num -= s
else:
print(-1)


Which is still better than yours in terms of time complexity, as it's $O(nS)$, $~10^8$, rather than $O(n + S^2)$, $10^3 + 10^{10}$.

• (Having space complexity exceed time complexity spells non-RAM.) – greybeard Jan 9 '18 at 12:20