How can I efficiently create the prefix failure array of a string? - python

I need to create the failure array of a string about 100000 letters long, but my code seems to take forever to run.
x = input("::").replace("\n","").strip()
p = ""
for count in range(len(x)-1):
count+=1
myn = 0
for c in range(count):
c+=1
if x[c:count] == x[:len(x[c:count])] and myn < len(x[c:count]):
myn = len(x[c:count])
break
p += str(myn)+" "
print(p+"0")
Is there any way to do this more efficiently?
Edit: I believe something called the KMP algorithm would do this. Can anyone show me how I would do this?

Related

How to format the output in a better way for geeksforgeeks problems

def doorcheck(n):
doors = []
for i in range(n):
doors.append(False)
for i in range(n):
for x in range(n):
if (x+1) % (i+1) == 0:
if(doors[x] is False):
doors[x] = 1
else:
doors[x] = 0
for i in range(n-1):
print(doors[i], end = ' ')
print(doors[n-1], end = '\n')
t = int(input())
for i in range(t):
n = int(input())
doorcheck(n)
Here I am trying to print each desired output in a separate line.
As asked in the question
Example:
Input:
2
3
5
Output:
1 0 0
1 0 0 1 0
And I have used
for i in range(n-1):
print(doors[i], end = ' ')
print(doors[n-1], end = '\n')
the above code for this purpose. Is there a better way to do it?
Edit 1: The code above I wrote has a bug. But anyways #Barmar has given an excellent solution to my problem, which was about formatting output in a concise manner. And he also gave a suggestion for initializing an array which contains same element throughout its length. Thanks.
If you just want to print the elements of doors separated by spaces, use join()
print(' '.join(map(str, doors)))
You can also replace the loop that initializes doors with:
doors = [False] * n

How to remove multiple consecutive sequences of consecutive duplicate characters in python

I am trying to preprocess some tweets for an ML project where I am having troubles with two types of strings e.g.
str1 = "coooool" and str2 = "gooooaaaaaal".
After removing repeated characters, I would like to maintain the word in str1, i.e.
cleaned_str1 = "cool" while cleaned_str2 = "goal".
I tried a few approaches that I found but I couldn't get the right output. Could someone help me with this? Thank you in advance.
Use regular expressions:
re.sub(r"(\w)\1+(\w)\2+", r"\1\2", "goooaaaal") # -> goal
re.sub(r"(\w)\1+(\w)\2+", r"\1\2", "coooool") # -> cool
def removeDuplicates(S):
n = len(S)
j = 0
if (n < 2) :
return
for i in range(n):
if (S[j] != S[i]):
j += 1
S[j] = S[i]
j += 1
S = S[:j]
return S
This was taken directly from Geeks for Geeks.
There is no way for a program to intuitively know that "cool" needs two "o's" as in your example.

Python program which prints out line number and length of list: Error

Now I'm using while loops to try and do this because I'm not too good at using for loops. As the title reads, I'm trying to print out a table which has the line number next to the length of each line.
Error: When I hit run all I get is the above print out (line and number of words with dashes below). I do not get a series of printouts of y and z
Note: I'm probably making this way harder than it needs to be
Code:
list1 = ['Lets go outside','pizza time','show me the money']
list2 = []
print('line number of words')
print('---- ---------------')
x = 0
len_l1 = len(list1)
while len_l1 > 0:
split_lis1 = list1[0+x].split(' ')
list2.append(split_lis1)
len_l1 -= 1
x += 1
while len_l1 > 0:
q = 1
y = len(list1) - len(list1) + q(x)
z = len(list2[0+x])
print(y, z)
len_l1 -= 1
x += 1
what I want the print out to look like:
line number of words
---- ---------------
0 3
1 2
2 4
Thanks.
Yes, you might have overcomplicated the solution as there are out of the box Python methods that help you easily solve problems like this. For iteration with indexes, use enumerate, in the example below we set the index to start at 1. We can also use some simple string formatting defined in fmt to ensure consistent spacings.
li = ['Lets go outside','pizza time','show me the money']
print('line number of words')
print('---- ---------------')
fmt = ('{} {}')
for idx, sentence in enumerate(li,1):
no_of_words = len(sentence.split())
print(fmt.format(idx, no_of_words))
Then simple use split to split the whitespaces and get the total number of words and let enumerate manage the whole thing for you.
>>
line number of words
---- ---------------
1 3
2 2
3 4
list1 = ['Lets go outside','pizza time','show me the money']
print('line number of words')
print('---- ---------------')
for i in range(0, len(list1)):
length = len(list1[i].split(" "))
print(i + 1, " ", length)
Check out python docs for range and for details.

