Is below sorting algorithm O(n)? - c++

Algorithm:
insert element counts in a map
start from first element
if first is present in a map, insert in output array (total number of count), increment first
if first is not in a map, find next number which is present in a map
Complexity: O(max element in array) which is linear, so, O(n).
vector<int> sort(vector<int>& can) {
unordered_map<int,int> mp;
int first = INT_MAX;
int last = INT_MIN;
for(auto &n : can) {
first = min(first, n);
last = max(last, n);
mp[n]++;
}
vector<int> out;
while(first <= last) {
while(mp.find(first) == mp.end()) first ++;
int cnt = mp[first];
while(cnt--) out.push_back(first);
first++;
}
return out;
}

Complexity: O(max element in array) which is linear, so, O(n).
No, it's not O(n). The while loop iterates last - first + 1 times, and this quantity depends on the array's contents, not the array's length.
Usually we use n to mean the length of the array that the algorithm works on. To describe the range (i.e. the difference between the largest and smallest values in the array), we could introduce a different variable r, and then the time complexity is O(n + r), because the first loop populating the map iterates O(n) times, the second loop populating the vector iterates O(r) times, and its inner loop which counts down from cnt iterates O(n) times in total.
Another more formal way to define n is the "size of the input", typically measured in the number of bits that it takes to encode the algorithm's input. Suppose the input is an array of length 2, containing just the numbers 0 and M for some number M. In this case, if the number of bits used to encode the input is n, then the number M can be on the order of O(2n), and the second loop does that many iterations; so by this formal definition the time complexity is exponential.

Related

Nearest permutation to given array

