No duplicates in an array [duplicate] - java

This question already has answers here:
How to get unique values from array
(13 answers)
Closed 8 years ago.
void RemoveDups(){
int f=0;
for(int i=1;i<nelems;i++){
if(arr[f]==arr[i]){
for(int k=i;k<nelems;k++)
{
arr[k]=arr[k+1];
}
nelems--;
}
if(i==(nelems+1)){
f++;
i=f+1; //increment again
}
}
}
This is the logic i have written to remove duplicate elements from an array ,but this is not working at all ?what changes i should make to make it work? or you people have better logic for doing the same considering time complexity.and i don't want to use built-in methods to achieve this.

int end = input.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (input[i] == input[j]) {
int shiftLeft = j;
for (int k = j + 1; k < end; k++, shiftLeft++) {
input[shiftLeft] = input[k];
}
end--;
j--;
}
}
}

I think you can use Set Collection
copy all the values to an HashSet and then using Iterator access the Values
Set<Integer> hashset= new HashSet<Integer>();

You have two options, C# has the Distinct() Linq expression that will do this for you (Missed the Java tag), however if you need to remove items, have you thought about sorting the list first, then comparing the current item to the previous item and if they're the same, remove them. It would mean your diplicate detection is only ever running through the array once.
If you're worried about sort you could easily implement an efficient bubble sort or somthing to that effect

You never decrease i after You compared for examlpe arr[0] to arr[5], You never will test arr[1] == arr[2]
You need to start a new loop (i) after You've incremented f.
try
for(int f=0;f<nelems-1;f++)
{
for(int i=f+1;i<nelems;i++)
{
...
}
}
with this nested for loop you can compare every two element of the array.

