How to understand this Python code for Twosum - python

The leetcode twosum problem:
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
I read someone's python code as following:
vis = {}
for i,num in enumerate(nums):
diff = target - num
if diff in vis:
return[vis[diff],i]
vis[num] = i
I can understand the majority of logic behind this code. However why the last line have to be in this order? It seems weird to me to make assignment after the return statement.
So I tried to move it to other places, but this will output null. Why does the last line have to be at that place?

The return statement is within the if statement, so it will only execute if diff is in vis, i.e., when you have found a diff you wanted, such that nums[diff] + nums[i] == target is True. If that doesn't happen, only then the final statement will be executed. So, it would add the diff for a later comparison and would move on with the next iteration.

Related

How is my almostIncreasingSequence(sequence) code incorrect? [CodeSignal]

I've seen some posts about this same question, and I think my logic is pretty much the same as their answers. But I cannot find where exactly I'm wrong here.
My code first checks the length of the provided sequence, if it is 2 or less it automatically returns True.
Next, it removes(pops) the first element and check if the rest are in ascending order.
If the sequence isn't in order, it replaces it with the original sequence and repeats the second step, but this time it removes the next element (pop(i)).
This continues until there are no more elements to remove, which ultimately returns as False
If in any of the iterations, the list is found to be in ascending order, the function returns True.
This is the code:
def almostIncreasingSequence(sequence):
original = sequence.copy()
if len(sequence) <= 2: return True
for i in range(len(sequence)):
sequence.pop(i)
# print(sequence)
for j in range(len(sequence)-1):
if sequence[j+1] <= sequence[j]:
sequence = original.copy()
elif j+1 == len(sequence)-1:
return True
if i == len(sequence)-1:
return False
And this is my result :'(
I think my logic may not be correctly implemented in the code. But I don't know how to test it. It'd be helpful if you can give me a sequence where this function will give a wrong answer.
Solve almostIncreasingSequence (Codefights)
This is one of the posts I was referring to at the very beginning. It also explains the almostIncreasingSequence(sequence) question and the answer explains the logic behind the code.
You don't have to try every element. Just find the violation of the ascension, and try to resolve it by removing one of the violators. Then check the rest of the list.
More formally, suppose that the sequence[:i] is in the ascending order, but sequence[i] < sequence[i+1]. You cannot keep them both; one must be gone. Which one, depends on sequence[i-1].
If sequence[i+1] < sequence[i-1], removal of sequence[i] wouldn't help: a violation will remain. Therefore, remove sequence[i+1]. Otherwise, remove sequence[i] (do you see why?). Finally, check that the rest of sequence is ascending.

Function result varies on each run

I have the following function that generates the longest palindrome of a string by removing and re-ordering the characters:
from collections import Counter
def find_longest_palindrome(s):
count = Counter(s)
chars = list(set(s))
beg, mid, end = '', '', ''
for i in range(len(chars)):
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i - 1]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
end = beg
end = ''.join(list(reversed(end)))
return beg + mid + end
out = find_longest_palindrome('aacggg')
print(out)
I got this function by 'translating' this example from C++
When ever I run my function, I get one of the following outputs at random it seems:
a
aca
agcga
The correct one in this case is 'agcga' as this is the longest palindrome for the input string 'aacggg'.
Could anyone suggest why this is occurring and how I could get the function to reliably return the longest palindrome?
P.S. The C++ code does not have this issue.
Your code depends on the order of list(set(s)).
But sets are unordered.
In CPython 3.4-3.7, the specific order you happen to get for sets of strings depends on the hash values for strings, which are explicitly randomized at startup, so it makes sense that you’d get different results on each run.
The reason you don’t see this in C++ is that the C++ set class template is not an unordered set, but a sorted set (based on a binary search tree, instead of a hash table), so you always get the same order in every run.
You could get the same behavior in Python by calling sorted on the set instead of just copying it to a list in whatever order it has.
But the code still isn’t correct; it just happens to work for some examples because the sorted order happens to give you the characters in most-repeated order. But that’s obviously not true in general, so you need to rethink your logic.
The most obvious difference introduced in your translation is this:
count[ch--]--;
… or, since you're looping over the characters by index instead of directly, more like:
count[chars[i--]]--;
Either way, this decrements the count of the current character, and then decrements the current character so that the loop will re-check the same character the next time through. You've turned this into something completely different:
count[chars[i - 1]] -= 1
This just decrements the count of the previous character.
In a for-each loop, you can't just change the loop variable and have any effect on the looping. To exactly replicate the C++ behavior, you'd either need to switch to a while loop, or put a while True: loop inside the for loop to get the same "repeat the same character" effect.
And, of course, you have to decrement the count of the current character, not decrement the count of the previous character that you're never going to see again.
for i in range(len(chars)):
while True:
if count[chars[i]] % 2 != 0:
mid = chars[i]
count[chars[i]] -= 1
else:
for j in range(0, int(count[chars[i]] / 2)):
beg += chars[i]
break
Of course you could obviously simplify this—starting with just looping for ch in chars:, but if you think about the logic of how the two loops work together, you should be able to see how to remove a whole level of indentation here. But this seems to be the smallest change to your code.
Notice that if you do this change, without the sorted change, the answer is chosen randomly when the correct answer is ambiguous—e.g., your example will give agcga one time, then aggga the next time.
Adding the sorted will make that choice consistent, but no less arbitrary.

