Python: fail to swap two elements in a list - python

Is there anyone can help me to have a look at this code.
I am trying to solve the first missing positive question in leetcode.
But this code cause an endless loop as I found I fail to swap the A[i] and A[A[i]-1]. But I have test to swap to elements in list using this simple code:
A = [2,1]
A[0], A[1] = A[1], A[0]
print A # A = [1,2]
I do not know what the mistake is :(
def firstMissingPositive(self, A):
i = 0
length = len(A)
while i < length:
if A[i] >= 1 and A[i] <= length:
if A[i] != i+1 and A[A[i]-1] != A[i]:
A[i], A[A[i]-1] = A[A[i]-1], A[i]
else:
i += 1
else:
i += 1
for i in range(length):
if A[i] != i+1:
return i+1
return length + 1

You're modifying A[i] during the execution of the assignment statement, and so the evaluation of A[A[i]-1] on the left-hand side of the = won't evaluate the way you're expecting it to. You need to change this:
A[i], A[A[i]-1] = A[A[i]-1], A[i]
to this:
tmp = A[i]-1
A[i], A[tmp] = A[tmp], A[i]
This phenomenon is addressed by a note in the Python Language Reference:
WARNING: Although the definition of assignment implies that overlaps between the left-hand side and the right-hand side are 'safe' (for example a, b = b, a swaps two variables), overlaps within the collection of assigned-to variables are not safe! For instance, the following program prints [0, 2]:
x = [0, 1]
i = 0
i, x[i] = 1, 2
print x

Related

Fastest (least execution time) approach to get max/min of an array of int without inbuilt functions except range() and len() [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
This post was edited and submitted for review 1 year ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I am looking for a faster, less execution time approach to get maximum and minimum elements of an array of integer, which means we need to sort an array of integers. Without using any inbuilt functions like sort() except range() and len() and using only one for or while loop, which I can't figure out.
def getMinMax( a, n):
while 1 == 1:
run = False
for i in range(n):
if i < (n-1) and a[i] > a[i+1]:
run = True
if run:
for i in range(n):
if i < (n-1) and a[i] > a[i+1]:
temp = a[i]
a[i] = a[i+1]
a[i+1] = temp
else:
break
return a[0], a[i], a
A = [2, 167, 56, 3, 10000, 1]
min_elem, max_elem, sorted_array = getMinMax(A, len(A))
min_elem, max_elem, sorted_array
Output:
(1, 10000, [1, 2, 3, 56, 167, 10000])
With one loop
def getMinMax( a, n):
min_elem = a[0]
max_elem = a[0]
for i in range(n):
if i < (n-1):
if a[i] > a[i+1]:
temp = a[i]
a[i] = a[i+1]
a[i+1] = temp
max_var, min_var = a[n-1], a[0]
return max_elem, min_elem
array = [3,123,200,4,500000,1]
getMinMax( array, len(array))
Output:
(500000, 3)
Basically, your method to find min and max is not having any major effect at all. Besides, it is taking more time to execute than the normal method of finding min and max. (i.e. to iterate twice and swap adjacent elements if the preceding and succeeding are lesser or greater, and then access the first and last element directly to get the min and max values resp.)
To demonstrate why your code is not efficient as the traditional method, I executed your code 100000000 times vs my traditional code the same number of times and found out that your code actually takes more time than mine!
import timeit
A = [3, 2, 1, 56, 10000, 167]
code1 = '''
def getMinMax( a, n):
while 1 == 1:
run = False
for i in range(n):
if i < (n-1) and a[i] > a[i+1]:
run = True
if run:
for i in range(n):
if i < (n-1) and a[i] > a[i+1]:
temp = a[i]
a[i] = a[i+1]
a[i+1] = temp
else:
break
print(a[i], a[0])
return a[i], a[0]
'''
code2 = '''
def min_max(A):
for i in range(len(A)):
for j in range(1, len(A)-1):
if A[j] > A[j+1]:
A[j],A[j+1] = A[j+1],A[j]
print(A[0], A[len(A)-1])
return A[0],A[len(A)-1]
'''
print(timeit.timeit(stmt=code1, number=100000000))
print(timeit.timeit(stmt=code2, number=100000000))
Output:
6.4907884000000005 #<-- your code's execution time after the 100000000th execution
5.600494200000001 #<-- my code's execution time after the 100000000th execution
I know this is ridiculous but if the person asking the question really doesn't want to use min() and/or max() then this also works:
def getMinMax(A):
if A:
a = sorted(A)
return a[0], a[-1]
return None, None
l=[1,2,3,4,5]
print(max(l),min(l))
Just use min() and max() function.
syntax:
for min()
min(iterable_name)
for max()
max(iterable_name)

Number of inversions with merge sort: Why do I not need to initialize a global variable here?

I implemented merge sort in python and am trying to get the number of inversions of a given array. An inversion is defined as a pair of indices 0 ≀ 𝑖 < 𝑗 < 𝑛 such that π‘Žπ‘– > π‘Žπ‘—. This problem is also described as 'how far away is an array from being sorted'.
Here is my code:
def merge(a,b):
c = [] # Output array
i, j = 0, 0 # Indices of the left and right split arrays
global num_inversions
# It looks like there is no need to initialize this? I don't understand this
while i < len(a) and j < len(b):
if a[i] <= b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
num_inversions = num_inversions + len(a) - i
if i == len(a):
c.extend(b[j:])
else:
c.extend(a[i:])
return c
def mergesort(a):
# Base case
if len(a) <= 1:
return a
mid = len(a) // 2
left_array = mergesort(a[:mid])
right_array = mergesort(a[mid:])
return merge(left_array, right_array)
if __name__ == '__main__':
#inp = input()
#n, *a = list(map(int, inp.split()))
a = [6, 5, 4, 3, 2, 1] # Sample input. Gives the correct answer 15
a_sorted = mergesort(a)
print(num_inversions)
I seem to be getting the correct result. What I don't understand is why the global variable num_inversions can be declared in the function, and why it doesn't need to be initialized.
Initializing it in the function is obviously wrong because the value will keep getting rewritten each time the function is called recursively.
Edit: Sorry, this question was incredibly stupid. I realized I did initialize it at some point while testing it, and forgot.

Merge sort in python: slicing vs iterating - impact on complexity

I want to check that my understanding of how python handles slices is correct.
Here's my implementation of merge sort:
def merge_sort(L):
def merge(a, b):
i, j = 0, 0
c = []
while i < len(a) and j < len(b):
if a[i] < b[j]:
c.append(a[i])
i += 1
elif b[j] < a[i]:
c.append(b[j])
j += 1
if a[i:]:
c.extend(a[i:])
if b[j:]:
c.extend(b[j:])
return c
if len(L) <= 1:
return L
else:
mid = len(L) // 2
left = merge_sort(L[:mid])
right = merge_sort(L[mid:])
return merge(left, right)
Am I right in thinking that I could replace this:
if a[i:]:
c.extend(a[i:])
if b[j:]:
c.extend(b[j:])
With this:
while i < len(a):
c.append(a[i])
i += 1
while j < len(b):
c.append(b[j])
j += 1
And have the exact same level of complexity? My understanding of slicing is that its complexity is equivalent to slice length? Is that correct?
Does the fact that I'm calling a slice twice (first in the condition, second time inside of it) make it 2x complexity?
Your implementation of mergesort has problems:
in the merge function's main loop, you do nothing if the values in a[i] and b[j] are equal, or more precisely if you have neither a[i] < b[i] nor a[i] > b[i]. This causes an infinite loop.
there is no need to define merge as a local function, actually there is no need to make it a separate function, you could inline the code and save the overhead of a function call.
Here is a modified version:
def merge_sort(L):
if len(L) <= 1:
return L
else:
mid = len(L) // 2
a = merge_sort(L[:mid])
b = merge_sort(L[mid:])
i, j = 0, 0
c = []
while i < len(a) and j < len(b):
if a[i] <= b[j]:
c.append(a[i])
i += 1
else:
c.append(b[j])
j += 1
if a[i:]:
c.extend(a[i:])
else:
c.extend(b[j:])
return c
Regarding performance, slicing or iterating has no impact on complexity since both operations have linear time cost.
Regarding performance, here are directions to try:
replace the test if a[i:] with if i < len(a). Creating the slice twice is costly.
perform the sort in place, avoiding the append operations
restructure the main loop to have a single test per iteration
Here is a modified version:
def merge_sort(L):
if len(L) <= 1:
return L
else:
mid = len(L) // 2
a = merge_sort(L[:mid])
b = merge_sort(L[mid:])
i, j, k = 0, 0, 0
while True:
if a[i] <= b[j]:
L[k] = a[i]
k += 1
i += 1
if (i == len(a)):
L[k:] = b[j:]
return L
else:
L[k] = b[j]
k += 1
j += 1
if (j == len(b)):
L[k:] = a[i:]
return L

maximum pairwise product fast solution

I am trying to apply a stress test on python maximum pairwise product, fast and slow algorithm. However, The fast code appears to return a wrong result in some tests. I think the problem comes from the if condition in the fast algorithm. The condition doesn't occur in some cases, though it should be applies. I wasn't able to figure out the problem. any help?
Here is the problem, I/P, O/P details:
Given a sequence of non-negative integers a0,…,anβˆ’1, find the maximum pairwise product, that is, the largest integer that can be obtained by multiplying two different elements from the sequence (or, more formally, max0≀iβ‰ j≀nβˆ’1aiaj). Different elements here mean ai and aj with iβ‰ j (it can be the case that ai=aj).
Input format
The first line of the input contains an integer n. The next line contains n non-negative integers a0,…,anβˆ’1 (separated by spaces).
Constraints:
2≀n≀2β‹…105; 0≀a0,…,anβˆ’1≀105.
Output format:
Output a single number β€” the maximum pairwise product.
from random import randint
from random import randrange
def max_pairwise(n,a):
# n = int(input())
res = 0
# a = [int(x) for x in input().split()]
assert(len(a) == n)
for i in range(0,n):
for j in range(i+1,n):
if a[i]*a[j] > res:
res = a[i]*a[j]
return(res)
def max_pairwise_fast(n,a):
# n = int(input())
# a = [int(x) for x in input().split()]
max_index1 = -1
max_index2 = -1
for i in range(0,n):
if a[i] > a[max_index1]:
max_index1 = i
else:
continue
for j in range(0,n):
if ((a[j] != a[max_index1]) and (a[j] > a[max_index2])):
max_index2 = j
else:
continue
res = a[max_index1]* a[max_index2]
return(res)
#stress_test
while(1):
n = randint(0,9) +2
print(n,"n")
a = []
for i in range (n):
a.append(randrange(9000))
for i in range(n):
print(a[i],'a[i]',"/n")
if (max_pairwise(n,a) == max_pairwise_fast(n,a)):
print(max_pairwise(n,a), max_pairwise_fast(n,a),"true")
else:
print(max_pairwise(n,a), max_pairwise_fast(n,a), "false")
break
This is an example of the result:
6 n
318 a[i] /n
7554 a[i] /n
7531 a[i] /n
7362 a[i] /n
4783 a[i] /n
4897 a[i] /n
56889174 56889174 true
5 n
6879 a[i] /n
6985 a[i] /n
8561 a[i] /n
5605 a[i] /n
3077 a[i] /n
59798585 59798585 true
9 n
8285 a[i] /n
3471 a[i] /n
2280 a[i] /n
2443 a[i] /n
5437 a[i] /n
2605 a[i] /n
1254 a[i] /n
6990 a[i] /n
2943 a[i] /n
57912150 68641225 false
In your fast implementation, when you are finding a largest number, you must also update the second largest to the value of the previous largest, otherwise, there are cases where you end up multiplying numbers that are not the two largest.
def product_of_two_largest(seq):
largest = float("-inf")
second_largest = float("-inf")
for elt in seq:
if elt > largest:
second_largest = largest
largest = elt
elif elt > second_largest:
second_largest = elt
return second_largest * largest
Note 1:
Your while loop must also be updated, you are calculating the values twice instead of once.
while(1):
n = randint(0,9) +2
print(n,"n")
a = []
for i in range (n):
a.append(randrange(9000))
for i in range(n):
print(a[i],'a[i]',"/n")
slow, fast = max_pairwise(n, a), two_largest_product(a)
if (slow == fast):
print(slow, fast, slow == fast)
else: # attention, this never happens now.
break
Note 2:
As we are dealing with only non-negative integers, you will likely have a faster implementation if you simply sort the sequence and multiply the last two numbers (in spite of the fact that sort is O(nlogn), vs O(n) for the fast implementation above.
b = sorted(a)
print("max1 x max2 = ", b[-1] * b[-2])
Note 3:
Using a heap data structure (from collections import heap) is the theoretical best way to find the n largest items, but you'd likely need to have 100,000's of items to make it worth your while.
def max_pairwise_fast(n, a):
max_index1 = 0
max_index2 = 0
for i in range(n):
if a[i] > max_index1:
max_index2 = max_index1
max_index1 = a[I]
elif a[i] > max_index2:
max_index2 = a[I]
return max_index1 * max_index2
if __name__ == '__main__':
input_n = int(input())
input_numbers = [int(x) for x in input().split()]
print(max_pairwise_fast(input_n, input_numbers))
This might not help you.
I was attempting this question at Coursera ( Assignment ) and found that we don't need to make the solution more complex. We can simply store the first two largest integers while scanning from the user and print their product. A complex solution is the main reason for the TLE error.
code in c
#include<stdio.h>
int main() {
long long n, a = 0, b = 0, i = 0, numb = 1;
scanf("%lld", &n);
for (i = 0; i < n; i++){
scanf("%lld", &numb);
if(numb >= a){
b = a;
a = numb;
}
else if(numb > b)
b = numb;
}
printf("%lld", a * b);
return 0;
}
With input array data:
Example: [1, 2, 3]
def max(arr):
a = 0
b = 0
for i in range(len(arr)):
if a == 0 & arr[i]>a:
a = arr[i]
else:
if arr[i]>a:
b = a
a = arr[i]
else:
if arr[i]>b:
b = arr[i]
return a*b;
def max_pairwise_fast(n, a):
max_index1 = 0
max_index2 = 0
for i in range(n):
if a[i] > max_index1:
max_index2 = max_index1
max_index1 = a[i]
elif a[i] > max_index2:
max_index2 = a[i]
return max_index1 * max_index2
if __name__ == '__main__':
input_n = int(input())
input_numbers = [int(x) for x in input().split()]
print(max_pairwise_fast(input_n, input_numbers))

Python Iterating and Comparing Multiple Lists

I have two lists of equal length: a and b. List b contains several of the same floating point numbers as list a at the same indices, but the other indices are replaced with zeros. These lists also contain several thousand values each.
I would like to iterate through list b until it gets to a non-zero value then iterate through list a from the same index until a greater value is reached. I want to then append that greater value to an empty list and then continue to iterate through list b until the next non-zero value and repeat.
c=[]
i = 0
j = 0
while i < len(a):
if b[i] == 0:
i = i + 1
if b[i] > 0:
j = i
if a[j] < b[i]:
j = j + 1
if a[j] == b[i]:
j = j + 1
if a[j] > b[i]:
c.append(a[j])
i = i + 1
I have tried multiple ways to do this with for and while loops and either end up just appending the whole of list a into the empty list or I create an infinite while loop, so any help or advice on how to get started would be greatly appreciated!
Incorporating #MichaelButscher's answer into this and adding another list d that contains dates that correspond to the values in lists a and b, I then appended the dates for the values that met the condition if a[j] > b[i]: into a new list e.
d=['05/01/2000','06/01/2000','07/01/2000','10/01/2000','11/01/2000','12/01/2000','23/10/2000','24/10/2000','25/10/2000','13/12/2000','14/12/2000','15/12/2000','20/02/2001','21/02/2001','21/09/2001','19/06/2002','20/06/2002']
a=[1.86,1.85,1.89,1.82,1.82,1.83,1.846,1.898,1.869,1.923,1.926,1.9677,1.959,2.02,2.802,2.7312,2.8035]
b=[0,0,1.89,0,0,0,0,0,0,0,0,1.9677,0,0,2.802,0,0]
c=[]
e=[]
i = 0
j = 0
# Run until break
while True:
while i < len(a):
if b[i] != 0:
break # break inner while
i += 1
else:
break # break outer while
# At this point: i < len(a) and b[i] != 0
j = i
while j < len(a):
if a[j] > b[i]:
# At this point: i < len(a) and b[i] != 0 and j < len(a) and a[j] > b[i]
c.append(a[j])
e.append(d[j])
break
j += 1
# At this point either appropriate j was found or j == len(a)
# Anyway, next i to check
i += 1
lists c and e were then printed in columns:
24/10/2000 1.898
24/10/2000 1.898
21/02/2001 2.02
10/09/2001 2.606
20/06/2002 2.8035
24/09/2002 3.8132
22/09/2015 4.0667
04/09/2015 3.853
01/09/2015 3.7031
10/05/2004 3.148
Some of the data is repeated and isn't in ascending date order even though the dates in list d were.
This can be done by nesting while loops. Outer while just runs forever (until break) inner while loops check for desired state.
Untested but should work:
c=[]
i = 0
j = 0
# Run until break
while True:
while i < len(a):
if b[i] != 0:
break # break inner while
i += 1
else:
break # break outer while
# At this point: i < len(a) and b[i] != 0
j = i
while j < len(a):
if a[j] > b[i]:
# At this point: i < len(a) and b[i] != 0 and j < len(a) and a[j] > b[i]
c.append(a[j])
break
j += 1
# At this point either appropriate j was found or j == len(a)
# Anyway, next i to check
i += 1

Categories