Difference between comparisons and swaps in insertion sort - algorithm

Given below is a pseudocode of insertion sort algorithm applied on array A (zero-based indexing).
def compare(a, b) :
if a > b return 1
else return -1
for i : 1 to length(A)
j = i - 1
while j > 0
if compare(A[j-1], A[j]) > 0
swap(A[j], A[j-1])
j = j - 1
else break
Given an array A of integers , find difference between number of compare function calls and number of swap function calls by above algorithm when applied on A.
Let us take an example with A = {1, 2, 4, 3}. If we apply insertion sort as above on A we call sequeunce of compare and swap functions in following order
compare (A[0], A[1])
compare (A[1], A[2])
compare (A[2], A[3])
swap (A[2], A[3])
compare (A[1], A[2])
Here compare function is called 4 times, swap function is called 1 time. The answer is 4-1 = 3.
I need to find the difference optimally without running the actual insertion sort algorithm which takes O(n^2).

For every i from 2 to length(A) the number of compare calls will be one more than the number of swap calls besides the situation where the current element is minimal among all elements from 1 to i (in this situation we exit from the loop when j becomes 0). The answer will be length(A)-1 - minimal number occurrences.
minElement = A[1] // one-based array
result = length(A) - 1
for i = 2 to length(A)
if A[i] < minElement
minElement = A[i]
result = result - 1

put a counter in while loop and another in if condition.
The subtraction of these two will give the answer.

Related

Given an array, sort it according to conditions on other values in the same array

This is a problem involving application of Data Structures and Algorithms. I was unable to solve it in a Geeks for Geeks Practice Test.
Problem:
There are 2 arrays of non whole numbers, A and B. A consists of people's heights. B of the numbers corresponding to each person in A, such that for every person i in A, exactly B[i] number of people with height >= A[i] should stand in-front of person i in A, after sorting A according to this condition.
We are supposed to arrange A in the given way.
Constraints:
1 <= N (number of people) <= 1000
1 <= A[i] <= 10000
Examples
A = [3 2 1]
B = [0 1 1]
out = [3 1 2]
A = [5 3 2 6 1 4]
B = [0 1 2 0 3 2]
out = [5 3 2 1 6 4]
def linsert(ans,elt,ind):
for i in range(len(ans)):
if ans[i] == None:
ind -= 1
if ind == 0:
break
return i
def arrange(a,b,n):
ans = [None for i in range(n)]
for i in range(n):
a[i] = (a[i],i)
a.sort(key = lambda x : x[0])
for i in range(n):
elt = a[i][0]
ind = b[a[i][1]]
ind = linsert(ans,elt,ind)
ans[ind] = elt
return ans
In the above code, the function arrange needs to be called for the final sorted arrangement.
We start with the smallest element, as pointed by #user3386109. We place it at posoition b[j] in an empty array ans, where j is index of the smallest number in a. We do this repeatedly, until all numbers are processed. In practice, this is done by first sorting A, then inserting at b[i] if it is empty, else looping over ans to find all empty locations where a number greater or equal can be placed, and then placing our number. Please feel free to optimize this if possible. Please feel free to translate this to other languages. If I were using C++, simply due to convinience, I would have simply used a min Heap of pair<int,int>(elt,i), where i is the position in the original unsorted array. Then, I would have popped the heap until it were empty, and placed elements in the same way I have above.
Due to the sorting in the solution, the cost is O(nlogn). Memory required is O(n), for the answer and indices both.

What is the minimum cost of arranging the range a (n) (a [i] <= 20) such that the equal values will form a continuous segment?