a good start is to eliminate duplicate elements without shrinking the array which is done lastly:
public class run2 extends Thread {
public static void main(String[] args) {
int arr[] = { 1, 2, 2, 3, 5, 6, 5, 5, 6, 7 };
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[j] == -1)
j++;
if (arr[i] == arr[j])
arr[j] = -1;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println();
for (int i = 0; i < arr.length; i++) {
if (arr[i] == -1) {
for (int j = i; j < arr.length; j++) {
if (arr[j] != -1) {
arr[i] = arr[j];
arr[j] = -1;
break;
}
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}

Adapt this code :
public static int[] removeDuplicates(int[] numbersWithDuplicates) {
// Sorting array to bring duplicates together
Arrays.sort(numbersWithDuplicates);
int[] result = new int[numbersWithDuplicates.length];
int previous = numbersWithDuplicates[0];
result[0] = previous;
for (int i = 1; i < numbersWithDuplicates.length; i++) {
int ch = numbersWithDuplicates[i];
if (previous != ch) {
result[i] = ch;
}
previous = ch;
}
return result;
}

As far as I understood from your code,you are comparing each value starting from index 0 to the rest of the element and when you see the element which is located at index f your are trying to shift the entire array and decrementing the size of array(nelems).Look at line no. 11
if(i==(nelems+1)){
f++;
i=f+1;
The problem is when i is set to f+1,i will again be incremented in the for loop for the next iteration.So basically i starts comparing from f+2.And also you are comparing i with (nelems+1) considering the case when nelems decremented but you are not considering the case when i reaches the end without decreasing nelems in that case i will never be equale to (nelems+1).Now considering your logic you could do 2 things.
1.Here is your working code.
for(int i=1;i<nelems;i++){
if(arr[f]==arr[i]){
for(int k=i+1;k<nelems;k++)
{
arr[k-1]=arr[k];
}
if(i==(nelems-1)){
f++;
i=f;
}
nelems--;
}
if(i==(nelems-1)){//end of the loop
f++;
i=f; //increment again
}
}
2.You could use an outer for loop alternatively that will increment the f value once the inner for is completed.
void RemoveDups(){
for(int f=0;f<nelems;++f){
for(int i=1;i<nelems;i++){
if(arr[f]==arr[i]){
for(int k=i;k<nelems;k++)
arr[k]=arr[k+1];
nelems--;
}
}
}
}
Now your problem is solved but the time complexity of your code will be(O(N^3)).
Now instead of shifting the entire array at line 4,you could just swap the arr[f] with last element.
if(arr[f]==arr[i]){
swap(arr[f],arr[nelems-1]);
nelems--;
}
it will reduce the time complexity from O(N^3) to O(N^2).
Now I'll suggest you my method
1.just sort the array.It will be done in O(NlogN).
2.now using one for loop you can get what do you wanted.
void RemoveDups(){
int k=0,i;
for(i=1;i<nelems;++i){
while(arr[i]==arr[i-1])
++i;
arr[k++]=arr[i-1];
}
arr[k++]=arr[i-1];
}
Now basically you got an array of size k,which contains non repeated element in sorted order and the time complexity of my solution is O(NlogN).

Related

what is the difference between j=i+1 and j=1 if i=0 (in a nested for loop)?

I don't understand the reason why the first for loop gives only one result, while the second gives me two results. Can someone explain to me how it works?
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
int[] array = {5,5,11,15};
int target = 10;
System.out.print("First Solution: ");
twoSum(array,target);
System.out.println();
System.out.print("Second Solution: ");
twoSum2(array,target);
}
public static void twoSum(int[] array, int target){
for(int i = 0; i < array.length; i++){
for(int j = i+1; j < array.length; j++){
if(array[i] + array[j] == target){
System.out.print(Arrays.toString(new int[]{i, j}));
}
}
}
}
// if i want all the possible solutions
public static void twoSum2(int[] array, int target){
for(int i = 0; i < array.length; i++){
for(int j = 1; j < array.length; j++){
if(array[i] + array[j] == target){
System.out.print(Arrays.toString(new int[]{i, j}));
}
}
}
}
}
first output: [0, 1]
second output: [0, 1][1, 1]
Assumption
Your use case is to find pairs of elements in array that sum up to a target value
What's happening in twoSum() method or j = i + 1 case
As the inner loop starts with the immediately next index of the outer loop you are distinct pairs which are adding up to the desired value
What's happening in twoSum2() method or j = 1 case
As the inner loop starts with the index 1 every time regardless of the outer index value you are getting duplicate pairs which are adding up to the desired value along with an erroneous situation of a single element getting counted twice(I believe it's a bug and should be handled by an if condition check). Moreover, since it's starting from index 1 instead of 0 even all duplicates are not guaranteed. This approach should be avoided if my assumption of your use case is correct
Recommendation
Try exploring the Hashset based approach for this problem here. You can utilize the code or tweak it to match your use case. It's time complexity will be linear i.e. O(n) better than the current algorithm used in your code which is quadratic i.e. O(n^2)
The first finds all (i, j) such that j > i in approx. n*n/2 steps.
The second loop is probably long. If meant for (i, j) such that i ≠ j
public static void twoSum2(int[] array, int target) {
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++){
if (j != i) {
if (array[i] + array[j] == target) {
System.out.print(Arrays.toString(new int[]{i, j}));
}
}
}
}
}
This excludes (0, 0), (1, 1), (2, 2), ...
However this takes approx. n² steps.
One could also take extend the first solution.
public static void twoSum2(int[] array, int target) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++){
if (array[i] + array[j] == target) {
System.out.print(Arrays.toString(new int[]{i, j}));
System.out.print(Arrays.toString(new int[]{j, i}));
}
}
}
}
Tip: Arrays.sort may be used so you may start with largest fitting number. And Arrays.binarySearch to find target - array[i].

Find number of duplicate that occurs in array - Java

