divide array when encountering zeroes - c++

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]);
}
}

Related

Find the index of the closest number that is greater than the current number

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

Error in quicksort using Hoare partitioning with iterators, error with some specific small arrays

I am trying to make a C++ Quicksort algorithm using Hoare's partitioning. However I keep running into arrays that aren't sorted correctly, while most arrays sort OK. An example of such a troubling array is {1, 3, 0, 4, 3} which results in {0, 3, 1, 3, 4}.
The code contains the Quicksort code in the quicksort class, and fuzzy testing in the main function.
#include <iostream>
#include <random>
#include <vector>
class quicksort
{
public:
template <class random_access_iterator>
void operator()(random_access_iterator begin, random_access_iterator end)
{
quicksort_recursive_step(begin, end);
}
private:
template <class random_access_iterator>
void quicksort_recursive_step(random_access_iterator begin, random_access_iterator end)
{
if ((end - begin) <= 1)
{
return;
}
auto left = begin;
auto right = (end - 1);
const auto pivot = *(left + ((right - left) / 2));
while (left < right)
{
while (*left < pivot)
{
left++;
}
while (*right > pivot)
{
right--;
}
if (left < right)
{
std::iter_swap(left, right);
left++;
right--;
}
}
auto separator = (right + 1);
quicksort_recursive_step(begin, separator);
quicksort_recursive_step(separator, end);
}
};
int main()
{
std::random_device rd;
std::mt19937 eng{rd()};
std::uniform_int_distribution<int> size_dist{0, static_cast<int>(5)};
quicksort sorter;
std::vector<int> test = {0, 0, 4, 0, 1};
sorter(test.begin(), test.end());
bool has_error = false;
while (!has_error)
{
std::vector<int> test_array(size_dist(rd));
if (!test_array.empty())
{
std::uniform_int_distribution<int> values_dist{0, static_cast<int>(test_array.size() - 1)};
std::generate(test_array.begin(), test_array.end(), [&values_dist, &rd]() { return values_dist(rd); });
}
std::vector<int> original_test_array(test_array);
std::cout << "Sorting array of size " << test_array.size() << " ... ";
for (const auto& t : original_test_array)
{
std::cout << t << ", ";
}
std::cout << std::endl;
sorter(test_array.begin(), test_array.end());
bool is_permutation = std::is_permutation(test_array.begin(), test_array.end(), original_test_array.begin());
bool is_sorted = std::is_sorted(test_array.begin(), test_array.end());
if (is_permutation && is_sorted)
{
std::cout << "OK" << std::endl;
}
else
{
has_error = true;
std::cout << "ERROR!" << std::endl;
std::cout << "Array was: ";
for (const auto& t : original_test_array)
{
std::cout << t << ", ";
}
std::cout << std::endl;
std::cout << "Result is: ";
for (const auto& t : test_array)
{
std::cout << t << ", ";
}
std::cout << std::endl;
}
}
return 0;
}
Possible output (error at the bottom):
Sorting array of size 0 ...
OK
Sorting array of size 2 ... 0, 1,
OK
Sorting array of size 5 ... 1, 2, 2, 0, 0,
OK
Sorting array of size 5 ... 4, 1, 3, 0, 0,
OK
Sorting array of size 5 ... 2, 2, 2, 4, 1,
OK
Sorting array of size 5 ... 1, 3, 3, 3, 1,
OK
Sorting array of size 4 ... 1, 0, 1, 3,
OK
Sorting array of size 1 ... 0,
OK
Sorting array of size 1 ... 0,
OK
Sorting array of size 3 ... 0, 2, 0,
OK
Sorting array of size 4 ... 0, 2, 1, 1,
OK
Sorting array of size 3 ... 0, 1, 1,
OK
Sorting array of size 4 ... 3, 1, 3, 1,
OK
Sorting array of size 4 ... 3, 2, 3, 3,
OK
Sorting array of size 2 ... 0, 0,
OK
Sorting array of size 4 ... 3, 3, 3, 1,
OK
Sorting array of size 3 ... 0, 2, 0,
OK
Sorting array of size 3 ... 0, 0, 2,
OK
Sorting array of size 1 ... 0,
OK
Sorting array of size 5 ... 2, 3, 4, 1, 3,
OK
Sorting array of size 3 ... 1, 1, 0,
OK
Sorting array of size 3 ... 1, 0, 2,
OK
Sorting array of size 3 ... 1, 0, 2,
OK
Sorting array of size 1 ... 0,
OK
Sorting array of size 4 ... 0, 3, 3, 3,
OK
Sorting array of size 0 ...
OK
Sorting array of size 5 ... 4, 1, 3, 1, 0,
OK
Sorting array of size 3 ... 2, 2, 1,
OK
Sorting array of size 0 ...
OK
Sorting array of size 2 ... 1, 1,
OK
Sorting array of size 0 ...
OK
Sorting array of size 2 ... 0, 1,
OK
Sorting array of size 2 ... 0, 1,
OK
Sorting array of size 2 ... 0, 0,
OK
Sorting array of size 5 ... 3, 0, 0, 3, 3,
OK
Sorting array of size 3 ... 0, 1, 2,
OK
Sorting array of size 2 ... 1, 0,
OK
Sorting array of size 3 ... 0, 2, 1,
OK
Sorting array of size 3 ... 1, 1, 0,
OK
Sorting array of size 0 ...
OK
Sorting array of size 4 ... 0, 3, 0, 2,
OK
Sorting array of size 0 ...
OK
Sorting array of size 2 ... 0, 0,
OK
Sorting array of size 0 ...
OK
Sorting array of size 1 ... 0,
OK
Sorting array of size 0 ...
OK
Sorting array of size 5 ... 4, 0, 1, 1, 3,
OK
Sorting array of size 0 ...
OK
Sorting array of size 5 ... 1, 3, 0, 4, 3,
ERROR!
Array was: 1, 3, 0, 4, 3,
Result is: 0, 3, 1, 3, 4,
How can I solve this error? Everytime I try to solve it, I break something else. I also can't find good examples combining Hoare's partitioning and iterators as Lomuto's partitioning is mostly used in educational literature. I also want to avoid using std::partition etc.
A typical post-increment and post-decrement version of Hoare partition scheme similar to what is used in the question, has to compensate for the possibility that the right index may be decremented below the beginning of the array.
As an alternative, this example code uses a pre-increment and pre-decrement version of Hoare partition scheme, except that it skips decrementing then incrementing the left (b in the code below) iterator, using a goto to jump into the middle of the two partitioning loops. I could change the code to avoid goto, but an optimizing compiler is probably going to compile as if the goto was there as in my source code. For an even number of elements, it uses the left middle element for pivot (p = *(b+(e-b-1)/2)).
#include <iostream>
#include <iterator>
#include <vector>
void QuickSort(std::vector<int>::iterator b, std::vector<int>::iterator e)
{
std::vector<int>::iterator i = b;
std::vector<int>::iterator j = e;
int p = *(b+(e-b-1)/2);
if((e-b) < 2)
return;
if(*i >= p)
goto loop0;
while(1){
while (*(++i) < p);
loop0:
while (*(--j) > p);
if (i >= j)
break;
std::swap(*i, *j);
}
j++;
QuickSort(b, j);
QuickSort(j, e);
}
int rnd32() /* random number */
{
static unsigned int r = 0u;
r = r * 1103515245u + 12345u;
return (int)r;
}
#define COUNT (1024)
int main(int argc, char**argv)
{
size_t i;
std::vector <int> a(COUNT);
for(i = 0; i < COUNT; i++)
a[i] = rnd32();
QuickSort(a.begin(), a.end());
for(i = 1; i < COUNT; i++){
if(a[i-1] > a[i])
break;
}
if(i == COUNT)
printf("passed\n");
else
printf("failed\n");
return(0);
}
I've found an answer to my own question. In my code, when the left and right iterators are exchanged and then cross each other, I end my while loop. Thus, it is swap(lef,right), left++, right-- and stop. However, the algorithm should do the while(*left < pivot){left++;} and while (*right > pivot){right--;} loops once more to set the separator at the right spot. This wasn't immediately obvious to me looking at CLRS's pseudocode, but there the while loops are also executed once more before the return.
HOARE-PARTITION(A, p, r)
x = A[p]
i = p - 1
j = r + 1
while TRUE
repeat
j = j - 1
until A[j] <= x
repeat
i = i + 1
until A[i] >= x
if i < j
exchange A[i] with A[j]
else
return j
The correct code is thus:
template <class T>
class quicksort
{
public:
template <class random_access_iterator>
void operator()(random_access_iterator begin, random_access_iterator end)
{
quicksort_recursive_step(begin, end);
}
private:
template <class random_access_iterator>
void quicksort_recursive_step(random_access_iterator begin, random_access_iterator end)
{
assert(begin <= end);
if ((end - begin) <= 1)
{
return;
}
auto left = begin;
auto right = (end - 1);
auto middle = (left + ((right - left) / 2));
const auto pivot = *middle;
while (*left < pivot)
{
left++;
}
while (*right > pivot)
{
right--;
}
while (left < right)
{
std::iter_swap(left, right);
left++;
while (*left < pivot)
{
left++;
}
right--;
while (*right > pivot)
{
right--;
}
}
auto bound = (right + 1);
quicksort_recursive_step(begin, bound);
quicksort_recursive_step(bound, end);
}
};

