This question already has answers here:
Sorting an array while moving duplicates to the end?
(4 answers)
Closed 9 years ago.
I have heard of sorting techniques like quicksort, bubblesort, mergesort and many others. I have an array like
arr[]={2, 3, 4, 1, 9, 5, 1, 2, 6, 8, 1, 3}
Using bubble sort I can get the sorting done as
arr[]={1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 8, 9}
But I need to sort the given array in this manner
arr[]={1, 2, 3, 4, 5, 6, 8, 9, 1, 1, 2, 3 )
That is, any re-occurances of values need to be moved to end of the array.
My idea is to bubblesort the array first and then using this sorted array, traverse through the array moving any repeated occurrences to end of the array.
Can it be done this way? If yes, what will be the algorithm after getting bubble sorted array.
Or is there a better way to achieve it.
You can conduct bubble sort in two passes.
In the first pass, find the smallest element and put it in the first place. Then find the element that is greater than the last element found but smallest from among the lot and put it in second place.
Do the above till you reach the maximum element.
Once you reach the maximum element, bubble sort on the remaining part of the array normally.
Order of complexity: Exactly as per Bubble sort, since you are just dividing it in two halves.
Full working code in C++:
#include <iostream>
using namespace std;
int main()
{
int arr[] = {2, 3, 4, 1, 9, 5, 1, 2, 6, 8, 1, 3};
int size = 12;
// find max element.
int max = -1;
for ( int I = 0; I < size; I++ ) {
if ( arr[I] > max )
max = arr[I];
}
int begin = 0;
bool maxPlaced = false;
int lastFound = -1;
while ( !maxPlaced ) {
// find the first element from the end,
// that is greater than elements already placed.
int end = size-1;
while ( arr[end] <= lastFound )
end--;
for ( int I = end; I > begin; I-- ) {
// swap if arr[i-1] is higher than arr[i]
// or arr[i-1] is a number that we have already placed.
if ( arr[I] < arr[I-1] || lastFound >= arr[I-1] ) {
int temp = arr[I];
arr[I] = arr[I-1];
arr[I-1] = temp;
}
}
// lastfound is the highest number that we have placed till now.
lastFound = arr[begin];
begin++;
if ( lastFound == max )
maxPlaced = true;
}
//continue bubble sort from begin position.
for ( int I = begin; I < size; I++ ) {
for ( int j = begin; j < size - 1 - (I-begin); j++ ) {
if (arr[j] > arr[j+1]) {
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
for ( int i = 0; i < size; i++ )
cout << arr[i] << " ";
return 0;
}
Output:
1 2 3 4 5 6 7 8 9 1 1 2 3
For input of {4,5,6,1,1,3,3,4,4,4,1,9,9,8,8}
Output:
1 3 4 5 6 8 9 1 1 3 4 4 4 8 9
Keep in mind that bubble-sort is the least efficient sorting algorithm of those 3 you mentioned.
It's O(n2) average case while the others are O(n log n).
Heap-sort
A variation on heap-sort comes to mind as an efficient (O(n log n)) way to do this.
Build a heap of the items.
Have a left and a right iterator into the array, pointing to the left-most and right-most positions respectively.
While the heap is not empty:
Remove the maximum.
If the removed item is the same as the last removed item, insert it at the right iterator and decrease the iterator.
Otherwise insert it at the left iterator and increase the iterator.
Now if the items at the end need to be sorted as well, just reverse their order (they should be in reverse order at the end of the above process).
In-place alternative - selection sort
Selection sort finds the maximum element at each step, so this can easily be modified to skip the applicable elements if they're greater than an already found element.
This can be done in-place (where the above can't), but is again O(n2).
int arr[] = {2, 3, 4, 1, 9, 5, 1, 2, 6, 8, 1, 3};
int arrLength = 12;
for (int i = 0; i < arrLength; i++)
{
int minPos = -1;
for (int j = i; j < arrLength; j++)
// either it's the first element, or it's greater than the last element
// and either it's the first such element we find, or smaller than the best one
if ((i == 0 || arr[j] > arr[i-1]) &&
(minPos == -1 || arr[j] < arr[minPos]))
{
minPos = j;
}
// no more elements to sort
if (minPos == -1)
break;
int temp = arr[i];
arr[i] = arr[minPos];
arr[minPos] = temp;
}
Live demo.
If the repeated elements needs to be sorted as well, this will need to be done additionally (with any sort method).
Related
For each integer in an array of positive integers, find the index of the closest integer that is greater than the current integer. Also, we need to search for the answer only to the left of the current integer.
For example -
Input array - [ 5, 4, 3, 6, 2, 3]
Output array - [ -1, 0, 1, -1, 3, 3]
Assign -1 to those numbers which don't have an answer.
There is a simple O(n^2) method, for each number run a for loop from the previous number to the beginning of the array.
for(int i=0; i<n; ++i)
{
output[i] = -1;
for(int j=i-1; j>=0; --j)
{
if(input[j] > input[i])
{
output[i] = j;
break;
}
}
}
This method is inefficient when 'n' is large. Is there a more efficient way?
I believe one popular O(n) solution is to use a stack, maintaining a descending sequence (hopefully the algorithm is clear enough from the commented code):
function f(A){
let stack = []
let output = []
for (let i=0; i<A.length; i++){
// While there are lower or
// equal elements on top of
// the stack
while (stack.length && A[ stack[stack.length-1] ] <= A[i])
stack.pop();
// The next greater element
// to the left
if (stack.length)
output.push(stack[stack.length-1]);
// There was none
else
output.push(-1);
stack.push(i);
}
return output;
}
var As = [
[5, 4, 3, 6, 2, 3],
[1, 2, 3, 4, 5],
[5, 4, 3, 2, 1],
[0, 3, -1, 5, 4]
];
for (let A of As){
console.log(`${ A }`);
console.log(`${ f(A) }`);
console.log('');
}
The proposed answer is an adaption of : https://www.geeksforgeeks.org/find-the-nearest-smaller-numbers-on-left-side-in-an-array/
The main idea is to use a stack to remember processed value. In the link, they care about the value but it can easily be adapted to output indices.
#include <iostream>
#include <vector>
#include <stack>
std::vector<int> function(std::vector<int> input) {
std::vector<int> output;
output.reserve(input.size());
// Create an empty stack
// first element of the pair is the index. second is the value
std::stack<std::pair<int,int>> S;
// Traverse all array elements
for (int i=0; i<input.size(); i++)
{
// Keep removing top element from S while the top
// element is less than or equal to arr[i]
while (!S.empty() && S.top().second <= input[i])
S.pop();
// If all elements in S were greater than arr[i]
if (S.empty())
output.push_back(-1);
else //Else print the nearest smaller element
output.push_back(S.top().first);
// Push this element
S.push({i, input[i]});
}
return output;
}
int main() {
std::vector<int> input{5, 4, 3, 6, 2, 3};
std::vector<int> output = function(input);
for(int index : output) {
std::cout << index << ' ';
}
return 0;
}
Output:
-1 0 1 -1 3 3
Compiler explorer : https://godbolt.org/z/8W3ecv
I am trying one of the practice problems on hackerrank.
I'm aware there is a better way to do it, but I would like to know why this way didn't work to understand it better.
The vector erase function seems to work as intended until the last couple of times and then erases at the wrong index, even though nothing changes.
debugger output:
1, 1, 3, 1, 2, 1, 3, 3, 3, 3, //what is currently in the vector
Delete indx 0 & 1 //The first pair that I will erase and increment count
3, 1, 2, 1, 3, 3, 3, 3, //continue...
Delete indx 0 & 4
1, 2, 1, 3, 3, 3,
Delete indx 0 & 2
2, 3, 3, 3,
Delete indx 1 & 2 //says to delete the first and second three
3, 3, //it looks like the 0th and some other index was erased instead
Delete indx 0 & 1
count returned is: 5
let me know if I can add to this question to make it better, thanks
int i, count = 0;
for (i=0;i<ar.size()-1;i++)
{
for (int j=i+1;j<ar.size();j++)
{
if (ar[i] == ar[j])
{
ar.erase(ar.begin()+i-1);
ar.erase(ar.begin()+j-1);
count++;
i=-1;
break;
}
}
if (ar.size()== 0)
break;
}
From what I understood, you only need the count of pairs (considering the removals).
for(int i = 0; i < ar.size() - 1; i++){
for(int j = i + 1; j < ar.size(); j++){
if(ar[i] == ar[j]) {
ar.erase( ar.begin() + j );
count++;
break;
}
}
}
This way you only need to perform 1 call of erase (which is slow, considering it moves all the elements in the right of the deleted element 1 slot to the left).
If you have big vectors, also consider not using ar.size() all the time (at least in j loop, since in i loop it's kind of essential). Try for(int j = i + 1, len = ar.size(); j < len; j++).
How can I find the maximum length between two similar elements in an array?
{6, 6, 4, 2, 3, 6, 1, 2, 3, 4, 5, 6, 5, 4}
from this array the maximum length between two 6's
is {1, 2, 3, 4, 5} not {4, 2, 3}
Your problem statement is to find maximum length of the subarray that only has unique elements.
This can obviously done in O(n*n) if you choose a range from i ... j and update max length if the subarray doesn't have duplicates.
max_len = 0
for(int i = 0; i < n; ++i)
for(int j = 0; j <= i; ++j)
max_len = max( len(arr[i ... j] ), max_len) if arr[i ... j] has unique elements
We can optimize the above code by storing the last occurance of each number and finding the distance based on it.
int find_max_length(vector<int> arr) {
map<int, int> last_occ; //store the last occurance of each number
int n = arr.size();
//initialize last occurance as -1
for(int i = 0; i < n; ++i)
last_occ[arr[i] ] = -1;
//store the starting position of the subarray that has unique numbers
int unique_pos = 0, max_length = 1;
for(int i = 0; i < n; ++i) {
if(last_occ[arr[i] ] != -1) // the number can't be a part of the subarray since a copy of it exists. Trackback subarray
unique_pos = last_occ[arr[i] ] + 1;
//all elements from unique_pos to the current index will be unique
max_length = max(max_length, i - unique_pos + 1);
last_occ[arr[i] ] = i;
}
return max_length;
}
You can make the program return the range of the index and print the numbers that are part of the max_length by making a slight modification.
This one runs in O(n)*log(n) since fetching from map is log n
I have an application in which integers are presented in no particular order. The integers presented can be repeat values. I have to maintain them in a sorted fashion. Each time a new entry is presented, it needs to be placed in the appropriate position so that the sorted order is maintained.
std::multiset seems to be one suggested solution with the best time, O(log n), for insertion.
Now, in addition to this sorted multiset, I have to maintain the cumulative sums in another container.
That is, if the sorted entries are:
1, 5, 7, 9 (in indices 0, 1, 2 and 3)
the cumulative sum container would be:
1, 6, 13, 22 (in indices 0, 1, 2 and 3)
I am having trouble figuring out how to use the std::multiset iterator that is returned after each insert(int) operation into the multiset in order to update the cumulative sum container. Note that the cumulative sum will only affect in those entries and indices that have to be moved because of the insert operation.
That is, if to the above list, insert(8) has to be performed, the updated containers would be:
Sorted entries:
1, 5, 7, 8, 9 (in indices 0, 1, 2, 3 and 4)
Cumulative sum:
1, 6, 13, 21, 30 (in indices 0, 1, 2, 3 and 4. Note that only entries in indices 3 and 4 are affected.)
At present, the only way I have been able to implement this is by using two arrays, one for the array of values and one for the cumulative sum. A working code that implements this is presented below:
#include <iostream>
int *arr = new int[100];//Array to maintain sorted list
int *cum_arr = new int[100];//Array to maintain cumulative sum
void insert_into_position(int val, int &last_valid_index_after_insertion) {
//Inserts val into arr such that after insertion
//arr[] has entries in ascending order.
int postoadd = last_valid_index_after_insertion;
//index in array at which to insert val
//initially set to last_valid_index_after_insertion
//Search from end of array until you find the right
//position at which to insert val
for (int ind = last_valid_index_after_insertion - 1; ind >= 0; ind--) {
if (arr[ind] > val) {
postoadd--;
}
else {
break;
}
}
//Move everything from and including postoadd one position to the right.
//Update the cumulative sum array as you go
for (int ind = last_valid_index_after_insertion - 1; ind >= postoadd; ind--) {
arr[ind + 1] = arr[ind];
cum_arr[ind + 1] = cum_arr[ind] + val;
}
//Update entry in index postoadd
arr[postoadd] = val;
if (postoadd > 0)
cum_arr[postoadd] = cum_arr[postoadd - 1] + val;
else
cum_arr[0] = val;
last_valid_index_after_insertion++;
}
int main(void)
{
int length = 0;
insert_into_position(1, length);
insert_into_position(5, length);
insert_into_position(7, length);
insert_into_position(9, length);
printf("\nPrint sorted array\n");
for (int i = 0; i < length; i++)
printf("%d ", arr[i]);
printf("\nPrint Cumulative sum array\n");
for (int i = 0; i < length; i++)
printf("%d ", cum_arr[i]);
insert_into_position(8, length);
printf("\nPrint sorted array\n");
for (int i = 0; i < length; i++)
printf("%d ", arr[i]);
printf("\nPrint Cumulative sum array\n");
for (int i = 0; i < length; i++)
printf("%d ", cum_arr[i]);
getchar();
}
As can be seen from this code, to calculate the cumulative sum, the integer array index, postoadd can be used until the end of the array is reached.
Is there any combination of containers that can perform better/more efficiently than the two integer arrays?
The return type of a std::multiset.insert(int) operation is an iterator that points to the inserted entry. Can this iterator be used to update another container that stores the cumulative sum?
Use an std::multimap, which keeps the keys sorted, and allows for duplicate keys.
Example:
#include <iostream>
#include <map>
int main ()
{
std::multimap<int,int> mymultimap = { {1, 1}, {5, 6}, {7, 13}, {9, 22} };
std::multimap<int,int>::iterator it;
it = mymultimap.insert (std::pair<char,int>(8, 8));
if(mymultimap.size() > 1) {
it->second = std::prev(it)->second + it->second;
++it;
while(it!=mymultimap.end()) {
it->second = std::prev(it)->second + it->first;
++it;
}
}
// showing contents:
std::cout << "mymultimap contains:\n";
for (it=mymultimap.begin(); it!=mymultimap.end(); ++it)
std::cout << (*it).first << " => " << (*it).second << '\n';
return 0;
}
Output:
mymultimap contains:
1 => 1
5 => 6
7 => 13
8 => 21
9 => 30
PS: Another approach would be to use std::multiset where every element would be std::pair, where the first would be the number, and the second the cumulative sum.
I am working on a project which need to find a certain number in a two dimensional array(a matrix) .the visiting order of matrix order is like this (4*4 matrix). Now I stand in the position 0. Equivalently, I want to visit the matrix element in diagonal firstly.
0 2 7 14
3 1 5 12
8 6 4 10
15 13 11 9
Besides, how to break two nest loop in c++ while do not use goto statement.
The following code will traverse a square matrix of any size, with priority on the diagonal
#define SIZE 4
static int test[SIZE][SIZE] =
{
{ 0, 2, 7, 14 },
{ 3, 1, 5, 12 },
{ 8, 6, 4, 10 },
{ 15, 13, 11, 9 }
};
int main( void )
{
int diagonal, delta;
for ( diagonal = 0; diagonal < SIZE; diagonal++ )
{
cout << test[diagonal][diagonal] << endl;
for ( delta = 1; delta <= diagonal; delta++ )
{
cout << test[diagonal-delta][diagonal] << endl;
cout << test[diagonal][diagonal-delta] << endl;
}
}
}
Here's one way to break out of a nested loop without a goto
done = false;
for ( i = 0; i < 10; i++ )
{
for ( j = 0; j < 10; j++ )
{
if ( some_condition_is_met )
{
done = true;
break;
}
}
if ( done )
break;
}
Use another array with array indices (since the size of your array is probably constant anyway), for instance, if you stored first array in one dimensional c++ array, then
int actual_arr[16];
int indices[16] = {0, 5, 1, 4, 10, 6, 9, 2, 8, 15, 11, 14, 7, 13, 3, 12 };
So then you can write a loop:
for (int i = 0; i < 16; ++i)
{
actual_arr[indices[i]]++;
}
So every field in indices is an index of actual_arr which will be visited at this point.
You can do it with two dimensional representation, too, if it required. Just replace int indices[16] with std::pair<int, int> indices[16] and you're good to go.
Especially when you have a fixed-size array and visit it many times, this is good solution, since it doesn't involve any computation in the loop.
Btw. As a sidenote, mathematically speaking, the indices array would be called a permutation and can be an operation in permutations group.
To move to the element on the right, you increment a row.
To move to the element on the left, you decrement a row.
To move to the element below, you increment a column.
To move to the element above, you decrement the column.
Now to move diagonally, observe how the row and columns change and apply a combination of the above.