I can't wrap my head around this. Need to find duplicates and I did. All now that is left is to print how many times a duplicate appears in the array. I just started with Java,so this needs to be hard coded for me to understand. Spend last two days trying to figure it out but with no luck.. Any help will be great! Talk is cheap,here is the code..
import java.util.Arrays;
public class LoopTest {
public static void main(String[] args) {
int[] array = {12,23,-22,0,43,545,-4,-55,43,12,0,-999,-87};
int positive_counter = 0;
int negative_counter = 0;
for (int i = 0; i < array.length; i++) {
if(array[i] > 0) {
positive_counter++;
} else if(array[i] < 0) {
negative_counter++;
}
}
int[] positive_array = new int[positive_counter];
int[] negative_array = new int[negative_counter];
positive_counter = 0;
negative_counter = 0;
for (int i = 0; i < array.length; i++) {
if(array[i] > 0) {
positive_array[positive_counter++] = array[i];
} else if(array[i] < 0) {
negative_array[negative_counter++] = array[i];
}
}
System.out.println("Positive array: " + (Arrays.toString(positive_array)));
System.out.println("Negative array: " + (Arrays.toString(negative_array)));
Arrays.sort(array);
System.out.println("Array duplicates: ");
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if(array[i] == array[j]) {
System.out.println(array[j]);
}
}
}
}
}
Since you are already sorting the array you can find the duplicates with just one loop (they will be next to each other right?). So you can do something like:
Arrays.sort(array);
System.out.println("Array duplicates: ");
int lastValueCount=1; //How many times we met the current value (at least 1 - this time)
for (int i = 1; i < array.length; i++){
if(array[i] == array[i-1])
lastValueCount++; //If it is the same as the previous increase the count
else {
if(lastValueCount>1) //If it is duplicate print it
System.out.println(array[i-1]+" was found "+lastValueCount+" times");
lastValueCount=1; //reset the counter
}
}
Result for your array is:
Array duplicates:
0 was found 2 times
12 was found 2 times
43 was found 2 times
Also you can use some of the Java bells and whistles like inserting the values into Map or something like that but I guess you are looking from an algorithmic point of view so the above is the simple answer with just one loop
Just go through your solution, first you separate positive and negative numbers in two different arrays, then you never use them, so what's the purpose of this separation ?
I am giving you just an idea related to your problem, it's better to solve it by your self so that you can get hands on Java.
Solution: you can use Dictionary-key value pair. Go through your array, put element in dictionary as a key and value as zero, on every iteration check if that key already exist in Dictionary, just increment its value. In the end, all of the values are duplicates that occurs in your array.
Hope it helps you.
From the algorithmic point of view, Veselin Davidov's answer is good (the most efficient).
In a production code, you would rather write it like this :
Map<Integer, Long> result =
Arrays.stream(array)
.boxed() //converts IntStream to Stream<Int>
.collect(Collectors.groupingBy(i -> i, Collectors.counting()));
The result is this Map :
System.out.println(result);
{0=2, 545=1, -4=1, -22=1, -87=1, -999=1, -55=1, 23=1, 43=2, 12=2}
An easy way would be using Maps. Without changing code too much:
for (int i = 0; i < array.length; i++) {
int count = 0;
for (int j = i + 1; j < array.length; j++) {
if(array[i] == array[j]) {
System.out.println(array[j]);
count++;
}
}
map.put(array[i], count);
}
Docs:
https://docs.oracle.com/javase/7/docs/api/java/util/Map.html
Edit: As a recommendation, after you are done with the example, you should analize your code and find what isn´t neccesary, what could be done better, etc.
Are all your auxiliary arrays neccesary? Are all loops necessary?
You can do it by creating an array list for duplicate values:-
Arrays.sort(array);
System.out.println("Array duplicates: ");
ArrayList<Integer> duplicates = new ArrayList<Integer>();
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array.length; j++) {
if(j != i && array[i] == array[j] && !duplicates.contains(array[i])){
duplicates.add(array[i]);
System.Out.println(duplicates[duplicates.size()-1]);
}
}
}
public static void findDuplicate(String s){
char[] charArray=s.toCharArray();
ArrayList<Character> duplicateList = new ArrayList<>();
System.out.println(Arrays.toString(charArray));
for(int i=0 ; i<=charArray.length-1; i++){
if(duplicateList.contains(charArray[i]))
continue;
for(int j=0 ; j<=charArray.length-1; j++){
if(i==j)
continue;
if(charArray[i] == charArray[j]){
duplicateList.add(charArray[j]);
System.out.println("Dupliate at "+i+" and "+j);
}
}
}
}

