Insertion Sort - troubles reading MIT Intro to Algos - algorithm

The MIT Intro to Algorithms describes insertion sort as:
I wrote this in Python as:
def sort(A):
for j in range(1, len(A)):
key = A[j];
i = j - 1;
# i > 0 should be i >= 0
while i > 0 and A[i] > key:
A[i + 1] = A[i]
i = i - 1;
A[i + 1] = key
return A
However the line while i > 0 introduces a bug - the first two keys are in the wrong positions. Changing this to while i >= 0 fixes this problem.
Why is this not included in the MIT Intro book? Am I reading it wrong?

The algorithm in the book is assuming indexing from 1 to A.length, inclusive, which is why it starts at an index of 2. Python has array indexing from 0 to len(A) - 1. You corrected for that in your range, but you neglected to correct for it in the loop test. Doing so fixes the problem.

#pjs is exactly right. I'll add that a methodical way to convert an algorithm written for 1-based arrays to 0-based with no off-by-1 errors is to use the algorithm as-is except subtract 1 at each array reference and then use algebra to simplify. Here you'd end up with:
def sort(A):
for j in range(2, len(A) + 1): # +1 is because Python ranges exclude high limit
key = A[j - 1]
i = j - 1
while i > 0 and A[i - 1] > key:
A[i + 1 - 1] = A[i - 1]
i = i - 1
A[i + 1 - 1] = key
return A
Of course it's easy to simplify by removing + 1 - 1, since that's adding zero! The result works fine.
If you want to make the code prettier with the outer range starting at 1 rather than 2, make the substitution jj = j - 1, which (adding 1 to both sides) means j = jj + 1:
def sort(A):
for jj in range(1, len(A)):
key = A[jj + 1 - 1]
i = jj + 1 - 1
while i > 0 and A[i - 1] > key:
A[i] = A[i - 1]
i = i - 1
A[i] = key
return A
Again removing + 1 - 1s, we have
def sort(A):
for jj in range(1, len(A)):
key = A[jj]
i = jj
while i > 0 and A[i - 1] > key:
A[i] = A[i - 1]
i = i - 1
A[i] = key
return A
This looks great, and I'd stop here. But yet another variation is possible with the substitution ii = i - 1 or i = ii + 1.
def sort(A):
for jj in range(1, len(A)):
key = A[jj]
ii + 1 = jj
while ii + 1 > 0 and A[ii + 1 - 1] > key:
A[ii + 1] = A[ii + 1 - 1]
ii + 1 = ii + 1 - 1
A[ii + 1] = key
return A
Hmmm... Those assignments to ii look weird. But we can straighten everything out with algebra yet again.
def sort(A):
for jj in range(1, len(A)):
key = A[jj]
ii = jj - 1 # Subtracted 1 from both sides
while ii >= 0 and A[ii] > key: # x + 1 > 0 iff x >= 0
A[ii + 1] = A[ii]
ii = ii - 1 # Subtracted 1 from both sides and simplified
A[ii + 1] = key
return A
Lo and behold, we have the code you proposed. Works every time.

Related

Explanation for Booth's Algorithm for Lexicographically minimal string rotation

Can someone please explain or comment me this code for Booth's Algorithm for Lexicographically minimal string rotation from wikipedia (https://en.wikipedia.org/wiki/Lexicographically_minimal_string_rotation#Booth.27s_Algorithm)?
def least_rotation(S: str) -> int:
"""Booth's algorithm."""
S += S # Concatenate string to it self to avoid modular arithmetic
f = [-1] * len(S) # Failure function
k = 0 # Least rotation of string found so far
for j in range(1, len(S)):
sj = S[j]
i = f[j - k - 1]
while i != -1 and sj != S[k + i + 1]:
if sj < S[k + i + 1]:
k = j - i - 1
i = f[i]
if sj != S[k + i + 1]: # if sj != S[k+i+1], then i == -1
if sj < S[k]: # k+i+1 = k
k = j
f[j - k] = -1
else:
f[j - k] = i + 1
return k
I am lost with the indices and the k etc. What does it mean, why is there [j - k - 1] indexing etc.?
Thanks!

Algorithm problem about Google kick start round B 2021