Question
I have two arrays of integers A[] and B[]. Array B[] is fixed, I need to to find the permutation of A[] which is lexiographically smaller than B[] and the permutation is nearest to B[]. Here what I mean is:
for i in (0 <= i < n)
abs(B[i]-A[i]) is minimum and A[] should be smaller than B[] lexiographically.
For Example:
A[]={1,3,5,6,7}
B[]={7,3,2,4,6}
So,possible nearest permutation of A[] to B[] is
A[]={7,3,1,6,5}
My Approach
Try all permutation of A[] and then compare that with B[]. But the time complexity would be (n! * n)
So is there any way to optimize this?
EDIT
n can be as large as 10^5
For better understanding
First, build an ordered map of the counts of the distinct elements of A.
Then, iterate forward through array indices (0 to n−1), "withdrawing" elements from this map. At each point, there are three possibilities:
If i < n-1, and it's possible to choose A[i] == B[i], do so and continue iterating forward.
Otherwise, if it's possible to choose A[i] < B[i], choose the greatest possible value for A[i] < B[i]. Then proceed by choosing the largest available values for all subsequent array indices. (At this point you no longer need to worry about maintaining A[i] <= B[i], because we're already after an index where A[i] < B[i].) Return the result.
Otherwise, we need to backtrack to the last index where it was possible to choose A[i] < B[i], then use the approach in the previous bullet-point.
Note that, despite the need for backtracking, the very worst case here is three passes: one forward pass using the logic in the first bullet-point, one backward pass in backtracking to find the last index where A[i] < B[i] was possible, and then a final forward pass using the logic in the second bullet-point.
Because of the overhead of maintaining the ordered map, this requires O(n log m) time and O(m) extra space, where n is the total number of elements of A and m is the number of distinct elements. (Since m ≤ n, we can also express this as O(n log n) time and O(n) extra space.)
Note that if there's no solution, then the backtracking step will reach all the way to i == -1. You'll probably want to raise an exception if that happens.
Edited to add (2019-02-01):
In a now-deleted answer, גלעד ברקן summarizes the goal this way:
To be lexicographically smaller, the array must have an initial optional section from left to right where A[i] = B[i] that ends with an element A[j] < B[j]. To be closest to B, we want to maximise the length of that section, and then maximise the remaining part of the array.
So, with that summary in mind, another approach is to do two separate loops, where the first loop determines the length of the initial section, and the second loop actually populates A. This is equivalent to the above approach, but may make for cleaner code. So:
Build an ordered map of the counts of the distinct elements of A.
Initialize initial_section_length := -1.
Iterate through the array indices 0 to n−1, "withdrawing" elements from this map. For each index:
If it's possible to choose an as-yet-unused element of A that's less than the current element of B, set initial_section_length equal to the current array index. (Otherwise, don't.)
If it's not possible to choose an as-yet-unused element of A that's equal to the current element of B, break out of this loop. (Otherwise, continue looping.)
If initial_section_length == -1, then there's no solution; raise an exception.
Repeat step #1: re-build the ordered map.
Iterate through the array indices from 0 to initial_section_length-1, "withdrawing" elements from the map. For each index, choose an as-yet-unused element of A that's equal to the current element of B. (The existence of such an element is ensured by the first loop.)
For array index initial_section_length, choose the greatest as-yet-unused element of A that's less than the current element of B (and "withdraw" it from the map). (The existence of such an element is ensured by the first loop.)
Iterate through the array indices from initial_section_length+1 to n−1, continuing to "withdraw" elements from the map. For each index, choose the greatest element of A that hasn't been used yet.
This approach has the same time and space complexities as the backtracking-based approach.
There are n! permutations of A[n] (less if there are repeating elements).
Use binary search over range 0..n!-1 to determine k-th lexicographic permutation of A[] (arbitrary found example) which is closest lower one to B[].
Perhaps in C++ you can exploit std::lower_bound
Based on the discussion in the comment section to your question, you seek an array made up entirely of elements of the vector A that is -- in lexicographic ordering -- closest to the vector B.
For this scenario, the algorithm becomes quite straightforward. The idea is the same as as already mentioned in the answer of #ruakh (although his answer refers to an earlier and more complicated version of your question -- that is still displayed in the OP -- and is therefore more complicated):
Sort A
Loop over B and select the element of A that is closest to B[i]. Remove that element from the list.
If no element in A is smaller-or-equal than B[i], pick the largest element.
Here is the basic implementation:
#include <string>
#include <vector>
#include <algorithm>
auto get_closest_array(std::vector<int> A, std::vector<int> const& B)
{
std::sort(std::begin(A), std::end(A), std::greater<>{});
auto select_closest_and_remove = [&](int i)
{
auto it = std::find_if(std::begin(A), std::end(A), [&](auto x) { return x<=i;});
if(it==std::end(A))
{
it = std::max_element(std::begin(A), std::end(A));
}
auto ret = *it;
A.erase(it);
return ret;
};
std::vector<int> ret(B.size());
for(int i=0;i<(int)B.size();++i)
{
ret[i] = select_closest_and_remove(B[i]);
}
return ret;
}
Applied to the problem in the OP one gets:
int main()
{
std::vector<int> A ={1,3,5,6,7};
std::vector<int> B ={7,3,2,4,6};
auto C = get_closest_array(A, B);
for(auto i : C)
{
std::cout<<i<<" ";
}
std::cout<<std::endl;
}
and it displays
7 3 1 6 5
which seems to be the desired result.

How to erase elements more efficiently from a vector or set?

Problem statement:
Input:
First two inputs are integers n and m. n is the number of knights fighting in the tournament (2 <= n <= 100000, 1 <= m <= n-1). m is the number of battles that will take place.
The next line contains n power levels.
The next m lines contain two integers l and r, indicating the range of knight positions to compete in the ith battle.
After each battle, all nights apart from the one with the highest power level will be eliminated.
The range for each battle is given in terms of the new positions of the knights, not the original positions.
Output:
Output m lines, the ith line containing the original positions (indices) of the knights from that battle. Each line is in ascending order.
Sample Input:
8 4
1 0 5 6 2 3 7 4
1 3
2 4
1 3
0 1
Sample Output:
1 2
4 5
3 7
0
Here is a visualisation of this process.
1 2
[(1,0),(0,1),(5,2),(6,3),(2,4),(3,5),(7,6),(4,7)]
-----------------
4 5
[(1,0),(6,3),(2,4),(3,5),(7,6),(4,7)]
-----------------
3 7
[(1,0),(6,3),(7,6),(4,7)]
-----------------
0
[(1,0),(7,6)]
-----------
[(7,6)]
I have solved this problem. My program produces the correct output, however, it is O(n*m) = O(n^2). I believe that if I erase knights more efficiently from the vector, efficiency can be increased. Would it be more efficient to erase elements using a set? I.e. erase contiguous segments rather that individual knights. Is there an alternative way to do this that is more efficient?
#define INPUT1(x) scanf("%d", &x)
#define INPUT2(x, y) scanf("%d%d", &x, &y)
#define OUTPUT1(x) printf("%d\n", x);
int main(int argc, char const *argv[]) {
int n, m;
INPUT2(n, m);
vector< pair<int,int> > knights(n);
for (int i = 0; i < n; i++) {
int power;
INPUT(power);
knights[i] = make_pair(power, i);
}
while(m--) {
int l, r;
INPUT2(l, r);
int max_in_range = knights[l].first;
for (int i = l+1; i <= r; i++) if (knights[i].first > max_in_range) {
max_in_range = knights[i].first;
}
int offset = l;
int range = r-l+1;
while (range--) {
if (knights[offset].first != max_in_range) {
OUTPUT1(knights[offset].second));
knights.erase(knights.begin()+offset);
}
else offset++;
}
printf("\n");
}
}
Well, removing from vector wouldn't be efficient for sure. Removing from set, or unordered set would be more effective (use iterators instead of indexes).
Yet the problem will still remain O(n^2), because you have two nested whiles running n*m times.
--EDIT--
I believe I understand the question now :)
First let's calculate the complexity of your code above. Your worst case would be the case that max range in all battles is 1 (two nights for each battle) and the battles are not ordered with respect to the position. Which means you have m battles (in this case m = n-1 ~= O(n))
The first while loop runs n times
For runs for once every time which makes it n*1 = n in total
The second while loop runs once every time which makes it n again.
Deleting from vector means n-1 shifts that makes it O(n).
Thus with the complexity of the vector total complexity is O(n^2)
First of all, you don't really need the inner for loop. Take the first knight as the max in range, compare the rest in the range one-by-one and remove the defeated ones.
Now, i believe it can be done in O(nlogn) with using std::map. The key to the map is the position and the value is the level of the knight.
Before proceeding, finding and removing an element in map is logarithmic, iterating is constant.
Finally, your code should look like:
while(m--) // n times
strongest = map.find(first_position); // find is log(n) --> n*log(n)
for (opponent = next of strongest; // this will run 1 times, since every range is 1
opponent in range;
opponent = next opponent) // iterating is constant
// removing from map is log(n) --> n * 1 * log(n)
if strongest < opponent
remove strongest, opponent is the new strongest
else
remove opponent, (be careful to remove it after iterating to next)
Ok, now the upper bound would be O(2*nlogn) = O(nlogn). If the ranges increases, that makes the run time of upper loop decrease but increases the number of remove operations. I'm sure the upper bound won't change, let's make it a homework for you to calculate :)
A solution with a treap is pretty straightforward.
For each query, you need to split the treap by implicit key to obtain the subtree that corresponds to the [l, r] range (it takes O(log n) time).
After that, you can iterate over the subtree and find the knight with the maximum strength. After that, you just need to merge the [0, l) and [r + 1, end) parts of the treap with the node that corresponds to this knight.
It's clear that all parts of the solution except for the subtree traversal and printing work in O(log n) time per query. However, each operation reinserts only one knight and erase the rest from the range, so the size of the output (and the sum of sizes of subtrees) is linear in n. So the total time complexity is O(n log n).
I don't think you can solve with standard stl containers because there'no standard container that supports getting an iterator by index quickly and removing arbitrary elements.

