算法系列:(一).聯機算法之>>求字符串數組中只出現過一次的字符串及索引

前言:

    最近閱讀 <數據結構與算法分析(java語言描述)> 一書, 其在 "算法分析" 一章中, 用一個求 "數值字符串最大子串和" 的例子演示了算法的奇妙.:

    相同的目的, 四種算法時間複雜度從O(N^{3})演變爲O(N^{2})再到O(N logN), 最後直接到O(N), 從而也順便介紹了一種叫做聯機算法的 "幾乎完美" 的算法;

    那什麼叫聯機算法呢?

 

正文:

     聯機算法: 是在任意時刻算法對要操作的數據只讀入(掃描)一次,一旦被讀入並處理,它就不需要再被記憶(第二次使用)了。而在此處理過程中算法能對它已經讀入的數據立即給出相應子序列問題的正確答案 (前n個值的正確答案)。圖示如下:

    

受此啓發, 想起最近其他人發的一道面試題: 編寫代碼, 統計字符串數組Str[100]中所有隻出現過一次的字符串及字符串在數組中的出現位置:

 

一般算法:

    看到此題, 博主第一時間隨手給出以下代碼:

    public static void main(String[] args) {
        //源數組生成
        final int SIZE=50000;
        String[] strings=new String[SIZE];
        Random random = new Random();
        for (int i = 0; i < SIZE; i++) {
            strings[i]=random.nextInt(SIZE/2)+"";
        }
        
        //開始算法
        long start = System.currentTimeMillis();
        int length = strings.length;//獲取數組長度
        Map<Integer, String> resultMap = new LinkedHashMap<>();
        boolean isSingle=true;

        for (int i = 0; i < length; ++i , isSingle=true) {//包括boolean的初始化
            if(strings[i]!=null&&!strings[i].equals("")){//去除無效元素
                for (int j = 1; j < length - i; j++) {//遍歷判斷:如果重複 則置空
                    if(strings[i].equals(strings[i+j])){
                        strings[i+j]=null;
                        isSingle=false;//確定當前元素不是單個
                    }
                }
                if (isSingle){//否則爲單個元素 則加入結果集
                    resultMap.put(i,strings[i]);
                }
            }
        }
        //算法結束
        long mild = System.currentTimeMillis();
        resultMap.keySet().forEach(key-> System.out.println("index:"+key+" == value:"+resultMap.get(key)));
        //值提取結束
        long end = System.currentTimeMillis();
        System.out.println("算法時間:"+(mild-start));
        System.out.println("值提取時間:"+(end-mild));
    }

爲了測試算法效率,將數組長度改爲50000,算法時間如下:

算法時間:16855毫秒
值提取時間:222毫秒

 

聯機算法:

    博主發現當字符串長度增加後,上述算法時間大大延長, 甚至當數據達到百萬千萬時失去了實際使用的意義, 當看到聯機算法, 恍然大悟, 於是給出真對該面試題的聯機算法:

    public static void main(String[] args) {
        //源數組生成
        final int SIZE=50000;
        String[] strings=new String[SIZE];
        Random random = new Random();
        for (int i = 0; i < SIZE; i++) {
            strings[i]=random.nextInt(SIZE/2)+"";
        }

        //開始算法
        long start = System.currentTimeMillis();
        int length = strings.length;//獲取數組長度
        Map<String, Integer> resultMap = new LinkedHashMap<>();
        Integer term;

        for (int index = 0; index < length; index++) {
            if (strings[index]!=null&&!"".equals(strings[index])){
                term=resultMap.get(strings[index]);
                if (term==null) {//如果沒遇到過
                    resultMap.put(strings[index],index);
                }else {//如果已經存了
                    resultMap.put(strings[index],-1);
                }
            }
        }

        //算法結束
        long mild = System.currentTimeMillis();
        resultMap.keySet().forEach(key-> {
            if (resultMap.get(key)>0){
                System.out.println("index:"+resultMap.get(key)+"    value:"+key);
            }
        });

        //值提取結束
        long end = System.currentTimeMillis();
        System.out.println("算法時間:"+(mild-start));
        System.out.println("值提取時間:"+(end-mild));
    }

    爲了測試算法效率,將數組長度改爲50000,算法時間如下 (當然博主電腦已經是七年的古董了):

算法時間:53毫秒
值提取時間:247毫秒

那麼聯機算法如果花相同的時間, 可以對多大的數組完成不重複值的篩選呢?結果是當博主將數組長度改爲10000000(一千萬)時, 得到如下結果 (即相同時間, 處理的數據量相差200倍): 

算法時間:11790毫秒
值提取時間:13357毫秒

    不難看出, 之所以有如此大的差距, 還是時間複雜度問題:

    前者時間複雜度爲: O(N^{2}), 後者 "聯機算法" 時間複雜度爲 O(N);  所以, 個人理解: 算法究其根本還是降低待處理集合中每個元素的平均被操作次數;

    當摩爾定律一去不復返, 人們開始普遍相信Amdahl定律對性能的提升, 此時的算法之美顯得尤爲突出!

----------------------------------------------------------------------------完--------------------------------------------------------------------------------------------
作者:划船一哥 
來源:CSDN 
https://me.csdn.net/weixin_42711325
版權聲明:本文爲博主原創文章,轉載請附上博文鏈接!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章