Delete duplicates from array C++ - c++

I am trying to create a simple program which calls on 2 functions. The first function takes a partially filled array, loops through it and deletes any duplicate values. When a value is deleted from the array, the remaining numbers are moved backwards to fill the gap i.e. when the function is finished, all null values of the array will be together at the end.
The second function prints the updated array.
My current code is below. At present when I run my code, the console shows:
2 6 0 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460 -858993460. It should be showing: 1 2 5 6 if it worked correctly.
Also, I am not sure how to move the remaining elements of the array backwards so that the null values will be together at the end.
#include "pch.h"
#include <iostream>
using namespace std;
void deleteRepeats(int *arr, int arraySize, int& posUsed);
void printArray(int *arr, int arraySize);
int main()
{
int arr[10] = { 1, 2, 2, 5, 6, 1};
int posUsed = 6;
int arraySize = 10;
deleteRepeats(arr, arraySize, posUsed);
printArray(arr, arraySize);
return 0;
}
void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
{
for (int i = 0; i < arraySize; i++)
{
for (int j = i; j < arraySize; j++)
{
if (arr[i] == arr[j])
{
for (int k = j; k < arraySize; k++)
{
arr[k] = arr[k + 1];
}
posUsed--;
}
else
j++;
}
}
}
}
void printArray(int *arr, int arraySize)
{
for (int i = 0; i < arraySize; i++)
{
cout << arr[i] << " ";
}
}

I would let the std containers to what you like to do.
Sort the vector
Use erase and unique to delete duplicates.
Here is the code
#include <vector>
#include <iostream>
#include <algorithm>
void print(const std::vector<int> &arr){
for (const auto & i : arr){
std::cout << i <<" ";
}
std::cout <<"\n";
}
int main() {
std::vector<int> arr{1, 2, 2, 5, 6, 1};
print(arr);
std::sort( arr.begin(), arr.end() );
arr.erase( std::unique( arr.begin(), arr.end() ), arr.end() );
print(arr);
}
Ps. Using int *arr, int arraySize is not very C++ like. Please always try to use a proper container (which almost always will be std::vector).
EDIT:
I changed my answer a bit, because I found this speed comparison (and actuallty the whole question answered).
What's the most efficient way to erase duplicates and sort a vector?

Given your assignment constraints (more C-like, than idiomatic C++), you can rewrite your function like this, to make it work:
void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
for (int i = 0; i < posUsed; ++i)
{
int duplicates = 0;
int j = i + 1;
// find the first duplicate, if exists
for ( ; j < posUsed; ++j)
{
if ( arr[i] == arr[j] ) {
++duplicates;
break;
}
}
// overwrite the duplicated values moving the rest of the elements...
for (int k = j + 1; k < posUsed; ++k)
{
if (arr[i] != arr[k])
{
arr[j] = arr[k];
++j;
}
// ...but skip other duplicates
else
{
++duplicates;
}
}
posUsed -= duplicates;
}
// clean up (could be limited to the duplicates only)
for (int i = posUsed; i < arraySize; ++i)
arr[i] = 0;
}

It might be easier to imagine the algorithm having separate input and output arrays. Then, in pseudo-code:
for i = 0 to input_array_size-1
Is input[i] equal to input[j] for any j between 0 and i-1?
Yes - do nothing
No - copy input[i] to output
To implement this with shared input and output, you need to have two array sizes, input_array_size and output_array_size. Then, the pseudo-code becomes
output_array_size = 0
for i = 0 to input_array_size-1
Is array[i] equal to array[j] for any j between 0 and output_array_size-1?
Yes - do nothing
No:
copy array[i] to array[output_array_size]
Increase output_array_size
Note: it writes output where the input once was, so the check for duplicates should look at all elements that were output. For example, if your array is 1, 2, 1, 3, 5, 6, 3, then for the last 3 the accumulated output is 1, 2, 3, 5, 6, and the code should compare all these with the current element.
To simplify debugging, where it says "do nothing", you can set current element to -1. This way, if you print your array during execution (for debugging), it will be clearer which elements were removed.

