[英]What is the most elegant way to remove a listener from a list from a callback
[英]What is the most elegant way to remove values that have duplicates from a Java array
我正在嘗試獲取一個數組,檢查是否有重復,並刪除該字母的所有實例,我目前正在嘗試使用的方法非常難看
例;
In: ABBCCDE
Out: ADE
要么
In: BCACDF
Out: BADF
我目前正在使用兩個for
循環查找重復對象,將用於該重復對象的Char []添加到OTHER數組中,然后再循環使用2個for循環從我的ErrorArray中刪除字符。
這可能是一個解決方案:
public static void main(String[] args) {
char[] arr = { 'A', 'B', 'B', 'C', 'C', 'D', 'E' };
Set<Character> in = new HashSet<>();
Set<Character> dupe = new HashSet<>();
for (char c : arr) {
if (!dupe.contains(c)) {
if (in.contains(c)) {
dupe.add(c);
in.remove(c);
} else {
in.add(c);
}
}
}
char[] arrR = new char[in.size()];
int i = 0;
for (char c : in) {
arrR[i++] = c;
}
for (char c : arrR) {
System.out.println(c);
}
}
public static String removeDuplicateChars (String sText)
{
String sResult = "";
char[] caText = sText.toCharArray();
int[] iaAsciiIndex = new int[128];
for (int i=0 ; i<caText.length; i++)
{
iaAsciiIndex[caText[i]] += 1;
}
for (int i=0 ; i<iaAsciiIndex.length ; i++)
{
if (iaAsciiIndex[i] == 1)
sResult += (char)i;
}
return sResult;
}
有很多解決此問題的方法,並且最佳解決方案取決於輸入內容。
romedius在他的答案中提出的解決方案很好,就像Alex在對Makoto的答案的評論中提出的解決方案一樣。
如果您認為HashSet / HashMap的操作為O(1),則它們為O(n)。 但是,現實情況很少出現這種情況,這取決於散列函數的適當程度以及鏈接列表數組的大小(或內部使用的任何結構-Java默認使用LL)。
因此,例如:Java的HashMaps和HashSets在最壞的情況下會插入O(n),因為它們會驗證重復項並因此遍歷鏈接列表,而不僅僅是添加其尾部。 僅當碰撞次數很高時才會發生這種情況。
如果您知道輸入的大小,則最好為其設置HashSet / HashMap的大小:HashMap(int initialCapacity)構造函數將執行此操作。 這樣,您就可以避免調整結構的大小,而這可能會嚴重影響性能。
如果不這樣做,它將使用默認容量。 然后,您僅取決於哈希函數的性能。
一個可靠的解決方案O(n log n)是對輸入進行排序,然后僅迭代一次,檢查數組的上一個或下一個位置是否等於所選的位置,如果有,則不添加它。 第二部分是O(n)。 保證排序為O(n logn),如果您使用的是Java 7,它將使用timsort,這非常快。
如果我正在面試某人,我會接受其中任何一種解決方案。
使用SET
可以自動刪除所有重復值。 由於使用的是數組,因此需要使用Arrays.asList(T.. a)
進行轉換Arrays.asList(T.. a)
SET<Character> uniqueCharacters = new HashSet<Character>(Arrays.asList(yourArray));
你沒有定義優雅 ,但我提交使用位掩碼和XOR刪除受騙者。 我認為這是優雅且極其有效的,因為它消除了用於刪除重復對象的導航集。
(這僅適用於大寫字母,但易於擴展。)
這是該概念的關鍵。 這是一個圍繞BitSet的簡單包裝,用於表示當前字符或已看到哪些字符,等等:
class Bitmask {
private static final int NUM_BITS = 26;
private static final int OFFSET = 65;
// e.g. {A,C,D} == [1,0,1,1,0, ...]
BitSet bitset = new BitSet(NUM_BITS);
public Bitmask() {}
public Bitmask(Bitmask bitmask) {
this.bitset = (BitSet) bitmask.bitset.clone();
}
public void set(char c) {
int whichBit = (int) c - OFFSET;
bitset.set(whichBit);
}
public List<Character> getAllSet() {
List<Character> all = new ArrayList<Character>();
for (int i = 0; i < NUM_BITS; i++) {
if (bitset.get(i)) {
char c = (char) (OFFSET + i);
all.add(new Character(c));
}
}
return all;
}
public void xor(Bitmask bitmask) {
this.bitset.xor(bitmask.bitset);
}
public void or(Bitmask bitmask) {
this.bitset.or(bitmask.bitset);
}
public void and(Bitmask bitmask) {
this.bitset.and(bitmask.bitset);
}
public void andNot(Bitmask bitmask) {
this.bitset.andNot(bitmask.bitset);
}
}
看起來很冗長,但是收益在算法中,這對N位集的XOR的答案是很大的負擔。
char[] input = {'A', 'B', 'B', 'B', 'C', 'D', 'E'}; //expect 'ACDE'
//char[] input = {'A', 'A', 'B', 'B', 'B', 'C'};
//char[] input = {'A', 'C', 'G' };
Bitmask moreThanOnceBitmask = new Bitmask();
Bitmask onceBitmask = new Bitmask();
for(char c : input) {
Bitmask thisBitmask = new Bitmask();
thisBitmask.set(c);
Bitmask tmpOnceBitmask = new Bitmask(onceBitmask);
// we've seen 'char c' at least once
onceBitmask.or(thisBitmask);
// we've seen 'char c' more than once
tmpOnceBitmask.and(thisBitmask);
moreThanOnceBitmask.or(tmpOnceBitmask);
}
// we want 'at least once' but not 'more than once'
Bitmask finalBitmask = new Bitmask(onceBitmask);
finalBitmask.andNot(moreThanOnceBitmask);
// build list
System.out.println(finalBitmask.getAllSet().toString());
Guava的多集類的合理解決方案:
char[] chars = new char[] { 'A', 'B', 'B', 'B', 'C', 'D', 'C', 'E' };
Multiset<Character> set = LinkedHashMultiset.create(Chars.asList(chars));
for (char c : chars ) {
int cnt = set.count(c);
if (cnt > 1) {
set.remove(c, cnt);
}
}
char[] singles = Chars.toArray(set);
System.out.println(new String(singles));
PS:使用LinkedHashMultiset而不是HashMultiset非常重要,因為LinkedHashMultiset版本在您進行迭代時會保留插入順序,而HashMultiset不會。
我並不是說這是內存使用效率最高的解決方案,因為會創建許多臨時集合。
但是,從代碼的角度來看,這很簡單,並且有人可以僅查看代碼即可推斷出您要執行的操作。
由於Java中缺少從char[]
到Set<Character>
以及返回的轉換的支持,因此基於Set
解決方案並不完美。
上述轉換所需的循環可以更有效地用於執行問題所需的實際處理。
我認為以下解決方案的極度簡單使其優雅。
它也是有效的,盡管是以(某種)大數組為代價的,但可以根據所需輸入字符集的知識來減小其大小。
public class Test extends TestCase { public void testDupes() { assertEquals("ADE", noDupes("ABBCCDE".toCharArray())); assertEquals("BADF", noDupes("BCACDF".toCharArray())); } public String noDupes(char[] in) { int[] count = new int[Character.MAX_VALUE]; for (char c: in) count[c]++; StringBuffer out = new StringBuffer(); for (char c: in) if (count[c]==1) out.append(c); return out.toString(); } }
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.