Remove duplicates in array, zero padding at end

I have a task, to remove duplicates in array, what by "remove" means to shift elements down by 1, and making the last element equal to 0,
so if I have int[] array = {1, 1, 2, 2, 3, 2}; output should be like:
1, 2, 3, 0, 0, 0
I tried this logic:
public class ArrayDuplicates {
public static void main(String[] args) {
int[] array = {1, 1, 2, 2, 3, 2};
System.out.println(Arrays.toString(deleteArrayDuplicates(array)));
}
public static int[] deleteArrayDuplicates(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[i] == array[j]) { //this is for comparing elements
for (; i > 0; i--) {
array[j + 1] = array[j]; //this is for shifting
}
array[array.length - 1] = 0; //making last element equal to "0"
}
}
}
return array;
}
}
But it doesn't work.. Is anyone familiar with a right solution?
I appreciate your assistance and attention very much.
Your Code:
In short, the approach you have chosen calls for a third loop variable, k, to represent the index that is currently being shifted left by 1 position.
i - the current unique item's position
j - the current position being tested for equality with unique item at i
k - the current position being shifted left due to erasure at j
Suggestion:
A more efficient approach would be to eliminate the repetitive left shifting which occurs each time a duplicate is found and instead keep track of an offset based on the number of duplicates found:
private static int[] deleteArrayDuplicates(int[] array) {
int dupes = 0; // total duplicates
// i - the current unique item's position
for (int i = 0; i < array.length - 1 - dupes; i++) {
int idupes = 0; // duplicates for current value of i
// j - the current position being tested for equality with unique item at i
for (int j = i + 1; j < array.length - dupes; j++) {
if (array[i] == array[j]) {
idupes++;
dupes++;
} else if(idupes > 0){
array[j-idupes] = array[j];
}
}
}
if(dupes > 0) {
Arrays.fill(array, array.length-dupes, array.length, 0);
}
return array;
}
This has similar complexity to the answer posted by dbl, although it should be slightly faster due to eliminating some extra loops at the end. Another advantage is that this code doesn't rely on any assumptions that the input should not contain zeroes, unlike that answer.
#artshakhov:
Here is my approach, which is pretty much close enough to what you've found but using a bit fewer operations...
private static int[] deleteArrayDuplicates(int[] array) {
for (int i = 0; i < array.length - 1; i++) {
if (array[i] == NEUTRAL) continue; //if zero is a valid input value then don't waste time with it
int idx = i + 1; //no need for third cycle, just use memorization for current shifting index.
for (int j = i + 1; j < array.length; j++) {
if (array[i] == array[j]) {
array[j] = NEUTRAL;
} else {
array[idx++] = array[j];
}
}
}
return array;
}
I just wrote the following code to answer your question. I tested it and I am getting the output you expected. If there are any special cases I may have missed, I apologize but it seemed to work for a variety of inputs including yours.
The idea behind is that we will be using a hash map to keep track if we have already seen a particular element in our array as we are looping through the array. If the map already contains that element- meaning we have already seen that element in our array- we just keep looping. However, if it is our first time seeing that element, we will update the element at the index where j is pointing to the element at the index where i is pointing to and then increment j.
So basically through the j pointer, we are able to move all the distinct elements to the front of the array while also making sure it is in the same order as it is in our input array.
Now after the first loop, our j pointer points to the first repeating element in our array. We can just set i to j and loop through the rest of the array, making them zero.
The time complexity for this algorithm is O(N). The space complexity is O(N) because of the hash table. There is probably a way to do this in O(N) time, O(1) space.
public static int[] deleteArrayDuplicates(int[] array) {
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
int j = 0;
for (int i = 0; i < array.length; i++) {
if (map.containsKey(array[i])) {
continue;
}
else {
map.put(array[i],1);
array[j] = array[i];
j++;
}
}
for (int i = j; i < array.length; i++) {
array[i] = 0;
}
return array;
}
Let me know if you have additional questions.
Spent a couple of hours trying to find a solution for my own, and created something like this:
public static int[] deleteArrayDuplicates(int[] array) {
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if (array[j] == array[i]) { //this is for comparing elements
int tempIndex = j;
while (tempIndex + 1 < array.length) {
array[tempIndex] = array[tempIndex + 1]; //this is for shifting elements down/left by "1"
array[array.length - 1] = 0; //making last element equal to "0"
tempIndex++;
}
}
}
}
return array;
}
Code is without any API-helpers, but seems like is working now.
Try this:
public static void main(String[] args)
{
int a[]={1,1,1,2,3,4,5};
int b[]=new int[a.length];
int top=0;
for( int i : a )
{
int count=0;
for(int j=0;j<top;j++)
{
if(i == b[j])
count+=1;
}
if(count==0)
{
b[top]=i;
top+=1;
}
}
for(int i=0 ; i < b.length ; i++ )
System.out.println( b[i] );
}
Explanation:
Create an another array ( b ) of same size of the given array.Now just include only the unique elements in the array b. Add the elements of array a to array b only if that element is not present in b.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class StackOverFlow {
public static void main(String[] args) {
int[] array = {1, 1, 2, 2, 3, 2};
Set<Integer> set=new HashSet<>();
for (int anArray : array) {
set.add(anArray);
}
int[] a=new int[array.length];
int i=0;
for (Integer s:set) {
a[i]=s;
i++;
}
System.out.println(Arrays.toString(a));
}
}
Hope this simple one may help you.
Make use of Set which doesn't allow duplicates.
We can use ARRAYLIST and Java-8 Streams features to get the output.
public static int[] deleteArrayDuplicates(int[] array) {
List<Integer> list = new ArrayList(Arrays.stream(array).boxed().distinct().collect(Collectors.toList()));
for (int i = 0; i < array.length; i++) {
if (i < list.size()) {
array[i] = list.get(i);
} else {
array[i] = 0;
}
}
return array;
}
OUTPUT
[1, 2, 3, 0, 0, 0]

