How to remove 2 consecutive duplicates from an array? c++ - c++

I have an array a={1,2,3,3,2,2,3,3} and I need to remove the duplicates like this:
1: a={1,2,2,2,3,3}
2: a={1,2,3,3}
3: a={1,2}
I need to remove 2 consecutive duplicates: (1,2,3,3 will be 1,2), (1,2,2,2 will be 1,2).
Here is my try, but as you can see, I need some help.
#include <iostream>
int main()
{
int n;
std::cin >> n;
int a[n];
for (int i = 0; i < n; i++)
std::cin >> a[i];
int i, j;
for (i = 0; i < n; i++)
if (a[i] == a[i + 1]) {
for (j = i + 1; j < n; j++)
a[j - 1] = a[j];
n--;
i--;
}
if (n != 0)
for (int i = 0; i < n; i++)
std::cout << a[i] << " ";
return 0;
}
My problem is that I don't know how to remove 2 consecutive values. After multiple tries, I can't resolve this. Thank you in advance!

I'm not going to write code for you, but here are my thoughts.
First, write a function to check if there even exists "consecutive duplicates":
//returns true if there are no consecutive duplicates within the array, false otherwise
func noConsecDups(arr a)
for int i = 0, i <= a.length-2, i++
if a[i] = a[i++]
return false
end of if
end of loop
return true
end function
Now, write a function that removes the consecutive duplicates recursively (might not have to do it recursively, that's just my initial thought) while checking to see if you even need to remove any!
//function that takes an array as input and returns the array with all consecutive duplicates removed
func removeConsecDups(arr a)
if a.length is 1, return a
if a.length is 2 and a[0] != a[1], return a
if(noConsecDups(a)) then there are no consecutive duplicates, return a
otherwise look through the array and just remove the first consecutive duplicates
for int j = 0, j <= a.length-2, j++
if a[j] = a[j+1]
remove a[j+1]
remove a[j]
break
end if statement
end loop
recursively call removeConsecDups(a)
end function

If you just need the final result (an array with no consecutive duplicates left) then your best bet is probably to use a stack and just traverse the whole input array once, comparing the values to the stack top and poping the duplicates off the stack.
If you need to print out the array state after every intermediate step, then #BarronDuBois's suggestion is the way to go.
Either way the code itself should be simple enough, I'd be glad to help with any specific issue.

Related

Can I create a for loop with two variables and still have time complexity of O(n)?

Say I have a for loop as:
for(int i=0,j=i+1;i<n-1,j<n;j++)
{
//some code
if(condition)
{
i++;
j=i;
}
}
What will be the time complexity and why?
Edited:
void printAllAPTriplets(int arr[], int n)
{
for (int i = 1; i < n - 1; i++)
{
// Search other two elements of
// AP with arr[i] as middle.
for (int j = i - 1, k = i + 1; j >= 0 && k < n;)
{
// if a triplet is found
if (arr[j] + arr[k] == 2 * arr[i])
{
cout << arr[j] << " " << arr[i]
<< " " << arr[k] << endl;
// Since elements are distinct,
// arr[k] and arr[j] cannot form
// any more triplets with arr[i]
k++;
j--;
}
// If middle element is more move to
// higher side, else move lower side.
else if (arr[j] + arr[k] < 2 * arr[i])
k++;
else
j--;
}
}
}
What would be the time complexity of this particular function and why?? #walnut #DeducibleSteak #Acorn .This is the code for "Printing all triplets in sorted array that form AP"
O(n^2) is when you iterate through all the possible values of one variable each time you iterate through the second one. As such:
for(int i=0; i < n; i++){
for (int j = 0; j < m; j++{
//Do some action
}
}
In your example, even though you're using two vars, but it's still a O(n).
Assuming that increasing i by one takes one second, then assigning the new i to j takes one second too, then the complexity is O(2n). Since constant numbers are insignificant when speaking about complexities, then the complexity of your code is still O(n)
The loop you have written does not make sense, because you are using the comma operator and discarding one of the conditions, so it is equivalent to j < n.
Even if the condition gets triggered many times (but a constant number w.r.t. n, i.e. not becoming larger as n grows), then you can easily show you will do <= k*n iterations, which means O(n) iterations.
If that is not true, but the condition is at least side-effect free, then you can only bound it by O(n^2), e.g. as #walnut suggests with j == n - 1 (like in a triangle matrix).
If you allow for side-effects in the condition (e.g. j = 0, with an equals sign), then it can be an infinite loop, so there is no possible bound.

How to Compare multiple variables at the same time in the C++?

I'm making Sudoku validater program that checks whether solved sudoku is correct or not, In that program i need to compare multiple variables together to check whether they are equal or not...
I have provided a snippet of code, what i have tried, whether every su[][] has different value or not. I'm not getting expecting result...
I want to make sure that all the values in su[][] are unequal.
How can i achieve the same, what are mistakes in my snippet?
Thanks...
for(int i=0 ; i<9 ;++i){ //for checking a entire row
if(!(su[i][0]!=su[i][1]!=su[i][2]!=su[i][3]!=su[i][4]!=su[i][5]!=su[i][6]!=su[i][7]!=su[i][8])){
system("cls");
cout<<"SUDOKU'S SOLUTION IS INCORRECT!!";
exit(0);
}
}
To check for each column uniqueness like that you would have to compare each element to the other ones in a column.
e.g.:
for (int i = 0; i < 9; ++i) {
for (int j = 0; j < 9; ++j) {
for (int k = j + 1; k < 9; ++k) {
if (su[i][j] == su[i][k]) {
system("cls");
cout << "SUDOKU'S SOLUTION IS INCORRECT!!\n";
exit(0);
}
}
}
}
Since there are only 8 elements per row this cubic solution shouldn't give you much overhead.
If you had a higher number N of elements you could initialize an array of size N with 0 and transverse the column. For the i-th element in the column you add 1 to that elements position in the array. Then transverse the array. If there's a position whose value is different from 1, it means you have a duplicated value in the column.
e.g.:
for (int i = 0; i < N; ++i) {
int arr[N] = {0};
for (int j = 0; j < N; ++j)
++arr[su[i][j] - 1];
for (int i = 0; i < N; ++i) {
if (arr[i] != 1) {
system("cls");
cout << "SUDOKU'S SOLUTION IS INCORRECT!!\n";
exit(0);
}
}
}
This approach is way more faster than the first one for high values of N.
The codes above check the uniqueness for each column, you would still have to check for each row.
PS: I have not tested the codes, it may have a bug, but hope you get the idea.

Intersection of 2 dynamically allocated arrays c++

I am trying to create a function that will find the intersection of two dynamically allocated arrays comparing array 1 to array 2. For any values in array 1 that are not in array 2, those values should be deleted in array 1 so that array 1 now only holds the common values of both arrays (no repeats). I cannot use vectors, hashes, or any other thing outside of my current functions in my class:
here is my code so far:
bool IntSet::contains(int val) const
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
return true;
}
return false;
}
this function compares an integer parameter to values currently stored in the array...if a value is in the array it returns true and if else false;
this next function takes in a value and removes that value from the array:
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
}
numValues--;
}
here's where I've been having problems, this next function is supposed to iterate through one array and compare those values with the values in the other array...if one value from one array is in the other, it should just skip it, but if a value is not in the array calling the function, it should delete that value from the calling array:
void IntSet::removeDifferent(const IntSet &set2)
{
for (int i = 0; i < set2.size(); i++)
{
if (!set2.contains(set[i]))
{
remove(set[i]);
}
}
}
ive tried about 50 different variations on the removeDifferent() function and I just can't seem to figure this one out. Could someone point me in the right direction?
You're iterating i through the indexes of set2, but then you're testing set[i]. Try this:
void IntSet::removeDifferent(const IntSet &set2)
{
for (int i = 0; i < numValues; ) {
if (!set2.contains(set[i])) {
remove(set[i]);
} else {
i++;
}
}
Note that I also removed i++ from the for loop header. This is because when you remove an element, all the following elements are shifted down, so the next element takes its place in the array. If you incremented i, it would skip that element.
You also need to fix remove. It should start its inner loop from i, so it only shifts down the elements after the one being removed, and it should stop at numValues-1, so it doesn't try to access outside the array when it copies set[j+1]. And as an optimization, it can break out of the outer loop once it has found a match (I assume IntSet doesn't allow duplicates, since you only decrement numValues by 1).
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val) {
for (int j = i; j < numValues - 1; j++) {
set[j] = set[j + 1];
}
break;
}
}
numValues--;
}
Your problem is in your remove() function:
void IntSet::remove(int val)
{
for (int i = 0; i < numValues; i++)
{
if (set[i] == val)
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
}
numValues--;
}
You can figure out yourself why this is wrong by using a paper and pencil here. Start with a typical example: let's say you found the value you're looking for in the third element of a five-element array:
if (set[i] == val)
In this example, i would be set to 2, and numValues would be set to five. It doesn't matter what val is. Whatever it is, you found it when i is 2, and numValues is five: you found it in the third element of a five element array. Keep that in mind.
Now, you know that you are now supposed to remove the third element in this five element array. But what do you think will happen next:
for (int j = 0; j < numValues; j++)
set[j] = set[j + 1];
Well, using the aforementioned paper and pencil, if you work it out, the following will happen:
set[1] will be copied to set[0]
set[2] will be copied to set[1]
set[3] will be copied to set[2]
set[4] will be copied to set[3]
set[5] will be copied to set[4]
There are two problems here:
A) There is no set[5]. Recall that this is a five-element array, si you only have set[0] through set[4]
B) You're not supposed to copy everything in array down to one element. You have to copy only the elements after the element you want to remove.
Fix these two problems, and you will probably find that everything will work correctly.