Without using built-in functions, a function should reverse a string without changing the '$' position

I need a Python function which gives reversed string with the following conditions.
$ position should not change in the reversed string.
Should not use Python built-in functions.
Function should be an efficient one.
Example : 'pytho$n'
Result : 'nohty$p'
I have already tried with this code:
list = "$asdasdas"
list1 = []
position = ''
for index, i in enumerate(list):
if i == '$':
position = index
elif i != '$':
list1.append(i)
reverse = []
for index, j in enumerate( list1[::-1] ):
if index == position:
reverse.append( '$' )
reverse.append(j)
print reverse
Thanks in advance.
Recognise that it's a variation on the partitioning step of the Quicksort algorithm, using two pointers (array indices) thus:
data = list("foo$barbaz$$")
i, j = 0, len(data) - 1
while i < j:
while i < j and data[i] == "$": i += 1
while i < j and data[j] == "$": j -= 1
data[i], data[j] = data[j], data[i]
i, j = i + 1, j - 1
"".join(data)
'zab$raboof$$'
P.S. it's a travesty to write this in Python!
A Pythonic solution could look like this:
def merge(template, data):
for c in template:
yield c if c == "$" else next(data)
data = "foo$barbaz$$"
"".join(merge(data, reversed([c for c in data if c != "$"])))
'zab$raboof$$'
Wrote this without using any inbuilt functions. Hope it fulfils your criteria -
string = "zytho$n"
def reverse(string):
string_new = string[::-1]
i = 0
position = 0
position_new = 0
for char in string:
if char=="$":
position = i
break
else:
i = i + 1
j = 0
for char in string_new:
if char=="$":
position_new = i
break
else:
j = j + 1
final_string = string_new[:position_new]+string_new[position_new+1:position+1]+"$"+string_new[position+1:]
return(final_string)
string_new = reverse(string)
print(string_new)
The output of this is-
nohty$x
To explain the code to you, first I used [::-1], which is just taking the last position of the string and moving forward so as to reverse the string. Then I found the position of the $ in both the new and the old string. I found the position in the form of an array, in case you have more than one $ present. However, I took for granted that you have just one $ present, and so took the [0] index of the array. Next I stitched back the string using four things - The part of the new string upto the $ sign, the part of the new string from after the dollar sign to the position of the $ sign in the old string, then the $ sign and after that the rest of the new string.

More pythonic way to handle this logic structure

I need to break up a length of numbers into chunks of 100 and what ever is left over and then add them to a final dictionary at the end.
I am able to do it with loops but I feel I might be missing something that would make this a much cleaner and efficient operation.
l = 238 # length of list to process
i = 0 #setting up count for while loop
screenNames = {}#output dictionary
count = 0 #count of total numbers processed
while i < l:
toGet = {}
if l - count > 100:#blocks off in chunks of 100
for m in range (0,100):
toGet[count] = m
count = count + 1
else:
k = count
for k in range (0,(l - count)):#takes the remainder of the numbers
toGet[count] = k
count = count + 1
i = l # kills loop
screenNames.update(toGet)
#This logic structure breaks up the list of numbers in chunks of 100 or their
#Remainder and addes them into a dictionary with their count number as the
#index value
print 'returning:'
print screenNames
The above code works but it feels clunky does anyone have any better ways of handling this?
as far as I can see, you map a key n to the value n % 100, so this might be as well written as
screenNames = dict((i, i%100) for i in range(238))
print screenNames
Running your code, it looks like you're just doing modular arithmetic:
l = 238
sn = {}
for i in xrange(l):
sn[i] = i % 100
print sn
Or more succinctly:
l = 238
print dict((i, i % 100) for i in xrange(l))
That works by constructing a dictionary based on key-pair tuples.

Categories

Resources