Finding MIN MAX pairs from array

Given a sorted array of N integers, I need to find to all pairs with different indexes(i!=j). I need the maximum (a[j]+a[i]-1) and minimum (a[j]-a[i]+1) out of all pairs with (j>i). Numbers aren't unique but their pairing is allowed. Numbers can't pair with themselves.
What I'm doing right now :
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
MAX= max(MAX,a[j] + a[i] -1);
MIN=min(MIN,a[j]-a[i]+1);
}
}
This gives the time complexity of O(n^2). Is there a way to reduce it to O(nlogn) or even less ?
To find the max you just need to add the elements at index n-1 and n-2, as the array is already sorted and the 2 biggest elements will be only at the end of the array. No other element in the array will be bigger than these and hence their sum will also be greater than the sum of any other elements.
MAX = a[n-1] + a[n-2] - 1;
Time complexity : O(1)
For finding the min , you should look for pivot in the array. I choose to start from a[0]. If space is not a constraint create another array of similar size and populate it with the delta values from your pivot.
int[] b = new int[n];
for(int i=1; i<n; i++)
{
b[i] = a[i] - a[0];
}
Now the second array will have the delta values from your pivot. All you have to find is the indices of the Minimum and next-Minimum values of Array b. These 2 will be the closest values to each and hence their difference will also be the least.
Time Complexity : O(n) + O(n) = O(n)
Space Complexity : O(n) as a new array of same size has to be created.