How to use Boolean variable as the if conditon in Python

I feel confused about the code as follows:
define this findmin function to find the smallest number in alist, O(n^2)
def findMin(alist):
overallmin=alist[0]
for i in alist:
issmallest=True
for j in alist:
if i>j:
issmallest=False
if issmallest:
overallmin = i
return overallmin
I can't understand: why the author set "issmallest = True" below the first for loop? Commonly when we feel like to use boolean values like this situation(such as assign boolean value to a variable at the beginning of the code or put the boolean values as the if-statement conditions)? Thanks!
Okay so first off, to erase a few of the mistakes in the code, a working example would be:
def findMin(alist):
overallmin=alist[0]
for i in alist:
issmallest=True
for j in alist:
if i>j:
issmallest=False
if issmallest:
overallmin = i
return overallmin
The idea behind this code is to compare all elements in a list with all others and keep the one that is smaller than all others. In the loop it is therefore assumed that the current element is the smallest issmallest = True until a smaller one is found. If a smaller one is found, the value of issmallest is changed to False. So if, after comparison with all others, issmallest is still True, then the element is truly the smallest and therefore fixed as such.
You could simplify this code , as there is no need in further comparing once the smallest element is found, i.e. you can leave the function. Also in this algorithm there is no need of keeping a variable for the smallest element. The corresponding code might read something like:
def findMin(alist):
for current_el in alist:
issmallest = True
for other_el in alist:
if other_el < current_el:
issmallest = False
if issmallest:
return current_el
But: Even for beginners, this is not a good code to find the minimum. I can say that as a beginner myself. It is much cleaner to go through the list once, with an element at hand, compare it while going through, and always keep the smallest.
So even with low afford you can write a much faster algorithm like this:
def findMin(alist):
smallest_el = alist.pop() # take out an element, no need to compare with itself
for other_el in alist:
if other_el < smallest_el:
smallest_el = other_el
return smallest_el
The condition of while always must evaluate to boolean. if it evaluates to true, the loop continues, otherwise, the statements after the loop will be executed. Please note: the code in your question did not involve a while loop. This code is very bad, please forget it, and everything that came with it. For learning, try this: https://www.learnpython.org/.

Trying to create a sorting algorithm from scratch in Python

