Quicksort partitioning infinite loop - python-3.x

arr = [7, 3, 5, 6, 7, 1, 8, 0, 4, 9, 6, 2]
def partitioning(arr, l, d):
pivot = 5
while l <= d:
while arr[l] < pivot:
l += 1
while arr[d] > pivot:
d -= 1
arr[l], arr[d] = arr[d], arr[l]
partitioning(arr, 0, len(arr) - 1)
print(arr)
I don't understand why when putting l <= d, when l and d become the same they stop moving and keep swapping to infinity?

Your infinite loop happens when l == d and arr[l] == arr[d] == pivot. In this situation, the inner loops never do anything and the swap also doesn't do anything since the two indexes are the same (so you're swapping the pivot with itself).
You want your top loop to quit in this situation, since the array has been completely partitioned. You should change the <= on the outer loop to <, and it should work.
You'll need to change the pivot-choice logic going forward (since if the pivot is not in the list, your inner loops might run l or d off the end of the list), but I assume that picking the constant 5 is just a preliminary thing.

Related

what is wrong with my code? leetcode - 189. Rotate Array

The code works perfectly fine for the first test case but gives wrong answer for the second one. Why is that?
arr = [1,2,3,4,5,6,7]
arr2 = [-1,-100,3,99]
def reverse(array, start, end):
while start < end:
array[start], array[end] = array[end], array[start]
start += 1
end -= 1
return array
def rotate(array, k):
reverse(array, 0, k)
reverse(array, k+1, len(array)-1)
reverse(array, 0, len(array)-1)
return array
print(rotate(arr, 3)) # output: [5, 6, 7, 1, 2, 3, 4]
# print(reverse(arr, 2, 4))
rotate(arr2, 2)
print(arr2) # output: [99, -1, -100, 3] (should be [3, 99, -1, -100])
Your existing logic does the following -
Move k + 1 item from front of the list to the back of the list.
But the solution needs to move k elements from back of the list to the front. Or another way to think is move len(array) - k element from front to the back.
To do so, two changes required in the rotate() -
Update k to len(array) - k
Change your logic to move k instead of k + 1 element from front to back
So, your rotate() needs to be changed to following -
def rotate(array, k):
k = len(array) - k
reverse(array, 0, k-1)
reverse(array, k, len(array)-1)
reverse(array, 0, len(array)-1)
return array
I think there are better ways to solve this but with your logic this should solve the problem.

How to check a list of lists against a list of lists and count their overlaps? (Python)

I have one list a containing 100 lists and one list x containing 4 lists (all of equal length). I want to test the lists in a against those in x. My goal is to find out how often numbers in a "touch" those in x. Stated differently, all the lists are points on a line and the lines in a should not touch (or cross) those in x.
EDIT
In the code, I am testing each line in a (e.g. a1, a2 ... a100) first against x1, then against x2, x3 and x4. A condition and a counter check whether the a's touch the x's. Note: I am not interested in counting how many items in a1, for example, touch x1. Once a1 and x1 touch, I count that and can move on to a2, and so on.
However, the counter does not properly update. It seems that it does not tests a against all x. Any suggestions on how to solve this? Here is my code.
EDIT
I have updated the code so that the problem is easier to replicate.
x = [[10, 11, 12], [14, 15, 16]]
a = [[11, 10, 12], [15, 17, 20], [11, 14, 16]]
def touch(e, f):
e = np.array(e)
f = np.array(f)
lastitems = []
counter = 0
for lst in f:
if np.all(e < lst): # This is the condition
lastitems.append(lst[-1]) # This allows checking the end values
else:
counter += 1
c = counter
return c
touch = touch(x, a)
print(touch)
The result I get is:
2
But I expect this:
1
2
I'm unsure of what exactly is the result you expect, your example and description are still not clear. Anyway, this is what I guess you want. If you want more details, you can uncomment some lines i.e. those with #
i = 0
for j in x:
print("")
#print(j)
counter = 0
for k in a:
inters = set(j).intersection(k)
#print(k)
#print(inters)
if inters:
counter += 1
#print("yes", counter)
#else:
#print("nope", counter)
print(i, counter)
i += 1
which prints
0 2
1 2