how to calculate complexity of a simple search

I have an array with n elements. Now I need to search an element x. Here is the program
int x[100],i,s;
cout<<"Enter how many number of element you have";
cin>>n;
for(i=0;i<n;i++)
{
cin>>x[i];
}
cout<<"Enter element which you want to search";
cin>>s;
for(i=0;i<n;i++)
{
if(x[i]==s)
{
cout<<"Item found in position"<<i;
break;
}
}
what's the time and space complexity of this program?
Space:
x[100] = 200 bytes
n = 1 byte
s = 1 byte
==================
Total = 202 bytes
is it correct?
Time Complexity:
Please help me to figure out
Best case scenario(if x matches first element of n) complexity?
Worst case scenario(if x matches last element of n or doesn't match) complexity?
Time Complexity:
Time complexity is nothing but number of comparisons done by computer in your code.
So, when you search your array you actually do n comparisons. Comparing each element in the array with your input element. So, in this case:
Best case: O(1) - Element is found in the first comparison.
Worst case: O(n) - Means you had to search through all the elements and you found the element at the last place of the array.
Space complexity:
Normally, this is seen in terms of numbers of elements in the array rather
then the total size taken by these elements. This is done because size of data
types differ on various architectures but number of elements is dependent on the
problem and not the machine.
Hence, in your case:
Space complexity = "n"..Since n elements are present in the array.

What do move and key comparison mean in c++?

Followings are written in a ppt about Insertion Sort in my class:
void insertionSort(DataType theArray[], int n) {
for (int unsorted = 1; unsorted < n; ++unsorted) {
DataType nextItem = theArray[unsorted];
int loc = unsorted;
for (;(loc > 0) && (theArray[loc-1] > nextItem); --loc)
theArray[loc] = theArray[loc-1];
theArray[loc] = nextItem;
}
}
-
Running time depends on not only the size of the array but also the contents of the array.
Best-case:  O(n)
Array is already sorted in ascending order.
Inner loop will not be executed.
>>>> The number of moves: 2*(n-1)  O(n)
>>>> The number of key comparisons: (n-1)  O(n)
Worst-case:  O(n2)
Array is in reverse order:
Inner loop is executed p-1 times, for p = 2,3, …, n
The number of moves: 2*(n-1)+(1+2+...+n-1)= 2*(n-1)+ n*(n-1)/2  O(n2)
The number of key comparisons: (1+2+...+n-1)= n*(n-1)/2  O(n2)
Average-case:  O(n2)
We have to look at all possible initial data organizations.
So, Insertion Sort is O(n2)
What exacly are move and key comparison?? I couldn't find an explanaiton on Google.
Let me word the algorithm first.
Assume at a given time there are two part of array. index 0 to index loc - 1 is sorted in ascending order and index loc to n - 1 is unsorted.
Start with element at loc, find its correct place in sorted part of the array and insert it there.
So now there are two loops:
First outer loop, starts with loc = 1 to loc = n, basically partitions the array in sorted and unsorted part.
Second inner loop finds position of element at loc in the sorted part of array ( 0 to loc - 1).
For the inner loop, to find correct location, you have to compare element at loc with, in worst case, all the elements in sorted part of array. This is key comparison.
To insert, you have to create a void in sorted part of the array for element at loc. This is done by swapping each element in sorted part to the next element. This is move.
Move is the number of swaps it has to perform in order to sort the data and the keys are the data that is compered.