Vector erase function not working properly

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++).

C++, not in order combination of array elements

I am trying to get all combinations of an array with C++ such that
double* list1 = new double[size];
Items in that array is {1,2,3,4,5}
I need to add all possible combinations into a stack, such as:
1+2, 1+2+3, 1+2+3+4,1+2+3+4+5, 1+3, 1+3+4, 1+3+4+5, 1+4, 1+4+5, 1+5...
the problem I am running into is I am doing this through 2 for loops and a while loop
for(int i = 0; i < size - 1; i++)
{
for(int j = i; j < size - 1; j++)
{
double temp = list1[i] + list1[j + 1];
list1combos.push(temp);
int k = j + 2;
while (k <= size - 1)
{
temp = temp + list1[k];
list1combos.push(temp);
k++;
}
}
}
I can get the ones I listed above but I have no clue how to code in combinations such as 1+3+5, or 1+2+5
Please advise on how to get those combinations, thanks stackoverflow!
Since the order does not matter, I would suggest having an array of the same size as your x and perform a binary increment on it, i.e. you start with the array inited to only 0s and count until you have only 1s. For every addition of a 1 you would pick a permutation from your x array.
First iteration:
0 0 0 0 0 -> empty
Second iteration:
0 0 0 0 1 -> you pick 5
3rd iteration:
0 0 0 1 0 -> you pick 4
4th iteration:
0 0 0 1 1 -> you pick 4 and 5
And so on until you reach:
1 1 1 1 1 -> you pick 1, 2, 3, 4 and 5
You can approach this problem by printing all subsets of a set {1,2,3,4,5}. There are 2^5 of them - or 2^5-1 since set {0) is meaningless for you.
This code can help you.
#include<iostream>
#include<list>
#include <iterator>
void print( std::list<int> l){
std::copy( l.begin(), l.end(), std::ostream_iterator<int>( std::cout, " "));
std::cout << std::endl;
}
void subset( int arr[], int size, int left, int index, std::list<int> &l){
if( left == 0){
print(l);
return;
}
for( int i = index; i < size; i++){
l.push_back( arr[i]);
subset( arr, size, left - 1, i + 1, l);
l.pop_back();
}
}
int main() {
int array[5] = { 1, 2, 3, 4, 5} ;
std::list<int> lt;
subset( array, 5, 1, 0, lt);
subset( array, 5, 2, 0, lt);
subset( array, 5, 3, 0, lt);
subset( array, 5, 4, 0, lt);
subset( array, 5, 5, 0, lt);
return 0;
}
http://ideone.com/J78J7q
more algorithms for subsets: generate all subsets of size k from a set
Others have already answered your question. I'll point out one important thing:
double* list1=new double(size);
This does not allocate an array of double with size elements.
Instead it allocates a single double and sets the value of it to size. Attempting to access it as an array results in undefined behavior and could lead to a crash.
You want to do this instead:
double* list1=new double[size];
Notice the use of square brackets. Also remember that you must call delete[] list1; instead of simply delete list1; when you want to release the allocated memory.
Following may help: http://ideone.com/SpCejs
template <std::size_t N>
bool increase(std::bitset<N>& bs)
{
for (std::size_t i = 0; i != bs.size(); ++i) {
if (bs.flip(i).test(i) == true) {
return true;
}
}
return false;
}
template <typename T, std::size_t N>
void print_combinaison(const std::array<T, N>& a)
{
std::bitset<N> bs;
do {
for (std::size_t i = 0; i != N; ++i) {
if (bs.test(i)) {
std::cout << a[i] << " ";
}
}
std::cout << std::endl;
} while (increase(bs));
}

