How do I fix my infinite loop from an if statement? - python

Alice has a W-word essay due tomorrow (1 ≤ W ≤ 10,000), but she's too
busy programming to bother with that! However, Alice happens to know
that H.S. High School's English teacher is sick of reading and grading
long essays, so she figures that if she just submits a "reasonable"
essay which fulfills the requirements but is as short as possible, she
may get some pity marks!
As such, Alice wants to write a program to generate a sequence of W
words to pass off as her essay, where each word is any string
consisting of 1 or more lowercase letters ("a".."z") (not necessarily
a real English word). The essay will have no punctuation or
formatting, as those seem unnecessary to Alice. In an attempt to
disguise the essay's generated nature, Alice will insist that all W
words are distinct. Finally, for her plan to come together, she'll
make the sum of the W words' lengths as small as possible.
Help Alice generate any essay which meets the above requirements.
As of now, I think I've identified a piece of code that is causing an infinite loop. However, I cannot find out how to fix it. My theory: the first if statement is contradicting with the other if statements, causing an infinite loop. It is starting to loop infinitely when it reaches third character words.
import string, math
w = int (raw_input(" "))
words = []
paragraph = ""
alphabet = string.ascii_lowercase
first_alpha = -1
second_alpha = 0
third_alpha = 1
switch_to_two_char = False
switch_to_three_char = False
def unique(s):
return len(set(s)) == len(s)
x = 0
while (x != w):
word = ""
if (x != 0):
word = " "
if (first_alpha >= 25):
first_alpha = 0
switch_to_two_char = True
elif (second_alpha >= 25):
second_alpha = 0
first_alpha += 1
elif (second_alpha >= 25 & first_alpha >= 25):
first_alpha = 0
second_alpha = 0
switch_to_three_char = True
elif (third_alpha >= 25):
second_alpha += 1
third_alpha = 0
else:
if (switch_to_two_char and not switch_to_three_char):
second_alpha += 1
if (switch_to_three_char):
third_alpha += 1
else:
first_alpha += 1
if (switch_to_two_char):
word += alphabet[second_alpha]
word += alphabet[first_alpha]
elif (switch_to_three_char):
word += alphabet[third_alpha]
word += alphabet[second_alpha]
word += alphabet[first_alpha]
else:
word += alphabet[first_alpha]
if (unique(word) == 0):
continue
if (word in words):
continue
else:
paragraph += word
words.append (word)
x += 1
print paragraph

When second_alpha add to 25, first_alpha+1 and second_alpha return to 0. So, when the first_alpha add to 25 finally, the second_alpha return to 0 again. Next loop, you program will go into this if-statement.
elif (first_alpha >= 25):
first_alpha = 0
switch_to_two_char = True
And then, both of first_alpha and second_alpha return to 0 again.

Related

Incorrect sliding window algorithm (in python)

While trying this question: https://leetcode.com/problems/permutation-in-string/
"Given two strings s1 and s2, return true if s2 contains a permutation
of s1, or false otherwise.
In other words, return true if one of s1's permutations is the
substring of s2."
I came up with a sliding window solution, but I did not want to use an additional hash table for keeping track of the letters in the current window. I am struggling to figure out why it is not correct.
Fails with this example: "trinitrophenylmethylnitramine" "dinitrophenylhydrazinetrinitrophenylmethylnitramine"
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
s1_ht = {}
for char in s1:
if char in s1_ht:
s1_ht[char] += 1
else:
s1_ht[char] = 1
start = 0
counter = len(s1_ht)
for i in range(0, len(s2), 1):
if s2[i] in s1_ht:
s1_ht[s2[i]] -= 1
if s1_ht[s2[i]] == 0:
counter -= 1
if i - start + 1 == len(s1):
if counter == 0:
return True
if s2[start] in s1_ht:
s1_ht[s2[start]] += 1
if s1_ht[s2[start]] > 0:
counter += 1
start += 1
return False
Great solution. But there is a minor mistake here:
if s1_ht[s2[start]] > 0:
counter += 1
In these lines of code, you increment the counter although s1_ht[ s2[start] ] was not zero before the incrementation. Let me explain with an example. Suppose s1_ht['t'] = 4. Then you find s2[start] = 't'. Therefore you increment s1_ht['t'] and set it equal to 5. But then you increment the counter which leads to an error. You shouldn't increment the counter since it already covers the character 't'. Swap that line with this:
if s1_ht[s2[start]] == 1: # just before the incrementation, it was zero
counter += 1
It passes the Leetcode test cases with 61 ms runtime and 14 MB memory on my machine.

Counting occurrences of a sub-string without using a built-in function

