【LeetCode #3 題解】 無重複字符的最長子串

一、題目

給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。

  • 示例 1:
輸入: "abcabcbb"
輸出: 3 
解釋: 因爲無重複字符的最長子串是 "abc",所以其長度爲 3
  • 示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 因爲無重複字符的最長子串是 "b",所以其長度爲 1
  • 示例 3:
輸入: "pwwkew"
輸出: 3
解釋: 因爲無重複字符的最長子串是 "wke",所以其長度爲 3。
     請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。

二、題解一:雙指針暴力查找法 8ms 5.4M

// 暴力查找法
int lengthOfLongestSubstring(char * s){
    char *begin=NULL, *end=NULL, *p=NULL;
    int result=0;

    begin = s;     // 字串開始指針
    end = s;     // 字串結束指針

    // 是否走到了字串最末尾
    while( (*end) != '\0' ){ 

        // 此時將當前end 字符與前面的所有字符依次匹配
        p = begin;

        // 當動態匹配指針走到 end 字符處時,結束前面字串匹配
        while( p != end ){   

            // 處理當前字符與前面任意字符存在重複的情況
            if( *end == *p ){

                // 保存長度
                if( (end-begin) > result){
                    result = end - begin;
                }
                // 將start 置於 p + 1處,重新進行下一輪匹配
                begin = p+1;
                break;
            }
            p++;
        }
        end++;      // 開始匹配下一個字符
    }

    // 處理特殊情況,也就是走到末尾時,未看到重複的字符
    result = result > end - begin ? result : end - begin;

    return result;
}

運行結果如下:
在這裏插入圖片描述


三、驚呆:雙指針暴力查找法 優化後 4 ms ? 假的

在前面的基礎上,將 if 判斷語名修改爲三元表達式,時間從 8ms 變爲 4ms ,有點不敢相信。。。
代碼如下:

// 雙指針暴力查找法

int lengthOfLongestSubstring(char * s){
    char *begin=s, *end=s, *p=NULL;	
    int result=0;

    // 是否走到了字串最末尾
    while( (*end) != '\0' ){ 

        // 此時將當前end 字符與前面的所有字符依次匹配
        p = begin;

        // 當動態匹配指針走到 end 字符處時,結束前面字串匹配
        while( p != end ){   

            // 處理當前字符與前面任意字符存在重複的情況
            if( *end == *p ){

                // 保存長度
                result = (end-begin) > result ? end - begin : result;
                
                // 將start 置於 p + 1處,重新進行下一輪匹配
                begin = p+1;
                break;
            }
            p++;
        }
        end++;      // 開始匹配下一個字符
    }

    // 處理特殊情況,也就是走到末尾時,未看到重複的字符
    result = result > end - begin ? result : end - begin;

    return result;
}

這個結果確實不敢相信,我懷疑是服務器運行的差異,經過多次運行,發現確實是這樣,和三元表達式沒半毛錢關係:
在這裏插入圖片描述


3.1 優化點1:指針賦值初始化,優化0.2M 內存

雖然前面的結果有問題,但賦值初始化,經過多次實測,確實優化了內存,雖然效果不明顯。
但養成這個習慣還是好的

將代碼指針初始化賦值,實測結果優化 0.2M 內存。
修改爲:

    char *begin=NULL, *end=NULL, *p=NULL;
    begin = s;     // 字串開始指針
    end = s;     // 字串結束指針

=====>

	char *begin=s, *end=s, *p=NULL;	

實測結果:
在這裏插入圖片描述


四、題解二:利用數組內容判定是否重複

在第一種方法中,我們使用兩個指針,
一個指針用來從字串頭走到尾,第二個指針用來再次遍歷字串判定是否重複。
因爲,本方法就是對第二個指針來進行優化,
通過數組查表法來判定是否重複,避免指針再次遍歷。

// 解法二、利用數組判定是否重複
// 

#define HASH_LEN 128

int lengthOfLongestSubstring(char * s){
    char *p = s;
    int max_count=0, start=0; 

    // 定義hash 數組, ascii 最大隻有128個字符
    int hash_s[HASH_LEN];   

    // 重置所有數組值爲 0
    memset(hash_s, 0x0, sizeof(hash_s));

    while(*p != '\0'){  
        
        // 通過數組中的值來判定是否重複
        // 如果字母是首次出現,hash_s[x]應該爲0
        // 如果讀取數組內容 > 0, 說明重複了,且其索引爲 hash_s[x] -1
        // 如果讀取數組內容 < start ,則說明字母在之前,不用管
        if( hash_s[ *p ] != 0 && hash_s[ *p ] >= start ){

            // 更新字串大小
            max_count = max_count > p-s - start  ? max_count : p-s - start ;

            // 更新字串起始位置爲 i+1
            start = hash_s[*p]; 
        }

        // 此入之所以加 1 是避免 -1 的操作
        hash_s[*p] = p-s + 1; 

        p++; 
    }

    // 更新字串大小
    max_count = max_count > p-s - start  ? max_count : p-s - start ;

    return max_count;
}

運行結果如下:
在這裏插入圖片描述

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