Permutations of multiple ranges of numbers

I need to generate permutations from multiple ranges of numbers in array.
using namespace std;
int generatePermutations(vector<int> &myVector, vector<vector<int> > &swappable) {
int i = 0, s = 0;
for (s = 0; s < swappable.size(); s++) {
do {
for (i = 0; i < myVector.size(); i++) {
printf("%i ", myVector[i]);
}
printf("\n");
swappable.pop_back();
generatePermutations(myVector, swappable);
} while (next_permutation(myVector.begin()+swappable[s][0],
myVector.begin()+swappable[s][1]));
}
}
int main() {
vector<int> myArray;
myArray.resize(6);
myArray[0] = 0;
myArray[1] = 1;
myArray[2] = 2;
myArray[3] = 3;
myArray[4] = 4;
myArray[5] = 5;
// Swappable positions (0 - first, 1 - last)
vector<vector<int> > swappable;
swappable.resize(2);
swappable[0].resize(2);
swappable[0][0] = 1; swappable[0][1] = 3;
swappable[1].resize(2);
swappable[1][0] = 4; swappable[1][1] = 6;
generatePermutations(myArray, swappable);
return 0;
}
The example above should generate something like this:
0 1 2 3 4 5
0 2 1 3 4 5
0 1 2 3 5 4
0 2 1 3 5 4
But it generates this:
0 1 2 3 4 5
0 1 2 3 4 5
I take it swappable is a set of ranges which may be swapped? So [[1, 3], [4, 6]] means anything in [1, 3) (indexes 1 and 2) can be swapped around in that range, and similarly for [4, 6)? Is it also true that the ranges will never overlap?
How does this look:
typedef vector<vector<int> >::const_iterator SwappableIter;
void generatePermutations(vector<int> &data,
SwappableIter begin, SwappableIter end)
{
if (begin == end) {
print(data);
}
else {
vector<int>::iterator start = data.begin() + (*begin)[0],
stop = data.begin() + (*begin)[1];
sort(start, stop);
do {
generatePermutations(data, begin + 1, end);
} while (next_permutation(start, stop));
}
}
You have created a seemingly correct iterative solution for the problem, but in each iteration, you remove an element from the swappable vector and make a recursive call.
As both myVector and swappable are passed by non-const reference, these recursive calls destroy the contents of the swappable vector before you are actually generating permutations.
Just remove the lines
swappable.pop_back();
generatePermutations(myVector, swappable);
and the code should start to work.
Here is a slightly modified version of your generation algorithm (which is broken).
int generatePermutations(vector<int> &myVector, vector<vector<int> >& swappable) {
do
{
do
{
print(myVector);
// generate permutations of the second segment
} while(next_permutation(myVector.begin() + swappable[1][0], myVector.begin() + swappable[1][1]));
// re-sort the second segment
sort(myVector.begin() + swappable[1][0], myVector.begin() + swappable[1][1]);
// calculate permutation of first segment
} while(next_permutation(myVector.begin() + swappable[0][0], myVector.begin() + swappable[0][1]));
}
EDIT: fixed now to generate the combinations, but only works for two ranges, Fred's solution above is more scalable..