I am extremely new to Python and i am trying my hand in Algorithms. I was just trying my hands in the in place sorting of an array using quicksort algo.
Below is my code . When i run this there is an infinite loop as output. Can anyone kindly go through the code and let me know where i am going wrong logically :
def quicksort(arr,start,end):
if start < end:
pivot = arr[int(start + (end - start)/2)]
while end > start:
while arr[start] < pivot:
start = start + 1
while arr[end] > pivot:
end = end - 1
if start <= end:
arr[start],arr[end] = arr[end],arr[start]
start = start + 1
end = end - 1
quicksort(arr,0,end)
quicksort(arr,start,len(arr) - 1)
else:
return
arr = list(map(int,input().split(" ")))
quicksort(arr,0,len(arr) - 1)
print ("The final sorted array:",arr)
Thanks for any help in advance.
Your recursion is wrong. After doing Hoare Partition, you should do :
call quicksort from start (of data that being sorted) to index that run from the end, and
call quicksort from end (of data that being sorted) to index that run from the start
So you have to create new variables beside the argument to maintain start,end and indices that move toward each other in the partition.
In order to not change a lot of your code, i suggest you to change the argument
def quicksort(arr,left,right):
start = left
end = right
and do this in the recursion
quicksort(arr,left,end)
quicksort(arr,start,right)
Related
I am using the quicksort algorithm in Python whereby it swaps the values in place. My question is how does Python know I am using the same list in the Partition and quicksort function?
As you can see below in my code for quicksort, the swap for the position of the values only happens in the partition function. Yet, without needing to do a return of the list to the quicksort function, it knows that I swapped the position of the values for the list in partition, thus printing the sorted list.
def quicksort(lst, start = 0, end = None):
if end is None:
end = len(lst) - 1
if start >= end:
return
p = partition(lst, start, end)
quicksort(lst, start, p-1)
quicksort(lst, p+1, end)
def partition(lst, start, end):
pivot = lst[start]
low = start + 1
high = end
while low <= high:
while lst[low] <= pivot:
low += 1
while lst[high] >= pivot:
high -= 1
if low <= high:
lst[low], lst[high] = lst[high], lst[low]
low += 1
high -= 1
lst[start], lst[high] = lst[high], lst[start]
return high
numbers = [7, 6, 2, 4, 9, 1000]
quicksort(numbers)
print(numbers)
Please accept my humble apologies if I have asked something redundant as I could not find anything regarding this. I am currently learning about algorithms through team treehouse, but they don't seem to have anything about it besides the video about quicksort which doesn't explain much. If you know of somewhere that has more information on this, your help will be greatly appreciated if you could share it with me! Thank you.
This is because values are passed by reference in python. When you pass your lst to your partition function, you are actually passing a reference to your list in your quicksort function, and not a copy of the list.
Got this example function from Hetland's python book.
def interval(start, stop=None, step=1):
if stop is None:
start, stop=0, start
result = []
i = start
while i < stop:
result.append(i)
i += step
return result
What are both starts doing in the if statement? And why is it there twice? I changed the latter start to an int and that changed the length of my list to that int.
I also can't seem to wrap my head around the interation part. In the example, start = 10. So, when iterating... while 10 < 0 it will continue to grow the list, increasing the count by step=1 each time. But, 10 isn't less than 0. How'd run in the first place?
The assignment should be parsed as
(start, stop) = (0, start)
That is, interval(10) is equivalent to interval(0, 10). Even though the first parameter's name is start, it's really the stop value if only one argument is provided.
The while loop is equivalent to the more straight-forward for loop
for i in range(start, stop + 1, step):
result.append(i)
except interval lets start, stop, and step all have types other than int.
A better design might be to require the use of keyword-only arguments, so that there's no ambiguity in the body of the function in how each parameter is used:
def interval(*, start=0, stop, step=1):
result = []
while start < stop:
result.append(start)
start += step
return result
Now you can call interval(stop=10) or interval(start=3, stop=10); either way, the parameter start is actually the starting value in both cases. It's a trade-off, though, in that you can no longer write interval(10) for what would be expected as the most common use case.
UPDATE 1 (Oct.16): The original code had a few logic errors which were rectified. The updated code below should now produce the correct output for all lists L, S.T they meet the criteria for a special list.
I am trying to decrease the running time of the following function:
The "firstrepeat" function takes in a special list L and an index, and produces the smallest index such that L[i] == L[j]. In other words, whatever the element at L[i] is, the "firstrepeat" function returns the index of the first occurrence of this element in the list.
What is special about the list L?:
The list may contain repeated elements on the increasing side of the list, or the decreasing side, but not both. i.e [3,2,1,1,1,5,6] is fine but not [4,3,2,2,1,2,3]
The list is decreasing(or staying the same) and then increasing(or staying the same).
Examples:
L = [4,2,0,1,3]
L = [3,3,3,1,0,7,8,9,9]
L = [4,3,3,1,1,1]
L = [1,1,1,1]
Example Output:
Say we have L = [4,3,3,1,1,1]
firstrepeat(L,2) would output 1
firstrepeat(L,5) would output 3
I have the following code. I believe the complexity is O(log n) or better (though I could be missing something). I am looking for ways to improve the time complexity.
def firstrepeat(L, i):
left = 0
right = i
doubling = 1
#A Doubling Search
#In doubling search, we start at one index and then we look at one step
#forward, then two steps forward, then four steps, then 8, then 16, etc.
#Once we have gone too far, we do a binary search on the subset of the list
#between where we started and where we went to far.
while True:
if (right - doubling) < 0:
left = 0
break
if L[i] != L[right - doubling]:
left = right - doubling
break
if L[i] == L[right - doubling]:
right = right - doubling
doubling = doubling * 2
#A generic Binary search
while right - left > 1:
median = (left + right) // 2
if L[i] != L[median]:
left = median
else:
right = median
f L[left] == L[right]:
return left
else:
return right
I have a solution for this problem on codewars.com that works when I run it in Sublime, but when I try to submit, I get this error:
Process was terminated. It took longer than 12000ms to complete
Why did my code time out?
Our servers are configured to only allow a certain amount of time for your code to execute. In rare cases the server may be taking on too much work and simply wasn't able to run your code efficiently enough. Most of the time though this issue is caused by inefficient algorithms. If you see this error multiple times you should try to optimize your code further.
The goal of the function is to find the next biggest number after a given number that you can make by rearranging the digits of a given number. For example, if I was given 216, I would need to return 261.
This is the code I have now:
import itertools
def next_bigger(n):
# takes a number like 472 and puts it in a list like so: [4, 7, 2]
num_arr = [int(x) for x in str(n)]
perms = []
total = ''
# x would be a permutation of num_arr, like [7, 2, 4]
for x in itertools.permutations(num_arr):
for y in x:
total += str(y)
perms.append(int(total))
total = ''
# bigger is all permutations that are bigger than n,
# so bigger[0] is the next biggest number.
# if there are no bigger permutations, the function returns -1
bigger = sorted([x for x in perms if x > n])
return bigger[0] if bigger else -1
I'm new to coding in Python, so is there some mistake I am making which causes my code to be extremely inefficient? Any suggestions are welcome.
Thanks for all the help you guys gave me. I ended up finding a solution from here using the Next Lexicographical Permutation Algorithm
This is my tidied up version of the solution provided here:
def next_bigger(n):
# https://www.nayuki.io/res/next-lexicographical-permutation-algorithm/nextperm.py
# https://www.nayuki.io/page/next-lexicographical-permutation-algorithm
# Find non-increasing suffix
arr = [int(x) for x in str(n)]
i = len(arr) - 1
while i > 0 and arr[i - 1] >= arr[i]:
i -= 1
if i <= 0:
return -1
# Find successor to pivot
j = len(arr) - 1
while arr[j] <= arr[i - 1]:
j -= 1
arr[i - 1], arr[j] = arr[j], arr[i - 1]
# Reverse suffix
arr[i : ] = arr[len(arr) - 1 : i - 1 : -1]
return int(''.join(str(x) for x in arr))
Why are you getting TLE (time limit exceeded)?
Because your algorithm has wrong complexity. How much permutations you will find for list with 3 elements? Only 6. But what if we use list with 23 elements? 25852016738884976640000.
This is too much for time limit.
So, if you want to have solve this problem you have to find solution without permutations. Please rethink how the numbers are written. The number 271 is bigger then 216 because the number on the second position has bigger value 7>1.
So, your solution has to find two numbers and swap them position. The number on the left have to smaller then the second one.
For example - for 111115444474444 you should find 5 and 7.
Then you swap them - and now you should sort sublist on right from the first position.
For example after swapped the values (111117444454444) you have to sort (444454444) -> (444444445). Now merge all, and you have solution.
import functools
def next_bigger(a):
a = map(int, str(a))
tmp = list(reversed(a))
for i, item_a in enumerate(reversed(a)):
for j in (range(i)):
if item_a < tmp[j]:
#you find index of number to swap
tmp[i]=tmp[j]
print(list(reversed(tmp[i:])))
tmp[j]=item_a
fin = list(reversed(tmp[i:])) + sorted(tmp[:i])
return functools.reduce(lambda x,y: x*10+y, fin)
return -1
A simple backtracking approach is to consider the digits one at a time. Starting from the most significant digit, pick the smallest number you have left that doesn't prevent the new number from exceeding the input. This will always start by reproducing the input, then will have to backtrack to the next-to-last digit (because there aren't any other choices for the last digit). For inputs like 897654321, the backtracking will immediately cascade to the beginning because there are no larger digits left to try in any of the intermediate slots.
You should sorting the num_arr in desc order and creating a number by combining the result.
Since OP required, next largest, OP needs to check starting from right, which right digit is larger then its very left digit and rotate their position.
Here is the final code:
def next_bigger(n):
num_arr = [int(x) for x in str(n)]
i = 0
i = len(num_arr) - 1
while(i > 0):
if num_arr[i] > num_arr[i-1]:
a = num_arr[i]
num_arr[i] = num_arr[i-1]
num_arr[i-1] = a
break
else:
i = i-1
newbig = "".join(str(e) for e in num_arr)
return int(newbig)
Now I edit to calculate next bigger element.
def perms(s):
if(len(s)==1):
return [s]
result=[]
for i,v in enumerate(s):
result += [v+p for p in perms(s[:i]+s[i+1:])]
return result
a=input()
b=perms(str(a))
if len(b)!=1:
for i in range(0,len(b)):
if b[i]==a:
print (b[i+1])
break
else:
print ("-1")
I tried to find the maximum value in a sorted list. but the recursion is not stopping. please, can somebody help me?
A = [5,16,28,43,0,1]
start = 0
end = len(A) - 1
mid = 0
print mid
def search(start, end, mid):
mid = int((start + end) / 2)
print mid
if A[mid] > [mid - 1] and A[mid] > A[mid + 1]:
return A[mid]
else:
if A[mid - 1] > A[mid + 1]:
search(start, mid, mid)
else:
search(mid, end, mid)
print search(start, end, mid)
You need to add a "basis case" (where the recursion stops).
A natural basis case for this problem: if start is equal to end, just return A[start]
EDIT:
I just looked at this and the more I look the more confused I get. Why are you using recursion to find a max? It would make more sense to use recursion to do a "binary search" to find a value inside a sorted list.
If you want to really find a max value, that's pretty easy. With recursion, we first want a "basis case" that gives us a trivial solution; then we want more code that will take us one step closer to that solution.
In this case, the basis case: we have only one value in the list; return it as the max. To be specific, if the start and end together specify just one value, return that one value. To make it proof against errors, might as well make this also handle the case where start is equal to or even greater than end.
Next remember the first value.
Next make a recursive call, but add one to start to reduce the size of the list we are considering. This is the part that takes us one step closer to a solution. Repeat this step enough times and we arrive at the basis case where there is only one value in the list to consider.
Finally compare the remembered first value with the result of the recursive call and return the larger of the two.
I'll lay it out in psuedocode for you:
BASIS CASE: start and end specify one value: return A[start]
save A[0] in a variable
save recursive_call_to_this_function(start+1, end) in a variable
compare two saved values and return the larger
Once you have tried to write the above in code, peek below this line for my working tested solution.
def recursive_max(start, end):
if start >= end - 1:
return A[start]
x0 = A[start]
x1 = recursive_max(start+1, end)
if x0 >= x1:
return x0
else:
return x1
print recursive_max(start, end)
I agree with most of steveha's answer, but rather than picking off one element at a time I'd suggest dividing the list into halves and finding the max in each half. You won't do any fewer comparisons, but the growth of the recursive stack will be O(log(len(A))) rather than O(len(A)). For large lists this would be the difference between getting a stack overflow or not.
My implementation (which takes the list as an argument rather than expecting it to be global) follows:
def recursive_max(value_list, start, end):
if start >= end:
return value_list[start]
mid = start + (end - start) // 2
lower_half_max = recursive_max(value_list, start, mid)
upper_half_max = recursive_max(value_list, mid+1, end)
if lower_half_max > upper_half_max:
return lower_half_max
else:
return upper_half_max