一道演算法題的分析
一位前輩發給我一道演算法題,這裡整理一下自己的解題思路。
請設計一種處理演算法能高效的檢查出字串中第一次出現的重複字元。給定的字串長度小於等於500個字元,包含字母、數字、英文符號。
解
查詢第一次出現的重複字元...
- 逐個遍歷字元,判斷當前字元之前的字元陣列中是否出現此字元,第一次出現則跳出迴圈
考察:在字元陣列中如何快速的查詢某個字元。
知識:
- 字元是Java中的原始(Primitive)型別,可以和int型別直接轉換的。它的包裝類為Character.
- 要查詢字元陣列是無序的,要不要對無序陣列進行排序?不需要排序:排序演算法最快的時間複雜度也為O(nlogn),而遍歷一遍的時間複雜度為O(n),所以如果只進行一次操作,排序不如遍歷。
- 如果能進行O(1),或者比O(1)略差一點的操作就好了,可以考慮使用HashMap,HashSet直接取值,HashMap內部使用陣列來儲存資料。
實現
- 普通版本,因為看到字串長度小於500個字元,查詢重複的字元,資料量比較小,普通的兩層迴圈在資料量小的時候也可以嘗試。時間複雜度為O(n^2)
/**
* 常規的查詢第一個重複字串的方法
* @return 當字串為空時,返回null
*/
public static Character normalFind(String str){
if (str == null || "".equals(str)) {
return null;
}
if (str.length() > 500){
//日誌,根據文件,判斷是否處理大字串
System.out.println("warn 輸入的字元長度過大");
}
for (int i = 1; i
- 剝離HashMap實現部分,自己實現HashMap內部的陣列存取,資料量比較小,採用簡化的連結串列。
- 考慮到資料量是在是太小的時候,這裡閾值設定為15,長度小於15時使用常規的查詢來操作,省的建立物件分配空間
- 可設定內部要索引的陣列容量。
依次遍歷每個字元,遍歷過的字元進行hashCode,字元的hashCode為自身代表的int值,hashCode與陣列容量求餘,將字元再以連結串列的形式存在陣列中,如果其它字元的求出的下標重複,將當前節點加入到連結串列的最後節點。
static class Node {
/**
* 存放下個節點
*/
Node next;
/**
* 存放當前節點的值
*/
int value;
public Node() {
}
public Node(Node next, int value) {
this.next = next;
this.value = value;
}
}
public static Character myFind(String str, Integer capacity) {
if (str == null || "".equals(str)) {
return null;
}
if (str.length() > 500) {
//日誌,根據說明判斷是否處理
System.out.println("warn 輸入的字元長度過大");
}
if (str.length() = 500){
capacity = 500;
}
Node[] chars = new Node[capacity];
for (int i = 0; i
- 採用HashSet,Java內建資料結構進行資料的存取
如果待查詢的字元陣列中不存在字元,就加入新的字元,如果存在字元就返回當前字元
public static Character setFind(String str) {
if (str == null || "".equals(str)) {
return null;
}
if (str.length() > 500) {
//日誌,根據說明判斷是否處理
System.out.println("warn 輸入的字元長度過大");
}
HashSet hashSet = new HashSet();
for (int i = 0; i
測試結果
測試程式碼如下:
/**
* 1. 字元型別為數字,字母,特殊字元
* 2. 陣列時連續的記憶體空間,可以直接根據下標來查詢元素
* 3. 計算機對數字比對字元敏感,因此字元的儲存採用數字形式
*/
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("請在執行時輸入字串");
return;
}
for (int i = 0; i
編譯執行程式
javac me/aihe/exam/FindFirstRepeatdChar.java
執行程式:
暫時只用了兩個長度的字串測試,可以多執行幾次檢視效果, 一般耗時和字串的長度與指定的陣列容量有關。
分析
- 這次寫的演算法是犧牲空間來換取時間,普通的按順序逐個對比不需要額外的空間。
- 演算法參考HashMap內部實現,但對其做了一些精簡處理,Node節點這次儲存的是字元字元的hashCode值,字元與int可以互相轉換,Node只儲存值就好了。
- 省去了HashMap的resize()操作,直接在查詢的時候指定陣列的容量。陣列的空間越大越不容易產生下標衝突,可以直接進行O(1)取出資料。
最後
最近越來越意識到演算法的重要性,也在惡補中,穩紮穩打,希望能早日實現目標。
附錄
完整程式碼:
package me.aihe.exam;
import java.math.BigDecimal;
import java.util.HashSet;
/**
* @author aihe 2018/6/27
*/
public class FindFirstRepeatdChar {
static class Node {
/**
* 存放下個節點
*/
Node next;
/**
* 存放當前節點的值
*/
int value;
public Node() {
}
public Node(Node next, int value) {
this.next = next;
this.value = value;
}
}
/**
* 普通的查詢第一個重複字串的方法
*
* @return
*/
public static Character normalFind(String str) {
if (str == null || "".equals(str)) {
return null;
}
if (str.length() > 500) {
//日誌,根據說明判斷是否處理
System.out.println("warn 輸入的字元長度過大");
}
//從第一個下標開始找
for (int i = 1; i 500) {
//日誌,根據說明判斷是否處理
System.out.println("warn 輸入的字元長度過大");
}
if (str.length() = 500){
capacity = 500;
}
Node[] chars = new Node[capacity];
for (int i = 0; i 500) {
//日誌,根據說明判斷是否處理
System.out.println("warn 輸入的字元長度過大");
}
if (capacity == null){
capacity = 16;
}
if (capacity >= 500){
capacity = 500;
}
HashSet hashSet = new HashSet(capacity);
for (int i = 0; i ?[]{}交換程式碼由學會制定單符編方案基文字資料。起始於後期年最初是美家供不同計算機在相互通訊時用作共遵守的西字它已被國際標準化組織定為國際標準,稱為ISO 646標準。適用於所有拉丁文字字母";
if (args.length == 0) {
System.out.println("請在執行時輸入字串");
return;
}
for (int i = 0; i
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1747/viewspace-2803354/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一道面試題的分析面試題
- 一道演算法題演算法
- 演算法分析:看雪CTF2019的一道逆向題目演算法TF2
- 演算法分析:BUUCTF-2019全國賽的一道逆向題演算法
- 一道前端演算法題前端演算法
- bugku一道逆向題目分析
- 「每日一道演算法題」Reverse Integer演算法
- 一道有意思的面試演算法題面試演算法
- 一道簡單的分配演算法題,求解演算法
- 演算法精講:分享一道值得分享的演算法題演算法
- 使用 AI 解決一道演算法題AI演算法
- 一道演算法題,引出collections.Counter的特殊用法演算法
- 最考驗換位思考的一道演算法題演算法
- LeetCode演算法簡單題--JavaScript(每天一道題)LeetCode演算法JavaScript
- 一道關於逆向的實戰CTF題目分析
- 每天一道演算法題:Z字形轉換演算法
- 每天一道演算法題:顛倒整數演算法
- 每日一道演算法題:1.兩數之和演算法
- 【20190326】【每天一道演算法題】求眾數(分治演算法)演算法
- 每日一道演算法題之矩陣的Z字型遍歷演算法矩陣
- 一道題
- JavaScript的一道加法題?JavaScript
- 一道新奇的招聘題
- 一道簡單的題
- 資料結構與演算法之一道題感受演算法(演算法入門)資料結構演算法
- 每天一道演算法題:最長迴文子串演算法
- 每天一道演算法題:無重複字元的最長子串演算法字元
- 前端學習演算法3:一道來自頭條的面試題前端演算法面試題
- 一道逆向題
- 一道數學題的解法
- 一道無聊的題目
- 阿里一道Java併發面試題 (詳細分析篇)阿里Java面試題
- 關於一道面試題的極其無聊的python演算法實現面試題Python演算法
- 每天一道演算法題:求兩個排序陣列的中位數演算法排序陣列
- 每日一道演算法題--leetcode 112--路徑總和--python演算法LeetCodePython
- 每日一道演算法題--leetcode 461--漢明距離--python演算法LeetCodePython
- 連結串列演算法題二,還原題目,用debug除錯搞懂每一道題演算法除錯
- 一道題引發的EventLoop思考OOP