Related
I've searched the Internet and known how to delete an element (with std::erase) and finding duplicates of an element to then delete it (vec.erase(std::unique(vec.begin(), vec.end()),vec.end());). But all methods only delete either an element or its duplicates.
I want to delete both.
For example, using this vector:
std::vector<int> vec = {2,3,1,5,2,2,5,1};
I want output to be:
{3}
My initial idea was:
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
int passedNumber = 0; //To tell amount of number not deleted (since not duplicated)
for (int i = 0; i != vec.size(); i = passedNumber) //This is not best practice, but I tried
{
if (vec[i] == vec[i+1])
{
int ctr = 1;
for(int j = i+1; j != vec.size(); j++)
{
if (vec[j] == vec[i]) ctr++;
else break;
}
vec.erase(vec.begin()+i, vec.begin()+i+ctr);
}
else passedNumber++;
}
}
And it worked. But this code is redundant and runs at O(n^2), so I'm trying to find other ways to solve the problem (maybe an STL function that I've never heard of, or just improve the code).
Something like this, perhaps:
void removeDuplicatesandElement(std::vector<int> &vec) {
if (vec.size() <= 1) return;
std::sort(vec.begin(), vec.end());
int cur_val = vec.front() - 1;
auto pred = [&](const int& val) {
if (val == cur_val) return true;
cur_val = val;
// Look ahead to the next element to see if it's a duplicate.
return &val != &vec.back() && (&val)[1] == val;
};
vec.erase(std::remove_if(vec.begin(), vec.end(), pred), vec.end());
}
Demo
This relies heavily on the fact that std::vector is guaranteed to have contiguous storage. It won't work with any other container.
You can do it using STL maps as follows:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
void retainUniqueElements(vector<int> &A){
unordered_map<int, int> Cnt;
for(auto element:A) Cnt[element]++;
A.clear(); //removes all the elements of A
for(auto i:Cnt){
if(i.second == 1){ // that if the element occurs once
A.push_back(i.first); //then add it in our vector
}
}
}
int main() {
vector<int> vec = {2,3,1,5,2,2,5,1};
retainUniqueElements(vec);
for(auto i:vec){
cout << i << " ";
}
cout << "\n";
return 0;
}
Output:
3
Time Complexity of the above approach: O(n)
Space Complexity of the above approach: O(n)
From what you have searched, we can look in the vector for duplicated values, then use the Erase–remove idiom to clean up the vector.
#include <vector>
#include <algorithm>
#include <iostream>
void removeDuplicatesandElement(std::vector<int> &vec)
{
std::sort(vec.begin(), vec.end());
if (vec.size() < 2)
return;
for (int i = 0; i < vec.size() - 1;)
{
// This is for the case we emptied our vector
if (vec.size() < 2)
return;
// This heavily relies on the fact that this vector is sorted
if (vec[i] == vec[i + 1])
vec.erase(std::remove(vec.begin(), vec.end(), (int)vec[i]), vec.end());
else
i += 1;
}
// Since all duplicates are removed, the remaining elements in the vector are unique, thus the size of the vector
// But we are not returning anything or any reference, so I'm just gonna leave this here
// return vec.size()
}
int main()
{
std::vector<int> vec = {2, 3, 1, 5, 2, 2, 5, 1};
removeDuplicatesandElement(vec);
for (auto i : vec)
{
std::cout << i << " ";
}
std::cout << "\n";
return 0;
}
Output: 3
Time complexity: O(n)
I want to expand a given vector by repeating every entry three times. For example, if the vector is [5,7]. The output vector should be [5 5 5 7 7 7]
#include<iostream.h>
#include<vector.h>
int main(void)
{
std::vector<int> x;
x.push_back(5);
x.push_back(7);
x.insert(x.end(), x.begin(), x.begin() + 1);
return 0;
}
This didnt work out. Any help would be appreciated.
A simple approach is to loop over the vector and create a new one:
std::vector<int> vec{5, 7};
// create a new vector
std::vector<int> new_vec;
new_vec.reserve(vec.size() * 3);
for (auto elem : vec) {
for (std::size_t i = 0; i < 3; ++i) {
new_vec.push_back(elem);
}
}
I don't know how simple code you want, but for example this works.
#include<iostream>
#include<vector>
int main(void)
{
std::vector<int> x;
x.push_back(5);
x.push_back(7);
for (std::vector<int>::iterator it = x.end(); it != x.begin(); )
{
it--;
it = x.insert(it, 2, *it);
}
// print the vector to check
for (size_t i = 0; i < x.size(); i++) std::cout << x[i] << " ";
std::cout << std::endl;
return 0;
}
Maybe something like this could help you achieve that:
#include <iostream>
#include <algorithm>
#include <vector>
template<typename T>
std::vector<T> RepeateEntryNumberOfTimes(std::vector<T> input, std::uint16_t numberOfTimes)
{
std::vector<T> result;
std::for_each(input.begin(), input.end(), [&result, numberOfTimes](T item){
for(std::uint16_t numberOfReps = 0; numberOfReps != numberOfTimes; ++numberOfReps)
{
result.push_back(item);
}
});
return result;
}
See godbolt example: https://godbolt.org/z/ns9o3b
Your code has problem since it inserting elements to same vector.
Modification of vector invalidates old iterators, so your code has undefined behavior.
Even ignoring this error, logic of your code doesn't seem to do what you are expecting.
template<typename In, typename Out>
Out replicate_elements(In b, In e, size_t n, Out o)
{
while(b != e) {
o = std::fill_n(o, n, *b++);
}
return o;
}
std::vector<int> foo(const std::vector<int>& x)
{
std::vector<int> r;
r.reserve(x.size() * 3);
replicate_elements(x.begin(), x.end(), 3, std::back_inserter(r));
return r;
}
https://www.godbolt.org/z/zvE5TG
Please tell me what is wrong in my approach.
When I run the code, it is taking too long to compute to see the result.
#include <iostream>
#include <vector>
using namespace std;
vector<int> vec;
vector<int> sort(vector<int> x) {
vector<int> y;
int i = 1;
reset:for(i = 1; i <= x.size(); i++){
for (int j = 1; j <= x.size();) {
if (j == i) {
j++;
}
else {
if (x[i - 1] > x[j - 1]) {
j++;
}
else {
i++;
goto reset;
}
}
}
y.push_back(x[i - 1]);
x.erase(x.begin() + i - 1);
}
return y;
}
int main(){
vec.push_back(5);
vec.push_back(9);
vec.push_back(3);
vec.push_back(6);
vec.push_back(2);
for (int i = 1; i <= vec.size(); i++) {
cout << sort(vec)[i-1] << " ";
}
}
I am sorting this given sequence of 5 integers into descending order. Please help.
My plan was to search for the greatest integer in the whole vector x and move to it to the vector y and repeat the process.
Simple bubble-sort example
I think that your sort function is entering an infinite loop because of the goto reset statement. If you want to implement a simple bubble-sort algorithm, you can do it like this:
#include <iostream>
#include <utility>
#include <vector>
void bubble_sort(std::vector<int>& v) {
if(v.size() == 0) return;
for(int max = v.size(); max > 0; max--) {
for(int i = 1; i < max; i++) {
int& current = v[i - 1];
int& next = v[i];
if(current < next)
std::swap(current, next);
}
}
}
This function takes a vector, and for every consecutive pair of elements in the vector, if they're out of order, it swaps them. This results in the smallest element "bubbling" to the top of the vector. The process is repeated until all the elements are in order.
If we test it, we see that it prints the right answer:
int main() {
std::vector<int> test = {5, 9, 3, 6, 2};
bubble_sort(test);
for(int i : test) {
std::cout << i << ' ';
}
std::cout << '\n';
}
Using std::sort to do this faster
The standard library provides a sort function that'll sort pretty much anything. std::sort is really well implemented, it's more efficient than bubble sort, and it's really easy to use.
By default, std::sort orders things in ascending order, although it's easy to change it so that it works in descending order. There are two ways to do this. The first way sorts the vector using the reverse iterators (which allow you to pretend the vector is in reverse order), and the second way sorts the vector using std::greater, which tells std::sort to sort things in reverse order.
// Way 1:
std::sort(test.rbegin(), test.rend());
// Way 2:
auto compare_func = std::greater<>();
std::sort(test.begin(), test.end(), compare_func);
We can re-write the program using std::sort:
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
std::vector<int> test = {5, 9, 3, 6, 2};
auto compare_function = std::greater<>();
std::sort(test.begin(), test.end(), compare_function);
for(int i : test) {
std::cout << i << ' ';
}
std::cout << '\n';
}
Why can't you just use std:sort? You can do this:
sort(vec.begin(), vec.end(), [](const int a, const int b) {return a > b; }); //1
As suggested in the comments, there are two alternatives to the above:
std::sort(vec.begin(), vec.end(), std::greater<>()); //2
and:
std::sort(vec.rbegin(), vec.rend()); //3
(2) and (3) avoid a custom comparison function, and (2) is arguably more explicit about it's intent. But I was interested in the performance, and so I did a quick bench comparison of the three.
With Clang 12.0, (1) was fastest:
Clang results here
However, with GCC 10.3 all three were near identical:
GCC results here
Interesting results! With GCC, it's your choice as to which version you prefer; otherwise I would go for (1) or (2).
I'm supposed to:
Print vector elements sorted without repetition.
Delete the elements that are printed from vector.
Repeat the the previous steps until vector is empty.
But it seems that my code takes more time so, I seek for optimisation. I've tried to do this task with std::vector and std::set.
Here is my approach:
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using namespace std;
int main () {
int n;
cin >> n;
vector<int> v(n);
set<int> st;
for (int i = 0; i < n; i++) {
cin >> v[i];
}
while (!v.empty()) {
for (int i = 0; i < v.size(); i++)
st.insert(v[i]);
for (auto x : st) {
cout << x << ' ';
auto it = find(v.begin(), v.end(), x);
if (it != v.end())
v.erase(it);
}
st.clear();
cout << "\n";
}
return 0;
}
For example input is like:
7
1 2 3 3 2 4 3
Output gonna be like this:
1 2 3 4
2 3
3
You might use std::map instead of std::vector/std::set to keep track of numbers:
#include <iostream>
#include <map>
int main () {
map<int, int> m;
int size;
std::cin >> size;
for (int i = 0; i != size; i++) {
int number;
std::cin >> number;
++m[number];
}
while (!m.empty()) {
for (auto it = m.begin(); it != m.end(); /*Empty*/) {
const auto number = it->first;
auto& count = it->second;
std::cout << number << ' ';
if (--count == 0) {
it = m.erase(it);
} else {
++it;
}
}
std::cout << "\n";
}
}
Complexity is now O(n log(n)) instead of O(n²) (with lot of internal allocations).
Due to it overwriting the elements expected to be deleted, std::unique won't be much use for this problem. My solution:
std::sort(v.begin(), v.end());
while (!v.empty())
{
int last = v.front();
std::cout << last << " ";
v.erase(v.begin());
for (auto it = v.begin(); it != v.end(); /* no-op */)
{
if (*it == last)
{
++it;
}
else
{
last = *it;
std::cout << last << " ";
it = v.erase(it);
}
}
std::cout << std::endl;
}
You could probably improve performance further by reversing the sorting of the vector, and then iterating through backwards (since it's cheaper to delete from closer to the back of the vector), but that would complicate the code further, so I'll say "left as an exercise for the reader".
You can use std::map
auto n = 0;
std::cin >> n;
std::map<int, int> mp;
while (--n >= 0) {
auto i = 0;
std::cin >> i;
mp[i] += 1;
}
while (!mp.empty()) {
for (auto& it: mp) {
std::cout << it.first << " ";
it.second--;
}
for (auto it = mp.begin(); it != mp.end(); ++it) {
if (it->second == 0) mp.erase(it);
}
std::cout << "\n";
}
without any erase
auto n = 0;
std::cin >> n;
std::map<int, int> mp;
while (--n >= 0) {
auto i = 0;
std::cin >> i;
mp[i] += 1;
}
auto isDone = false;
while (!isDone) {
isDone = true;
for (auto& it: mp) {
if (it.second > 0) std::cout << it.first << " ";
if (--it.second > 0) isDone = false;
}
std::cout << "\n";
}
Here is a solution using sort and vector. It uses a second vector to hold the unique items and print them.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
int main()
{
std::vector<int> v{1,2,3,3,2,4,3};
std::sort(v.begin(), v.end());
std::vector<int>::iterator vit;
while(!v.empty()){
std::vector<int> printer;
std::vector<int>::iterator pit;
vit = v.begin();
while (vit != v.end()){
pit = find(printer.begin(), printer.end(), *vit);
if (pit == printer.end()){
printer.push_back(*vit);
vit = v.erase(vit);
} else {
++vit;
}
}
std::copy(printer.begin(), printer.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << '\n';
}
}
Output:
1 2 3 4
2 3
3
It's not clear (at least to me) exactly what you're talking about when you mention "efficiency". Some people use it to refer solely to computational complexity. Others think primarily in terms of programmer's time, while still others think of overall execution speed, regardless of whether that's obtained via changes in computational complexity, or (for one example) improved locality of reference leading to better cache utilization.
So, with that warning, I'm not sure whether this really improves what you care about or not, but it's how I think I'd do the job anyway:
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
// preconditions: input range is sorted
template <class BidiIt>
BidiIt partition_unique(BidiIt begin, BidiIt end) {
auto pivot = end;
for (auto pos = begin; pos != pivot; ++pos) {
auto mid = std::next(pos);
for ( ; mid < pivot && *mid == *pos; ++mid, --pivot)
;
std::rotate(std::next(pos), mid, end);
}
return pivot;
}
template <class It>
void show(It b, It e, std::ostream &os) {
while (b != e) {
os << *b << ' ';
++b;
}
os << '\n';
}
int main() {
std::vector<int> input{ 1, 2, 3, 3, 2, 4, 3 };
std::sort(input.begin(), input.end());
auto begin = input.begin();
auto pos = begin;
while ((pos = partition_unique(begin, input.end())) != input.end()) {
show(begin, pos, std::cout);
begin = pos;
}
show(begin, input.end(), std::cout);
}
I'm not really sure it's possible to improve the computational complexity much over what this does (but it might be--I haven't thought about it enough to be sure one way or the other). Compared to some versions I see posted already, there's a decent chance this will improve overall speed (e.g., since it just moves things around inside the same vector, it's likely to get better locality than those that copy data from one vector to another.
The code is in java but the idea remains the same.
At first, I sort the array. Now, the idea is to create buckets.
This means that each line of sorted elements is like a bucket. So, find the count of each element. Now, put that element into each bucket, count number of times. If it so happens that bucket size is less, create a new bucket and add the current element to it.
In the end, print all buckets.
Time Complexity is O(nlog(n)) for sorting and O(n) for the buckets since you have to visit each and every element to print it. So, it's O(nlog(n)) + O(n) = O(nlog(n)) asymptotically.
Code:
import java.util.*;
public class GFG {
public static void main(String[] args){
int[] arr1 = {1,2,3,3,2,4,3};
int[] arr2 = {45,98,65,32,65,74865};
int[] arr3 = {100,100,100,100,100};
int[] arr4 = {100,200,300,400,500};
printSeries(compute(arr1,arr1.length));
printSeries(compute(arr2,arr2.length));
printSeries(compute(arr3,arr3.length));
printSeries(compute(arr4,arr4.length));
}
private static void printSeries(List<List<Integer>> res){
int size = res.size();
for(int i=0;i<size;++i){
System.out.println(res.get(i).toString());
}
}
private static List<List<Integer>> compute(int[] arr,int N){
List<List<Integer>> buckets = new ArrayList<List<Integer>>();
Arrays.sort(arr);
int bucket_size = 0;
for(int i=0;i<N;++i){
int last_index = i;
if(bucket_size > 0){
buckets.get(0).add(arr[i]);
}else{
buckets.add(newBucket(arr[i]));
bucket_size++;
}
for(int j=i+1;j<N;++j){
if(arr[i] != arr[j]) break;
if(j-i < bucket_size){
buckets.get(j-i).add(arr[i]);
}else{
buckets.add(newBucket(arr[i]));
bucket_size++;
}
last_index = j;
}
i = last_index;
}
return buckets;
}
private static List<Integer> newBucket(int value){
List<Integer> new_bucket = new ArrayList<>();
new_bucket.add(value);
return new_bucket;
}
}
OUTPUT
[1, 2, 3, 4]
[2, 3]
[3]
[32, 45, 65, 98, 74865]
[65]
[100]
[100]
[100]
[100]
[100]
[100, 200, 300, 400, 500]
This is what i came up with:
http://coliru.stacked-crooked.com/a/b3f06693a74193e5
The key idea:
sort vector
print by iterating. just print a value if it differs from last printed
remove unique elements. i have done this with what i called inverse_unique. the std library comes with an algorithm called unique, which will remove all duplicates. i inverted this so that it will just keep all dublicates.
so we have no memory allocation at all. i cant see how one could make the algorithm more efficient. we are just doing the bare minimum and its exactly done the way a human thinks about.
i tested it with several combinations. hope its bug free ;-P
code:
#include <iostream>
#include <algorithm>
#include <vector>
template<class ForwardIt>
ForwardIt inverse_unique(ForwardIt first, ForwardIt last)
{
if (first == last)
return last;
auto one_ahead = first+1;
auto dst = first;
while(one_ahead != last)
{
if(*first == *one_ahead)
{
*dst = std::move(*first);
++dst;
}
++first;
++one_ahead;
}
return dst;
}
void print_unique(std::vector<int> const& v)
{
if(v.empty()) return;
// print first
std::cout << v[0] << ' ';
auto last_printed = v.cbegin();
// print others
for(auto it = std::next(std::cbegin(v)); it != std::cend(v); ++it)
{
if(*it != *last_printed)
{
std::cout << *it << ' ';
last_printed = it;
}
}
std::cout << "\n";
}
void remove_uniques(std::vector<int> & v)
{
auto new_end = inverse_unique(std::begin(v), std::end(v));
v.erase(new_end, v.end());
}
int main ()
{
std::vector<int> v = {1, 2, 3, 3, 2, 4, 3};
std::sort(std::begin(v), std::end(v));
while (!v.empty())
{
print_unique(v);
remove_uniques(v);
}
return 0;
}
Edit: updated inverse_unique function. should be easy to understand now.
Half baked at http://coliru.stacked-crooked.com/a/c45df1591d967075
Slightly modified counting sort.
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <map>
int main() {
std::vector<int> v{1,2,3,3,2,4,3};
std::map<int, int> map;
for (auto x : v)
++map[x];
while(map.size()) {
for(auto pair = map.begin(); pair != map.end(); ) {
std::cout << pair->first << ' ';
if (!--pair->second)
pair = map.erase(pair);
else
++pair;
}
std::cout << "\n";
}
return 0;
}
I'm trying to change the data inside a vector's element by using a function. It happens that the elements are changed just inside the function. How can I keep the changings outside the function? Do I must use pointers?
The code:
#include <iostream>
#include <vector>
using namespace std;
void populate( int size_, vector<int> pop)
{
//Set the vector's size and populate the vector
pop.resize(size_);
for(int i = 0; i<3 ; i++)
{
pop[i] = i;
}
}
int main()
{
vector<int> vec;
int size = 3;
populate(size, vec);
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
The output at cout should be : 0 1 2
But it is empty.
What you're trying to do is easily and idiomaticaly done with standard library facilities:
int size = 3;
std::vector<int> vec(size);
std::iota(vec.begin(), vec.end(), 0); // include algorithm for this
You need to take the vector by reference
void populate( int size_, vector<int>& pop)
Otherwise you are passing in a copy of the vector, populating it, then returning, but the original vector is unmodified.
Or as #juanchopanza recommended, since the sole purpose of this function is to make this vector for you, it could be
vector<int> populate( int size_ )
{
vector<int> temp(size_);
for(int i = 0; i < size_ ; i++)
{
pop[i] = i;
}
return temp;
}
Then
int main()
{
int size = 3;
vector<int> vec = populate(size, vec);
for(vector<int>::iterator it = vec.begin(); it != vec.end(); ++it)
{
cout << *it << endl;
}
}
You are sending in the vector to populate by value. This creates a copy, so pop is a copy of vec. Changes you make only affect pop.