there are only two changes made as you can see
1: you were traversing the whole array as you have declared a posUsed=6 variable which is because there are only 6 elements so in in loops you need to traverse in array upto posUsed index like i<posUsed j<posUsed k<posUsed
2: the second changes is in j loop j=i+1 because you don't need to compare the element of any index with element of the same index you have to compare it with elements after that index. if you compare it with same element it will be same and the program will delete that same element which results in ERROR.
onw more thing is that we don't traverse after posUsed index because after that the array is already empty/zero or null whatever you call it
and if you want to display just the non duplicated elements and not the zero's at the end of the array just add if(arr[i]==0) return; in the printArray function loop before cout statement
void deleteRepeats(int *arr, int arraySize, int& posUsed)
{
{
for (int i = 0; i < posUsed; i++)
{
for (int j = i+1; j < posUsed; j++)
{
if (arr[i] == arr[j])
{
for (int k = j; k < posUsed; k++)
{
arr[k] = arr[k + 1];
}
}
}
}
}
}

using two pointers
and if the array sorted
int removeDuplicates(vector<int>& nums) {
if(nums.size() == 0) return 0;
int i = 0;
for(int j = 1; j < nums.size(); j++)
if(nums[j] != nums[i]) nums[++i] = nums[j];
// return new array length
return i + 1;
}
//input: [1, 1, 2, 1] (arr1)
//output: 2 (returned length)
// print unique element
for(int i = 0; i < output; i++) cout << arr1[i] << '\n';
// [1, 2]
time complexity: O(N/2) -> O(N)
space complexity: O(1)

Removing duplicate elements from an unsorted array by O(n^2) complexity.
for (i = 1; i < vec.size(); i++)
{
for (j = 0; j < i; j++)
{
if (vec[i] == vec[j])
{
vec[i] = -1; //Every duplicate element will replace by -1
}
}
}
for (i = 0; i < vec.size(); i++)
{
if (vec[i] != -1)
{
copy.push_back(vec[i]);
/*if you are using an array then store this value into a new array.
first, declare a new array. The new array size will be equal to the
previous array. Like this :
int newArr[sizeOfPreviousArrary];
int j = 0;
newArr[j] = arr[i];
j++;
*/
}
}

Removing duplicate elements from an sorted array by O(n) complexity.
for (i = 0; i < n; i++)
{
if (arr[i] != arr[i+1]){
vec.push_back(arr[i]);
/*if you are using an array then store this value into a new array.
first, declare a new array. The new array size will be equal to the
previous array. Like this :
int newArr[sizeOfPreviousArrary];
int j = 0;
newArr[j] = arr[i];
j++;
*/
}
}

Use map or set for deleting duplicates
void removeDuplicates(int arr[], int n)
{
int i;
// Initialise a set
// to store the array values
set<int> s;
// Insert the array elements
// into the set
for (i = 0; i < n; i++) {
// insert into set
s.insert(arr[i]);
}
set<int>::iterator it;
// Print the array with duplicates removed
cout << "\nAfter removing duplicates:\n";
for (it = s.begin(); it != s.end(); ++it)
cout << *it << ", ";
cout << '\n';
}

Related

find frequency in array using vector