My teacher challenged me of finding a way to count the occurences of the word "bob" in any random string variable without str.count(). So I did,
a = "dfjgnsdfgnbobobeob bob"
compteurDeBob = 0
for i in range (len(a) - 1):
if a[i] == "b":
if a[i+1] == "o":
if a[i+2] == "b":
compteurDeBob += 1
print(compteurDeBob)
but I wanted to find a way to do that with a word of any length as shown below, but I have no clue on how to do that...
a = input("random string: ")
word = input("Wanted word: ")
compteurDeBob = 0
for i in range (len(a)-1):
#... i don't know...
print(compteurDeBob)
a = input("random string: ")
word = input("Wanted word: ")
count = 0
for i in range(len(a)-len(word)):
if a[i:i+len(word)] == word:
count += 1
print(count)
If you want your search to be case-insensitive, then you can use lower() function:
a = input("random string: ").lower()
word = input("Wanted word: ").lower()
count = 0
for i in range(len(a)):
if a[i:i+len(word)] == word:
count += 1
print(count)
For the user input
Hi Bob. This is bob
the first approach will output 1 and the second approach will output 2
To count all overlapping occurrences (like in your example) you could just slice the string in a loop:
a = input("random string: ")
word = input("Wanted word: ")
cnt = 0
for i in range(len(a)-len(word)+1):
if a[i:i+len(word)] == word:
cnt += 1
print(cnt)
You can use string slicing. One way to adapt your code:
a = 'dfjgnsdfgnbobobeob bob'
counter = 0
value = 'bob'
chars = len(value)
for i in range(len(a) - chars + 1):
if a[i: i + chars] == value:
counter += 1
A more succinct way of writing this is possible via sum and a generator expression:
counter = sum(a[i: i + chars] == value for i in range(len(a) - chars + 1))
This works because bool is a subclass of int in Python, i.e. True / False values are considered 1 and 0 respectively.
Note str.count won't work here, as it only counts non-overlapping matches. You could utilise str.find if built-ins are allowed.
The fastest way to calculate overlapping matches is the Knuth-Morris-Pratt algorithm [wiki] which runs in O(m+n) with m the string to match, and n the size of the string.
The algorithm first builds a lookup table that acts more or less as the description of a finite state machine (FSM). First we construct such table with:
def build_kmp_table(word):
t = [-1] * (len(word)+1)
cnd = 0
for pos in range(1, len(word)):
if word[pos] == word[cnd]:
t[pos] = t[cnd]
else:
t[pos] = cnd
cnd = t[cnd]
while cnd >= 0 and word[pos] != word[cnd]:
cnd = t[cnd]
cnd += 1
t[len(word)] = cnd
return t
Then we can count with:
def count_kmp(string, word):
n = 0
wn = len(word)
t = build_kmp_table(word)
k = 0
j = 0
while j < len(string):
if string[j] == word[k]:
k += 1
j += 1
if k >= len(word):
n += 1
k = t[k]
else:
k = t[k]
if k < 0:
k += 1
j += 1
return n
The above counts overlapping instances in linear time in the string to be searched, which was an improvements of the "slicing" approach that was earlier used, that works in O(m×n).

count an occurrence of a string in a bigger string

I am looking to understand what I can do to make my code to work. Learning this concept will probably unlock a lot in my programming understanding. I am trying to count the number of times the string 'bob' occurs in a larger string. Here is my method:
s='azcbobobegghakl'
for i in range(len(s)):
if (gt[0]+gt[1]+gt[2]) == 'bob':
count += 1
gt.replace(gt[0],'')
else:
gt.replace(gt[0],'')
print count
How do I refer to my string instead of having to work with integers because of using for i in range(len(s))?
Try this:
def number_of_occurrences(needle, haystack, overlap=False):
hlen, nlen = len(haystack), len(needle)
if nlen > hlen:
return 0 # definitely no occurrences
N, i = 0, 0
while i < hlen:
consecutive_matching_chars = 0
for j, ch in enumerate(needle):
if (i + j < hlen) and (haystack[i + j] == ch):
consecutive_matching_chars += 1
else:
break
if consecutive_matching_chars == nlen:
N += 1
# if you don't need overlap, skip 'nlen' characters of 'haystack'
i += (not overlap) * nlen # booleans can be treated as numbers
i += 1
return N
Example usage:
haystack = 'bobobobobobobobobob'
needle = 'bob'
r = number_of_occurrences(needle, haystack)
R = haystack.count(needle)
print(r == R)
thanks. your support help to birth the answer in. here what I have :
numBobs = 0
for i in range(1, len(s)-1):
if s[i-1:i+2] == 'bob':
numBobs += 1
print 'Number of times bob occurs is:', numBobs

Python - variable not updating in loop