Why are elements of my array being over written?

I have written a simple function in Python which aims to find, if from two elements a and b, one can be obtained from another by swapping at most one pair of elements in one of the arrays.
This is my function:
def areSimilar(a, b):
test = 0
for i in range(len(b)):
for j in range(len(b)):
b2 = b
b2[i] = b[j]
b2[j] = b[i]
if a == b2:
test = 1
return(test==1)
The issue is that upon inspecting b, it has changed even though I don't actually perform any calculations on b - what's going on!!??
(EDITED: to better address the second point)
There are two issues with your code:
When you do b2 = b this just creates another reference to the underlying object. If b is mutable, any change made to b2 will be reflected in b too.
When a single swapping suffices there is no need to test further, but if you keep on looping the test will be successful again with i and j swapped, so test condition is hit either never or (at least -- depending on the amount of duplicates) twice. While this would not lead to incorrect results, it would normally be regarded as an error in the logic.
To fix your code, you could just create a copy of b. Assuming that by Python arrays you actually mean Python lists one way of doing it would be to create a new list every time by replacing b2 = b with b2 = list(b). A more efficient approach is to perform the swapping on b itself (and swap back):
def are_similar(a, b):
for i in range(len(b)):
for j in range(len(b)):
b[i], b[j] = b[j], b[i]
if a == b:
b[i], b[j] = b[j], b[i] # swap back
return True
else:
b[i], b[j] = b[j], b[i] # swap back
return False
print(are_similar([1, 1, 2, 3], [1, 2, 1, 3]))
# True
print(are_similar([1, 1, 2, 3], [3, 2, 1, 1]))
# False
By contrast, you can see how inefficient (while correct) the copying-based approach is:
def are_similar2(a, b):
for i in range(len(b)):
for j in range(len(b)):
b2 = list(b)
b2[i] = b[j]
b2[j] = b[i]
if a == b2:
return True
return False
print(are_similar2([1, 1, 2, 3], [1, 2, 1, 3]))
# True
print(are_similar2([1, 1, 2, 3], [3, 2, 1, 1]))
# False
with much worse timings, even on relatively small inputs:
a = [1, 1, 2, 3] + list(range(100))
b = [1, 2, 1, 3] + list(range(100))
%timeit are_similar(a, b)
# 10000 loops, best of 3: 22.9 µs per loop
%timeit are_similar2(a, b)
# 10000 loops, best of 3: 73.9 µs per loop
I would got with Sadap's code, but if you want to copy, use :
import copy
def areSimilar(a, b):
test = 0
for i in range(len(b)):
for j in range(len(b)):
b2 = copy.deepcopy(b)
b2[i] = copy.deepcopy(b[j])
b2[j] = copy.deepcopy(b[i])
if a == b2:
test = 1
if test == 1:
return True
else:
return False

Dynamic programming table - Finding the minimal cost to break a string

