Python - variable not updating in loop - python

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)

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.

Python lowest missing integer: Codility Demo Task. What am I missing?

I'm playing with the Codality Demo Task. It's asking to design a function which determines the lowest missing integer greater than zero in an array.
I wrote a function that works, but Codility tests it as 88% (80% correctness). I can't think of instances where it would fail.
def solution(A):
#If there are negative values, set any negative values to zero
if any(n < 0 for n in A):
A = [(i > 0) * i for i in A]
count = 0
else: count = 1
#Get rid of repeating values
A = set(A)
#At this point, we may have only had negative #'s or the same # repeated.
#If negagive #'s, or repeated zero, then answer is 1
#If repeated 1's answer is 2
#If any other repeated #'s answer is 1
if (len(A) == 1):
if (list(A)[0] == 1):
return 2
else:
return 1
#Sort the array
A = sorted(A)
for j in range(len(A)):
#Test to see if it's greater than zero or >= to count. If so, it exists and is not the lowest integer.
#This fails if the first # is zero and the second number is NOT 1
if (A[j] <= count or A[j] == 0): #If the number is lt or equal to the count or zero then continue the count
count = count + 1
elif (j == 1 and A[j] > 1): return 1
else:
return count
return count
UPDATE:
I got this to 88% with the fixes above. It still fails with some input. I wish Codility would give the inputs that fail. Maybe it does with a full subscription. I'm just playing with the test.
UPDATE 2: Got this to 100% with Tranbi's suggestion.
def solution(A):
#Get rid of all zero and negative #'s
A = [i for i in A if i > 0]
#At this point, if there were only zero, negative, or combination of both, the answer is 1
if (len(A) == 0): return 1
count = 1
#Get rid of repeating values
A = set(A)
#At this point, we may have only had the same # repeated.
#If repeated 1's answer is 2
#If any other repeated #'s only, then answer is 1
if (len(A) == 1):
if (list(A)[0] == 1):
return 2
else:
return 1
#Sort the array
A = sorted(A)
for j in range(len(A)):
#Test to see if it's >= to count. If so, it exists and is not the lowest integer.
if (A[j] <= count): #If the number is lt or equal to the count then continue the count
count = count + 1
else:
return count
return count
Besides that bug for len=1, you also fail for example solution([0, 5]), which returns 2.
Anyway... Since you're willing to create a set, why not just make this really simple?
def solution(A):
A = set(A)
count = 1
while count in A:
count += 1
return count
I don't think this is true:
#At this point, we may have only had negative #'s or the same # repeated. If so, then the answer is 1+ the integer.
if (len(A) == 1):
return list(A)[0]+1
If A = [2] you should return 1 not 3.
Your code is quite confusing though. I think you could replace
if any(n < 0 for n in A):
A = [(i > 0) * i for i in A]
with
A = [i for i in A if i > 0]
What's the point of keeping 0 values?
I don't think this is needed:
if (len(A) == 1):
if (list(A)[0] == 1):
return 2
else:
return 1
It's already taken into account afterwards :)
Finally got a 100% score.
def solution(A):
# 1 isn't there
if 1 not in A:
return 1
# it's easier to sort
A.sort()
# positive "hole" in the array
prev=A[0]
for e in A[1:]:
if e>prev+1>0:
return prev+1
prev=e
# no positive "hole"
# 1 is in the middle
return A[-1]+1

For loop stores old variable value?

I am trying to implement ZigZag from LeetCode. Somehow during the second recursive call my second for loop within "addElements" retains the value from the last call. Why does this happen?
I have shared the output below - my question is in regards to how beg and end stay the same value until 3, then beg moves to 6 as expected but end remains at 3.
https://leetcode.com/problems/zigzag-conversion/
class Solution:
def convert(self, s: str, numRows: int) -> str:
row = [''] * len(s)
self.s = s
self.numRows = numRows
self.final_grid = []
for i in range(numRows):
self.final_grid.append(list(row))
self.addElements(0, 0)
final_arr = []
for i in self.final_grid:
final_arr += i
final_word = ''
for i in final_arr:
if i != "":
final_word += i
return (final_word)
def addElements(self, count, column):
print(column, "beg")
for i in range(self.numRows):
if count > len(self.s) - 1:
break
self.final_grid[i][column] = self.s[count]
count += 1
for i in range(1, self.numRows - 1):
if count > len(self.s) - 1:
break
self.final_grid[self.numRows - i - 1][column + i] = self.s[count]
count += 1
print(column, "end")
self.addElements(count, column + self.numRows - 1)
INPUT: "PAYPALISHIRING" 4
STDOUT:
0 beg
0 end
3 beg
3 end
6 beg
3 end **why does this stay at 3?
6 beg
0 end
3 beg
3 end
6 beg
3 end
6 beg
Output: "PINALSIGYAHRGPIG"
Expected: "PINALSIGYAHRPI"
The problem appears to be this block:
for i in range(1, self.numRows - 1):
if count > len(self.s) - 1:
break
self.final_grid[self.numRows - i - 1][column + i] = self.s[count]
count += 1
print(column, "end")
self.addElements(count, column + self.numRows - 1)
Here, you are recursing for every element in the loop. You probably meant:
def addElements(self, count, column):
for i in range(self.numRows):
if count >= len(self.s):
return # <-- return instead of break
self.final_grid[i][column] = self.s[count]
count += 1
for i in range(1, self.numRows - 1):
if count >= len(self.s):
return # <-- return instead of break
self.final_grid[self.numRows-i-1][column+i] = self.s[count]
count += 1
self.addElements(count, column + self.numRows - 1)
#^^^ move this outside of the loop
With these changes, the output matches expected: "PINALSIGYAHRPI". The code is still a bit awkward and the various conditionals are strangely placed, doing double duty as pre/post conditions, so I'd consider a re-write.
Caveat: I've only taken a look at this problem and I'm not vouching that this code will work on the remainder of the tests. For one, it uses a huge amount of memory, so there is likely a way to build the result without creating a giant n x m array. There are other minor inefficiencies, like building the result array character by character, then building the result string from the array (runs in quadratic time because strings are immutable).
Instead of:
final_arr = []
for i in self.final_grid:
final_arr += i
final_word = ''
for i in final_arr:
if i != "":
final_word += i
return (final_word)
use:
return "".join(map("".join, self.final_grid))
Instead of:
row = [''] * len(s)
consider:
row = [''] * ((len(s) // 2) + 1)
Because the last element of the for loop stores the last variable.
To make so that you don't have that variable type del variable if you try to use that variable without reassigning a new value, it will throw an error

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

How to replace the for with a while loop

How can I change the for loop into a while loop. What are the significant differences between using for and while loop?
S="I had a cat named amanda when I was little"
count = 0
for i in S:
if i =="a":
count += 1
print (count)
Following is the while loop implementation of same code.
i = 0
count = 0
while i < len(S):
if S[i] == 'a':
count += 1
i += 1
print count
You need a counter which will be incremented each time "while counter < len(S)"
Here's a start:
index = 0
count = 0
while index < len(S):
#do something with index and S ...
index += 1
You could also do it via the boolean nature of an empty string/list/dictionary.
S="I had a cat named amanda when I was little"
count = 0
while S:
# pop the first character off of the string
ch, S = S[0], S[1:]
if ch == "a":
count += 1
print (count)

Categories

Resources