Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
I consider Merge sort as divide and conquer because,
Divide - Array is literally divided into sub arrays without any processing(compare/swap), and the problem sized is halved/Quartered/....
Conquer - merge() those sub arrays by processing(compare/swap)
Code gives an impression that it is Divide&Conquer,
if(hi <= lo) return;
int mid = lo + (hi-lo)/2; //No (compare/swap) on elements before divide
sort(a, aux, lo, mid); // Problem is halved(Divide)
sort(a, aux, mid+1, hi);
merge(a, aux, lo, mid); // (Compare/swap) happens here during Merge - Conquer
Merge sort trace says, that problem is granulated and then processed,
But in Quick sort,
Firstly, Complete array is processed(compare/swap) using a partition element(pivot) and fix the final position of pivot, and then problem size is halved/Quartered/.... for re-partitioning,
Code does not give an impression of divide & conquer,
if(hi <= lo) return;
int j = partition(a, lo, hi); // Do you call this divide phase?
sort(a, lo, j-1); // This looks like divide phase, because problem is halved
sort(a, j+1, hi);
Quick sort trace, shows that processing is started on complete array and then reaches granular level,
Questions:
My understanding of Divide phase mean, reducing(half) the problem size. In Quick sort, do you consider processing(compare/swap) array and partition using pivot, as Divide phase?
My understanding of Conquer phase mean, gathering/merging back. In quick sort, Where does conquer phase mean?
Note: Am a beginner, in sorting algorithms
Divide & Conquer algorithms have 3 stages:
Divide,
Conquer,
Combine,
For merge sort (http://www.cs.umd.edu/~meesh/351/mount/lectures/lect6-divide-conquer-mergesort.pdf):
Divide: Split the array into 2 subarrays,
Conquer: Merge sort the resulting subarrays recursively,
Combine: Merge the two sorted subarrays into a single sorted list.
For quick sort (https://www.cs.rochester.edu/~gildea/csc282/slides/C07-quicksort.pdf):
Divide: First rearrange then split the array into 2 subarrays,
Conquer: Quick sort the resulting subarrays recursively,
Combine: None.
Note: Thanks to University of Rochester and University of Maryland CS departments.
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Currently I have this sorting algorithm:
public static void sort(int[] A, int i, int j) {
if (i == j) return;
if(j == i+1) {
if(A[i] > A[j]) {
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
}
else {
int k = (int) Math.floor((j-i+1)/3);
sort(A,i, j-k);
sort(A,i+k, j);
sort(A,i,j-k);
}
}
It's sorting correctly, however, the asymptotic comparison is quite high: with T(n) = 3T(n-f(floor(n/3)) and f(n) = theta(n^(log(3/2)3)
Therefore, I'm currently thinking of replacing the third recursion sort(A,i,j-k) with an newly written, iterative method to optimize the algorithm. However, I'm not really sure how to approach the problem and would love to gather some ideas. Thank you!
If I understand this correct, you first sort the first 2/3 of the list, then the last 2/3, then sort the first 2/3 again. This actually works, since any misplaced items (items in the first or last 2/3 that actually belong into the last or first 1/3) will be shifted and then correctly sorted in the next pass of the algorithm.
There are certainly two points that can be optimized:
in the last step, the first 1/3 and the second 1/3 (and thus the first and second half of the region to sort) are already in sorted order, so instead of doing a full sort, you could just use a merge-algorithm, which should run in O(n)
instead of sorting the first and last 2/3, and then merging the elements from the overlap into the first 1/3, as explained above, you could sort the first 1/2 and last 1/2 and then merge those parts, without overlap; the total length of array processed is the same (2/3 + 2/3 + 2/3 vs. 1/2 + 1/2 + 2/2), but the merging-part will be faster than the sorting-part
However, after the second "optimization" you will in fact have more or less re-invented Merge Sort.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
suppose that we have a m*n matrix that each rows are in order. so, i only know that order of best algorithm for this problem is O(m(log m + log n)).
(It was a test question and result is this order)
but i don't know how this algorithm works
One idea can be like this.
If I ask you what is the rank of a given number x in the original matrix? How do you answer this question?
One answer can be:
Just binary search the first occurrence of x or greater element on each row. and then add the individual ranks.
int rank = 1;
for (int i = 0; i < m; ++i) {
rank += std::lower_bound(matrix[i].begin(), matrix[i].end(), x);
}
This can be done in O(m * log n) time(m binary searches on n sized arrays).
Now we just need to do a binary search on x(between 0 and INT_MAX or matrix[0][k]) to find the kth rank. Since INT_MAX is const, that will make the overall time complexity O(m * log n) theoretically. One optimization, which can be done use intelligent ranges in place of matrix[i].begin(), matrix[i].end().
PS: Still wondering the O(m*(log m + log n)) or O( m * (log mn)) solution.
This question already has answers here:
Kendall tau distance (a.k.a bubble-sort distance) between permutations in base R
(3 answers)
Closed 5 years ago.
I am given two sequences of integers with equal length, e.g.
3 1 2 5 4
5 3 2 1 4
I want to find the Kendall Tau distance between the two, i.e. the number of inverted pairs between the sequences. For instance, we have (3, 5) (3 is before 5) in the first sequence and (5, 3) in the second one. I did a quick O(n^2) algorithm to check the number, but it gets too computationally intense for large sequences of length 40,000 and on. I've read that I can count the number of inversions in doing a bubble sort, transforming the first sequence into the second one, but that's yet again O(n^2).
unsigned short n, first[50001], second[50001], s;
int sum = 0;
cin >> n;
for(int i=1; i<n+1; i++){
cin >> first[i];
}
// in the second array exchange the actual entries in the sequence with their indices
// that way we can quickly check if a pair is inverted
for(int i=1; i<n+1; i++){
cin >> s
second[s]=i;
}
for(int i=1; i<n+1; i++){
for (int j = i+1; j < n+1; j++)
// i < j always
// when we check the indices of the respective entries in the second array
// the relationship should stay otherwise we have an inversion
if(second[first[i]]>=second[first[j]])sum++;
}
This problem seems closely related to the problem of counting inversions in an array, with the difference being that in this case an inversion means "the elements are swapped relative to the other sequence" rather than "the elements are out of order." Since there's a nice O(n log n)-time algorithm for counting inversions, it seems like it would be reasonable to try to find a way to adapt that algorithm to solve this particular problem.
The divide-and-conquer algorithm for counting inversions is based on mergesort and assumes that given any two elements in the sequence there's a fast (O(1)-time) way to compare them to see if they're in the proper order. If we can find a way to somehow annotate the elements of the second sequence so that in time O(1) we can determine whether any pair of elements from that sequence are in order or out of order, then we can just run the fast counting inversions algorithm to get the answer you're looking for.
Here's one way to do this. Create some auxiliary data structure (say, a balanced BST) that associates the elements of the first array with their indices in the first array. Then, make a copy of the second array, annotating each element with its corresponding position in the first array. This in total takes time O(n log n). Then, run the standard O(n log n)-time algorithm for counting inversions in the second array, except when comparing elements, compare by their associated index rather than their values. This in total takes time O(n log n) to complete.
This was the question, I was asked in interview.
What is the best time complexity you can get to find a min and max of array?
I replied: O(n). Iterate through the array, keeping track of the max and min found so far. very simple and straightForward.
The interviewer asked can you improve it using divide and conquer. I said probably not. Then the conversation went on and finally I was asked to implement divide and conquer approach.
Here it is:
public class MinMaxInArray {
public static int[] findMinMax(int[] array, int i, int j){
// base cases
int arrLen = j - i + 1;
if (arrLen == 1)
return new int[]{array[i], array[j]}; //j and i are the same
if (arrLen == 2){
int min = Math.min(array[i], array[j]);
int max = Math.max(array[i], array[j])
return new int[]{min, max};
}
// actual divide and conquer
int mid = i + (j-i)/2;
int[] leftMinMax = findMinMax(array, i, mid);
int[] rightMinMax = findMinMax(array, mid+1, j);
return new int[]{ Math.min(leftMinMax[0], rightMinMax[0]), Math.max(leftMinMax[1], rightMinMax[1]) };
}
public static void main(String[] args){
int[] array = {20, 5, 7, 25, 30, 1, 9, 12};
int[] minMax= findMinMax(array, 0, array.length - 1); //minMax[0] = minimum value, minMax[1] = maximum value
System.out.println("min = " + minMax[0] + ", max = " + minMax[1] );
}
}
I am confident that this is still O(n) since all elements are compared. But the interviewer insisted that it is O(log n) and asked me to think about it. I thought quite a bit and I am convinced it is O(n). Just applying divide and conquer does not always reduce complexity if I am correct.
Please correct me if my understanding that this algorithm is still O(n).
Thank you
You are correct. Unless the array is sorted, you still have to examine every element in each half (and each quarter and each eighth as you recur).
The only way it can be O(log N) is if you can discard half the search space each recursion level (such as searching for a specific value in a sorted list) and the only way that can happen is if it's sorted.
But then, of course, the min and max operations become O(1) since you just grab the first and last element of the list, no need to search at all.
Now it may be that the examiner was suggesting divide-and-conquer in terms of farming off the different halves of each problem level to different execution engines so they could run in parallel. That's the only other way I could see it giving you O(log N) but I see no real evidence based on what's posted that suggests this was the case, and I think it would need quite a few engines.
It's true that using divide and conquer the time complexity for finding min and max is O(n).
But using divide and conquer the number of comparisons can be reduced to a great extent which indeed reduces time if the data is huge.
So divide and conquer approach does 3/2n -2 comparisons if n is a power of 2. And it does more than 3/2n -2 comparisons if n is not a power of 2.
I also agree "Find min,max using Divide & Conquer" is O(N)
because in "Divide and Conqer"
Divide --->Takes O(n), as it divide every segment into smaller one.
Conquer--->It could be any function, which is giving result. So Time complexity will be based on what conquer is doing. Like in Merge sort,Merging part takes log(n) time.
As in this case conquer is constant operation
I "invented" "new" sort algorithm. Well, I understand that I can't invent something good, so I tried to search it on wikipedia, but all sort algorithms seems like not my. So I have three questions:
What is name of this algorithm?
Why it sucks? (best, average and worst time complexity)
Can I make it more better still using this idea?
So, idea of my algorithm: if we have an array, we can count number of sorted elements and if this number is less that half of length we can reverse array to make it more sorted. And after that we can sort first half and second half of array. In best case, we need only O(n) - if array is totally sorted in good or bad direction. I have some problems with evaluation of average and worst time complexity.
Code on C#:
public static void Reverse(int[] array, int begin, int end) {
int length = end - begin;
for (int i = 0; i < length / 2; i++)
Algorithms.Swap(ref array[begin+i], ref array[begin + length - i - 1]);
}
public static bool ReverseIf(int[] array, int begin, int end) {
int countSorted = 1;
for (int i = begin + 1; i < end; i++)
if (array[i - 1] <= array[i])
countSorted++;
int length = end - begin;
if (countSorted <= length/2)
Reverse(array, begin, end);
if (countSorted == 1 || countSorted == (end - begin))
return true;
else
return false;
}
public static void ReverseSort(int[] array, int begin, int end) {
if (begin == end || begin == end + 1)
return;
// if we use if-operator (not while), then array {2,3,1} transforms in array {2,1,3} and algorithm stop
while (!ReverseIf(array, begin, end)) {
int pivot = begin + (end - begin) / 2;
ReverseSort(array, begin, pivot + 1);
ReverseSort(array, pivot, end);
}
}
public static void ReverseSort(int[] array) {
ReverseSort(array, 0, array.Length);
}
P.S.: Sorry for my English.
The best case is Theta(n), for, e.g., a sorted array. The worst case is Theta(n^2 log n).
Upper bound
Secondary subproblems have a sorted array preceded or succeeded by an arbitrary element. These are O(n log n). If preceded, we do O(n) work, solve a secondary subproblem on the first half and then on the second half, and then do O(n) more work – O(n log n). If succeeded, do O(n) work, sort the already sorted first half (O(n)), solve a secondary subproblem on the second half, do O(n) work, solve a secondary subproblem on the first half, sort the already sorted second half (O(n)), do O(n) work – O(n log n).
Now, in the general case, we solve two primary subproblems on the two halves and then slowly exchange elements over the pivot using secondary invocations. There are O(n) exchanges necessary, so a straightforward application of the Master Theorem yields a bound of O(n^2 log n).
Lower bound
For k >= 3, we construct an array A(k) of size 2^k recursively using the above analysis as a guide. The bad cases are the arrays [2^k + 1] + A(k).
Let A(3) = [1, ..., 8]. This sorted base case keeps Reverse from being called.
For k > 3, let A(k) = [2^(k-1) + A(k-1)[1], ..., 2^(k-1) + A(k-1)[2^(k-1)]] + A(k-1). Note that the primary subproblems of [2^k + 1] + A(k) are equivalent to [2^(k-1) + 1] + A(k-1).
After the primary recursive invocations, the array is [2^(k-1) + 1, ..., 2^k, 1, ..., 2^(k-1), 2^k + 1]. There are Omega(2^k) elements that have to move Omega(2^k) positions, and each of the secondary invocations that moves an element so far has O(1) sorted subproblems and thus is Omega(n log n).
Clearly more coffee is required – the primary subproblems don't matter. This makes it not too bad to analyze the average case, which is Theta(n^2 log n) as well.
With constant probability, the first half of the array contains at least half of the least quartile and at least half of the greatest quartile. In this case, regardless of whether Reverse happens, there are Omega(n) elements that have to move Omega(n) positions via secondary invocations.
It seems this algorithm, even if it performs horribly with "random" data (as demonstrated by Per in their answer), is quite efficient for "fixing up" arrays which are "nearly-sorted". Thus if you chose to develop this idea further (I personally wouldn't, but if you wanted to think about it as an exercise), you would do well to focus on this strength.
this reference on Wikipedia in the Inversion article alludes to the issue very well. Mahmoud's book is quite insightful, noting that there are various ways to measure "sortedness". For example if we use the number of inversions to characterize a "nearly-sorted array" then we can use insertion sort to sort it extremely quickly. However if your arrays are "nearly-sorted" in slightly different ways (e.g. a deck of cards which is cut or loosely shuffled) then insertion sort will not be the best sort to "fix up" the list.
Input: an array that has already been sorted of size N, with roughly N/k inversions.
I might do something like this for an algorithm:
Calculate number of inversions. (O(N lg(lg(N))), or can assume is small and skip step)
If number of inversions is < [threshold], sort array using insertion sort (it will be fast).
Otherwise the array is not close to being sorted; resort to using your favorite comparison (or better) sorting algorithm
There are better ways to do this though; one can "fix up" such an array in at least O(log(N)*(# new elements)) time if you preprocess your array enough or use the right data-structure, like an array with linked-list properties or similar which supports binary search.
You can generalize this idea even further. Whether "fixing up" an array will work depends on the kind of fixing-up that is required. Thus if you update these statistics whenever you add an element to the list or modify it, you can dispatch onto a good "fix-it-up" algorithm.
But unfortunately this would all be a pain to code. You might just be able to get away with want is a priority queue.