c++ array can't get the right array

I have Array A[9]= {1,2,3,4,5,6,7,8,9} and I need to delete the numbers which are not dividing by 2. The code I tried to do:
int main()
{
int n;
ifstream fd(Cdf);
fd>>n; // read how many numbers are in the file.
int A[n];
for(int i = 0; i < n; i++)
{
fd >> A[i]; //read the numbers from file
}
for(int i = 0; i < n; i ++) // moving the numbers.
{
if(A[i] % 2 !=0)
{
for(int j = i; j < n; j++)
{
A[i] = A[i+1];
}
}
}
fd.close();
return 0;
}
But I get numbers like 224466888. what I need to do to get 2,4,6,8?
I need to delete numbers in the same array.
First you should use std::vector for dynamic size arrays.
Second, for removing numbers that are even in a vector, you can do :
std::vector<int> inf = {12,0,5,6,8};
auto func = [](int i){return i % 2 != 0;};
inf.erase(std::remove_if(inf.begin(),inf.end(),func), inf.end());
EDIT :
Ok, so you can still do this without std::vectors, but it will be uglier :
#include <algorithm>
int res[] = {2,5,9,8,6,7};
int size = 6;
auto func = [](int i){return i % 2 != 0;};
int new_size = std::remove_if(res,res + size, func) - res;
All the data you want is in [0, new_size[ range, the other part of your array is now garbage.
Your removal loop is indexing with the wrong variable:
for(int j = i; j < n; j++)
{
A[i] = A[i+1];
}
You're using i, which doesn't change in the loop.
Change it to j. You also need to subtract one from the upper limit, as you'd step outside of the array otherwise when accessing A[j + 1].
for(int j = i; j < n - 1; j++)
{
A[j] = A[j + 1];
}
An array can't be used for your purpose. It is allocated on stack and its size can't be changed dynamically (you can't change the size of an array in general, not only when it is allocated on stack).
You could allocate a second array and keep reallocating it with realloc everytime you add a new element but that's not the good way to do it. You are working with C++ so just use a std::vector<int> and your problems will be solved:
std::vector<int> evenArray;
evenArray.reserve(sizeof(A)/sizeof(A[0])/2);
if (number is even) {
evenArray.pushBack(number);
}
Mind that vector stores elements contiguously so this is legal:
int *evenA = &evenArray[0];
For your inner for loop you should be referencing j, not i.
for(int j = i; j < n - 1; j++)
{
A[j] = A[j+1];
}
Otherwise, what's the point of creating j?
Of course, this also means if you read the whole array back you will display all the characters that were shifted (which will just be equal to the last number). So, you should probably keep track of the new length of the array and just iterate to that instead of the end of the array.
EDIT:
In the inner for loop you need to loop to n - 1 otherwise when you have A[j + 1] it will go off the end of the array when you to change it, which may or may not give you a runtime error.

Sorting two arrays into a combined array

I haven't done any programming classes for a few years, so please forgive any beginner mistakes/methods of doing something. I'd love suggestions for the future. With the code below, I'm trying to check the values of two arrays (sorted already) and put them into a combined array. My solution, however inefficient/sloppy, is to use a for loop to compare the contents of each array's index at j, then assign the lower value to index i of the combinedArray and the higher value to index i+1. I increment i by 2 to avoid overwriting the previous loop's indexes.
int sortedArray1 [5] = {11, 33, 55, 77, 99};
int sortedArray2 [5] = {22, 44, 66, 88, 00};
combinedSize = 10;
int *combinedArray;
combinedArray = new int[combinedSize];
for(int i = 0; i <= combinedSize; i+=2)
{
for(int j = 0; j <= 5; j++)
{
if(sortedArray1[j] < sortedArray2[j])
{
combinedArray[i] = sortedArray1[j];
combinedArray[i+1] = sortedArray2[j];
}
else if(sortedArray1[j] > sortedArray2[j])
{
combinedArray[i] = sortedArray2[j];
combinedArray[i+1] = sortedArray1[j];
}
else if(sortedArray1[j] = sortedArray2[j])
{
combinedArray[i] = sortedArray1[j];
combinedArray[i+1] = sortedArray2[j];
}
}
}
for(int i = 0; i < combinedSize; i++)
{
cout << combinedArray[i];
cout << " ";
}
And my result is this
Sorted Array 1 contents: 11 33 55 77 99
Sorted Array 2 contents: 0 22 44 66 88
5 77 5 77 5 77 5 77 5 77 Press any key to continue . . .
In my inexperienced mind, the implementation of the sorting looks good, so I'm not sure why I'm getting this bad output. Advice would be fantastic.
what about this:
int i=0,j=0,k=0;
while(i<5 && j<5)
{
if(sortedArray1[i] < sortedArray2[j])
{
combinedArray[k]=sortedArray1[i];
i++;
}
else
{
combinedArray[k]=sortedArray2[j];
j++;
}
k++;
}
while(i<5)
{
combinedArray[k]=sortedArray1[i];
i++;k++;
}
while(j<5)
{
combinedArray[k]=sortedArray2[j];
j++; k++;
}
Firstly, there are some immediate problems with how you use C++:
You use = instead of == for equality check (hence causing undesired value assignments and the if-condition to return true when it shouldn't);
Your outer loops upper boundary is defined as i <= 10, while the correct boundary check would be i < 10;
You have a memory leak at the end of the function because you fail to de-allocate memory. You need a delete [] combinedArray at the end.
Secondly, your outer loop iterates through all values of the destination array, and in each step uses an inner loop to iterate through all values of the source arrays. That is not what you want. What you want is one loop counting from j=0 to j<5 and iterating through the source arrays. The positions in the destination array are then determined as 2*j and 2*j+1, and there is no need for an inner loop.
Thirdly, as explained in the comment, a correct implementation of sorted-list merge needs two independent counters j1 and j2. However, your current input is hardwired into the code, and if you replace 00 with 100, your current algorithm (after the corrections above are made) will actually work for the given input.
Finally, but less importantly, I wonder why your destination array is allocated on the heap using new. As long as you are dealing with small arrays, you may allocate it on the stack just like the source arrays. If, however, you allocate it on the heap, better use a std::unique_ptr<>, possibly combined with std::array<>. You'll get de-allocation for free then without having to think of putting a delete [] statement at the end of the function.
Before even looking at the implementation, check the algorithm and write it down with pen and paper. The first thing that pops is that you are assuming that the first two elements in the result will come one from each source array. That need not be the case, consider two arrays where all elements in one are smaller than all elements in the other and the expected result:
int a[] = { 1, 2, 3 };
int b[] = { 4, 5, 6 };
If you want the result sorted, then the first three elements come all from the first array. With that in mind think on what you really know about the data. In particular, both arrays are sorted, which means that the first elements will be smaller than the rest of the elements in the respective array. The implication of this is that the smaller element is the smaller of the heads. By putting that element into the result you have reduced the problem to a smaller set. You have a' = { 2, 3 }, b = { 4, 5, 6 } and res = { 1 } and a new problem that is finding the second element of res knowing that a' and b are sorted.
Figure out in paper what you need to do, then it should be straight forward to map that to code.
So, I modified your code to make it work. Actually it would be good idea to have two pointer/index for two sorted arrays. So that you can update your corresponding pointer after adding it to your combinedArray. Let me know if you don't understand any part of this code. Thanks.
int sortedArray1 [5] = {11, 33, 55, 77, 99};
int sortedArray2 [5] = {0, 22, 44, 66, 88};
int combinedSize = 10;
int *combinedArray;
combinedArray = new int[combinedSize];
int j = 0;
int k = 0;
for(int i = 0; i < combinedSize; i++)
{
if (j < 5 && k < 5) {
if (sortedArray1[j] < sortedArray2[k]) {
combinedArray[i] = sortedArray1[j];
j++;
} else {
combinedArray[i] = sortedArray2[k];
k++;
}
}
else if (j < 5) {
combinedArray[i] = sortedArray1[j];
j++;
}
else {
combinedArray[i] = sortedArray2[k];
k++;
}
}
for(int i = 0; i < combinedSize; i++)
{
cout << combinedArray[i];
cout << " ";
}
cout<<endl;
The else if(sortedArray1[j] = sortedArray2[j]), did you mean else if(sortedArray1[j] == sortedArray2[j])?
The former one will assign the value of sortedArray2[j] to sortedArray1[j] -- and that's the reason that why you get 5 77 5 77...
But where's the 5 come from? There's no 5 in either sortedArray, yet I find for(int j = 0; j <= 5; j++) must be something wrong. The highest index of a size N array is N-1 rather than N in C/C++(but not in Basic).. so use j<5 as the condition, or you may fall into some situation which is hard to explain or predict..
After all, there's problem in your algorithm itself, every time the outer loop loops, it will at last compare the last elements in the two arrays, which makes the output to repeat two numbers.
So you need to correct your algorithm too, see Merge Sort.
Slightly different approach, which is IMHO a bit cleaner:
//A is the first array, m its length
//B is the second array, n its length
printSortedAndMerged(int A[], int m, int B[], int n){
int c[n+m];
int i=0, j=0;
for(int k=0; k < n+m; k++){
if(i < m && j < n){
if(A[i] < B[j]){
c[k] = A[i];
i++;
}
else{
c[k] = B[j];
j++;
}
continue; //jump to next iteration
}
if(i < m){ // && ~(j < n)
//we already completely traversed B[]
c[k] = A[i];
i++;
continue;
}
if(j < n){ // %% ~(i < m)
//we already completely traversed A[]
c[k] = B[j];
j++;
continue;
}
//we should never reach this
cout << "Wow, something wrong happened!" << endl;
}//for
for(int i=0; i<n+m; i++){
cout << c[i] << endl;
}
}
Hope it helps.