I'm taking a course on programming (I'm a complete beginner) and the current assignment is to create a Python script that sorts a list of numbers in ascending order without using built-in functions like "sorted".
The script I started to come up with is probably laughably convoluted and inefficient, but I'd like to try to make it work eventually. In other words, I don't want to just copy someone else's script that's better.
Also, as far as I can tell, this script (if it ever functioned) would probably just put things in a NEW order that wouldn't necessarily be ascending. This is just a start, though, and hopefully I'll fix that later.
Anyway, I've run in to several problems with the current incarnation, and the latest is that it just runs forever without printing anything.
So here it is (with hashes explaining what I was trying to accomplish). If someone could look over it and tell me why the code does not match my explanations of what each block is supposed to do, that would be great!
# The numbers to be inputted, could be anything
numList = [1, 25, 5, 6, 17, 4]
# The final (hopefully sorted) list
numSort = []
# The index
i = 0
# Run the loop until you run out of numbers
while len(numList) != 0:
# If there's only one value left in numList,
# attach it to the end of numSort.
# (Variable 'basket' is just for transporting numbers)
if len(numList) == 1:
basket = numList.pop()
numSort.append(basket)
# The rest of the elifs are supposed to compare values
# that sit next to each other.
# If there's still a number in numList after 'i'
# and 'i' is smaller than that next number
# then pop 'i' and attach it to the end of numSort
elif numList[i+1] != numList[-1] and numList[i] < numList[i+1]:
basket = numList.pop(i)
numSort.append(basket)
# If there's NOT a number after 'i'
# then compare 'i' to the first number in the list instead.
elif numList[i+1] == numList[-1] and numList[i] < numList[0]:
basket = numList.pop(i)
numSort.append(basket)
# If 'i' IS the last number in the list
# and has nothing to compare itself to,
# Then start over and go through it again
# from the beginning
elif numList [i+1] == numList[-1]:
i = 0
# If 'i' is not at the end of numList yet
# and 'i' is NOT smaller than the next number
# and there are still numbers left
# then move on to the next pair
# and continue comparing and moving numbers
else:
i = i+1
# Hopefully these will be in ascending order eventually.
print(numSort)
Here is a simple way to sort your list with a classic loop :
myList = [2,99,0,56,8,1]
for i,value in enumerate(myList):
for j,innerValue in enumerate(myList):
if value < innerValue: #for order desc use '>'
myList[j],myList[i]=myList[i],myList[j]
print(myList)
The Algorithm behind this code is :
fix one value of the list and compare it with the rest
if it is smallest then switch the index of two values
I hope this will help you
Your conditions are essentially:
If there is only one number in the list
The current number is less than the next, which is not equal to the last number
The current number is less than the first number, and the next number is equal to the last number
The next number is equal to the last number
If you trace out the code by hand you will see how in many cases, none of these will evaluate to true and your "else" will be executed and i will be incremented. Under these conditions, certain numbers will never be removed from your original list (none of your elifs will catch them), i will increment until the next number is equal to the last number, i will be reset to zero, repeat. You are stuck in an infinite loop. You will need to update your if-statement in such a way that all numbers will eventually be caught by a block other than your final elif.
On a separate note, you are potentially comparing a number to only one number in the current list before appending it to the "sorted" list. You will likely need to compare the number you want to add to your "sorted" list and find its proper place in THAT list rather than merely appending.
You should also consider finding the end of list using a method more like
if i == len(numList) - 1
This will compare the index to the length of the list rather than comparing more values in the list which are not necessarily relevant to the order you are trying to create.

Quick Sort using Python

I was wondering if someone can help me to fix the error my code for quick sort has:
It does not compile and highlights the last line of the code in red.
I can not figure out what is wrong. sort is already defined as a function so why is it highlighted as red?
def sort(*myarray):
less = []
equal = []
greater = []
if len(myarray) > 1:
pivot = myarray[0]
for x in myarray:
if x < pivot:
less.append(x)
if x == pivot:
equal.append(x)
if x > pivot:
greater.append(x)
return sort(less)+sort(equal)+sort(greater)
else:
return myarray
print sort([12,4,5,6,7,3,1,15])
You're defining the function as taking a variable number of arguments (the *myarray bit), but then using myarray inside as a single argument (the list to sort), when it is a list containing the list to sort.
You probably should remove the * from your function parameter. This questions esplains it quite thoroughly.
You could keep the *, but then you would have to play a bit with tuple unpacking to get the same result.
edit
Although the above is true, this might not be the issue you're encountering.
IDLE will give you the invalid syntax error on the ast line, because in interactive mode - with lines starting with >>>, it accepts only one statement at a time. In your case that statement is the sort() definition.
Try hitting enter 2 times after the function definition, this should get you back to the repl, where you can introduce another statement (print sort([12,4,5,6,7,3,1,15]))
There are a couple things wrong which makes me curious how you are testing this:
Python code is not "compiled", it is interpreted. (Okay, not precisely true; it's parsed into a sort of byte-code; still, it's not compiled in the same sense as a language such as C, where the entire program has to be converted into machine instructions before any of it can be run.) Also you mention the last line of code is highlighted in red -- by what?
This code actually works, but only if you remote the star/asterisk in front of myarray in def sort(*myarray):. Otherwise it actually returns a single-element tuple containing the original array.
Assuming you have two or more elements that equal a pivot at some point, you get an infinite loop, because you will get: equal = [x,x] (two elements at least), and then invoke sort([x,x]), which in its turn will take x as a pivot, and create equal = [x,x], and cause sort([x,x]), ....
Simple solution to this problem: What should be the output of the sort(equal)? How do you sort a list of identical elements?
Edit: Well, your comments show that you are looking for a different problem, but I'll leave it here because it explains a different issue you have with your code and should be solved.
If it is a function for quick sorting, can you really use the function sort in it?
Wouldn't something like this work?
def qsort(list):
pivind=0
left, right, pivot= [], [], []
for x in list:
if list[pivind]==x: pivot.append(x)
elif list[pivind]>x: left.append(x)
else: right.append(x)
if len(left)>1: left=qsort(left)
if len(right)>1: right=qsort(right)
return (left + pivot + right)

Categories

Resources