My dividing sequence code does not solve all problems presented to it - java

This problem is about sequences of positive integers a1,a2,…,aN. A subsequence of a sequence is anything obtained by dropping some of the elements. For example, 3,7,11,3 is a subsequence of 6,3,11,5,7,4,3,11,5,3 , but 3,3,7 is not a subsequence of 6,3,11,5,7,4,3,11,5,3 .
A fully dividing sequence is a sequence a1,a2,…,aN where ai divides aj whenever i < j. For example, 3,15,60,720 is a fully dividing sequence.
Given a sequence of integers your aim is to find the length of the longest fully dividing subsequence of this sequence.
Consider the sequence 2,3,7,8,14,39,145,76,320
It has a fully dividing sequence of length 3, namely 2,8,320, but none of length 4 or greater.
Consider the sequence 2,11,16,12,36,60,71,17,29,144,288,129,432,993 .
It has two fully dividing subsequences of length 5 - (2,12,36,144,288) or (2,12,36,144,432).
To solve this problem, I have written the following code:
import java.util.Scanner;
class DivSeq {
private int n, input[];
void accept() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
input = new int[n];
for(int i = 0; i<n; i++)
input[i] = sc.nextInt();
sc.close();
}
int size(int a[]) {
//this function returns the number of non zero entries in an array
int ctr = 0;
for(int i = 0; i<a.length; i++) {
if(a[i]==0)
break;
else
ctr++;
}
return ctr;
}
int sequence() {
int subseq[], pvrseq[], seq[], j, a = 1, q, k = 1, f = 0;
subseq = new int [n];
pvrseq = new int [n];
seq = new int [n];
for(int i = 0; i<n-1; i++) {
k = 1;
for(int c = 0; c<seq.length; c++)
seq[c] = 0;
//seq has been initialized, now inserting 1st value
seq[0] = input[i];
//creating the sequence
for(j = i+1; j<n; j++) {
if(input[j]%input[i]==0)
seq[k++] = input[j];
}
//if size of sequence is 1, then there is no use of checking it
if(size(seq)<2)
continue;
subseq[0] = seq[0];
a = 1;
while(a<size(seq)-1) {
k = 2;
for(int p = a; p<size(seq)-1; p++) {
//initial value of subsequence
if(subseq[1] == 0)
subseq[1] = seq[p];
//creating the subsequence
for(q = p+1; q<size(seq); q++) {
if(seq[q]%seq[p]==0) {
subseq[k++] = seq[q];
p = q-1;
f = 1;
break;
}
}
if(f==1 && q==size(seq)-1)
break;
}
//checking the size of subsequence and previous sequence
if(size(pvrseq)<size(subseq)) {
for(int y = 0; y<subseq.length; y++)
pvrseq[y] = subseq[y];
for(int y = 1; y<subseq.length; y++)
subseq[y] = 0;
}
a++;
}
}
return size(pvrseq);
}
public static void main(String [] args) {
DivSeq obj = new DivSeq();
obj.accept();
System.out.println(obj.sequence());
}
}
This code solves some of the test cases that it is supposed to solve.
case 1: 2,3,7,8,14,39,145,76,320
desired output = 3
case 2: 2,11,16,12,36,60,71,17,29,144,288,129,432,993
desired output = 5
Rest of the test cases are invisible.
However, it does not solve all of them and I cannot understand why. It manages to meet only 4/11 test cases (including case 1 and case 2).

#LuCio and #Aldert I found an alternate way to solve the problem. Here is the code:
import java.util.Scanner;
class DivSeqUpdated {
private int n, input[], weight[];
void accept() {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
input = new int[n];
weight = new int[n];
for(int i = 0; i<n; i++)
input[i] = sc.nextInt();
sc.close();
}
int max(int x, int y) {
return x<y?y:x;
}
int sequence(int src, int a[], int n) {
if(weight[src]==-1) {
int i, tmp = 0;
for(i = src+1; i<n; i++) {
if(a[i]%a[src]==0)
tmp = max(tmp, sequence(i,a,n));
}
weight[src] = tmp+1;
}
return weight[src];
}
public static void main(String [] args) {
DivSeqUpdated obj = new DivSeqUpdated();
obj.accept();
for(int i = 0; i<obj.n; i++)
obj.weight[i] = -1;
int tmp = 0;
for(int i = 0; i<obj.n; i++)
tmp = obj.max(tmp, obj.sequence(i,obj.input,obj.n));
System.out.println(tmp);
}
}
It gives a result of 11/11 tests which solves the issue. I hope this can help other users as well.

I would take a recursive approach to determine the longest subsequence of a sequence.
protected static int[] subsequence(int[] seq) {
int[] longestSub = new int[0];
for (int i = 0; i < seq.length; i++) {
int[] subAtI = subseq(subarray(seq, i));
if (longestSub.length < subAtI.length) {
longestSub = subAtI;
}
}
return longestSub;
}
private static int[] subseq(int[] seq) {
if (seq.length == 1) {
return seq;
}
int[] longestSub = new int[0];
int current = seq[0];
for (int i = 1; i < seq.length; i++) {
int number = seq[i];
if (number > 0 && current > 0 && number % current == 0) {
int[] subAtI = subseq(subarray(seq, i));
if (longestSub.length < subAtI.length) {
longestSub = subAtI;
}
}
}
return concat(current, longestSub);
}
private static int[] concat(int current, int[] sub) {
int[] result = new int[sub.length + 1];
result[0] = current;
System.arraycopy(sub, 0, result, 1, sub.length);
return result;
}
private static int[] subarray(int[] seq, int i) {
int length = seq.length - i;
int[] result = new int[length];
System.arraycopy(seq, i, result, 0, length);
return result;
}
For a sequence iterate over each integer (seq[i]) and determine the subsequence for that integer (subsequence(subarray(seq, i))). The longest subsequence is the result.
Applying that to some example from the question:
public static void main(String[] args) throws IOException {
printLongestSub(new int[] { 2, 11, 16, 12, 36, 60, 71, 17, 29, 144, 288, 129, 432, 993 }); // [2, 12, 36, 144, 288]
printLongestSub(new int[] { 2, 3, 7, 8, 14, 39, 145, 76, 320 }); // [2, 8, 320]
printLongestSub(new int[] { 2 }); // [2]
printLongestSub(new int[] { 2, 5 }); // [2]
printLongestSub(new int[] { 5, 6, 12 }); // [6, 12]
printLongestSub(new int[] { 5, 6, 12, 11, 33, 99 }); // [11, 33, 99]
}
private static void printLongestSub(int[] seq) {
System.out.println(Arrays.toString(subsequence(seq)));
}

Related

Java concatenate two arrays into one and sort it