I am trying to solve the 'Love-Letter' mystery problem of HackerRank using Python, but I am stuck at a place where in my loop a variable is not getting updated.
s = input()
first_char = s[0]
last_char = s[-1]
ascii_first_char = ord(first_char)
ascii_last_char = ord(last_char)
count = 0
i = 1
while ascii_first_char < ascii_last_char:
count += abs((ascii_last_char-ascii_first_char))
ascii_first_char = ord(s[i])
ascii_last_char = ord(s[-i])
i += 1
print(count)
If you try to run that, you would see that alc is not changing it's value according to ord(s[i]) where I keeps incrementing. Why is that happening?
You get the first letter with s[0] and the last with s[-1]. In your loop you take the next letters with the same index i.
I don't understand your condition in the while loop. Instead of "ascii_first_char < ascii_last_char" you should test if you have looked at every element of the string. For that we have to loop len(s)/2 times. Something like:
while i < len(s) - i:
or equivalent
while 2*i < len(s):
And this conditions only work for even length. I prefer for-loops when I know how many times I will loop
current_line = input()
# if length is even, we don't care about the letter in the middle
# abcde <-- just need to look for first and last 2 values
# 5 // 2 == 2
half_length = len(current_line) // 2
changes = 0
for i in range(index):
changes += abs(
ord(current_line[i]) - ord(current_line[-(i+1)])
)
print (changes)
s1 = ['abc','abcba','abcd','cba']
for s in s1:
count = 0
i = 0
j = -1
median = len(s)/2
if median == 1:
count += abs(ord(s[0])-ord(s[-1]))
else:
while i < len(s)/2:
count += abs(ord(s[j])-ord(s[i]))
i += 1
j -= 1
print(count)

Looping and Counting w/find

So I am working diligently on some examples for my homework and came across yet another error.
The original:
word = 'banana'
count = 0
for letter in word:
if letter == 'a':
count = count + 1
print count
Ok. Looks simple.
I then used this code in a function name count and generalized it so that it accepts the string and the letter as argument.
def count1(str, letter):
count = 0
word = str
for specific_letter in word:
if specific_letter == letter:
count = count + 1
print count
This is where I'm still not sure what I'm doing wrong.
I have to rewrite this function so that instead of traversing the string, it uses the three-parameter version of find from the previous section. Which this is:
def find(word, letter, startat):
index = startat
while index <= len(word):
if word[index] == letter:
return index
index = index + 1
return -1
This is how far I got... but the program doesn't work the way I want it to.
def find(str, letter, startat):
index = startat
word = str
count = 0
while index <= len(word):
if word[index] == letter:
for specific_letter in word:
if specific_letter == letter:
count = count + 1
print count
index = index + 1
Can someone point me in the right direction. I want to understand what I'm doing instead of just given the answer. Thanks.
The point of the exercise is to use the previously defined function find as a building block to implement a new function count. So, where you're going wrong is by trying to redefine find, when you should be trying to change the implementation of count.
However, there is a wrinkle in that find as you have given has a slight error, you would need to change the <= to a < in order for it to work properly. With a <=, you could enter the body of the loop with index == len(word), which would cause IndexError: string index out of range.
So fix the find function first:
def find(word, letter, startat):
index = startat
while index < len(word):
if word[index] == letter:
return index
index = index + 1
return -1
And then re-implement count, this time using find in the body:
def count(word, letter):
result = 0
startat = 0
while startat < len(word):
next_letter_position = find(word, letter, startat)
if next_letter_position != -1:
result += 1
startat = next_letter_position + 1
else:
break
return result
if __name__ == '__main__':
print count('banana', 'a')
The idea is to use find to find you the next index of the given letter.
In your code you don't use the find function.
If you want to try something interesting and pythonic: Change the original find to yield index and remove the final return -1. Oh, and fix the <= bug:
def find(word, letter, startat):
index = startat
while index < len(word):
if word[index] == letter:
yield index
index = index + 1
print list(find('hello', 'l', 0))
Now find returns all of the results. You can use it like I did in the example or with a for position in find(...): You can also simply write count in terms of the length of the result.
(Sorry, no hints on the final function in your question because I can't tell what you're trying to do. Looks like maybe you left in too much of the original function and jumbled their purposes together?)
Here's what I came up with: This should work.
def find(word, letter, startat)
index = startat
count = 0
while index < len(word):
if word[index] == letter:
count = count + 1 ##This counts when letter matches the char in word
index = index + 1
print count
>>> find('banana', 'a', 0)
3
>>> find('banana', 'n', 0)
2
>>> find('mississippi', 's', 0)
4
>>>
Try using :
def find_count(srch_wrd, srch_char, startlookingat):
counter = 0
index = startlookingat
while index < len(srch_wrd):
if srch_wrd[index] == srch_char:
counter += 1
index += 1
return counter`
def count_letter2(f, l):
count = 0
t = 0
while t < len(f):
np = f.find(l, t)
if np != -1:
count += 1
t = np + 1
"I was wrong by doing t =t +1"
else:
break
return count
print(count_letter2("banana", "a"))
print(count_letter2("abbbb", "a"))

Categories

Resources