Data Structures and Algorithms: (CS210/ESO207/ESO211)
Data Structures and Algorithms: (CS210/ESO207/ESO211)
(CS210/ESO207/ESO211)
Lecture 14
Algorithm paradigm of Divide and Conquer continued
Counting the number of inversions
1
Divide and Conquer paradigm for
Algorithm Design
2
Divide and Conquer paradigm
An Overview
A problem in this paradigm is solved in the following way.
1. First Divide the problem instance into two or more instances
of the same problem. Solve each smaller instances
recursively (base case suitably defined).
2. Combine the solutions of the smaller instances to get the
solution of the original instance.
3
This is usually the main nontrivial step
in the design of an algorithm using
divide and conquer strategy
Example 3
4
Counting the number of inversions
in an array
Counting Inversions in an array
Problem description
Definition (Inversion): Given an array A of size n, a pair (i,j), 0i<j<n is
called an inversion if A[i]>A[j].
Example:
Inversions are : (1,2), (1,4), (3,4), (1,6), (3,6), (5,6), (5,7)
AIM: An efficient algorithm to count the number of inversions in an array A.
5
A 3 15 8 19 9 67 11 27
0 1 2 3 4 5 6 7
Counting Inversions in an array
Problem familiarization
Trivial-algo(A[0..n-1])
{ count 0;
For(j=1 to n-1) do
{ For( i=0 to j-1 )
{ If (A[i]>A[j]) count count + 1;
}
}
}
Time complexity: O(
)
Question: What can be the max. no. of inversions in an array A ?
Answer:
, which is O(
).
Question: Is the algorithm given above optimal ?
Answer: No, our aim is not to report all inversions but to report the count.
6
Let us try to design a
Divide and Conquer based algorithm
7
How do we approach using divide & conquer
8
A 3 15 8 19 9 67 11 27
0 1 2 3 4 5 6 7
I
II
III
Counting Inversions
Divide and Conquer based algorithm
CountInversion( A,i,k) // Counting no. of inversions in A[i..k]
If (i=k) return 0;
Else{ mid (i+k)/2;
I
CountInversion(A,i,mid);
II
CountInversion(A,mid+1,k);
. Code for
III
.
return
I
+
II
+
III
;
}
9
How to efficiently compute
III
(Inversions of type III) ?
Aim: For each mid<jk, count the elements in A[i..mid] that are greater than A[j].
Trivial way: O(size of the subarray A[i..mid]) time for a given j.
O(n) time for a given j in the first call of the algorithm.
O(n
2
) time for computing
III
since there are n/2 possible values of j.
10
A 3 15 8 19 9 67 11 27
0 1 2 3 4 5 6 7
III
O(
) time algo
How to efficiently compute
III
(Inversions of type III) ?
Key Observation: We have to perform n/2 operations of the same kind:
How many elements in A[i..mid] are greater than A[j] ?
Lesson from Data Structures :
We should build a suitable data structure storing elements of A[i..mid] so
that the above operation can be performed efficiently for any j.
Question: What should be the data structure ?
Answer: Sorted subarray A[i..mid].
11
Counting Inversions
First algorithm based on divide & conquer
CountInversion( A,i,k)
If (i=k) return 0;
Else{ mid (i+k)/2;
I
CountInversion(A,i,mid);
II
CountInversion(A,mid+1,k);
. Code for
III
.
return
I
+
II
+
III
;
}
12
Sort(A,i,mid);
For each mid<jk
do binary search for A[j] in A[i..mid] to compute
the number of elements greater than A[j].
Add this number to
III
;
2 T(n/2)
c n log n
Counting Inversions
First algorithm based on divide & conquer
Time complexity analysis:
If n = 1,
T(n) = c for some constant c
If n > 1,
T(n) = cn log n + 2 T(n/2)
= cn log n + cn ((log n)-1) +
T(n/
)
= cn log n + cn ((log n)-1) + cn ((log n)-2) +
T(n/
)
= O(n
n)
13
Can we improve it further ?
Sequence of observations
To achieve better running time
The extra log n factor arises because for the combine step, we are
spending O(n log n) time instead of O(n).
The reason for O(n log n) time for the combine step is due to the
following tasks:
Sorting A[0..n/2] takes O(n log n) time.
Doing Binary Search for n/2 elements from A[n/2n-1]
Each of the above tasks have optimal running time.
So the only way to improve the running time of combine step is to look
for some new ideas to compute
III
.
14
Learn from the past knowledge
15
Many of you noticed some similarity between
the code of the O(n
III
III
+ (mid-p+1);
Counting Inversions
Final algorithm based on divide & conquer
Sort_and_CountInversion(A,i,k)
{ If (i=k) return 0;
else
{ mid(i+k)/2;
I
Sort_and_CountInversion (A,i,mid);
II
Sort_and_CountInversion (A,mid+1,k);
Create a temporary array C[0..k-i]
III
Merge_and_CountInversion(A,i,mid,k,C);
Copy C[0..k-i] to A[i..k];
return
I
+
II
+
III
;
}
}
20
2 T(n/2)
O(n)
Counting Inversions
Final algorithm based on divide & conquer
Time complexity analysis:
If n = 1,
T(n) = c for some constant c
If n > 1,
T(n) = cn + 2 T(n/2)
= O(n log n)
Theorem: There is a divide and conquer based algorithm for
computing the number of inversions in an array of size n. The
running time of the algorithm is O(n log n).
21
The second practice sheet of problems is available on
moodle. Make sincere attempts to solve its exercises.