Array Manipulation - Move items up and Add Similar in Java

So, I am having to do some complicated Array manipulation and am having some difficulty. Thought i might ask you guys for help.
Anyhow, What i am trying to do is basically the following.
Let's say i have an array of numbers, with zeroes peppered. So, What i wanna do is move all elements up to the top of the array and therefore, fill the elements with zereos in them.
I'll use an example to explain ;
Let's say the array is : {4,4,0,2,0,2}
What i wanna do is : {4,4,2,2,0,0}
So, all the numbers are in one area basically and sorted.
Now, the second thing i wanna do is add all similar numbers, so if we continue with the above example : {8,4,0,0,0,0}
Now, what i have tried to is basically run through the whole loop and move the next item back when i see a zero and replace that with a zero but that is leading to some issues.
Some suggestions would be awesome. Thansk
Edit :
I figured out how to do the sorting etc and a little bit of the addition , Here is what i have. Please let me know if you suggestions to make it better.
for(int j = 0; j < row.length ; j++){
for(int i = 0 ; i < row.length ; i++){
if(row[i] == 0){
row[i] = row[i+1];
row[i+1] = 0;
} else if(row[i] == row[i+1] ){
row[i] = row[i+1] + row[i];
row[i+1] = 0;
}
}
}
}
However, the sorting is all fine but there is a slight issue with the addition of similar elements.
So, If we something like {2,2,2,2,0,0} after sorting then my addition part will do this : {8,0,0,0,0,0} which isn't what i want. What it should be is {4,4,0,0,0,0}
A simple way to do that is to split the work in two parts: Combine pairs, and push elements left. About the order of operations:
pushLeft then combine
Orignal array: {4,2,0,2,0,4}
After pushLeft: {4,2,2,4,0,0}
After combine: {4,4,4,0,0,0}
With this order, you have to take care of the holes you create while combining values.
combine then pushLeft
Orignal array: {4,2,0,2,0,4}
After combine: {4,4,0,0,0,4}
After pushLeft: {4,4,4,0,0,0}
Those can be implemented using a simple loop for each function. There is also the possibility to do it all in a single loop (combining and pushing left), but it is more tricky.
My code is below (2nd method), but you may want to give it a try yourself before:
public static int[] goLeft(int[] a) {
int[] arr = a.clone();
for (int j = 0, i = 0; j < arr.length; j++) {
if (arr[j] != 0) {
arr[i] = arr[j];
if (i++ != j) arr[j] = 0;
}
}
return arr;
}
public static int[] combine(int[] a) {
int[] arr = a.clone();
for (int j = 1, i = 0; j < arr.length; j++) {
if (arr[i] == 0 && arr[j] != 0) {
i = j;
} else if (arr[j] != 0 && i != j) {
if (arr[j] == arr[i]) {
arr[i] *= 2;
arr[j] = 0;
i = j;
} else {
i = j;
}
}
}
return arr;
}
public static void main(String[] args) {
int[] a1 = new int[] {4,2,0,2,4};
System.out.println(Arrays.toString(a1));
System.out.println(Arrays.toString(Main.goLeft(Main.combine(a1))));
// [4, 4, 4, 0, 0]
}