I'm solving the longest progression problem in Google kick start 2021 Round B using python.
Here is the link to the problem: https://codingcompetitions.withgoogle.com/kickstart/round/0000000000435a5b
I have written the following code but it seems that there's always the wrong answer in a test case, I have tried all situations as far as I concerned, can someone give me the help that where's the problem in my code, thanks!
def solution(A, N):
i, j = 0, 1
ranges = {}
res = 0
left = {}
right = {}
while j < N:
diff = A[j] - A[i]
while j < N and A[j]-A[i] == (j-i)*diff:
j += 1
ranges[(i, j-1)] = diff
left[i] = (i, j-1)
right[j-1] = (i, j-1)
if j <= N-1 or i > 0:
res = max(res, j-i+1)
else:
res = max(res, j-i)
i = j-1
# check if two ranges can be merged
for i in range(1, N-1):
if i == 1:
if i+1 in left:
l1, r1 = left[i+1]
if A[i+1]-A[i-1] == 2*ranges[left[i+1]]:
res = max(res, r1-l1+3)
elif i == N-2:
if i-1 in right:
l1, r1 = right[i-1]
if A[i + 1] - A[i - 1] == 2 * ranges[right[i - 1]]:
res = max(res, r1 - l1 + 3)
else:
if i+1 in left and i-1 in right and ranges[right[i-1]] == ranges[left[i+1]]:
l1, r1 = right[i - 1]
l2, r2 = left[i+1]
if A[i+1]-A[i-1] == 2*ranges[left[i+1]]:
res = max(r1-l1+r2-l2+3, res)
return res
if __name__ == "__main__":
T = int(input().strip())
for i in range(T):
N = int(input().strip())
A = list(map(int, input().strip().split(" ")))
res = solution(A, N)
print("Case #{}: {}".format(i+1, res))
The merging logic is incorrect. The code only tries to merge the entire ranges. In a simple failing case
1 2 3 6 5 4
it misses that replacing 6 with 4 would produce 1 2 3 4 5.

Confusion Regarding deepest pit within an Array

I got this question as prerequisite for an interview,
A non-empty zero-indexed array A consisting of N integers is given. A
pit in this array is any triplet of integers (P, Q, R) such that: 0 ≤
P < Q < R < N;
sequence [A[P], A[P+1], ..., A[Q]] is strictly decreasing, i.e. A[P] >
A[P+1] > ... > A[Q];
sequence A[Q], A[Q+1], ..., A[R] is strictly increasing, i.e. A[Q] <
A[Q+1] < ... < A[R].
The depth of a pit (P, Q, R) is the number min{A[P] − A[Q], A[R] −
A[Q]}. For example, consider array A consisting of 10 elements such
that:
A[0] = 0
A[1] = 1
A[2] = 3
A[3] = -2
A[4] = 0
A[5] = 1
A[6] = 0
A[7] = -3
A[8] = 2
A[9] = 3
Triplet (2, 3, 4) is one of pits in this array, because sequence
[A[2], A[3]] is strictly decreasing (3 > −2) and sequence [A[3], A[4]]
is strictly increasing (−2 < 0). Its depth is min{A[2] − A[3], A[4] −
A[3]} = 2.
Triplet (2, 3, 5) is another pit with depth 3.
Triplet (5, 7, 8) is yet another pit with depth 4. There is no pit in
this array deeper (i.e. having depth greater) than 4.
It says that Triplet (5, 7, 8) has the deepest pit depth of 4.
but isn't Triplet (2, 7, 9) has the deepest pit depth 6?
corresponding value of Triplet (2, 7, 9) is (3, -3, 3) and it also satisfies the conditions mentioned, i.e.
1) 0 ≤ P < Q < R < N
2) A[P] > A[P+1] > ... > A[Q] and A[Q] < A[Q+1] < ... < A[R]
so in this case min{A[P] − A[Q], A[R] − A[Q]} is 6.
What am i missing here?
P.S. if you think this post does not belong here in this forum then please point out where should i post it.
See the sequence from P to Q for 2 to 7.
It is 3 -2 0 1 0 -3.
sequence [A[P], A[P+1], ..., A[Q]] is strictly decreasing, i.e. A[P] > A[P+1] > ... > A[Q];
The rule says that this should be a decreasing sequence. But it isn't. 3>-2 but -2 is not greater than 0. Here the sequence breaks.
From 7 to 9. No problem as the sequence is increasing. -3<2<3.
answer of the deepest pit problem in swift :
func solution(_ array: [Int]) -> Int {
//guaranty we have at least three elements
if array.isEmpty {
print("isEmpty")
return -1
}
if array.count < 3 {
print("is less than 3")
return -1
}
//extremum point; max or min points
var extremumPoints = [Int]()
//adding first element
extremumPoints.append(array[0])
//calculate extremum points for 1 to one before last element
for i in 1..<(array.count - 1) {
let isRelativeExtremum = ((array[i] - array[i - 1]) * (array[i] - array[i + 1])) > 0
//we call a point semi-extremum if a point is equal to previous element or next element and not equal to previous element or next element
let isSemiExtremum = ((array[i] != array[i - 1]) && (array[i] == array[i + 1])) || ((array[i] != array[i + 1]) && (array[i] == array[i - 1]))
if isRelativeExtremum || isSemiExtremum {
extremumPoints.append(array[i])
}
}
//adding last element
extremumPoints.append(array[array.count - 1])
//we will hold depthes in this array
var depthes = [Int]()
for i in 1..<(extremumPoints.count - 1) {
let isBottomOfaPit = extremumPoints[i] < extremumPoints[i - 1] && extremumPoints[i] < extremumPoints[i + 1]
if isBottomOfaPit {
let d1 = extremumPoints[i - 1] - extremumPoints[i]
let d2 = extremumPoints[i + 1] - extremumPoints[i]
let d = min(d1, d2)
depthes.append(d)
}
}
//deepest pit
let deepestPit = depthes.max()
return deepestPit ?? -1
}
//****************************
let A = [0,1,3,-2,0,1,0,-3,2,3]
let deepestPit = solution(A)
print(deepestPit) // 4
def deepest(A):
def check(p, q, r, A):
if A[p] > A[q] and A[q] < A[r]:
return min(A[p] - A[q], A[r] - A[q])
else:
return -1
max_depth = 0
for i in range(1, len(A) - 2):
if A[i-1] > A[i] < A[i + 1]:
p = i
r = i
while 0 <= p and r <= len(A) - 1:
depth = check(p, i, r, A)
max_depth = max(max_depth, depth)
p -= 1
r += 1
return max_depth

