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++).
Related
I want to divide an array into multiple(or one, maybe zero) arrays like the example below:
array = [0 1 1 2 3 4 0 3 0 3 3 0 5 6 7] -> array1 = [1 1 2 3 4] array2 = [3] array3 = [3 3] array4 = [5 6 7]
my naive approach to do this was first removing zeros from left and right then proceed to use two iterators to find the begin and end of every subarray and by using a vector constructor build the subarrays and pass them to a function. But I know for a fact that my approach is naive and inefficient so I would appreciate some suggestions on how to approach this more efficiently.
Thanks a lot guys!
also this is my code for my approach(a is the mother array):
for(int i = 0; i < a.size(); i++){
if(a[i] != 0)
break;
a.erase(a.begin() + i);
}
for(int i = a.size() - 1; i >= 0; i--){
if(a[i] != 0)
break;
a.erase(a.begin() + i);
}
auto begin = a.begin();
auto end = a.begin() + 1;
for (int i = 0; i < a.size(); i++){
if(a[i] == 0){
vector<int> temp(begin, end);
color(temp);
begin = end + 1;
end = begin + 1;
}
else end++;
}
One of the approach to solve this problem is to create an auxiliary array which contains index of all zero elements (in implementation const_iterator is used rather than index). This problem can be solved without creating such auxiliary array but the advantage of it is, you can find number of sub arrays are going to be created in advance. Approach is as follows,
Iterate input array and put index of zero elements in auxiliary array,
InputArray = [0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7]
Array contains zero elements index = [0, 6, 8, 11]
As you an see above there are four divider (zero index entries) which divides input array into 3 sub arrays and last zero is at index 11 and that is not last element of input array that's why one more sub array will be create so total sub arrays = 4 and for other details please see code,
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using std::cout;
std::vector<std::vector<int>> splitAtZero(const std::vector<int>& arr){
std::vector<std::vector<int>::const_iterator> divider;
divider.reserve(std::max<std::size_t>(arr.size() / 4, 2));
for(std::vector<int>::const_iterator it = arr.cbegin(), endIt = arr.cend(); endIt != it; ++it){
if(0 == *it){
divider.push_back(it);
}
}
if(divider.empty()){
return {arr};
}
if(arr.size() == divider.size()){
return {};
}
std::size_t numOfSubArray = (divider.size() - 1) + (arr.cbegin() != divider.front() ? 1 : 0) +
(arr.cend() != divider.back() ? 1 : 0);
std::vector<std::vector<int>> subArr;
subArr.reserve(numOfSubArray);
std::vector<int>::const_iterator it = arr.cbegin();
for(std::vector<int>::const_iterator divderIt : divider){
if(divderIt - it > 0){
subArr.emplace_back(it, divderIt);
}
it = divderIt + 1;
}
if(arr.cend() != it){
subArr.emplace_back(it, arr.cend());
}
return subArr;
}
int main(){
std::string comma("");
for(std::vector<int>& subArr : splitAtZero({0, 1, 1, 2, 3, 4, 0, 3, 0, 3, 3, 0, 5, 6, 7})){
cout<< comma<< "[";
std::copy(subArr.cbegin(), subArr.cbegin() + (subArr.size() - 1), std::ostream_iterator<int>(cout, ", "));
cout<< subArr.back()<< "]";
comma = ", ";
}
cout<< '\n';
}
Output:
[1, 1, 2, 3, 4], [3], [3, 3], [5, 6, 7]
In the following approach that I propose you can retrieve the sub-arrays with a single sequential scan, with no need to exclude zeros at the beginning or at the end:
std::vector<std::vector<int>> arrays;
std::vector<int> currentArray;
for (int i = 0; i < a.size; i++)
{
if (a[i] == 0 || i == a.size - 1)
{
if (currentArray.size() != 0)
{
arrays.push_back(currentArray);
currentArray.clear();
}
}
else
{
currentArray.push_back(a[i]);
}
}
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
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 array _data and I'm trying to add a number to the array at a certain position. Every number after the index of position should be shifted one index to the right. I'm having trouble conceptually in doing this.
This is what I have as of now:
void list::add(int num, size_t position)
{
for (int i = 0; i < _size; i++)
{
_data[position + i + 1] = _data[position + i];
}
_data[position] = num;
}
For example, say num = 9 and position = 3 and the given values in the array are {1, 3, 4, 5, 6, 7}. I would want it to be {1, 3, 4, 9, 5, 6, 7}. What ends up happening, though, is that it grabs the number that has already been replaced and puts that back into the array. (ex 1, 3, 4, 9, 5, 5, 5}.
It's depending on type of your variable _data:
If it's an array:
for (std::size_t i = _size - 1; i != position; --i)
{
_data[i] = _data[i - 1];
}
_data[position] = num;
If it's a vector:
_data.insert(_data.begin() + position, num);
Anyway, it's recommended to use a std::vector instead of raw array, and it's NOT recommended to use underscore at the beginning of variable name
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).