difference between these two bubble sort implementations [duplicate]

This question already has answers here:
bubble sort with a boolean to determine whether array is already sorted
(3 answers)
Closed 8 years ago.
I have two implementations of bubble sort, but one of them works fine and other one does not can anybody explain me what is the difference in these two
first one this works fine
private static int[] sortBuble(int[] a) {
boolean swapped = true;
for (int i = 0; i < a.length && swapped; i++) {
swapped = false;
System.out.println("number of iteration" + i);
for (int j = 1; j < a.length; j++) {
if (a[j - 1] > a[j]) {
int temp = a[j - 1];
a[j - 1] = a[j];
a[j] = temp;
swapped = true;
}
}
}
return a;
}
Second one this does not work, but they look more or less same
private static int[] sortBuble1(int[] a) {
boolean swapped = true;
for (int i = 0; i < a.length && swapped; i++) {
swapped = false;
System.out.println("number of iteration" + i);
for (int j = i + 1; j < a.length; j++) {
if (a[i] > a[j]) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
swapped = true;
}
}
}
return a;
}
They are not the same. You are holding i constant for each iteration of the inner-for loop in the second example, and using a[i] for comparison, which is just incorrect. As I said in my other answer, the first is also inefficient. The following is an optimized version of the first one:
private static int[] bubblesort(int[] nums)
{
boolean done = false;
for (int i = 0; i < nums.length && !done; i++)
{
done = true;
for (int j = nums.length-1; j > i; j--)
{
if (nums[j] < nums[j-1])
{
int temp = nums[j];
nums[j] = nums[j-1];
nums[j-1] = temp;
done = false;
}
}
}
return nums;
}
At the end of the ith iteration, we know that the first i elements are sorted, so we don't need to look at them anymore. We need the boolean to determine if we need to continue or not. If no swaps are made, then we are done. We can remove the boolean and it will still work, but will be less efficient.
The difference lies in the indexes used for the arrays.
In the first case, your inner for loop with j is independent of i. Also, you use adjacent values of j while swapping, so that you are always swapping adjacent values in the array.
In the second case, your inner for loop starts j from i + 1. And you're using both i and j to index your array. So you're actually not comparing adjacent elements, but elements that may be far apart (e.g., when i=1 and j=4). That is not bubble sort, and this algorithm will not work that way.

Categories

Resources