配列内の重複した値を削除する独自の実装を作成するように求められました。これが私が作成したものです。しかし、1,000,000個の要素を使用したテストの後、完了するまでに非常に長い時間がかかりました。アルゴリズムを改善するためにできることや、削除すべきバグはありますか?
独自の実装を作成する必要があります- Set
、HashSet
など、またはイテレーターなどの他のツールを使用しないでください。単に重複を削除する配列。
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;
}
この質問はまだ多くの注目を集めているので、コピーして回答することにしました Code Review.SEからのこの回答 :
あなたは、バブルソートと同じ哲学に従っていますが、それは非常に、非常に、非常に遅いです。これを試しましたか?:
順序なし配列を quicksort でソートします。クイックソートは、バブルソートよりもはるかに高速です(ソートしているわけではありませんが、従うアルゴリズムは、配列を横断するバブルソートとほぼ同じです)。
次に、重複の削除を開始します(繰り返される値は隣同士になります)。
for
ループでは、source
とdestination
の2つのインデックスを使用できます。 (各ループで、source
をdestination
にコピーし、それらが同じでない限り、両方を1ずつ増やします)。重複を見つけるたびに、ソースをインクリメントします(コピーを実行しません)。 @morgano
Setコレクションの助けを借りることができます
int end = arr.length;
Set<Integer> set = new HashSet<Integer>();
for(int i = 0; i < end; i++){
set.add(arr[i]);
}
このsetを繰り返し処理する場合、一意の値のみが含まれます。反復コードは次のとおりです。
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
注:配列はソートされていると仮定しています
コード:
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);
出力:
1 3 7 8 9 10
最も内側のforループを削除することにより、元のコード自体にわずかな変更を加えます。
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;
}
範囲は0〜1000であると想定できるため、非常にシンプルで効率的なソリューションがあります。
//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;
}
これは線形時間O(n)で実行されます。警告:返された配列はソートされるため、それが違法である場合、この回答は無効です。
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
この問題には多くの解決策があります。
ソートアプローチ
セットアプローチ
返されたすべての準備ができたアイテムを表すブール配列を作成します(これは配列内のデータに依存します)。
大量のデータを扱う場合、解決策を選択します。追加のメモリを割り当てないため、ソートは非常に高速です。小さいデータセットの場合、複雑さはn ^ 2になりますが、大きいiの場合はn log nになります。
2つのブール配列を作成するとどうなります。1は負の値、1は正の値で、すべてfalseで初期化します。
次に、入力配列を徹底的に循環させ、既に値を見つけている場合は配列を検索します。そうでない場合は、出力配列に追加し、既に使用済みとしてマークします。
これは、配列内の要素を並べ替える簡単な方法です
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]);
}
}
}
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));
}
}
出力:5 6 8 0 1 2 9 11
0 1 2 5 6 8 9 11
0 1 2 5 6 8 9 11
試しに上記のコードを書きました。ありがとう。
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;
}
O(N ^ 3)時間ではなくO(N)時間で実行
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;
}
}
これが目的を支援または解決することを願っています。
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);
}
配列を並べ替えてから、ループして重複を削除する必要があります。他のツールを使用できないため、beコードを自分で記述する必要があります。
クイックソートの例は、Java インターネット上 (この例のベース)で簡単に見つけることができます。
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;
}
したがって、プロセスは3つのステップで実行されます。
O(nlgn)
O(n)
O(n)
したがって、これはO(n^3)
アプローチを大幅に改善します。
出力:
[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]
編集
OP状態配列内の値は実際には関係ありません。ただし、範囲は0〜1000であると想定できます。これは、O(n)ソートを使用できる古典的なケースです。
サイズrange +1
、この場合は1001
の配列を作成します。次に、データをループ処理し、データポイントに対応する各インデックスの値をインクリメントします。
次に、結果の配列を圧縮して、インクリメントされていない値を削除します。これにより、カウントが無視されるため、値が一意になります。
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));
}
出力:
[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000]
[1, 2, 4, 7, 8, 9, 1000]
ソートされた配列の場合、次のインデックスを確認するだけです。
//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;
}
ユーザー入力を更新するのはそれほど面白くないですが、制約を考慮して...
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);
}
配列の並べ替えは、nlog(n)アルゴリズムに簡単に置き換えることができます。
私はこれがちょっと死んでいることを知っていますが、私は自分自身のためにこれを書きました。これは、ハッシュセットに追加してからすべての要素を取り出すこととほぼ同じです。 O(nlogn)最悪の場合で実行する必要があります。
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;
}
}
セットを使用せずに整数配列から重複を削除する最も効率的な方法は、一時配列を作成して元の配列を繰り返し、一時配列に数値が存在するかどうかを確認し、配列にプッシュしないか、一時配列に入れて結果として一時配列を返すことです。次のコードスニペットを検討してください。
package com.numbers;
import Java.util.Arrays;
public class RemoveDuplicates {
public int[] removeDuplicate(int[] array) {
int[] tempArray = new int[array.length];
int j = 0;
for (int i : array) {
if (!isExists(tempArray, i)) {
tempArray[j++] = i;
}
}
return tempArray;
}
public static boolean isExists(int[] array, int num) {
if (array == null)
return false;
for (int i : array) {
if (i == num) {
return true;
}
}
return false;
}
public static void main(String[] args) {
int [] array = { 10, 20, 30, 10, 45, 30 };
RemoveDuplicates duplicates = new RemoveDuplicates();
System.out.println("Before removing duplicates : " + Arrays.toString(array));
int [] newArray = duplicates.removeDuplicate(array);
System.out.println("After removing duplicates : " + Arrays.toString(newArray));
}
}
これはどうですか?ソートされた配列の場合数字、重複なしで配列を印刷するにはSetを使用せずにまたは他のコレクション、配列のみ:
public static int[] removeDuplicates(int[] array) {
int[] nums =new int[array.length];
int addedNum = 0;
int j=0;
for(int i=0;i<array.length;i++) {
if (addedNum != array[i]) {
nums[j] = array[i];
j++;
addedNum = nums[j-1];
}
}
return Arrays.copyOf(nums, j);
}
33020ナノ秒で処理された1040個の重複した数値の配列(.033020ミリ秒)。
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 class RemoveDuplicates {
public static void main(String[] args) {
int[] arr = {2,2,2,2,2,5,9, 4,5,6,1,6,6,2,4,7};
arr = removeDuplicates(arr);
print(arr);
}
public static int[] removeDuplicates(int [] arr) {
final int garbage = -2147483648;
int duplicates = 0;
for(int i=0; i<arr.length; i++) {
for(int j=i+1; j<arr.length; j++) {
if (arr[i] == arr[j]) {
arr[i] = garbage;
duplicates++;
}
}
}
int[] nArr = new int[arr.length - duplicates];
int nItr = 0;
for(int i=0; i<arr.length; i++) {
if (arr[i] != garbage) {
nArr[nItr] = arr[i];
nItr++;
}
}
return nArr;
}
public static void print(int [] arr) {
for (int n : arr) {
System.out.print(n + "\t");
}
}
}
なぜすべての人がこれを行の下にチェックしないのですか?
Set、HashSetなど、またはイテレータなどの他のツールを使用しないために、独自の実装を作成する必要があります。単に重複を削除する配列。
上記の行を気にしながら、非常に単純な実装を投稿しています。
public class RemoveDuplicates {
public static void main(String[] args) {
int[] arr = { 1, 2, 3, 4, 2, 3, 1 }; // input array
int len = arr.length;
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < len; j++) {
if (arr[i] == arr[j]) {
while (j < (len) - 1) {
arr[j] = arr[j - 1];
j++;
}
len--;
}
}
}
for (int i = 0; i < len; i++) {
System.out.print(" " +arr[i]);
}
}
}
入力:1、2、3、4、2、3、1
出力:1 2 3 4
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;
}
public void removeDup(){
String[] arr = {"1","1","2","3","3"};
boolean exists = false;
String[] arr2 = new String[arr.length];
int count1 = 0;
for(int loop=0;loop<arr.length;loop++)
{
String val = arr[loop];
exists = false;
for(int loop2=0;loop2<arr2.length;loop2++)
{
if(arr2[loop2]==null)break;
if(arr2[loop2]==val){
exists = true;
}
}
if(!exists) {
arr2[count1] = val;
count1++;
}
}
}
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();
}
Android Killerのアイデアは素晴らしいと思いますが、HashMapを活用できるかどうか疑問に思いました。だから私は少し実験をしました。そして、HashMapはHashSetよりも高速であることがわかりました。
コードは次のとおりです。
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());
結果は次のとおりです。
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
これが私の解決策です。時間の複雑さはo(n ^ 2)です
public String removeDuplicates(char[] arr) {
StringBuilder sb = new StringBuilder();
if (arr == null)
return null;
int len = arr.length;
if (arr.length < 2)
return sb.append(arr[0]).toString();
for (int i = 0; i < len; i++) {
for (int j = i + 1; j < len; j++) {
if (arr[i] == arr[j]) {
arr[j] = 0;
}
}
if (arr[i] != 0)
sb.append(arr[i]);
}
return sb.toString().trim();
}
Java 8ストリームの使用が許可されている場合:
Arrays.stream(arr).distinct().toArray();
さて、Set
やその他のコレクションを使用することはできません。ここで私が今のところ見ない解決策の1つは、本質的にビットの配列である Bloom filter の使用に基づくものです。
ブルームフィルターは、セット自体または要素を保存せずにセット内の要素の存在をすばやく確認するために使用できる、高速でスペース効率の良い、非常に便利な手法です。 (通常は小さい)偽陽性率がありますが、偽陰性率はありません。言い換えれば、あなたの質問に対して、ブルームフィルターが、要素がこれまでに見られなかったことを告げるなら、あなたはそれが見られなかったと確信することができます。しかし、要素が見られたと言ったら、実際に確認する必要があります。リストに重複があまり多くない場合は、これにより多くの時間を節約できます(これらについては、誤検出の確率が小さい場合を除き、ループする必要はありません-通常、このレートは、ブルームフィルターに与えるスペース(経験則:1%の偽陽性率に対して一意の要素ごとに10ビット未満)。
ブルームフィルターには多くの実装があります。 here または here なので、この回答では繰り返しません。最後のリファレンスで説明されているAPI、特にput(E e)
の- 説明 を想定してみましょう。
true
この操作の結果としてブルームフィルターのビットが変更された場合。ビットが変更された場合、これはフィルターにオブジェクトが最初に追加されたときにdefinitelyです。ビットが変更されていない場合、このmightがオブジェクトがフィルターに初めて追加された可能性があります。 (...)
そのようなブルームフィルターを使用した実装は次のようになります。
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();
}
明らかに、着信配列をその場で変更できる場合、ArrayList
:の必要はありません。最後に、一意の要素の実際の数がわかっているときは、arraycopy()
だけです。
これは、Set、Map、List、または追加のコレクションを使用せず、2つの配列のみを使用します。
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;
}
}
そしてそれをテストするメイン
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"));
}
}
そして出力:
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
代わりにarraylistを使用してこれを行う、より簡単でより良い方法を次に示します。
public static final <T> ArrayList<T> removeDuplicates(ArrayList<T> in){
ArrayList<T> out = new ArrayList<T>();
for(T t : in)
if(!out.contains(t))
out.add(t);
return out;
}
これはインタビューの質問です。配列から重複を削除します。セットまたはコレクションは使用しません。完全なソリューションは次のとおりです。
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