Array and simple queries using vector - c++

I am solving "https://www.hackerrank.com/challenges/array-and-simple-queries/copy-from/145435292" problem. while solving this problem I got stuck in one logical error.
I have tried to solve this problem in this way.
int main()
{
long long int i,j,k,l,x,n,m,a[3],c;
vector<long long int> g1;
cin>>n>>m;
for (i=0;i<n;i++)
{
cin>>x;
g1.push_back(x);
}
for(i=0;i<m;i++)
{
for(j=0;j<3;j++)
{
cin>>a[j];
}
if(a[0]==1)
{
c=0;
g1.insert(g1.begin(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
c=a[2]-a[1];
c++;
g1.erase(g1.begin() + a[1]+(c-1), g1.begin() + a[2]+c);
}
else
{
g1.insert(g1.end(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
g1.erase(g1.begin() + a[1]-1, g1.begin() + a[2]);
}
cout<<"\n";
for (auto y = g1.begin(); y != g1.end(); ++y)
cout << *y << " ";
}
// c=g1[0]-g1[n-1];
// if(c<0)
// {
// c=c*-1;
// }
// cout<<c<<"\n";
// cout<<"\n";
// for (auto y = g1.begin(); y != g1.end(); ++y)
// cout << *y << " ";
return 0;
}
The input format is-
n,m: where n is the total number and m is the total number of queries.
The next line is n numbers.
The next lines contain m queries.
Type 1 queries are represented as 1 i j : Modify the given array by removing elements from i to j and adding them to the front.
Type 2 queries are represented as 2 i j : Modify the given array by removing elements from i to j and adding them to the back
For Input:
7 2
1 2 3 4 5 6 7
1 3 6
1 3 6
My output is:
3 4 5 6 1 2 7
5 6 3 4 3 4 7
But my output should be:
3 4 5 6 1 2 7
5 6 1 2 3 4 7
Please help me out.

Regarding this line:
g1.insert(g1.begin(),g1.begin()+(a[1]-1),g1.begin()+a[2]);
// ^^ ^^ ^^ It's the same
I can't find a specific quote from the Standard, but in 22.3.11.5 [Containers.sequences.vector.modifiers (insert, emplace_back, emplace, push_back)] it's specified:
Causes reallocation if the new size is greater than the old capacity.
Reallocation invalidates all the references, pointers, and iterators referring to the elements in the sequence, as well as the past-the-end iterator. If no reallocation happens, then references, pointers, and iterators before the insertion point remain valid but those at or after the insertion point, including the past-the-end iterator, are invalidated.
The cppreference.com page about std::vector::insert has the following clarifications (emphasis mine)
template< class InputIt >
iterator insert( const_iterator pos, InputIt first, InputIt last );
Inserts elements at the specified location in the container.
...
The behavior is undefined if first and last are iterators into *this.
...
first, last - the range of elements to insert, can't be iterators into container for which insert is called.
It's also worth noting that inserting at the beginnning and then erasing the elements in the middle of a vector may be a rather inefficient method.
The expected results could be easily achieved using another algorithm, std::rotate:
if (a[0] == 1)
{
std::rotate(
g1.begin(), // First element of the range to be left rotated.
g1.begin() + (a[1] - 1), // Element which will become the first
g1.begin() + a[2] // Last element of the range to be modified.
);
}
else
{
std::rotate(
g1.begin() + (a[1] - 1),
g1.begin() + a[2],
g1.end()
);
}

Related

How do I implement adding and removing elements of an array?

How to implement output of all elements of an array?
A task:
N guys are arranged in a circle. Starting the countdown from the 1st, each k is removed, closing the circle after each removal. Who is left? Display the order of removal from the circle.
#include <iostream>
#include <conio.h>
int counter(int n, int k) {
int function = n >= 1 ? (counter (n - 1, k) + k - 1) % n + 1: 1;
return function;
};
int main(void) {
setlocale(LC_ALL, "Russian");
int peoples;
int quantity;
std::cin >> peoples;
std::cin >> quantity;
std::cout << "Remaining : " << counter(peoples, quantity);
return 0;
}
My code outputs the remaining one item.
How to implement replenishment of an array with elements.
for (i = 0, i < 5, i++) {
cout << ?;
}
output:
[1, 2, 3, 4, 5]
something like this)
and how can you implement the removal of array elements
for example deleting every third array element in a circle
Output:
1 2 3 4 5
1 2 4 5
2 4 5
2 4
4
How do I implement adding and removing elements of an array?
There is no way to add or remove elements from an array. An array has a constant number of elements that doesn't change through the life of the array.
If you need to represent a dynamic sequence of objects that can grow or shrink, you need a more complex data structure. std::vector is an implementation of such data structure. You can add using std::vector::push_back and remove using std::vector::erase.

C++ push_back in vectors

I built a recursive function that reads a vector as input and returns a new vector in which every two consecutive elements are switched. For example input: 1 2 3 4 5 6 and output: 2 1 4 3 6 5. The thing I don't get is that when I write the function this way:
vector<int> reverse(vector<int> v) {
if (v.size() < 2)
return v;
else
{
int pos1 = v.at(0); //= 1
int pos2 = v.at(1); //= 2
v.erase(v.begin()); //v = 2 3 4 5 6
v.erase(v.begin()); //v = 3 4 5 6
vector<int> rev = reverse(v);
rev.push_back(pos2); //rev = 2
rev.push_back(pos1); //rev = 2 1
return rev;
}
}
i get 6 5 4 3 2 1. I know the vector::push_back() adds the elements at the end of the vector, so why not 2 1 4 3 6 5? When I wrote it this way it gave me the good answer though (2 1 4 3 6 5) but idk why:
vector<int> reverse(vector<int> v) {
if (v.size() < 2)
return v;
else
{
int pos1 = v.at(v.size() - 2); //= 5
int pos2 = v.at(v.size() - 1); //= 6
v.pop_back(); //v = 1 2 3 4 5
v.pop_back(); //v = 1 2 3 4
vector<int> rev = reverse(v); //call the recursive function
rev.push_back(pos2); //rev = 5
rev.push_back(pos1); //rev = 6 5
return rev;
}
}
The main() function is this:
int main() {
vector<int> w;
int zahl;
cout << "Please give the vector or any letter to end the input: "<< endl;
while (cin >> zahl)
{
w.push_back(zahl);
}
for (int elem : reverse(w))
{
cout << elem << ", ";
}
return 0;
}
It's an easy fix.
The problem with your code is that the recursive step does not correctly translate a correctly constructed sub-result to a slightly larger one.
You would want to do:
// Correctly create the head of the result.
vector<int> rev = {pos2, pos1};
// Now you want to handle the tail, and assuming the output of reverse
// is correct for smaller lists, this would be achieved by appending
// the rest.
const auto sub = reverse(v);
rev.insert(rev.end(), sub.begin(), sub.end());
This ensures that if your list starts with 1 2, it would turn into a list with 2 1, followed by a correctly processed tail.
Your second code worked because you were processing the sequence in reverse, so your recursive step was in fact correct.
The result you obtain is incorrect because in the last call to your function you return an empty vector, and then you push at the back of this vector your last pair of numbers inverted, so 6,5, so you do proceding back in the call stack.
Let's have a look to what you have at every call (first call, second call, ecc.):
v=[1,2,3,4,5,6] ->recursive call
v=[3,4,5,6] ->recursive call
v=[5,6] ->recursive call
v=[] ->return empty vector
rev=[], push back the first two elements of v in reverse order, so rev=[6,5] ->return rev
rev=[6,5], push back the first two elements of v in reverse order, so rev=[6,5,4,3] ->return rev
rev=[6,5,4,3], push back the first two elements of v in reverse order, so rev=[6,5,4,3,2,1]
For this reason, you need first to have a vector with the first two numbers reversed and then attach the processed tail, as suggested above.
Please note that you are constructing copies of the vector every time you call the function. You can create a reversed copy without modifying the copy of the argument given as argument. I would use iterators instead, so that every time your function "sees" a smaller portion of the original vector, without touching it. Here an implementation:
vector<int> reverse(vector<int>::const_iterator begin, vector<int>::const_iterator end) {
if (begin==end-1) //the vector has an odd number of elements, let's append the last element
return vector<int>(1, *(end-1));
else if(begin>=end) //the vector has en even number of elements
return vector<int>();
else
{
vector<int> pairWiseReversed({*(begin+1), *begin});
vector<int> tail=reverse(begin+2, end);
pairWiseReversed.insert(pairWiseReversed.end(), tail.begin(), tail.end());
return pairWiseReversed;
}
}
vector<int> buildReversed(const vector<int>& input){
return reverse(input.begin(), input.end());
}
And here a main:
int main() {
vector<int> v{1,2,3,4,5,6};
cout<<"Input vector"<<endl;
for(auto n:v)
cout<<n<<" ";
cout<<endl;
vector<int> res=buildReversed(v);
cout<<"Output vector"<<endl;
for(auto n:res)
cout<<n<<" ";
cout<<endl;
return 0;
}

What is wrong with my comparison function?

I am trying to sort vector of pair of pair and int as below. But not getting expected output. In the actual output, the last element is supposed to come before the second element.Can someone please explain what i am missing?
int main()
{
using elem_type = std::pair<std::pair<int,int>,int>;
std::vector<elem_type> vec;
vec.push_back(std::make_pair(std::make_pair(3, 1), 2));
vec.push_back(std::make_pair(std::make_pair(6, 5), 4));
vec.push_back(std::make_pair(std::make_pair(6, 4), 7));
vec.push_back(std::make_pair(std::make_pair(5, 4), 6));
auto cmp = [](const elem_type & left, const elem_type & right){
return ((left.first.first< right.first.first)
&&
(left.first.second < right.first.second));
};
std::sort(vec.begin(), vec.end(), cmp);
//print sorted vector
for(size_t i = 0; i < vec.size(); ++i){
std::cout << vec[i].first.first << " " << vec[i].first.second << " " << vec[i].second << "\n";
}
}
Expected output
3 1 2
5 4 6
6 4 7
6 5 4
Actual output
3 1 2
6 5 4
6 4 7
5 4 6
You haven't explained how you want to sort your triples, so all I can say is that your expectations are wrong.
Your comparison function considers your last three elements to be equal.
A triple (x0,x1,x2) is considered less than another triple (y0,y1,y2) if x0 < y0 and x1 < y1. For example, when comparing (6,4,7) and (6,5,4), neither triple is considered less than the other because the first number in each triple is the same (6 < 6 is false). Similarly, (5,4,6) is considered equal to (6,4,7) because neither is less than the other (4 < 4 is false).
The only thing you might reasonably expect is that (5,4,6) < (6,5,4), but your comparison function also says both of those are equal to (6,4,7). In other words, the function claims there are values a, b, c where a = b and b = c but a < c. This makes no sense, so your comparison function is broken.
If all you want is a lexicographical ordering, you don't need to do anything special:
std::sort(vec.begin(), vec.end());
std::pair sorts by its first component first; if those are equal, it compares the second components. That seems to be exactly the behavior you expect.

Quick sort apparently taking O(n^2) when left or right-most element is selected as pivot

So um, I'm trying to learn Quick sort and have implemented the below code for it. However, it seems to run in O(n^2) instead of O(nlogn) when I take leftmost or rightmost element as pivot...
I am unable to figure out what's wrong with my code but I'm most likely making some very basic stupid mistake; can anyone please help and explain me where I'm going wrong?
Thanks a lot in advance! Here's my code:
#include <iostream>
#include <vector>
typedef int64_t int64;
int64 numberOfComparisons;
using namespace std;
int partitionAroundPivot(vector<int64>& a, int l, int r) {
numberOfComparisons = numberOfComparisons + (r - l) - 1 ;
int ppos;
ppos = l;
int64 p = a[ppos]; //Gives pivot
if(ppos != l)
swap(a[ppos], a[l]);
int i = l + 1, j;
for(j = l + 1; j <= r; j++){
if(a[j] < p)
{
swap(a[j], a[i]); //Swap with leftmost element bigger than pivot, i.e. v[i]
i++;
}
}
//Now pivot needs to go to its proper place
swap(a[l], a[i - 1]);
return ppos; //WRONG, will return l always, need to return i-1
}
void quickSort(vector<int64>& a, int l, int r) //Inplace so no return stuff
{
if( r - l <= 0)
return ;
int pivotPosition = partitionAroundPivot(a, l, r);
cout << "Called Qsort with positions l " <<l << " r " << r << " Pivot pos " << pivotPosition << endl;
for (int i = l; i < r; i++)
cout << a[i] <<" " ;
cout << endl;
quickSort(a, l , pivotPosition - 1 );
quickSort(a, pivotPosition + 1 , r );
}
int main() {
vector<int64> x = {3, 2, 1, 8, 6, 7, 6, 4};
quickSort(x, 0, x.size() -1);
return 0;
}
Part of the output is below:
Called Qsort with positions l 0 r 9 Pivot pos 0
1 2 3 4 6 10 9 5 7
Pivot: 2
Called Qsort with positions l 1 r 9 Pivot pos 1
2 3 4 6 10 9 5 7
Pivot: 3
EDIT: Part of the reason why I asked this was because I am supposed to calculate the number of comparisons done in total theoritically, and I simply used a (size of subarray at each partition call - 1) as the value (the actual ones will be different, I know since only part of the comparisons actually happen). This is seen in the numberOfComparisons variable above.
Now the thing is, for sorting 100 numbers, all from 1-100, none unique and mostly random, it shows the number of computations as 4851, that's close to 100*99/2 aka n*(n-1)/2 where n = 100. This led me to believe that it's doing O(n^2) time. Is this correct...?
EDIT2: I was being so stupid after all. The partitionAroundPivot was always returning l aka the first position of the subarray, resulting in one of the splits being a zero length subarray and another, the rest of the array. I need to pass back the position where a[l] actually goes and not l; i-1 in this case. Lesson learnt, I guess.
Thank you very much for the help, guys!
Qucksort is O(n log n) but in average, it is O(n^2) in worst case and O(nlogn) in best-case. The most important aspect to get a good efficiency is to select a good pivot.
In your program, you have selected one of the worst pivots because if you select the first or the last one, in case of ordered (or reverse-ordered) vectors, your algorithm is in the worst case efficiency.
This is why you have to think about your algorithm to select the pivot. One of the most used methods is to select the median of three, for example, the first, middle and last elements. Thus, you algorithm applied to a ordered vector is O(nlogn).
UPDATE: The complexity is determined by a profile of growth, not a specific case. In fact, you could have a very high value for a particular size of the problem, while the profile increases more smoothly when the problem size becomes very large. Before checking anything, run the program with several individual values reaching a very large n.

C++ Printing Contents of array backwards One incorrect digit

As part of a program I'm trying to print the contents of an array in reverse order. It is working fine except for one value and I can't figure out why.
I haven't gotten onto functions yet so I haven't used them in my code here is the snippet
case 7:
for (int i = 11; i != -1; i--)// The variable i is initialised to 11. While i is not equal to -1 decrement i by 1.
{
infile >> list[i];//Read in values for array from data.dat
cout << list[i] << " ";// Outputting the array in reverse order.
outfile << "The array in reverse order is: " << list[i] << " " << endl;// Outputting the array in reverse order to file.
}
cout << endl;
break;
The array is filled with the following numbers
8 16 12 6 16 4 8 10 2 16 12 6
The expected output is:
6 12 16 2 10 8 4 16 6 12 16 8
The output I'm getting is:
6 12 16 2 10 8 4 16 6 12 6 8
Any help appreciated
The right way to reverse an iterator is to shift it down by one.
Forward:
T a[N];
for (std::size_t i = 0; i != N; ++i)
{
consume(a[i]);
}
Backward:
T a[N];
for (std::size_t i = 0; i != N; ++i)
{
std::size_t const ri = N - i - 1;
// ^^^
consume(a[ri]);
}
You can write a loop where you actually decrement the loop variable directly, but it's awkward since you either have to use signed integers or otherwise do an additional - 1 when using the index, and it's altogether unnatural, hard to read and easy to get wrong. I'd much rather recommend always using the forward-moving loop as shown here and compute the reverse iterator separately.
Incidentally, this logic is already encapsulated in the iterator wrapper std::reverse_iterator, which is build from a normal, bidirectional moving iterator but decrements by one when being dereferenced. You can either reverse a sequence yourself by using make_reverse_iterator, or by using the free rbegin/rend functions:
#include <iterator>
T a[N];
for (auto rit = std::crbegin(a); rit != std::crend(a); ++rit)
{
consume(*rit);
}