How can I change my code to get a count for every element?
With my code everything is okay. And it works, but how can I change only that part?
#include <iostream>
#include <vector>
void countFreq(int arr[], int n)
{
// Mark all array elements as not visited
std::vector<bool> visited(n, false);
// Traverse through array elements and
// count frequencies
for (int i = 0; i < n; i++) {
// Skip this element if already processed
if (visited[i] == true)
continue;
// Count frequency
int count = 1;
for (int j = i + 1; j < n; j++) {
if (arr[i] == arr[j]) {
visited[j] = true;
count++;
}
}
std::cout<<count<<" ";
}
}
int main()
{
int n;
std::cin>>n;
int arr[n];
for(int i = 0; i < n; i++){
std::cin>>arr[i];
}
countFreq(arr, n);
return 0;
}
And about the result`
input 10
1 1 2 2 3 3 4 4 5 5
output 2 2 2 2 2
but I want to get
output 2 2 2 2 2 2 2 2 2 2
(for every element)
Your function contains extra code that ends up confusing you. The visited variable is essentially unnecessary. Start the count at 0 and make no special case for the "current" cell and you'll find that some very simple code will do what you need:
void countFreq(int arr[], int n)
{
// Traverse through array elements and
// count frequencies
for (int i = 0; i < n; i++) {
// Count frequency
int count = 0;
for (int j = 0; j < n; j++) {
if (arr[i] == arr[j]) {
count++;
}
}
std::cout << count << " ";
}
}
You need to save the result to an array for each number. Then when you find any processed number then print counter from the saved array.
#include <iostream>
#include <vector>
#include <unordered_map>
void countFreq(int arr[], int n)
{
// Mark all array elements as not visited
std::vector<bool> visited(n, false);
std::unordered_map<int, int> counter;
// Traverse through array elements and
// count frequencies
for (int i = 0; i < n; i++)
{
// Skip this element if already processed
if (visited[i] == true)
{
std::cout << counter[arr[i]] << " ";
continue;
}
// Count frequency
int count = 1;
for (int j = i + 1; j < n; j++)
{
if (arr[i] == arr[j])
{
visited[j] = true;
count++;
}
}
counter[arr[i]] = count;
std::cout<<count<<" ";
}
}
int main()
{
int n;
std::cin>>n;
int arr[n];
for(int i = 0; i < n; i++)
{
std::cin>>arr[i];
}
countFreq(arr, n);
return 0;
}
The issue is that you discard the values already visited.
One possibility is instead to memorize the count when the value is visited the first time,
and to memorize the index value of the first value appearance, when a value is visited the 2nd, 3rd ... time.
#include <iostream>
#include <vector>
void countFreq(const std::vector<int>& arr) {
int n = arr.size();
// Mark all array elements as not visited
std::vector<int> mem_count(n, n);
// Traverse through array elements and
// count frequencies
for (int i = 0; i < n; i++) {
// Skip this element if already processed
if (mem_count[i] != n) {
std::cout << mem_count[mem_count[i]] << " ";
continue;
}
// Count frequency
int count = 1;
for (int j = i + 1; j < n; j++) {
if (arr[i] == arr[j]) {
mem_count[j] = i;
count++;
}
}
mem_count[i] = count;
std::cout << count << " ";
}
}
int main() {
int n;
std::cin>>n;
std::vector<int> arr(n);
for(int i = 0; i < n; i++){
std::cin >> arr[i];
}
countFreq(arr);
return 0;
}
You can find the frequencies of numbers this way if you know the what is your maximum element in the input array. lets say m is maximum number in your array.
so you have to create a new array of size m. you can simply co-relate them as m buckets. from 0 to m. And each bucket will hold the count of each element in the input array. The index of each bucket will refer to element in the input array. This has time complexity O(1) if we know what is the max element the array.
You can do this way:
std::vector<int> frequencey(std::vector<int>& nums){
auto max = *(std::max_element(nums.begin(), nums.end()));
std::vector<int> frequencies(max + 1, 0);
for(int i = 0; i < nums.size(); ++i){
frequencies[nums[i]] +=1;
}
return frequencies;
}
This is very simple
#include <vector>
#include <map>
#include <iostream>
void main()
{
std::vector<int> v { 1,1,2,2,3,3,4,4,5,5 }; // Your input vector
// Count "frequencies"
std::map<int, int> m;
for (auto i : v)
m[i]++;
// Print output
for (auto i : v)
std::cout << m[i] << " ";
}

ERROR: AddressSanitizer: negative-size-param: (size=-4)

Trying to write some code, and erase() is giving me a runtime error. What's wrong with the way I used erase?
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int size = nums.size();
vector<int> list;
for(int i = 1; i <= size; i++)
list.push_back(i);
for(int i = 0; i < size; i++) {
int num = nums[i];
list[num - 1] = 0;
}
for(int i = 0; i < size; i++) {
if(list[i] == 0) {
list.erase(list.begin() + i);
}
}
return list;
}
};
Here's the problem I am trying to solve
Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.
Example:
Input:
[4,3,2,7,8,2,3,1]
Output:
[5,6]
Since all the non solutions were marked 0, you can remove all 0's in the vector using list.erase( remove (list.begin(), list.end(), 0), list.end() );
My first suggestion, concentrate on this:
for(int i = 0; i < size; i++) {
if(list[i] == 0) {
list.erase(list.begin() + i);
}
}
You are removing elements from list which changes the size. This will lead to accessing elements beyond your list.

How to switch C++ array elements positions based on specified conditions?

I'm having a little problem with getting my head around this homework task. The task says: "Write a function called MoveSmallest that moves all the minimal integer elements at the start of the array. All the remaining items must stay at their places. (the array and its size are parameters)
Example: the array: 2, 3, 5, 1, 2, 3, 6, 4, 2, 1, 1 changes into 1, 1, 1, 2, 3, 5, 2, 3, 6, 4, 2
void MoveSmallest(int A[],int n)
{
int Min;
for(int i=0;i<n;i++)
{
if(i==0)
{
Min=A[i];
}
else if(A[i]<=Min)
{
Min=A[i];
}
}
So far I've only figured to check which one is the smallest element of the array. I don't have any ideas what to do next.
Once you have found the minimum value, all there is left to do is moving things around in order to have the minimum values at the beginning of the array.
You can do this by permuting the values until you have arrived to the "left" of the array (i.e index 0).
void MoveSmallest(int A[],int n)
{
int Min;
for(int i=0;i<n;i++)
{
if(i==0)
{
Min=A[i];
}
else if(A[i]<=Min)
{
Min=A[i];
}
}
for(int i = 0; i < n; i++)
{
if(A[i] == Min)
{
for(int j = i; j > 0; j--)
{
int tmp = A[j];
A[j] = A[j-1];
A[j-1] = tmp;
}
}
}
}
You could also use std::swap to do the permutation, instead of the temporary variable tmp.
Starting from the end of the array, keep track of how many minimal elements you have encountered. Then whenever you encounter a non-minimum element, move it to the right the number of minimal elements you have encountered so far:
void MoveSmallest(int A[], int n)
{
int min;
//Find min logic
//shift non-min elements and count min elements
int cnt = 0;
for (int i = n-1; i >=0; --i)
{
if (A[i] == min)
cnt++;
else
A[i+cnt] = A[i];
}
//Add min elements
for (int i = 0; i < cnt; ++i)
A[i] = min;
}
This will run in O(n) time and O(1) space.
Since your posts mention "basic C++" but not mention what is "basic", here is another solution. This is under the assumption that creating arrays for "work" purposes is considered "basic C++".
void MoveSmallest(int A[], int n)
{
// get the minimum value
int Min = A[0];
for (int i = 1; i < n; ++i)
{
if (A[i] < Min)
Min = A[i];
}
// get the count of the number of minimum values
int minCount = 0;
for (int i = 0; i < n; ++i)
{
if (A[i] == Min)
++minCount;
}
if (minCount > 0)
{
// create a work array and fill in the first
// minCount values with the minimum value
int *B = new int[n];
for (int i = 0; i < minCount; ++i)
B[i] = Min;
// now fill in the rest of the work array with the values
// in the A[] array that are not equal to Min
int current_pos = minCount;
for (int i = 0; i < n; ++i)
{
if (A[i] != Min)
B[current_pos++] = A[i];
}
// Now copy work array back to A array
for (int i = 0; i < n; ++i)
A[i] = B[i];
// get rid of work array
delete[] B;
}
}
Live Example
This runs in linear time O(n), as opposed to quadratic time O(n*n).
The disadvantage of course is that you need room for the work array, so the memory cost is linear O(n).

vector.insert doesn't resize vector?

i'm trying to create a function that takes in a vector by reference and if it sees a vector entry 2, it would take delete the entry and replace it with 4 copies of 5.
so if the vector is 222 (then it is size n = 3), i want 555555555555 as the new vector
however, it only works properly for the first few, when the index is < n.
so right now, it would change vector a to be 555522
any ideas how to make the vector resize?
void replace2 (vector <int>* a, int n){
for (int i = 0; i < n; ++i){
if ((*a)[i] == 2){
(*a).erase((*a).begin() + i);
for(int j = 0; j < 4; ++j){
(*a).insert((*a).begin() + i, 5);
}
}
}
}
The problem with using
for ( int i = 0; i < n; ++i ) { ... }
has already been pointed out in one of the comments:
After the first iteration of the loop, (*a)[i] no longer equals 2. Remaining iterations do nothing.
Your function will be simplified if you iterate from the end of the vector and go back.
Also, pass a reference to the vector instead of a pointer.
Here's a complete program:
#include <vector>
#include <iostream>
void replace2(std::vector <int>& a, int n){
for (int i = n-1; i >= 0; --i){
if (a[i] == 2){
a.erase(a.begin() + i);
for(int j = 0; j < 4; ++j){
a.insert(a.begin() + i, 5);
}
}
}
}
int main()
{
std::vector<int> a{2, 2, 2};
replace2(a, 3);
for(auto item : a )
{
std::cout << item;
}
std::cout << std::endl;
}
See it working at https://ideone.com/0Lip5j.

Getting segmentation fault (vector declaration)

Find out the maximum sub-array of non negative numbers from an array.
The sub-array should be continuous. That is, a sub-array created by choosing the second and fourth element and skipping the third element is invalid.
Maximum sub-array is defined in terms of the sum of the elements in the sub-array. Sub-array A is greater than sub-array B if sum(A) > sum(B).
This is my solution:
vector<int> Solution::maxset(vector<int> &A) {
// Do not write main() function.
// Do not read input, instead use the arguments to the function.
// Do not print the output, instead return values as specified
// Still have a doubt. Checkout www.interviewbit.com/pages/sample_codes/ for more details
vector <int> bla;
int sum[100]={0};
int k = 0;
int j = 1;
for (int i =0; i < A.size(); i++){
if (A[i] > -1){
sum[k] = A[i] + sum[k];
}
else {
k++;
}
}
cout<<sum[0]<<" ";
cout<<sum[1]<<" ";
cout << sum[2] << " ";
int s = 0;
for (int i =0; i< 100; i++){
if (s < sum[i]){
s = sum[i];
k = i;
}
}
cout << s;
int count = 0;
for (int i =0; i < A.size(); i++){
if (A[i] < 0) {
count ++;
}
if (count == k) {
int j = i+1;
int x = 0;
while (A[j] > 0 && j< (A.size()-1)) {
// bla[x] = A[j];
x++;
j++;
}
}
}
return bla;
}
If I uncomment the line bla[x] = A[j], I get segmentation error. Can someone explain how to undetstand this error? I read it somewhere that there is not enough space in stack. I do not understand how.
Thank you
You can pass the size to a vector object or you can call it's default constructor which creates a vector object with 0 size.
std::vector<int> vecInt(10);
for(int i(0); i < vecInt.size(); i++)
vecInt[i] = i;
Or you can declare a vector with size 0:
std::vector<int> vecInt;
vecInt[0] = 10; // segfault
Because you try to store values in an un-allocated space.
To solve such problem use push_back to store and pop to clear:
So your example can be like this:
while (A[j] > 0 || j< (A.size()-1)) {
// bla[x] = A[j];
bla.push_back(A[j]);
x++;
j++;
}