生活随笔
收集整理的這篇文章主要介紹了
数据结构与算法--第一个只出现一次的字符
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
第一個只出現一次的字符
public class FindNotRepeatChar {public static void main(String[] args
) {System.out
.println(findNotRepeatCharHashMap("wersdfxvsdfwer"));
}public static char findNotRepeatCharHashMap(String str
){if(str
== null){return '\u0000';}if(str
.length() == 1){return str
.charAt(0);}Map<Character, Integer> map
= new HashMap<>();char[] target
= str
.toCharArray();for (int i
= 0; i
< target
.length
; i
++) {Character key
= target
[i
];if(map
.containsKey(key
)){map
.put(key
, map
.get(key
) + 1);}else {map
.put(key
, 1);}}for (int i
= 0; i
< target
.length
; i
++) {if(map
.get(target
[i
]) == 1){return target
[i
];}}return '\u0000';}}
public class FindNotRepeatChar {public static void main(String[] args
) {System.out
.println(findNotRepeatChar("wersdfxvsdfwer"));}public static char findNotRepeatChar(String str
){if(str
== null){return '\u0000';}if(str
.length() == 1){return str
.charAt(0);}int[] charValue
= new int[256];char[] target
= str
.toCharArray();for (int i
= 0; i
< target
.length
; i
++) {Integer position
= new Character(target
[i
]).hashCode();charValue
[position
] += 1;}for (int i
= 0; i
< target
.length
; i
++) {Integer position
= new Character(target
[i
]).hashCode();if(charValue
[position
] == 1){return target
[i
];}}return '\u0000';}
}
-
以上代碼能正確得到我們需要的結果,并且第一次遍歷,在哈希表中更新一個字符出現的次數時間是O(1)。如果字符串長度為n,那么一次掃描時間復雜度是O(n)
-
第二次遍歷得到的Hash表同樣可以O(1)時間復雜度得到一個字符的次數,所以時間復雜度依然是O(1)
-
這樣總的來說時間復雜度還是O(1)
-
同時我們需要一個 65535 的整數數組,由于數組的大小是個常數,也就是數組大小不會和目標字符串的長度相關,那么空間復雜度是O(1)
-
問題:
- 在方法三種,的確可以在純英文字符的情況下得到確定值,算法也是正確的,但是實際上工作中字符遠比65535個多,而且hashCode也會有沖突的時候,比如***存在中英文混合情況,方法二就無法求解***
-
方法四:
- 基于方法二的基礎上我們解決中英文混用造成的沖突以及順序問題
- 我想到了HashMap中用到的哈希沖突解決方法,分離鏈表發
- 我們定義一個鏈表數組,每次沖突后,將沖突元素添加到鏈表尾部
- 然后依次遍歷找出為 1 的節點即可
- 如下實現:
public class FindNotRepeatChar {public static void main(String[] args
) {System.out
.println(findNotRepeatCharCompatibleChina("wersdfxxv我sdfwer"));}
public static char findNotRepeatCharCompatibleChina(String str
){if(str
== null){return '\u0000';}if(str
.length() == 1){return str
.charAt(0);}ListNode listArray
[] = new ListNode[str
.length()];char[] target
= str
.toCharArray();for (int i
= 0; i
< target
.length
; i
++) {Integer position
= (new Character(target
[i
]).hashCode())%str
.length();if(listArray
[position
] == null){listArray
[position
] = new ListNode(String.valueOf(target
[i
]), 1);}else {ListNode listNode
= MyLinkedList.search(listArray
[position
], String.valueOf(target
[i
]));if(listNode
!= null){listNode
.setValue(listNode
.getValue()+1);}else {MyLinkedList.addToTail(listArray
[position
], String.valueOf(target
[i
]), 1);}}}for (int i
= 0; i
< listArray
.length
; i
++) {if(listArray
[i
] != null){ListNode header
= listArray
[i
];while (header
!= null){if(header
.getValue() == 1){return header
.getKey().charAt(0);}header
= header
.getNext();}}}return '\u0000';}}
-
如上,算法參照HashMap的思想對hash表進行處理,算法能得到正確的值。
-
我們試圖通過一個 字符串大小的鏈表數組來存儲對應存量數據,其中涉及到HashCode%str.length取模得到對應位置
-
雖然獲取數組位置的時候回有沖突,并且不能保證順序,但是我們每次都通過原始數組去查找遍歷,依然可以得到第一個出現一次的字符
-
方法中用的鏈表ListNode,以及鏈表對應的方法 MyLinkedList 都是自定義的方法,可以在之前的文章:數據結構與算法–鏈表實現以及應用 找到詳細的實現以及說明。
-
方法的時間時間復雜度兩次遍歷都是O(n)
-
在每次遍歷有hash沖突的節點時候,我們需要調用 MyLinkedList.search 找到當前key值對應的節點,此處復雜度取決于hash沖突的多少
-
因此時間復雜度應該大于O(n)
-
空間復雜度額外存儲于字符串長度正相關也是O(n)
-
方法五
- 在方法四中算法是正確,但是有一定的復雜度,涉及到hash沖突解決,取模定位,鏈表節點查詢這種復雜的操作
- 因為我們收到方法三的定式思維影響用的hash表的結構存儲,其實完全不用
- 我們可以用鏈表存儲,不用hash作為key,直接用對應的字符作為key,這樣可以用少于O(n)的空間來存儲
- 如上分析有如下實現:
public class FindNotRepeatChar {public static void main(String[] args
) {System.out
.println(findNotRepeatCharCompatibleChinaLinkList("哈哈wersvdfxx我v我sdfwer去"));}public static char findNotRepeatCharCompatibleChinaLinkList(String str
) {if (str
== null) {return '\u0000';}if (str
.length() == 1) {return str
.charAt(0);}ListNode listNode
= new ListNode(String.valueOf(str
.charAt(0)), 1);char[] target
= str
.toCharArray();for (int i
= 1; i
< target
.length
; i
++) {ListNode header
= MyLinkedList.search(listNode
, String.valueOf(target
[i
]));if(header
!= null){header
.setValue(header
.getValue() + 1);}else {MyLinkedList.addToTail(listNode
, String.valueOf(target
[i
]), 1);}}for (int i
= 0; i
< target
.length
; i
++) {ListNode targetNode
= MyLinkedList.search(listNode
, String.valueOf(target
[i
]));if(targetNode
!= null && targetNode
.getValue() == 1){return target
[i
];}}return '\u0000';}
}
- 如上用鏈表存儲的實現方式時間復雜度與之前一樣,也是大于O(n),但是在代碼復雜度上減少很多
- 此方法不涉及到hash沖突解決等問題,都是直接存儲,空間復雜度是小于O(n)的
上一篇:數據結構與算法–丑數
下一篇:數據結構與算法–數組中的逆序對
總結
以上是生活随笔為你收集整理的数据结构与算法--第一个只出现一次的字符的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。