A certain string-processing language offers a primitive operation
which splits a string into two pieces. Since this operation involves
copying the original string, it takes n units of time for a string of
length n, regardless of the location of the cut. Suppose, now, that
you want to break a string into many pieces.
The order in which the breaks are made can affect the total running
time. For example, suppose we wish to break a 20-character string (for
example "abcdefghijklmnopqrst") after characters at indices 3, 8, and
10 to obtain for substrings: "abcd", "efghi", "jk" and "lmnopqrst". If
the breaks are made in left-right order, then the first break costs 20
units of time, the second break costs 16 units of time and the third
break costs 11 units of time, for a total of 47 steps. If the breaks
are made in right-left order, the first break costs 20 units of time,
the second break costs 11 units of time, and the third break costs 9
units of time, for a total of only 40 steps. However, the optimal
solution is 38 (and the order of the cuts is 10, 3, 8).
The input is the length of the string and an ascending-sorted array with the cut indexes. I need to design a dynamic programming table to find the minimal cost to break the string and the order in which the cuts should be performed.
I can't figure out how the table structure should look (certain cells should be the answer to certain sub-problems and should be computable from other entries etc.). Instead, I've written a recursive function to find the minimum cost to break the string: b0, b1, ..., bK are the indexes for the cuts that have to be made to the (sub)string between i and j.
totalCost(i, j, {b0, b1, ..., bK}) = j - i + 1 + min {
totalCost(b0 + 1, j, {b1, b2, ..., bK}),
totalCost(i, b1, {b0 }) + totalCost(b1 + 1, j, {b2, b3, ..., bK}),
totalCost(i, b2, {b0, b1 }) + totalCost(b2 + 1, j, {b3, b4, ..., bK}),
....................................................................................
totalCost(i, bK, {b0, b1, ..., b(k - 1)})
} if k + 1 (the number of cuts) > 1,
j - i + 1 otherwise.
Please help me figure out the structure of the table, thanks!
For example we have a string of length n = 20 and we need to break it in positions cuts = [3, 8, 10]. First of all let's add two fake cuts to our array: -1 and n - 1 (to avoid edge cases), now we have cuts = [-1, 3, 8, 10, 19]. Let's fill table M, where M[i, j] is a minimum units of time to make all breaks between i-th and j-th cuts. We can fill it by rule: M[i, j] = (cuts[j] - cuts[i]) + min(M[i, k] + M[k, j]) where i < k < j. The minimum time to make all cuts will be in the cell M[0, len(cuts) - 1]. Full code in python:
# input
n = 20
cuts = [3, 8, 10]
# add fake cuts
cuts = [-1] + cuts + [n - 1]
cuts_num = len(cuts)
# init table with zeros
table = []
for i in range(cuts_num):
table += [[0] * cuts_num]
# fill table
for diff in range(2, cuts_num):
for start in range(0, cuts_num - diff):
end = start + diff
table[start][end] = 1e9
for mid in range(start + 1, end):
table[start][end] = min(table[start][end], table[
start][mid] + table[mid][end])
table[start][end] += cuts[end] - cuts[start]
# print result: 38
print(table[0][cuts_num - 1])
Just in case you may feel easier to follow when everything is 1-based (same as DPV Dasgupta Algorithm book problem 6.9, and same as UdaCity Graduate Algorithm course initiated by GaTech), following is the python code that does the equivalent thing with the previous python code by Jemshit and Aleksei. It follows the chain multiply (binary tree) pattern as taught in the video lecture.
import numpy as np
# n is string len, P is of size m where P[i] is the split pos that split string into [1,i] and [i+1,n] (1-based)
def spliting_cost(P, n):
P = [0,] + P + [n,] # make sure pos list contains both ends of string
m = len(P)
P = [0,] + P # both C and P are 1-base indexed for easy reading
C = np.full((m+1,m+1), np.inf)
for i in range(1, m+1): C[i, i:i+2] = 0 # any segment <= 2 does not need split so is zero cost
for s in range(2, m): # s is split string len
for i in range(1, m-s+1):
j = i + s
for k in range(i, j+1):
C[i,j] = min(C[i,j], P[j] - P[i] + C[i,k] + C[k,j])
return C[1,m]
spliting_cost([3, 5, 10, 14, 16, 19], 20)
The output answer is 55, same as that with split points [2, 4, 9, 13, 15, 18] in the previous algorithm.

String concatenation queries