You provide 1 string: a1, a2..an (a [i] <= 20)
Requirement: The minimum cost (number of steps) to swap any two elements in the sequence so that the final sequence obtained has equal values ​​that lie in succession:
Each step you can only choose 2 adjacent values to swap: swap (a [i], a [i + 1]) = 1steps
example:
1 1 3 1 3 2 3 2
Swap (a [3], a [4])
Swap (a [6], a [7])
-> 1 1 1 3 3 3 2 2
minimum = 2
I need your help.
Note that since A[i] <= 20 we can go ahead and enumerate every subset of all A[i] and fit comfortably within any time constraints.
Let M be the number of unique A[i], then there is a O(NM + M * 2^M) dynamic programming solution with bitmasks.
note that when I say moving an A[i] I mean moving every element with value A[i]
To understand how we do this let's first consider the brute force solution. We have some set of unique A[i] moved to the front of the string, and then at each step we pick the next A[i] to move behind what we had originally. This is O(M! * N).
There's one important observation to be made here: if we have some set of A[i] at the start of the string, and then we move the next one, the order of our original set of A[i] doesn't actually matter. Any move will cost the same regardless of the order.
Let cost(subset, A[i]) be the cost of moving all A[i] behind that subset of A[i] at the front of the string. Then we can write the following:
dp = [float('inf')] * (1 << M) # every subset of A[i]
dp[0] = 0
for mask in range(len(dp)):
for bit in range(M):
# if this A[i] hasn't been moved to the front, we move it to the front
if (mask >> bit) & 1 == 0:
dp[mask^(1 << bit)] = min(dp[mask^(1 << bit)], dp[mask] + cost(mask, bit))
If we compute cost naively then we have O(M * 2^M * N). However we can precompute every value of cost with O(1) per value.
Here's how we can do this:
Idea: The number of swaps needed to sort an array is the number of inversions.
Let's define a new array inversions[M][M], where inversions[i][j] is the number of times j comes after i in the arr. For clarity here's how we would compute it naively:
for i in range(len(arr)):
for j in range(i + 1, len(arr)):
if arr[i] != arr[j]: inversions[arr[i]][arr[j]] += 1
Assume that we have inversions, then we can compute cost(subset, A[i]) like so:
cost = 0
for bit in range(M):
# if bit isn't in the mask and thus needs to get swapped with A[i]
if (subset >> bit) & 1 == 0:
cost += inversions[bit][A[i]]
What's left is the following:
Compute inversions in O(NM). This can be done with keeping a count of each M at each index in N.
Currently cost is O(M) and not O(1). We can run a separate dynamic programming on cost to build an array cost[(1 << M)][M], where cost[i][j] is the cost to move item j to subset i.
For sake of completeness here is a complete code written in C++. It's my submission for the same problem on codeforces. Note that in that code cost is named contribution.

Counting valid sequences with dynamic programming