My task is to concatenate two arrays into one and sort it. I have already concatenated arrays, but can't sort it.
My idea: Create a new array. In concatenated array through the loop, find the smallest element, push it to a new array and in the end, make it the largest number. However, this approach doesn't work.
My Code:
public class Concat_arrays {
public static void main(String[] args) {
int[] a1 = {4, 5, 3, 2, 1};
int[] a2 = {10, 29, 0};
int[] a3 = new int[a2.length+a1.length];
int index = 0;
for (int i = index; i<a1.length; i++) {
a3[i] = a1[i];
index++;
}
int indexA2 = 0;
while (indexA2<a2.length) {
a3[index] = a2[indexA2];
index++;
indexA2++;
}
int[] a4 = new int[a3.length];
for (int i = 0; i<a3.length; i++) {
int min_index = getMin(a3);
a4[i] = a3[min_index];
a3[min_index] = 999999;
}
}
public static int getMin(int[] array) {
int min_element = 0;
int min_element_index = 0;
for (int i = 0; i<array.length; i++) {
if (min_element>=array[i]) {
min_element_index = i;
}
}
return min_element_index;
}
Output:
4
999999
999999
999999
999999
999999
999999
999999
You are on the right track on your idea, but your getMin method is incorrect. I have updated it below. (Your idea can be improved)
public static int getMin(int[] array) {
int min_element = Integer.MAX_VALUE; // Do not set it to 0 since there might be elements that has the value of 0
int min_element_index = 0;
for (int i = 0; i < array.length; i++) {
if (min_element >= array[i]) {
min_element = array[i]; // You have to update your minimum element
min_element_index = i;
}
}
return min_element_index;
}
Also in this part a3[min_index] = 999999; better to set it to a3[min_index] = Integer.MAX_VALUE; since there might be elements which are greater than 999999.
You can use Java Streams, a special kind of collections:
int[] a1 = {4, 5, 3, 2, 1};
int[] a2 = {10, 29, 0};
Stream<Integer> a1Stream = Stream.of(4, 5, 3, 2, 1);
Stream<Integer> a2Stream = Stream.of(10, 29, 0);
Stream<Integer> finalArray = Stream.concat(a1Stream, a2Stream).sorted();
finalArray.forEach(s -> System.out.println(s));

Using an array to find the multiples of two ints

Im a programming student and im having alot of trouble with this question:
"complete a static method multiplesOf which takes two int parameters, number and count. The method body must return an int array containing the first count multiples of number. For example,
multiplesOf(5, 4) should return the array { 5, 10, 15, 20 }
multiplesOf(11, 3) should return the array { 11, 22, 33 }
multiplesOf(1, 15) should return the array { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }
You must not use System.out.print or System.out.println in your method."
This is my current code:
public static void main(String[] args) {
multiplesOf(5,4);
}
public static int[] multiplesOf (int number, int count) {
int[] a = new int[count];
a[0]= number;
for(int i = 0; i<count; i++) {
a[i] = (a[i]*count);
}
return a;
}
Ive been trying to figure out why the array "a" still only has the values 0,1,2,3
Try:
public static int[] multiplesOf(int number, int count) {
int[] a = new int[count];
for(int i = 1; i <= count; i++) {
a[i - 1] = number * i;
}
return a;
}
a[0] = number;
for(int i = 1; i<count; i++)
{
a[i] = (i+1)*number;
}
try this
public static int[] multiplesOf (int number, int count)
{
int[] a = new int[count];
a[0] = number;
for(int i = 1; i<count; i++)
{
a[i] = number * (i + 1);
}
return a;
}
output
[5, 10, 15, 20]
public static int[] multiplesOf(int number, int count) {
int[] a = new int[count];
for (int i = 0; i < count; i++) {
a[i] = (number * (i+1));
}
return a;
}
use this
public static int[] multiplesOf (int number, int count) {
int[] a = new int[count];
for(int i = 1; i<=count; i++) {
//a[i-1] beacuse we started iterating array at i=1
a[i-1] = (i*number);
}
return a;
}
multiplesOf(5, 4) returns -> the array { 5, 10, 15, 20 }

how to print non repeated numbers from integer array using java and without using predefined api's? [duplicate]

I was asked to write my own implementation to remove duplicated values in an array. Here is what I have created. But after tests with 1,000,000 elements it took very long time to finish. Is there something that I can do to improve my algorithm or any bugs to remove ?
I need to write my own implementation - not to use Set, HashSet etc. Or any other tools such as iterators. Simply an array to remove duplicates.
public static int[] removeDuplicates(int[] arr) {
int end = arr.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (arr[i] == arr[j]) {
int shiftLeft = j;
for (int k = j+1; k < end; k++, shiftLeft++) {
arr[shiftLeft] = arr[k];
}
end--;
j--;
}
}
}
int[] whitelist = new int[end];
for(int i = 0; i < end; i++){
whitelist[i] = arr[i];
}
return whitelist;
}
you can take the help of Set collection
int end = arr.length;
Set<Integer> set = new HashSet<Integer>();
for(int i = 0; i < end; i++){
set.add(arr[i]);
}
now if you will iterate through this set, it will contain only unique values. Iterating code is like this :
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
If you are allowed to use Java 8 streams:
Arrays.stream(arr).distinct().toArray();
Note: I am assuming the array is sorted.
Code:
int[] input = new int[]{1, 1, 3, 7, 7, 8, 9, 9, 9, 10};
int current = input[0];
boolean found = false;
for (int i = 0; i < input.length; i++) {
if (current == input[i] && !found) {
found = true;
} else if (current != input[i]) {
System.out.print(" " + current);
current = input[i];
found = false;
}
}
System.out.print(" " + current);
output:
1 3 7 8 9 10
Slight modification to the original code itself, by removing the innermost for loop.
public static int[] removeDuplicates(int[] arr){
int end = arr.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (arr[i] == arr[j]) {
/*int shiftLeft = j;
for (int k = j+1; k < end; k++, shiftLeft++) {
arr[shiftLeft] = arr[k];
}*/
arr[j] = arr[end-1];
end--;
j--;
}
}
}
int[] whitelist = new int[end];
/*for(int i = 0; i < end; i++){
whitelist[i] = arr[i];
}*/
System.arraycopy(arr, 0, whitelist, 0, end);
return whitelist;
}
There exists many solution of this problem.
The sort approach
You sort your array and resolve only unique items
The set approach
You declare a HashSet where you put all item then you have only unique ones.
You create a boolean array that represent the items all ready returned, (this depend on your data in the array).
If you deal with large amount of data i would pick the 1. solution. As you do not allocate additional memory and sorting is quite fast. For small set of data the complexity would be n^2 but for large i will be n log n.
Since you can assume the range is between 0-1000 there is a very simple and efficient solution
//Throws an exception if values are not in the range of 0-1000
public static int[] removeDuplicates(int[] arr) {
boolean[] set = new boolean[1001]; //values must default to false
int totalItems = 0;
for (int i = 0; i < arr.length; ++i) {
if (!set[arr[i]]) {
set[arr[i]] = true;
totalItems++;
}
}
int[] ret = new int[totalItems];
int c = 0;
for (int i = 0; i < set.length; ++i) {
if (set[i]) {
ret[c++] = i;
}
}
return ret;
}
This runs in linear time O(n). Caveat: the returned array is sorted so if that is illegal then this answer is invalid.
class Demo
{
public static void main(String[] args)
{
int a[]={3,2,1,4,2,1};
System.out.print("Before Sorting:");
for (int i=0;i<a.length; i++ )
{
System.out.print(a[i]+"\t");
}
System.out.print ("\nAfter Sorting:");
//sorting the elements
for(int i=0;i<a.length;i++)
{
for(int j=i;j<a.length;j++)
{
if(a[i]>a[j])
{
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
//After sorting
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+"\t");
}
System.out.print("\nAfter removing duplicates:");
int b=0;
a[b]=a[0];
for(int i=0;i<a.length;i++)
{
if (a[b]!=a[i])
{
b++;
a[b]=a[i];
}
}
for (int i=0;i<=b;i++ )
{
System.out.print(a[i]+"\t");
}
}
}
OUTPUT:Before Sortng:3 2 1 4 2 1 After Sorting:1 1 2 2 3 4
Removing Duplicates:1 2 3 4
Since this question is still getting a lot of attention, I decided to answer it by copying this answer from Code Review.SE:
You're following the same philosophy as the bubble sort, which is
very, very, very slow. Have you tried this?:
Sort your unordered array with quicksort. Quicksort is much faster
than bubble sort (I know, you are not sorting, but the algorithm you
follow is almost the same as bubble sort to traverse the array).
Then start removing duplicates (repeated values will be next to each
other). In a for loop you could have two indices: source and
destination. (On each loop you copy source to destination unless they
are the same, and increment both by 1). Every time you find a
duplicate you increment source (and don't perform the copy).
#morgano
import java.util.Arrays;
public class Practice {
public static void main(String[] args) {
int a[] = { 1, 3, 3, 4, 2, 1, 5, 6, 7, 7, 8, 10 };
Arrays.sort(a);
int j = 0;
for (int i = 0; i < a.length - 1; i++) {
if (a[i] != a[i + 1]) {
a[j] = a[i];
j++;
}
}
a[j] = a[a.length - 1];
for (int i = 0; i <= j; i++) {
System.out.println(a[i]);
}
}
}
**This is the most simplest way**
What if you create two boolean arrays: 1 for negative values and 1 for positive values and init it all on false.
Then you cycle thorugh the input array and lookup in the arrays if you've encoutered the value already.
If not, you add it to the output array and mark it as already used.
package com.pari.practice;
import java.util.HashSet;
import java.util.Iterator;
import com.pari.sort.Sort;
public class RemoveDuplicates {
/**
* brute force- o(N square)
*
* #param input
* #return
*/
public static int[] removeDups(int[] input){
boolean[] isSame = new boolean[input.length];
int sameNums = 0;
for( int i = 0; i < input.length; i++ ){
for( int j = i+1; j < input.length; j++){
if( input[j] == input[i] ){ //compare same
isSame[j] = true;
sameNums++;
}
}
}
//compact the array into the result.
int[] result = new int[input.length-sameNums];
int count = 0;
for( int i = 0; i < input.length; i++ ){
if( isSame[i] == true) {
continue;
}
else{
result[count] = input[i];
count++;
}
}
return result;
}
/**
* set - o(N)
* does not guarantee order of elements returned - set property
*
* #param input
* #return
*/
public static int[] removeDups1(int[] input){
HashSet myset = new HashSet();
for( int i = 0; i < input.length; i++ ){
myset.add(input[i]);
}
//compact the array into the result.
int[] result = new int[myset.size()];
Iterator setitr = myset.iterator();
int count = 0;
while( setitr.hasNext() ){
result[count] = (int) setitr.next();
count++;
}
return result;
}
/**
* quicksort - o(Nlogn)
*
* #param input
* #return
*/
public static int[] removeDups2(int[] input){
Sort st = new Sort();
st.quickSort(input, 0, input.length-1); //input is sorted
//compact the array into the result.
int[] intermediateResult = new int[input.length];
int count = 0;
int prev = Integer.MIN_VALUE;
for( int i = 0; i < input.length; i++ ){
if( input[i] != prev ){
intermediateResult[count] = input[i];
count++;
}
prev = input[i];
}
int[] result = new int[count];
System.arraycopy(intermediateResult, 0, result, 0, count);
return result;
}
public static void printArray(int[] input){
for( int i = 0; i < input.length; i++ ){
System.out.print(input[i] + " ");
}
}
public static void main(String[] args){
int[] input = {5,6,8,0,1,2,5,9,11,0};
RemoveDuplicates.printArray(RemoveDuplicates.removeDups(input));
System.out.println();
RemoveDuplicates.printArray(RemoveDuplicates.removeDups1(input));
System.out.println();
RemoveDuplicates.printArray(RemoveDuplicates.removeDups2(input));
}
}
Output:
5 6 8 0 1 2 9 11
0 1 2 5 6 8 9 11
0 1 2 5 6 8 9 11
I have just written the above code for trying out. thanks.
public static int[] removeDuplicates(int[] arr){
HashSet<Integer> set = new HashSet<>();
final int len = arr.length;
//changed end to len
for(int i = 0; i < len; i++){
set.add(arr[i]);
}
int[] whitelist = new int[set.size()];
int i = 0;
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
whitelist[i++] = it.next();
}
return whitelist;
}
Runs in O(N) time instead of your O(N^3) time
Not a big fun of updating user input, however considering your constraints...
public int[] removeDup(int[] nums) {
Arrays.sort(nums);
int x = 0;
for (int i = 0; i < nums.length; i++) {
if (i == 0 || nums[i] != nums[i - 1]) {
nums[x++] = nums[i];
}
}
return Arrays.copyOf(nums, x);
}
Array sort can be easily replaced with any nlog(n) algorithm.
This is simple way to sort the elements in the array
public class DublicatesRemove {
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("enter size of the array");
int l = Integer.parseInt(br.readLine());
int[] a = new int[l];
// insert elements in the array logic
for (int i = 0; i < l; i++)
{
System.out.println("enter a element");
int el = Integer.parseInt(br.readLine());
a[i] = el;
}
// sorting elements in the array logic
for (int i = 0; i < l; i++)
{
for (int j = 0; j < l - 1; j++)
{
if (a[j] > a[j + 1])
{
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
// remove duplicate elements logic
int b = 0;
a[b] = a[0];
for (int i = 1; i < l; i++)
{
if (a[b] != a[i])
{
b++;
a[b]=a[i];
}
}
for(int i=0;i<=b;i++)
{
System.out.println(a[i]);
}
}
}
Okay, so you cannot use Set or other collections. One solution I don't see here so far is one based on the use of a Bloom filter, which essentially is an array of bits, so perhaps that passes your requirements.
The Bloom filter is a lovely and very handy technique, fast and space-efficient, that can be used to do a quick check of the existence of an element in a set without storing the set itself or the elements. It has a (typically small) false positive rate, but no false negative rate. In other words, for your question, if a Bloom filter tells you that an element hasn't been seen so far, you can be sure it hasn't. But if it says that an element has been seen, you actually need to check. This still saves a lot of time if there aren't too many duplicates in your list (for those, there is no looping to do, except in the small probability case of a false positive --you typically chose this rate based on how much space you are willing to give to the Bloom filter (rule of thumb: less than 10 bits per unique element for a false positive rate of 1%).
There are many implementations of Bloom filters, see e.g. here or here, so I won't repeat that in this answer. Let us just assume the api described in that last reference, in particular, the description of put(E e):
true if the Bloom filter's bits changed as a result of this operation. If the bits changed, this is definitely the first time object has been added to the filter. If the bits haven't changed, this might be the first time object has been added to the filter. (...)
An implementation using such a Bloom filter would then be:
public static int[] removeDuplicates(int[] arr) {
ArrayList<Integer> out = new ArrayList<>();
int n = arr.length;
BloomFilter<Integer> bf = new BloomFilter<>(...); // decide how many bits and how many hash functions to use (compromise between space and false positive rate)
for (int e : arr) {
boolean might_contain = !bf.put(e);
boolean found = false;
if (might_contain) {
// check if false positive
for (int u : out) {
if (u == e) {
found = true;
break;
}
}
}
if (!found) {
out.add(e);
}
}
return out.stream().mapToInt(i -> i).toArray();
}
Obviously, if you can alter the incoming array in place, then there is no need for an ArrayList: at the end, when you know the actual number of unique elements, just arraycopy() those.
For a sorted Array, just check the next index:
//sorted data!
public static int[] distinct(int[] arr) {
int[] temp = new int[arr.length];
int count = 0;
for (int i = 0; i < arr.length; i++) {
int current = arr[i];
if(count > 0 )
if(temp[count - 1] == current)
continue;
temp[count] = current;
count++;
}
int[] whitelist = new int[count];
System.arraycopy(temp, 0, whitelist, 0, count);
return whitelist;
}
You need to sort your array then then loop and remove duplicates. As you cannot use other tools you need to write be code yourself.
You can easily find examples of quicksort in Java on the internet (on which this example is based).
public static void main(String[] args) throws Exception {
final int[] original = new int[]{1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1};
System.out.println(Arrays.toString(original));
quicksort(original);
System.out.println(Arrays.toString(original));
final int[] unqiue = new int[original.length];
int prev = original[0];
unqiue[0] = prev;
int count = 1;
for (int i = 1; i < original.length; ++i) {
if (original[i] != prev) {
unqiue[count++] = original[i];
}
prev = original[i];
}
System.out.println(Arrays.toString(unqiue));
final int[] compressed = new int[count];
System.arraycopy(unqiue, 0, compressed, 0, count);
System.out.println(Arrays.toString(compressed));
}
private static void quicksort(final int[] values) {
if (values.length == 0) {
return;
}
quicksort(values, 0, values.length - 1);
}
private static void quicksort(final int[] values, final int low, final int high) {
int i = low, j = high;
int pivot = values[low + (high - low) / 2];
while (i <= j) {
while (values[i] < pivot) {
i++;
}
while (values[j] > pivot) {
j--;
}
if (i <= j) {
swap(values, i, j);
i++;
j--;
}
}
if (low < j) {
quicksort(values, low, j);
}
if (i < high) {
quicksort(values, i, high);
}
}
private static void swap(final int[] values, final int i, final int j) {
final int temp = values[i];
values[i] = values[j];
values[j] = temp;
}
So the process runs in 3 steps.
Sort the array - O(nlgn)
Remove duplicates - O(n)
Compact the array - O(n)
So this improves significantly on your O(n^3) approach.
Output:
[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1]
[1, 1, 1, 2, 4, 4, 7, 8, 8, 9, 9]
[1, 2, 4, 7, 8, 9, 0, 0, 0, 0, 0]
[1, 2, 4, 7, 8, 9]
EDIT
OP states values inside array doesn't matter really. But I can assume that range is between 0-1000. This is a classic case where an O(n) sort can be used.
We create an array of size range +1, in this case 1001. We then loop over the data and increment the values on each index corresponding to the datapoint.
We can then compact the resulting array, dropping values the have not been incremented. This makes the values unique as we ignore the count.
public static void main(String[] args) throws Exception {
final int[] original = new int[]{1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000};
System.out.println(Arrays.toString(original));
final int[] buckets = new int[1001];
for (final int i : original) {
buckets[i]++;
}
final int[] unique = new int[original.length];
int count = 0;
for (int i = 0; i < buckets.length; ++i) {
if (buckets[i] > 0) {
unique[count++] = i;
}
}
final int[] compressed = new int[count];
System.arraycopy(unique, 0, compressed, 0, count);
System.out.println(Arrays.toString(compressed));
}
Output:
[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000]
[1, 2, 4, 7, 8, 9, 1000]
public static void main(String args[]) {
int[] intarray = {1,2,3,4,5,1,2,3,4,5,1,2,3,4,5};
Set<Integer> set = new HashSet<Integer>();
for(int i : intarray) {
set.add(i);
}
Iterator<Integer> setitr = set.iterator();
for(int pos=0; pos < intarray.length; pos ++) {
if(pos < set.size()) {
intarray[pos] =setitr.next();
} else {
intarray[pos]= 0;
}
}
for(int i: intarray)
System.out.println(i);
}
I know this is kinda dead but I just wrote this for my own use. It's more or less the same as adding to a hashset and then pulling all the elements out of it. It should run in O(nlogn) worst case.
public static int[] removeDuplicates(int[] numbers) {
Entry[] entries = new Entry[numbers.length];
int size = 0;
for (int i = 0 ; i < numbers.length ; i++) {
int nextVal = numbers[i];
int index = nextVal % entries.length;
Entry e = entries[index];
if (e == null) {
entries[index] = new Entry(nextVal);
size++;
} else {
if(e.insert(nextVal)) {
size++;
}
}
}
int[] result = new int[size];
int index = 0;
for (int i = 0 ; i < entries.length ; i++) {
Entry current = entries[i];
while (current != null) {
result[i++] = current.value;
current = current.next;
}
}
return result;
}
public static class Entry {
int value;
Entry next;
Entry(int value) {
this.value = value;
}
public boolean insert(int newVal) {
Entry current = this;
Entry prev = null;
while (current != null) {
if (current.value == newVal) {
return false;
} else if(current.next != null) {
prev = current;
current = next;
}
}
prev.next = new Entry(value);
return true;
}
}
int tempvar=0; //Variable for the final array without any duplicates
int whilecount=0; //variable for while loop
while(whilecount<(nsprtable*2)-1) //nsprtable can be any number
{
//to check whether the next value is idential in case of sorted array
if(temparray[whilecount]!=temparray[whilecount+1])
{
finalarray[tempvar]=temparray[whilecount];
tempvar++;
whilecount=whilecount+1;
}
else if (temparray[whilecount]==temparray[whilecount+1])
{
finalarray[tempvar]=temparray[whilecount];
tempvar++;
whilecount=whilecount+2;
}
}
Hope this helps or solves the purpose.
package javaa;
public class UniqueElementinAnArray
{
public static void main(String[] args)
{
int[] a = {10,10,10,10,10,100};
int[] output = new int[a.length];
int count = 0;
int num = 0;
//Iterate over an array
for(int i=0; i<a.length; i++)
{
num=a[i];
boolean flag = check(output,num);
if(flag==false)
{
output[count]=num;
++count;
}
}
//print the all the elements from an array except zero's (0)
for (int i : output)
{
if(i!=0 )
System.out.print(i+" ");
}
}
/***
* If a next number from an array is already exists in unique array then return true else false
* #param arr Unique number array. Initially this array is an empty.
* #param num Number to be search in unique array. Whether it is duplicate or unique.
* #return true: If a number is already exists in an array else false
*/
public static boolean check(int[] arr, int num)
{
boolean flag = false;
for(int i=0;i<arr.length; i++)
{
if(arr[i]==num)
{
flag = true;
break;
}
}
return flag;
}
}
public static int[] removeDuplicates(int[] arr) {
int end = arr.length;
HashSet<Integer> set = new HashSet<Integer>(end);
for(int i = 0 ; i < end ; i++){
set.add(arr[i]);
}
return set.toArray();
}
You can use an auxiliary array (temp) which in indexes are numbers of main array. So the time complexity will be liner and O(n). As we want to do it without using any library, we define another array (unique) to push non-duplicate elements:
var num = [2,4,9,4,1,2,24,12,4];
let temp = [];
let unique = [];
let j = 0;
for (let i = 0; i < num.length; i++){
if (temp[num[i]] !== 1){
temp[num[i]] = 1;
unique[j++] = num[i];
}
}
console.log(unique);
If you are looking to remove duplicates using the same array and also keeping the time complexity of O(n). Then this should do the trick. Also, would only work if the array is sorted.
function removeDuplicates_sorted(arr){
let j = 0;
for(let x = 0; x < arr.length - 1; x++){
if(arr[x] != arr[x + 1]){
arr[j++] = arr[x];
}
}
arr[j++] = arr[arr.length - 1];
arr.length = j;
return arr;
}
Here is for an unsorted array, its O(n) but uses more space complexity then the sorted.
function removeDuplicates_unsorted(arr){
let map = {};
let j = 0;
for(var numbers of arr){
if(!map[numbers]){
map[numbers] = 1;
arr[j++] = numbers;
}
}
arr.length = j;
return arr;
}
Note to other readers who desire to use the Set method of solving this problem: If original ordering must be preserved, do not use HashSet as in the top result. HashSet does not guarantee the preservation of the original order, so LinkedHashSet should be used instead-this keeps track of the order in which the elements were inserted into the set and returns them in that order.
This is an interview question.
public class Test4 {
public static void main(String[] args) {
int a[] = {1, 2, 2, 3, 3, 3, 6,6,6,6,6,66,7,65};
int newlength = lengthofarraywithoutduplicates(a);
for(int i = 0 ; i < newlength ;i++) {
System.out.println(a[i]);
}//for
}//main
private static int lengthofarraywithoutduplicates(int[] a) {
int count = 1 ;
for (int i = 1; i < a.length; i++) {
int ch = a[i];
if(ch != a[i-1]) {
a[count++] = ch;
}//if
}//for
return count;
}//fix
}//end1
But, it's always better to use Stream :
int[] a = {1, 2, 2, 3, 3, 3, 6,6,6,6,6,66,7,65};
int[] array = Arrays.stream(a).distinct().toArray();
System.out.println(Arrays.toString(array));//[1, 2, 3, 6, 66, 7, 65]
How about this one, only for the sorted Array of numbers, to print the Array without duplicates, without using Set or other Collections, just an Array:
public static int[] removeDuplicates(int[] array) {
int[] nums = new int[array.length];
int addedNumber = 0;
int j = 0;
for(int i=0; i < array.length; i++) {
if (addedNumber != array[i]) {
nums[j] = array[i];
j++;
addedNumber = nums[j-1];
}
}
return Arrays.copyOf(nums, j);
}
An array of 1040 duplicated numbers processed in 33020 nanoseconds(0.033020 millisec).
public static void main(String[] args) {
Integer[] intArray = { 1, 1, 1, 2, 4, 2, 3, 5, 3, 6, 7, 3, 4, 5 };
Integer[] finalArray = removeDuplicates(intArray);
System.err.println(Arrays.asList(finalArray));
}
private static Integer[] removeDuplicates(Integer[] intArray) {
int count = 0;
Integer[] interimArray = new Integer[intArray.length];
for (int i = 0; i < intArray.length; i++) {
boolean exists = false;
for (int j = 0; j < interimArray.length; j++) {
if (interimArray[j]!=null && interimArray[j] == intArray[i]) {
exists = true;
}
}
if (!exists) {
interimArray[count] = intArray[i];
count++;
}
}
final Integer[] finalArray = new Integer[count];
System.arraycopy(interimArray, 0, finalArray, 0, count);
return finalArray;
}
I feel Android Killer's idea is great, but I just wondered if we can leverage HashMap. So I did a little experiment. And I found HashMap seems faster than HashSet.
Here is code:
int[] input = new int[1000000];
for (int i = 0; i < input.length; i++) {
Random random = new Random();
input[i] = random.nextInt(200000);
}
long startTime1 = new Date().getTime();
System.out.println("Set start time:" + startTime1);
Set<Integer> resultSet = new HashSet<Integer>();
for (int i = 0; i < input.length; i++) {
resultSet.add(input[i]);
}
long endTime1 = new Date().getTime();
System.out.println("Set end time:"+ endTime1);
System.out.println("result of set:" + (endTime1 - startTime1));
System.out.println("number of Set:" + resultSet.size() + "\n");
long startTime2 = new Date().getTime();
System.out.println("Map start time:" + startTime1);
Map<Integer, Integer> resultMap = new HashMap<Integer, Integer>();
for (int i = 0; i < input.length; i++) {
if (!resultMap.containsKey(input[i]))
resultMap.put(input[i], input[i]);
}
long endTime2 = new Date().getTime();
System.out.println("Map end Time:" + endTime2);
System.out.println("result of Map:" + (endTime2 - startTime2));
System.out.println("number of Map:" + resultMap.size());
Here is result:
Set start time:1441960583837
Set end time:1441960583917
result of set:80
number of Set:198652
Map start time:1441960583837
Map end Time:1441960583983
result of Map:66
number of Map:198652
This is not using Set, Map, List or any extra collection, only two arrays:
package arrays.duplicates;
import java.lang.reflect.Array;
import java.util.Arrays;
public class ArrayDuplicatesRemover<T> {
public static <T> T[] removeDuplicates(T[] input, Class<T> clazz) {
T[] output = (T[]) Array.newInstance(clazz, 0);
for (T t : input) {
if (!inArray(t, output)) {
output = Arrays.copyOf(output, output.length + 1);
output[output.length - 1] = t;
}
}
return output;
}
private static <T> boolean inArray(T search, T[] array) {
for (T element : array) {
if (element.equals(search)) {
return true;
}
}
return false;
}
}
And the main to test it
package arrays.duplicates;
import java.util.Arrays;
public class TestArrayDuplicates {
public static void main(String[] args) {
Integer[] array = {1, 1, 2, 2, 3, 3, 3, 3, 4};
testArrayDuplicatesRemover(array);
}
private static void testArrayDuplicatesRemover(Integer[] array) {
final Integer[] expectedResult = {1, 2, 3, 4};
Integer[] arrayWithoutDuplicates = ArrayDuplicatesRemover.removeDuplicates(array, Integer.class);
System.out.println("Array without duplicates is supposed to be: " + Arrays.toString(expectedResult));
System.out.println("Array without duplicates currently is: " + Arrays.toString(arrayWithoutDuplicates));
System.out.println("Is test passed ok?: " + (Arrays.equals(arrayWithoutDuplicates, expectedResult) ? "YES" : "NO"));
}
}
And the output:
Array without duplicates is supposed to be: [1, 2, 3, 4]
Array without duplicates currently is: [1, 2, 3, 4]
Is test passed ok?: YES

Pulling distinct values from a array in java

Have a program where the user inputs 10 int values into the array. Lastly I need to pull out the distinct values and display them. Added my second for loop which would determine if the the value is distinct (i.e. meaning if the number appears multiple times it is only displayed once).
For instance, let say I pass in the numbers: 1, 2, 3, 2, 1, 6, 3, 4, 5, 2 the distinct array should only contain numbers {1, 2, 3, 6, 4, 5}
import java.util.Scanner;
import java.io.*;
public class ArrayDistinct {
public static void main(String[] args) throws IOException {
Scanner input = new Scanner(System.in);
// Create arrays & variables
int arrayLength = 10;
int[] numbers = new int[arrayLength];
int[] distinctArray = new int[arrayLength];
int count = 0;
System.out.println("Program starting...");
System.out.print("Please enter in " + numbers.length + " numbers: ");
for (int i = 0; i < numbers.length; i++) {
numbers[i] = input.nextInt();
}
for (int i = 0; i < numbers.length; i++) {
int temp = numbers[i];
int tempTwo = numbers[i + 1];
if (tempTwo == temp) {
count++;
distinctArray[i] = temp;
}
}
// Print out results
} // end main
} // end class
Try this :
Set<Integer> uniqueNumbers = new HashSet<Integer>(Arrays.asList(numbers));
uniqueNumbers will contain only unique values
In Java 8
Stream< T > distinct()
Returns a stream consisting of the distinct elements (according to
Object.equals(Object)) of this stream. For ordered streams, the
selection of distinct elements is stable (for duplicated elements, the
element appearing first in the encounter order is preserved.) For
unordered streams, no stability guarantees are made.
Code:
Integer[] array = new Integer[]{5, 10, 20, 58, 10};
Stream.of(array)
.distinct()
.forEach(i -> System.out.print(" " + i));
Output:
5,10,20,58
Read More About distinct function
Try this code.. it will work
package Exercises;
import java.util.Scanner;
public class E5Second
{
public static void main(String[] args)
{
Scanner In = new Scanner(System.in);
int [] number = new int [10];
fillArr(number);
boolean [] distinct = new boolean [10];
int count = 0;
for (int i = 0; i < number.length; i++)
{
if (isThere(number,i) == false)
{
distinct[i] = true;
count++;
}
}
System.out.println("\nThe number of distinct numbers is " + count);
System.out.print("The distinct numbers are: ");
displayDistinct(number, distinct);
}
public static void fillArr(int [] number)
{
Scanner In = new Scanner(System.in);
System.out.print("Enter ten integers ");
for (int i = 0; i < number.length; i++)
number[i] = In.nextInt();
}
public static boolean isThere(int [] number, int i)
{
for (int j = 0; j < i; j++)
if(number[i] == number[j])
return true;
return false;
}
public static void displayDistinct(int [] number, boolean [] distinct)
{
for (int i = 0; i < distinct.length; i++)
if (distinct[i])
System.out.print(number[i] + " ");
}
}
One possible logic: If you're supposed to only sort out "unique" numbers, then you'll want to test each number as it's entered and added to the first array, and loop through the array and see if it's equal to any of the numbers already there; if not, add it to the "unique" array.
Sets in java doesn't allow duplicates:
Integer[] array = new Integer[]{5, 10, 20, 58, 10};
HashSet<Integer> uniques = new HashSet<>(Arrays.asList(array));
That's it.
Something like this should work for you:
Scanner input = new Scanner(System.in);
// Create arrays & variables
int arrayLength = 10;
int[] numbers = new int[arrayLength];
int[] distinctArray = new int[arrayLength];
int count = 0;
Set<Integer> set = new HashSet<Integer>();
System.out.println("Program starting...");
System.out.print("Please enter in " + numbers.length + " numbers: ");
for (int i = 0; i < numbers.length; i++) {
set.add(input.nextInt());
}
for(Integer i : set)
{
System.out.println("" + i);
}
This will only add unique values to the set.
int a[] = { 2, 4, 5, 3, 3, 3, 4, 6 };
int flag = 0;
for (int i = 0; i < a.length; i++)
{
flag = 0;
for (int j = i + 1; j < a.length; j++)
{
if (a[i] == a[j])
{
flag = 1;
}
}
if (flag == 0)
{
System.out.println(a[i]);
}
}

How to efficiently remove duplicates from an array without using Set

I was asked to write my own implementation to remove duplicated values in an array. Here is what I have created. But after tests with 1,000,000 elements it took very long time to finish. Is there something that I can do to improve my algorithm or any bugs to remove ?
I need to write my own implementation - not to use Set, HashSet etc. Or any other tools such as iterators. Simply an array to remove duplicates.
public static int[] removeDuplicates(int[] arr) {
int end = arr.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (arr[i] == arr[j]) {
int shiftLeft = j;
for (int k = j+1; k < end; k++, shiftLeft++) {
arr[shiftLeft] = arr[k];
}
end--;
j--;
}
}
}
int[] whitelist = new int[end];
for(int i = 0; i < end; i++){
whitelist[i] = arr[i];
}
return whitelist;
}
you can take the help of Set collection
int end = arr.length;
Set<Integer> set = new HashSet<Integer>();
for(int i = 0; i < end; i++){
set.add(arr[i]);
}
now if you will iterate through this set, it will contain only unique values. Iterating code is like this :
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
If you are allowed to use Java 8 streams:
Arrays.stream(arr).distinct().toArray();
Note: I am assuming the array is sorted.
Code:
int[] input = new int[]{1, 1, 3, 7, 7, 8, 9, 9, 9, 10};
int current = input[0];
boolean found = false;
for (int i = 0; i < input.length; i++) {
if (current == input[i] && !found) {
found = true;
} else if (current != input[i]) {
System.out.print(" " + current);
current = input[i];
found = false;
}
}
System.out.print(" " + current);
output:
1 3 7 8 9 10
Slight modification to the original code itself, by removing the innermost for loop.
public static int[] removeDuplicates(int[] arr){
int end = arr.length;
for (int i = 0; i < end; i++) {
for (int j = i + 1; j < end; j++) {
if (arr[i] == arr[j]) {
/*int shiftLeft = j;
for (int k = j+1; k < end; k++, shiftLeft++) {
arr[shiftLeft] = arr[k];
}*/
arr[j] = arr[end-1];
end--;
j--;
}
}
}
int[] whitelist = new int[end];
/*for(int i = 0; i < end; i++){
whitelist[i] = arr[i];
}*/
System.arraycopy(arr, 0, whitelist, 0, end);
return whitelist;
}
There exists many solution of this problem.
The sort approach
You sort your array and resolve only unique items
The set approach
You declare a HashSet where you put all item then you have only unique ones.
You create a boolean array that represent the items all ready returned, (this depend on your data in the array).
If you deal with large amount of data i would pick the 1. solution. As you do not allocate additional memory and sorting is quite fast. For small set of data the complexity would be n^2 but for large i will be n log n.
Since you can assume the range is between 0-1000 there is a very simple and efficient solution
//Throws an exception if values are not in the range of 0-1000
public static int[] removeDuplicates(int[] arr) {
boolean[] set = new boolean[1001]; //values must default to false
int totalItems = 0;
for (int i = 0; i < arr.length; ++i) {
if (!set[arr[i]]) {
set[arr[i]] = true;
totalItems++;
}
}
int[] ret = new int[totalItems];
int c = 0;
for (int i = 0; i < set.length; ++i) {
if (set[i]) {
ret[c++] = i;
}
}
return ret;
}
This runs in linear time O(n). Caveat: the returned array is sorted so if that is illegal then this answer is invalid.
class Demo
{
public static void main(String[] args)
{
int a[]={3,2,1,4,2,1};
System.out.print("Before Sorting:");
for (int i=0;i<a.length; i++ )
{
System.out.print(a[i]+"\t");
}
System.out.print ("\nAfter Sorting:");
//sorting the elements
for(int i=0;i<a.length;i++)
{
for(int j=i;j<a.length;j++)
{
if(a[i]>a[j])
{
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
//After sorting
for(int i=0;i<a.length;i++)
{
System.out.print(a[i]+"\t");
}
System.out.print("\nAfter removing duplicates:");
int b=0;
a[b]=a[0];
for(int i=0;i<a.length;i++)
{
if (a[b]!=a[i])
{
b++;
a[b]=a[i];
}
}
for (int i=0;i<=b;i++ )
{
System.out.print(a[i]+"\t");
}
}
}
OUTPUT:Before Sortng:3 2 1 4 2 1 After Sorting:1 1 2 2 3 4
Removing Duplicates:1 2 3 4
Since this question is still getting a lot of attention, I decided to answer it by copying this answer from Code Review.SE:
You're following the same philosophy as the bubble sort, which is
very, very, very slow. Have you tried this?:
Sort your unordered array with quicksort. Quicksort is much faster
than bubble sort (I know, you are not sorting, but the algorithm you
follow is almost the same as bubble sort to traverse the array).
Then start removing duplicates (repeated values will be next to each
other). In a for loop you could have two indices: source and
destination. (On each loop you copy source to destination unless they
are the same, and increment both by 1). Every time you find a
duplicate you increment source (and don't perform the copy).
#morgano
import java.util.Arrays;
public class Practice {
public static void main(String[] args) {
int a[] = { 1, 3, 3, 4, 2, 1, 5, 6, 7, 7, 8, 10 };
Arrays.sort(a);
int j = 0;
for (int i = 0; i < a.length - 1; i++) {
if (a[i] != a[i + 1]) {
a[j] = a[i];
j++;
}
}
a[j] = a[a.length - 1];
for (int i = 0; i <= j; i++) {
System.out.println(a[i]);
}
}
}
**This is the most simplest way**
What if you create two boolean arrays: 1 for negative values and 1 for positive values and init it all on false.
Then you cycle thorugh the input array and lookup in the arrays if you've encoutered the value already.
If not, you add it to the output array and mark it as already used.
package com.pari.practice;
import java.util.HashSet;
import java.util.Iterator;
import com.pari.sort.Sort;
public class RemoveDuplicates {
/**
* brute force- o(N square)
*
* #param input
* #return
*/
public static int[] removeDups(int[] input){
boolean[] isSame = new boolean[input.length];
int sameNums = 0;
for( int i = 0; i < input.length; i++ ){
for( int j = i+1; j < input.length; j++){
if( input[j] == input[i] ){ //compare same
isSame[j] = true;
sameNums++;
}
}
}
//compact the array into the result.
int[] result = new int[input.length-sameNums];
int count = 0;
for( int i = 0; i < input.length; i++ ){
if( isSame[i] == true) {
continue;
}
else{
result[count] = input[i];
count++;
}
}
return result;
}
/**
* set - o(N)
* does not guarantee order of elements returned - set property
*
* #param input
* #return
*/
public static int[] removeDups1(int[] input){
HashSet myset = new HashSet();
for( int i = 0; i < input.length; i++ ){
myset.add(input[i]);
}
//compact the array into the result.
int[] result = new int[myset.size()];
Iterator setitr = myset.iterator();
int count = 0;
while( setitr.hasNext() ){
result[count] = (int) setitr.next();
count++;
}
return result;
}
/**
* quicksort - o(Nlogn)
*
* #param input
* #return
*/
public static int[] removeDups2(int[] input){
Sort st = new Sort();
st.quickSort(input, 0, input.length-1); //input is sorted
//compact the array into the result.
int[] intermediateResult = new int[input.length];
int count = 0;
int prev = Integer.MIN_VALUE;
for( int i = 0; i < input.length; i++ ){
if( input[i] != prev ){
intermediateResult[count] = input[i];
count++;
}
prev = input[i];
}
int[] result = new int[count];
System.arraycopy(intermediateResult, 0, result, 0, count);
return result;
}
public static void printArray(int[] input){
for( int i = 0; i < input.length; i++ ){
System.out.print(input[i] + " ");
}
}
public static void main(String[] args){
int[] input = {5,6,8,0,1,2,5,9,11,0};
RemoveDuplicates.printArray(RemoveDuplicates.removeDups(input));
System.out.println();
RemoveDuplicates.printArray(RemoveDuplicates.removeDups1(input));
System.out.println();
RemoveDuplicates.printArray(RemoveDuplicates.removeDups2(input));
}
}
Output:
5 6 8 0 1 2 9 11
0 1 2 5 6 8 9 11
0 1 2 5 6 8 9 11
I have just written the above code for trying out. thanks.
public static int[] removeDuplicates(int[] arr){
HashSet<Integer> set = new HashSet<>();
final int len = arr.length;
//changed end to len
for(int i = 0; i < len; i++){
set.add(arr[i]);
}
int[] whitelist = new int[set.size()];
int i = 0;
for (Iterator<Integer> it = set.iterator(); it.hasNext();) {
whitelist[i++] = it.next();
}
return whitelist;
}
Runs in O(N) time instead of your O(N^3) time
Not a big fun of updating user input, however considering your constraints...
public int[] removeDup(int[] nums) {
Arrays.sort(nums);
int x = 0;
for (int i = 0; i < nums.length; i++) {
if (i == 0 || nums[i] != nums[i - 1]) {
nums[x++] = nums[i];
}
}
return Arrays.copyOf(nums, x);
}
Array sort can be easily replaced with any nlog(n) algorithm.
This is simple way to sort the elements in the array
public class DublicatesRemove {
public static void main(String args[]) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("enter size of the array");
int l = Integer.parseInt(br.readLine());
int[] a = new int[l];
// insert elements in the array logic
for (int i = 0; i < l; i++)
{
System.out.println("enter a element");
int el = Integer.parseInt(br.readLine());
a[i] = el;
}
// sorting elements in the array logic
for (int i = 0; i < l; i++)
{
for (int j = 0; j < l - 1; j++)
{
if (a[j] > a[j + 1])
{
int temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
}
}
// remove duplicate elements logic
int b = 0;
a[b] = a[0];
for (int i = 1; i < l; i++)
{
if (a[b] != a[i])
{
b++;
a[b]=a[i];
}
}
for(int i=0;i<=b;i++)
{
System.out.println(a[i]);
}
}
}
Okay, so you cannot use Set or other collections. One solution I don't see here so far is one based on the use of a Bloom filter, which essentially is an array of bits, so perhaps that passes your requirements.
The Bloom filter is a lovely and very handy technique, fast and space-efficient, that can be used to do a quick check of the existence of an element in a set without storing the set itself or the elements. It has a (typically small) false positive rate, but no false negative rate. In other words, for your question, if a Bloom filter tells you that an element hasn't been seen so far, you can be sure it hasn't. But if it says that an element has been seen, you actually need to check. This still saves a lot of time if there aren't too many duplicates in your list (for those, there is no looping to do, except in the small probability case of a false positive --you typically chose this rate based on how much space you are willing to give to the Bloom filter (rule of thumb: less than 10 bits per unique element for a false positive rate of 1%).
There are many implementations of Bloom filters, see e.g. here or here, so I won't repeat that in this answer. Let us just assume the api described in that last reference, in particular, the description of put(E e):
true if the Bloom filter's bits changed as a result of this operation. If the bits changed, this is definitely the first time object has been added to the filter. If the bits haven't changed, this might be the first time object has been added to the filter. (...)
An implementation using such a Bloom filter would then be:
public static int[] removeDuplicates(int[] arr) {
ArrayList<Integer> out = new ArrayList<>();
int n = arr.length;
BloomFilter<Integer> bf = new BloomFilter<>(...); // decide how many bits and how many hash functions to use (compromise between space and false positive rate)
for (int e : arr) {
boolean might_contain = !bf.put(e);
boolean found = false;
if (might_contain) {
// check if false positive
for (int u : out) {
if (u == e) {
found = true;
break;
}
}
}
if (!found) {
out.add(e);
}
}
return out.stream().mapToInt(i -> i).toArray();
}
Obviously, if you can alter the incoming array in place, then there is no need for an ArrayList: at the end, when you know the actual number of unique elements, just arraycopy() those.
For a sorted Array, just check the next index:
//sorted data!
public static int[] distinct(int[] arr) {
int[] temp = new int[arr.length];
int count = 0;
for (int i = 0; i < arr.length; i++) {
int current = arr[i];
if(count > 0 )
if(temp[count - 1] == current)
continue;
temp[count] = current;
count++;
}
int[] whitelist = new int[count];
System.arraycopy(temp, 0, whitelist, 0, count);
return whitelist;
}
You need to sort your array then then loop and remove duplicates. As you cannot use other tools you need to write be code yourself.
You can easily find examples of quicksort in Java on the internet (on which this example is based).
public static void main(String[] args) throws Exception {
final int[] original = new int[]{1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1};
System.out.println(Arrays.toString(original));
quicksort(original);
System.out.println(Arrays.toString(original));
final int[] unqiue = new int[original.length];
int prev = original[0];
unqiue[0] = prev;
int count = 1;
for (int i = 1; i < original.length; ++i) {
if (original[i] != prev) {
unqiue[count++] = original[i];
}
prev = original[i];
}
System.out.println(Arrays.toString(unqiue));
final int[] compressed = new int[count];
System.arraycopy(unqiue, 0, compressed, 0, count);
System.out.println(Arrays.toString(compressed));
}
private static void quicksort(final int[] values) {
if (values.length == 0) {
return;
}
quicksort(values, 0, values.length - 1);
}
private static void quicksort(final int[] values, final int low, final int high) {
int i = low, j = high;
int pivot = values[low + (high - low) / 2];
while (i <= j) {
while (values[i] < pivot) {
i++;
}
while (values[j] > pivot) {
j--;
}
if (i <= j) {
swap(values, i, j);
i++;
j--;
}
}
if (low < j) {
quicksort(values, low, j);
}
if (i < high) {
quicksort(values, i, high);
}
}
private static void swap(final int[] values, final int i, final int j) {
final int temp = values[i];
values[i] = values[j];
values[j] = temp;
}
So the process runs in 3 steps.
Sort the array - O(nlgn)
Remove duplicates - O(n)
Compact the array - O(n)
So this improves significantly on your O(n^3) approach.
Output:
[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1]
[1, 1, 1, 2, 4, 4, 7, 8, 8, 9, 9]
[1, 2, 4, 7, 8, 9, 0, 0, 0, 0, 0]
[1, 2, 4, 7, 8, 9]
EDIT
OP states values inside array doesn't matter really. But I can assume that range is between 0-1000. This is a classic case where an O(n) sort can be used.
We create an array of size range +1, in this case 1001. We then loop over the data and increment the values on each index corresponding to the datapoint.
We can then compact the resulting array, dropping values the have not been incremented. This makes the values unique as we ignore the count.
public static void main(String[] args) throws Exception {
final int[] original = new int[]{1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000};
System.out.println(Arrays.toString(original));
final int[] buckets = new int[1001];
for (final int i : original) {
buckets[i]++;
}
final int[] unique = new int[original.length];
int count = 0;
for (int i = 0; i < buckets.length; ++i) {
if (buckets[i] > 0) {
unique[count++] = i;
}
}
final int[] compressed = new int[count];
System.arraycopy(unique, 0, compressed, 0, count);
System.out.println(Arrays.toString(compressed));
}
Output:
[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000]
[1, 2, 4, 7, 8, 9, 1000]
public static void main(String args[]) {
int[] intarray = {1,2,3,4,5,1,2,3,4,5,1,2,3,4,5};
Set<Integer> set = new HashSet<Integer>();
for(int i : intarray) {
set.add(i);
}
Iterator<Integer> setitr = set.iterator();
for(int pos=0; pos < intarray.length; pos ++) {
if(pos < set.size()) {
intarray[pos] =setitr.next();
} else {
intarray[pos]= 0;
}
}
for(int i: intarray)
System.out.println(i);
}
I know this is kinda dead but I just wrote this for my own use. It's more or less the same as adding to a hashset and then pulling all the elements out of it. It should run in O(nlogn) worst case.
public static int[] removeDuplicates(int[] numbers) {
Entry[] entries = new Entry[numbers.length];
int size = 0;
for (int i = 0 ; i < numbers.length ; i++) {
int nextVal = numbers[i];
int index = nextVal % entries.length;
Entry e = entries[index];
if (e == null) {
entries[index] = new Entry(nextVal);
size++;
} else {
if(e.insert(nextVal)) {
size++;
}
}
}
int[] result = new int[size];
int index = 0;
for (int i = 0 ; i < entries.length ; i++) {
Entry current = entries[i];
while (current != null) {
result[i++] = current.value;
current = current.next;
}
}
return result;
}
public static class Entry {
int value;
Entry next;
Entry(int value) {
this.value = value;
}
public boolean insert(int newVal) {
Entry current = this;
Entry prev = null;
while (current != null) {
if (current.value == newVal) {
return false;
} else if(current.next != null) {
prev = current;
current = next;
}
}
prev.next = new Entry(value);
return true;
}
}
int tempvar=0; //Variable for the final array without any duplicates
int whilecount=0; //variable for while loop
while(whilecount<(nsprtable*2)-1) //nsprtable can be any number
{
//to check whether the next value is idential in case of sorted array
if(temparray[whilecount]!=temparray[whilecount+1])
{
finalarray[tempvar]=temparray[whilecount];
tempvar++;
whilecount=whilecount+1;
}
else if (temparray[whilecount]==temparray[whilecount+1])
{
finalarray[tempvar]=temparray[whilecount];
tempvar++;
whilecount=whilecount+2;
}
}
Hope this helps or solves the purpose.
package javaa;
public class UniqueElementinAnArray
{
public static void main(String[] args)
{
int[] a = {10,10,10,10,10,100};
int[] output = new int[a.length];
int count = 0;
int num = 0;
//Iterate over an array
for(int i=0; i<a.length; i++)
{
num=a[i];
boolean flag = check(output,num);
if(flag==false)
{
output[count]=num;
++count;
}
}
//print the all the elements from an array except zero's (0)
for (int i : output)
{
if(i!=0 )
System.out.print(i+" ");
}
}
/***
* If a next number from an array is already exists in unique array then return true else false
* #param arr Unique number array. Initially this array is an empty.
* #param num Number to be search in unique array. Whether it is duplicate or unique.
* #return true: If a number is already exists in an array else false
*/
public static boolean check(int[] arr, int num)
{
boolean flag = false;
for(int i=0;i<arr.length; i++)
{
if(arr[i]==num)
{
flag = true;
break;
}
}
return flag;
}
}
public static int[] removeDuplicates(int[] arr) {
int end = arr.length;
HashSet<Integer> set = new HashSet<Integer>(end);
for(int i = 0 ; i < end ; i++){
set.add(arr[i]);
}
return set.toArray();
}
You can use an auxiliary array (temp) which in indexes are numbers of main array. So the time complexity will be liner and O(n). As we want to do it without using any library, we define another array (unique) to push non-duplicate elements:
var num = [2,4,9,4,1,2,24,12,4];
let temp = [];
let unique = [];
let j = 0;
for (let i = 0; i < num.length; i++){
if (temp[num[i]] !== 1){
temp[num[i]] = 1;
unique[j++] = num[i];
}
}
console.log(unique);
If you are looking to remove duplicates using the same array and also keeping the time complexity of O(n). Then this should do the trick. Also, would only work if the array is sorted.
function removeDuplicates_sorted(arr){
let j = 0;
for(let x = 0; x < arr.length - 1; x++){
if(arr[x] != arr[x + 1]){
arr[j++] = arr[x];
}
}
arr[j++] = arr[arr.length - 1];
arr.length = j;
return arr;
}
Here is for an unsorted array, its O(n) but uses more space complexity then the sorted.
function removeDuplicates_unsorted(arr){
let map = {};
let j = 0;
for(var numbers of arr){
if(!map[numbers]){
map[numbers] = 1;
arr[j++] = numbers;
}
}
arr.length = j;
return arr;
}
Note to other readers who desire to use the Set method of solving this problem: If original ordering must be preserved, do not use HashSet as in the top result. HashSet does not guarantee the preservation of the original order, so LinkedHashSet should be used instead-this keeps track of the order in which the elements were inserted into the set and returns them in that order.
This is an interview question.
public class Test4 {
public static void main(String[] args) {
int a[] = {1, 2, 2, 3, 3, 3, 6,6,6,6,6,66,7,65};
int newlength = lengthofarraywithoutduplicates(a);
for(int i = 0 ; i < newlength ;i++) {
System.out.println(a[i]);
}//for
}//main
private static int lengthofarraywithoutduplicates(int[] a) {
int count = 1 ;
for (int i = 1; i < a.length; i++) {
int ch = a[i];
if(ch != a[i-1]) {
a[count++] = ch;
}//if
}//for
return count;
}//fix
}//end1
But, it's always better to use Stream :
int[] a = {1, 2, 2, 3, 3, 3, 6,6,6,6,6,66,7,65};
int[] array = Arrays.stream(a).distinct().toArray();
System.out.println(Arrays.toString(array));//[1, 2, 3, 6, 66, 7, 65]
How about this one, only for the sorted Array of numbers, to print the Array without duplicates, without using Set or other Collections, just an Array:
public static int[] removeDuplicates(int[] array) {
int[] nums = new int[array.length];
int addedNumber = 0;
int j = 0;
for(int i=0; i < array.length; i++) {
if (addedNumber != array[i]) {
nums[j] = array[i];
j++;
addedNumber = nums[j-1];
}
}
return Arrays.copyOf(nums, j);
}
An array of 1040 duplicated numbers processed in 33020 nanoseconds(0.033020 millisec).
public static void main(String[] args) {
Integer[] intArray = { 1, 1, 1, 2, 4, 2, 3, 5, 3, 6, 7, 3, 4, 5 };
Integer[] finalArray = removeDuplicates(intArray);
System.err.println(Arrays.asList(finalArray));
}
private static Integer[] removeDuplicates(Integer[] intArray) {
int count = 0;
Integer[] interimArray = new Integer[intArray.length];
for (int i = 0; i < intArray.length; i++) {
boolean exists = false;
for (int j = 0; j < interimArray.length; j++) {
if (interimArray[j]!=null && interimArray[j] == intArray[i]) {
exists = true;
}
}
if (!exists) {
interimArray[count] = intArray[i];
count++;
}
}
final Integer[] finalArray = new Integer[count];
System.arraycopy(interimArray, 0, finalArray, 0, count);
return finalArray;
}
I feel Android Killer's idea is great, but I just wondered if we can leverage HashMap. So I did a little experiment. And I found HashMap seems faster than HashSet.
Here is code:
int[] input = new int[1000000];
for (int i = 0; i < input.length; i++) {
Random random = new Random();
input[i] = random.nextInt(200000);
}
long startTime1 = new Date().getTime();
System.out.println("Set start time:" + startTime1);
Set<Integer> resultSet = new HashSet<Integer>();
for (int i = 0; i < input.length; i++) {
resultSet.add(input[i]);
}
long endTime1 = new Date().getTime();
System.out.println("Set end time:"+ endTime1);
System.out.println("result of set:" + (endTime1 - startTime1));
System.out.println("number of Set:" + resultSet.size() + "\n");
long startTime2 = new Date().getTime();
System.out.println("Map start time:" + startTime1);
Map<Integer, Integer> resultMap = new HashMap<Integer, Integer>();
for (int i = 0; i < input.length; i++) {
if (!resultMap.containsKey(input[i]))
resultMap.put(input[i], input[i]);
}
long endTime2 = new Date().getTime();
System.out.println("Map end Time:" + endTime2);
System.out.println("result of Map:" + (endTime2 - startTime2));
System.out.println("number of Map:" + resultMap.size());
Here is result:
Set start time:1441960583837
Set end time:1441960583917
result of set:80
number of Set:198652
Map start time:1441960583837
Map end Time:1441960583983
result of Map:66
number of Map:198652
This is not using Set, Map, List or any extra collection, only two arrays:
package arrays.duplicates;
import java.lang.reflect.Array;
import java.util.Arrays;
public class ArrayDuplicatesRemover<T> {
public static <T> T[] removeDuplicates(T[] input, Class<T> clazz) {
T[] output = (T[]) Array.newInstance(clazz, 0);
for (T t : input) {
if (!inArray(t, output)) {
output = Arrays.copyOf(output, output.length + 1);
output[output.length - 1] = t;
}
}
return output;
}
private static <T> boolean inArray(T search, T[] array) {
for (T element : array) {
if (element.equals(search)) {
return true;
}
}
return false;
}
}
And the main to test it
package arrays.duplicates;
import java.util.Arrays;
public class TestArrayDuplicates {
public static void main(String[] args) {
Integer[] array = {1, 1, 2, 2, 3, 3, 3, 3, 4};
testArrayDuplicatesRemover(array);
}
private static void testArrayDuplicatesRemover(Integer[] array) {
final Integer[] expectedResult = {1, 2, 3, 4};
Integer[] arrayWithoutDuplicates = ArrayDuplicatesRemover.removeDuplicates(array, Integer.class);
System.out.println("Array without duplicates is supposed to be: " + Arrays.toString(expectedResult));
System.out.println("Array without duplicates currently is: " + Arrays.toString(arrayWithoutDuplicates));
System.out.println("Is test passed ok?: " + (Arrays.equals(arrayWithoutDuplicates, expectedResult) ? "YES" : "NO"));
}
}
And the output:
Array without duplicates is supposed to be: [1, 2, 3, 4]
Array without duplicates currently is: [1, 2, 3, 4]
Is test passed ok?: YES

Categories