I have a list of characters, say x in number, denoted by b[1], b[2], b[3] ... b[x]. After x,
b[x+1] is the concatenation of b[1],b[2].... b[x] in that order. Similarly,
b[x+2] is the concatenation of b[2],b[3]....b[x],b[x+1].
So, basically, b[n] will be concatenation of last x terms of b[i], taken left from right.
Given parameters as p and q as queries, how can I find out which character among b[1], b[2], b[3]..... b[x] does the qth character of b[p] corresponds to?
Note: x and b[1], b[2], b[3]..... b[x] is fixed for all queries.
I tried brute-forcing but the string length increases exponentially for large x.(x<=100).
Example:
When x=3,
b[] = a, b, c, a b c, b c abc, c abc bcabc, abc bcabc cabcbcabc, //....
//Spaces for clarity, only commas separate array elements
So for a query where p=7, q=5, answer returned would be 3(corresponding to character 'c').
I am just having difficulty figuring out the maths behind it. Language is no issue
I wrote this answer as I figured it out, so please bear with me.
As you mentioned, it is much easier to find out where the character at b[p][q] comes from among the original x characters than to generate b[p] for large p. To do so, we will use a loop to find where the current b[p][q] came from, thereby reducing p until it is between 1 and x, and q until it is 1.
Let's look at an example for x=3 to see if we can get a formula:
p N(p) b[p]
- ---- ----
1 1 a
2 1 b
3 1 c
4 3 a b c
5 5 b c abc
6 9 c abc bcabc
7 17 abc bcabc cabcbcabc
8 31 bcabc cabcbcabc abcbcabccabcbcabc
9 57 cabcbcabc abcbcabccabcbcabc bcabccabcbcabcabcbcabccabcbcabc
The sequence is clear: N(p) = N(p-1) + N(p-2) + N(p-3), where N(p) is the number of characters in the pth element of b. Given p and x, you can just brute-force compute all the N for the range [1, p]. This will allow you to figure out which prior element of b b[p][q] came from.
To illustrate, say x=3, p=9 and q=45.
The chart above gives N(6)=9, N(7)=17 and N(8)=31. Since 45>9+17, you know that b[9][45] comes from b[8][45-(9+17)] = b[8][19].
Continuing iteratively/recursively, 19>9+5, so b[8][19] = b[7][19-(9+5)] = b[7][5].
Now 5>N(4) but 5<N(4)+N(5), so b[7][5] = b[5][5-3] = b[5][2].
b[5][2] = b[3][2-1] = b[3][1]
Since 3 <= x, we have our termination condition, and b[9][45] is c from b[3].
Something like this can very easily be computed either recursively or iteratively given starting p, q, x and b up to x. My method requires p array elements to compute N(p) for the entire sequence. This can be allocated in an array or on the stack if working recursively.
Here is a reference implementation in vanilla Python (no external imports, although numpy would probably help streamline this):
def so38509640(b, p, q):
"""
p, q are integers. b is a char sequence of length x.
list, string, or tuple are all valid choices for b.
"""
x = len(b)
# Trivial case
if p <= x:
if q != 1:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
return p, b[p - 1]
# Construct list of counts
N = [1] * p
for i in range(x, p):
N[i] = sum(N[i - x:i])
print('N =', N)
# Error check
if q > N[-1]:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
print('b[{}][{}]'.format(p, q), end='')
# Reduce p, q until it is p < x
while p > x:
# Find which previous element character q comes from
offset = 0
for i in range(p - x - 1, p):
if i == p - 1:
raise ValueError('q={} out of bounds for p={}'.format(q, p))
if offset + N[i] >= q:
q -= offset
p = i + 1
print(' = b[{}][{}]'.format(p, q), end='')
break
offset += N[i]
print()
return p, b[p - 1]
Calling so38509640('abc', 9, 45) produces
N = [1, 1, 1, 3, 5, 9, 17, 31, 57]
b[9][45] = b[8][19] = b[7][5] = b[5][2] = b[3][1]
(3, 'c') # <-- Final answer
Similarly, for the example in the question, so38509640('abc', 7, 5) produces the expected result:
N = [1, 1, 1, 3, 5, 9, 17]
b[7][5] = b[5][2] = b[3][1]
(3, 'c') # <-- Final answer
Sorry I couldn't come up with a better function name :) This is simple enough code that it should work equally well in Py2 and 3, despite differences in the range function/class.
I would be very curious to see if there is a non-iterative solution for this problem. Perhaps there is a way of doing this using modular arithmetic or something...

Resources