Bubble Sort - to VB.NET

If I had the following pseudocode, would I need to add anything further onto it as mentioned below. Your help is much appreciated:
**repeat
swapped = false**
for i from 1 <- N
for j <- 0 to N - 1
if a[j] > a[j + 1]
swap( a[j], a[j + 1] )
**swapped = true
end if**
**end for
until not swapped**
Are the lines I have ** REQUIRED to be in there? For example, if a question asked 'write in pseudocode for the bubble sort algorithm' would I be required to write it out fully (including the ** items) or without them is OK?
We are required to 'rope learn' the code and obviously the smaller the code the better and the easier it is to remember.
Thanks!
Sub Main()
Dim Numlist() As Integer = {23435, 1, 433, 5234}
'here you can use any numbers in any order
Dim Count As Integer = 0
Dim Swapvalue As Integer
For ii = 0 To Numlist.Length - 2
For i = 0 To Numlist.Length - 2
Count += 1
If Numlist(i) > Numlist(i + 1) Then
Swapvalue = Numlist(i)
Numlist(i) = Numlist(i + 1)
Numlist(i + 1) = Swapvalue
End If
Next
Next
Console.WriteLine("Number of comparisons: {0}", Count)
For i = 0 To Numlist.Length - 1
Console.WriteLine(Numlist(i))
Next
End Sub

How to lexicographicly enumerate unordered pairs of integers

what is the algorithm (or rather formula) which, for each pair integers i and j with j >= i, gives an integer k = k(i,j) such that
k(0,0) = 0
k(i,j2) = k(i,j1)+1 for j2 = j1 + 1
k(i,0) = k(i-1,i-1) + 1 , i >= 1
holds?
In other words, if you fill up the left-lower part of matrix row by row from left to right with the natural numbers, starting at 0, how can you compute the value of a cell given the index of its row i and the column index j <= i?
Thank you very much!
proof of Alleo answer:
first write your second formula from j to 1
k(i,j)= k(i,j-1) + 1
k(i,j-1) = k(i,j-2) + 1
...
k(i,1) = k(i,0) + 1
sum up these formulas you get :
k(i,j) = k(i,0) + 1+1 ..+1 = k(i,0) + j (1)
now from your 3rd formula:
k(i,0) = k(i-1,i-1) + 1
using (1) :
k(i-1,i-1) = k(i-1,0) + i-1
then
k(i,0) = k(i-1,0) + i
then since k(0,0) = 0
k(i,0) = sum(p for p=0 to i) = i*(i+1)/2 (2)
then
(1) & (2) => k(i,j) = i*(i+1)/2 + j
This is i*(i+1)/2 + j. You are welcome to check

Resources