I am pretty new to Dynamic Programming, but I am trying to get better. I have an exercise from a book, which asks me the following question (slightly abridged):
You want to construct sequence of length N from numbers from the set {1, 2, 3, 4, 5, 6}. However, you cannot place the number i (i = 1, 2, 3, 4, 5, 6) more than A[i] times consecutively, where A is a given array. Given the sequence length N (1 <= N <= 10^5) and the constraint array A (1 <= A[i] <= 50), how many sequences are possible?
For instance if A = {1, 2, 1, 2, 1, 2} and N = 2, this would mean you can only have one consecutive 1, two consecutive 2's, one consecutive 3, etc. Here, something like "11" is invalid since it has two consecutive 1's, whereas something like "12" or "22" are both valid. It turns out that the actual answer for this case is 33 (there are 36 total two-digit sequences, but "11", "33", and "55" are all invalid, which gives 33).
Somebody told me that one way to solve this problem is to use dynamic programming with three states. More specifically, they say to keep a 3d array dp(i, j, k) with i representing the current position we are at in the sequence, j representing the element put in position i - 1, and k representing the number of times that this element has been repeated in the block. They also told me that for the transitions, we can put in position i every element different from j, and we can only put j in if A[j] > k.
It all makes sense to me in theory, but I've been struggling with implementing this. I have no clue how to begin with the actual implementation other than initializing the matrix dp. Typically, most of the other exercises had some sort of "base case" that were manually set in the matrix, and then a loop was used to fill in the other entries.
I guess I am particularly confused because this is a 3D array.
For a moment let's just not care about the array. Let's implement this recursively. Let dp(i, j, k) be the number of sequences with length i, last element j, and k consecutive occurrences of j at the end of the array.
The question now becomes how do we write the solution of dp(i, j, k) recursively.
Well we know that we are adding a j the kth time, so we have to take each sequence of length i - 1, and has j occurring k - 1 times, and add another j to that sequence. Notice that this is simply dp(i - 1, j, k - 1).
But what if k == 1? If that's the case we can add one occurence of j to every sequence of length i - 1 that doesn't end with j. Essentially we need the sum of all dp(i, x, k), such that A[x] >= k and x != j.
This gives our recurrence relation:
def dp(i, j, k):
# this is the base case, the number of sequences of length 1
# one if k is valid, otherwise zero
if i == 1: return int(k == 1)
if k > 1:
# get all the valid sequences [0...i-1] and add j to them
return dp(i - 1, j, k - 1)
if k == 1:
# get all valid sequences that don't end with j
res = 0
for last in range(len(A)):
if last == j: continue
for n_consec in range(1, A[last] + 1):
res += dp(i - 1, last, n_consec)
return res
We know that our answer will be all valid subsequences of length N, so our final answer is sum(dp(N, j, k) for j in range(len(A)) for k in range(1, A[j] + 1))
Believe it or not this is the basis of dynamic programming. We just broke our main problem down into a set of subproblems. Of course, right now our time is exponential because of the recursion. We have two ways to lower this:
Caching, we can simply keep track of the result of each (i, j, k) and then spit out what we originally computed when it's called again.
Use an array. We can reimplement this idea with bottom-up dp, and have an array dp[i][j][k]. All of our function calls just become array accesses in a for loop. Note that using this method forces us iterate over the array in topological order which may be tricky.
There are 2 kinds of dp approaches: top-down and bottom-up
In bottom up, you fill the terminal cases in dp table and then use for loops to build up from that. Lets consider bottom-up algo to generate Fibonacci sequence. We set dp[0] = 1 and dp[1] = 1 and run a for loop from i = 2 to n.
In top down approach, we start from the "top" view of the problem and go down from there. Consider the recursive function to get n-th Fibonacci number:
def fib(n):
if n <= 1:
return 1
if dp[n] != -1:
return dp[n]
dp[n] = fib(n - 1) + fib(n - 2)
return dp[n]
Here we don't fill the complete table, but only the cases we encounter.
Why I am talking about these 2 types is because when you start learning dp, it is often difficult to come up with bottom-up approaches (like you are trying to). When this happens, first you want to come up with a top-down approach, and then try to get a bottom up solution from that.
So let's create a recursive dp function first:
# let m be size of A
# initialize dp table with all values -1
def solve(i, j, k, n, m):
# first write terminal cases
if k > A[j]:
# this means sequence is invalid. so return 0
return 0
if i >= n:
# this means a valid sequence.
return 1
if dp[i][j][k] != -1:
return dp[i][j][k]
result = 0
for num = 1 to m:
if num == j:
result += solve(i + 1, num, k + 1, n)
else:
result += solve(i + 1, num, 1, n)
dp[i][j][k] = result
return dp[i][j][k]
So we know what terminal cases are. We create a dp table of size dp[n + 1][m][50]. Initialize it with all values 0, not -1.
So we can do bottom-up as:
# initially all values in table are zero. With loop below, we set the valid endings as 1.
# So any state trying to reach valid terminal states will get 1, but invalid states will
# return the values 0
for num = 1 to m:
for occour = 1 to A[num]:
dp[n][num][occour] = 1
# now to build up from bottom, we start by filling n-1 th position
for i = n-1 to 1:
for num = 1 to m:
for occour = 1 to A[num]:
for next_num = 1 to m:
if next_num != num:
dp[i][num][occour] += dp[i + 1][next_num][1]
else:
dp[i][num][occour] += dp[i + 1][num][occour + 1]
The answer will be:
sum = 0
for num = 1 to m:
sum += dp[1][num][1]
I am sure there must be some more elegant dp solution, but I believe this answers your question. Note that I considered that k is the number of times j-th number has been repeated consecutively, correct me if I am wrong with this.
Edit:
With the given constraints the size of the table will be, in the worst case, 10^5 * 6 * 50 = 3e7. This would be > 100MB. It is workable, but can be considered too much space use (I think some kernels doesn't allow that much stack space to a process). One way to reduce it would be to use a hash-map instead of an array with top down approach since top-down doesn't visit all the states. That would be mostly true in this case, for example if A[1] is 2, then all the other states where 1 has occoured more that twice need not be stored. Ofcourse this would not save much space if A[i] has large values, say [50, 50, 50, 50, 50, 50]. Another approach would be to modify our approach a bit. We dont actually need to store the dimension k, i.e. the times j has appeared consecutively:
dp[i][j] = no of ways from i-th position if (i - 1)th position didn't have j and i-th position is j.
Then, we would need to modify our algo to be like:
def solve(i, j):
if i == n:
return 1
if i > n:
return 0
if dp[i][j] != -1
return dp[i][j]
result = 0
# we will first try 1 consecutive j, then 2 consecutive j's then 3 and so on
for count = 1 to A[j]:
for num = 1 to m:
if num != j:
result += solve(i + count, num)
dp[i][j] = result
return dp[i][j]
This approach will reduce our space complexity to O(10^6) ~= 2mb, while time complexity is still the same : O(N * 6 * 50)

Have O(n^2) algorithm for "two-sum", convert to O(n) linear solution [duplicate]

This question already has answers here:
Find a pair of elements from an array whose sum equals a given number
(33 answers)
Closed 5 years ago.
I have an O(n^2) solution to the classic two-sum problem. Where A[1...n] sorted array of positive integers. t is some positive integer.
Need to show that A contains two distinct elements a and b s.t. a+ b = t
Here is my solution so far:
t = a number;
for (i=0; i<A.length; i++)
for each A[j]
if A[i] + A[j] == t
return true
return false
How do I make this a linear solution? O(n) scratching my head trying to figure it out.
Here's an approach I have in mind so far. i will start at the beginning of A, j will start at the end of A. i will increment, j will decrement. So I'll have two counter variables in the for loop, i & j.
There are couple of ways to improve upon that.
You could extend your algorithm, but instead of doing a simple search for every term, you could do a binary search
t = a number
for (i = 0; i < A.length; i++)
j = binarySearch(A, t - A[i], i, A.length - 1)
if (j != null)
return true
return false
Binary search is done by O(log N) steps, since you perform a binary search per every element in the array, the complexity of the whole algorithm would be O(N*log N)
This already is a tremendous improvement upon O(N^2), but you can do better.
Let's take the sum 11 and the array 1, 3, 4, 8, 9 for example.
You can already see that (3,8) satisfy the sum. To find that, imagine having two pointers, once pointing at the beginning of the array (1), we'll call it H and denote it with bold and another one pointing at the end of the array (9), we'll call it T and denote it with emphasis.
1 3 4 8 9
Right now the sum of the two pointers is 1 + 9 = 10.
10 is less than the desired sum (11), there is no way to reach the desired sum by moving the T pointer, so we'll move the H pointer right:
1 3 4 8 9
3 + 9 = 12 which is greater than the desired sum, there is no way to reach the desired sum by moving the H pointer, moving it right will further increase the sum, moving it left bring us to the initital state, so we'll move the T pointer left:
1 3 4 8 9
3 + 8 = 11 <-- this is the desired sum, we're done.
So the rules of the algorithm consist of moving the H pointer left or moving the T pointer right, we're finished when the sum of the two pointer is equal to the desired sum, or H and T crossed (T became less than H).
t = a number
H = 0
T = A.length - 1
S = -1
while H < T && S != t
S = A[H] + A[T]
if S < t
H++
else if S > t
T--
return S == t
It's easy to see that this algorithm runs at O(N) because we traverse each element at most once.
You make 2 new variables that contain index 0 and index n-1, let's call them i and j respectively.
Then, you check the sum of A[i] and A[j] and if the sum is smaller than t, then increment i (the lower index), and if it is bigger then decrement j (the higher index). continue until you either find i and j such that A[i] + A[j] = t so you return true, or j <= i, and you return false.
int i = 0, j = n-1;
while(i < j) {
if(A[i] + A[j] == t)
return true;
if(A[i] + A[j] < t)
i++;
else
j--;
return false;
Given that A[i] is relatively small (maybe less than 10^6), you can create an array B of size 10^6 with each value equal to 0. Then apply the following algorithm:
for i in 1...N:
B[A[i]] += 1
for i in 1...N:
if t - A[i] > 0:
if B[t-A[i]] > 0:
return True
Edit: well, now that we know that the array is sorted, it may be wiser to find another algorithm. I'll leave the answer here since it still applies to a certain class of related problems.

How can i find the total number of distinct arrays that can be obtained after applying given operation exactly k times?

Given an array and elements inside the array are in range [-10^6, 10^6].
We also have an integer kand we need to find how many different arrays can be obtained by applying an operation exactly k times. The only operation is to pick any element of the array and multiply it by -1.
For example, Array A = {1, 2, 1} and k = 2, different array obtained after k operations is 4 ({1, 2, 1}, {-1, -2, 1}, {-1, 2, -1}, {1, -2,-1}).
Although, Code and explanation are provided here but it is hard to understand. Please someone simplify that explanation or give some other approach to solve the problem. Thanks.
Let the size of the array be n. First see that the answer doesn't depend on the order of operations done.
Consider the two cases :
Case 1 : There are no zeros in the array and
Case 2 : There are non-zero number of zeros in the array.
Considering Case 1 :
Sub-Case 1 : Number of elements >= number of operations i.e n > k
Suppose we allow a maximum of 1 operation on every element, we can see that we can get nck different arrays having k changed elements from the original array.
But what happens when we do 2 operations on a single element ? The element basically doesn't change and keeping in mind that the order of operations doesn't change, you can put it this way : You took the initial array, selected an element, multiplied it by -1 twice and hence you are with the exact original array now but with just k-2 operations in your hand which means that we are throwing away 2 of our k chances initially. Now we can carefully perform the k-2 operations one on each element and get nck-2 different arrays. Similarly you can throw away 4, 6, 8, .... chances and get nck-4, nck-6, nck-8, ..... arrays respectively for each case.
This leads to nck+nck-2+nck-4+nck-6+ nck-8+ ....... number of possible arrays if no element in the array is zero.
Sub Case 2 : n < k
Since the number of operations are greater than number of elements you have to throw away some of your operations because you have to apply more than 1 operation on at least one element. So, if n and k both are even or both are odd you should throw k-n of your operations and have n operations left and from here it is just the sub case 1. If one is odd and one is even you have to throw away k-n+1 of your operations and have n-1 operations left and again it is just the sub case 1 from this point. You can try to get the expression for this case.
Considering case 2 :
Notice that in the earlier case you were only able to throw away an even number of operations.
Even here, there arise the cases n >= k and n < k.
For n >= k case :
Since there is at least one zero, you will now be able to throw away any number of operations by just applying that number of operations on any of the zeros since multiplying a zero with -1 doesn't affect it.
So the answer here will simply be nck+nck-1+nck-2+nck-3+ nck-4+ .......
And for n < k case :
The answer would be ncn+ncn-1+ncn-2+ncn-3+ ncn-4+ ....... = 2n
I think this is a dynamic programming problem because you have to calculate the sum of ncrs. Logic wise it is a combinatorics problem.
Ok let's go throught the code,
First there is this function nChoosek: it is a function that calculate the combination calculator, and this is what will be used to solve the problem
Conbinaison is basically the number of selecting part of a collection https://en.wikipedia.org/wiki/Combination Example for array {1, 2, 3} if I tell you chose two item from the three item of the array this is Combination of tow from three, in the code it is nChoosek(2,3) = card{(1,2), (2,3), (1,3)} = 3
If we consider the problem with those three additional conditions
1- you can't multiply the same item twice
2- n<=k
3- there is no zero in the array
The solution here will be nChoosek(k,n) but since those constraints exist we have to deal with each one of them
For the first one we can multiply the same item twice: so for nChoosek(k,n) we should the number of array that we can have if we multiply an item (or many) twice by -1..
but wait let's consider the combinaition when we multiply a single item twice: here we lost two multiplication without changing the array so the number of combination that we have will be nChoosek(k -2 ,n)
The same way if we decide to multiply two item twice the result will be nChoosek(k -4 ,n)
From that comes
for(; i >= 0; i -= 2){
ans += nChoosek(n, i);
ans = ans % (1000000007l);
}
For the case where k > n applying the algorithm imply that we will multiply at least one element twice so it is similar to applying the algorthm with k-2 and n
if k-2 still bigger than n we can by the same logic transform it to its equivalent with n and k-4 and so on until k-2*i <=n and k- 2 *(i+1) > 0 It is obvious here that this k-2*i will be n or n-1 so the new k will be n or n-1 and this justify this code
if(k <= n){
i = k;
}else if((k % 2 == 0 && n % 2 == 0) || (k % 2 != 0 && n % 2 != 0)){
i = n;
}else if((k % 2 == 0 && n % 2 != 0) || (k % 2 != 0 && n % 2 == 0)){
i = n - 1;
}
Now the story of zero, if we consider T1 = {1,2,3} and T2 ={0,1,0,0,2,3,0,0,0} and k =2 you can notice that the dealing with an array with length = n and has m zero is similar to dealing with array of length = n-m with no zero

Resources