JavaScript數據結構與算法(串)

KMP算法

例如一個字符串有30W個字符判斷是否存在"I am Chinese". 相似這樣的查找字符的毫無疑問須要使用KMP. KMP算法由二個部分組成.算法

  1. 獲取查找串的部分匹配表PMT
  2. 源串根據PMT進行回滾 回滾位數 = 已匹配的字符數 - 對應的部分匹配值

PMT

最大匹配數是前綴集合與後綴集合的交集中最長元素的長度bash

// abababc 
   function PMT(str){
            let next = [], n = 0;
            next[0] = 0;
            for (let i = 1; i < str.length; i++) {
                while (n > 0 && str[i] != str[n]) {  // 當前字符不等於第n+1位字符 那麼n爲次大匹配格式再進行判斷
                    n = next[n-1]
                }
                if (str[i] == str[n]) {
                    n++;
                }
                next[i] = n;
            }
            return next;
        }
    }
    PMT("ababa")   => [0, 0, 1, 2, 3]
複製代碼

while (n > 0 && str[i] != str[n])這段代碼可能比較難理解. 主要是根據next(n-1)最大匹配數來計算next(n). 若是str[i] == str[n]那麼next[n] = next[n-1]+1, 不然將n設置爲次大匹配數next[n-1]; 若是仍是理解不了能夠看知乎ui

回滾

若是沒有匹配上,源串會進行回滾回滾位數 = 已匹配的字符數 - 對應的部分匹配值spa

function KMP(){
    const next = PMT(k);
    let index = -1;
    for (let i = 0; i < str.length; i++) {
        for (let j = 0; j < k.length; j++){
            if (str[i] == k[j]) { // 若是相等
                if (j == k.length-1) {  // 徹底匹配                         
                    index = i-k.length+1
                    break;
                }
                i++;
            } else {    
                i = i-j+next[j] 
                break;
            }
        }
    }
    if (index == -1) {
        return false;
    }
}
複製代碼

字符串壓縮

lintcode設計

設計一種方法,經過給重複字符計數來進行基本的字符串壓縮。 例如,字符串 aabcccccaaa 可壓縮爲 a2b1c5a3 。而若是壓縮後的字符數不小於原始的字符數,則返回原始的字符串。code

const compress = function (str) {
    if (!str.length) {
        return str;
    }
    let newstr = str[0], num = 1;
       for (let i = 1; i < str.length; i++) {
            if (str[i] == str[i-1]) {
                num++;
                if (i == str.length - 1) {
                    newstr += num
                }
            } else {
                    newstr += num;
                newstr += str[i]
                num =1;
            }
        }
        if (newstr.length >= str.length) {
            return str
        }
        return newstr
}
複製代碼

最長無重複字符的子串

lintcode索引

給定一個字符串,請找出其中無重複字符的最長子字符串。 例如,在"abcabcbb"中,其無重複字符的最長子字符串是"abc",其長度爲 3。ip

const lengthOfLongestSubstring = function (str) {
  let max = 0,
        i = 0,
        index = 0,
        hash = {};
    while (i < str.length) {
        let letter = str[i];
        if (!hash[letter]){
            hash[letter] = true;
            if (i-index+1 >= max){
                max = i-index+1
            }
        } else {
            while (index < i) {
                if (str[index] != letter) {
                    hash[str[index]] = false;
                   index++
                } else {
                    index++;
                    break
                }
            }
            hash[letter] = true;
        }
        i++;
    }
    return max
}
複製代碼

有效迴文串

lintcode字符串

給定一個字符串,判斷其是否爲一個迴文串。只考慮字母和數字,忽略大小寫。 例如"A man, a plan, a canal: Panama" 是一個迴文。get

const isPalindrome = function (str) {
   var i = 0, j = str.length-1;
    if (str.length == 1) {
        return true
    } 
    while (j >= i+1) {
            if (!/[\da-zA-z]/.test(str[i])) {
                i++
            }
            if (!/[\da-zA-z]/.test(str[j])) {
                j--
            }
            if ( j >i && str[i].toLowerCase() != str[j].toLowerCase()) {
                return false
            }
            i++; j--;
        }
        return true
    }
}
複製代碼

羅馬數字轉整數

lintcode

給定一個羅馬數字,將其轉換成整數。 回的結果要求在1到3999的範圍內。。

const romanToInt = function (str) {
    let map = new Map([["I", 1], ["V", 5], ["X", 10], ["L", 50], ["C", 100], ["D", 500], ["M", 1000]]);
    let total = 0;
    // 左減必須爲1位  右減不超過3位
    if (str.length == 1) {
        return map.get(str[0]);
    }
    for (let i = 1; i < str.length; i++) {
        let rightNum = map.get(str[i]);
        let leftNum = map.get(str[i-1]);
        if (rightNum > leftNum) {
            total += (rightNum-leftNum);
            i++;
        } else {
            total += leftNum;
        }
        if (i == str.length-1) {
            total += map.get(str[i]); 
        }
    }
    return total
}
複製代碼

One Edit Distance

lintcode

給你兩個字符串 S 和 T, 判斷他們是否只差一步編輯。 例如字符串 s = "aDb", t= "adb"返回true

const isOneEditDistance = function (s, t) {
    if (Math.ceil(s.length-t.length) >= 2){
        return false;
    }
    let len = Math.abs(s.length, t.length);
    let count = 0;  // 調整次數
    for (let i = 0, j = 0; i < len ; i++) {
         if (s[i] != t[j]) {  
            count++;
            if (count >= 2) {
                return false
            }
            if (s.length > t.length) {
                j--
            } else if (s.length < t.length) {
                i--
            }       
        }
        j++;
    }
    if (count == 1 || (count == 0 && Math.abs(s.length-t.length) == 1)) {
        return true;
    } else {
        return false;
    }
}
複製代碼

Find All Anagrams in a String

lintcode

給定一個字符串 s 和一個 非空字符串 p ,找到在 s 中全部關於 p 的字謎的起始索引。 字符串僅由小寫英文字母組成,字符串 s 和 p 的長度不得大於 40,000。 輸出順序可有可無。

const findAnagrams = (s, p) => {
    let indexs = [],
        storehash = {},
        hash  = {}
    for (let i = 0; i < p.length; i++) {
        let str = p[i];
        storehash[str] = storehash[str] ? storehash[str] + 1 : 1;
        hash[str] = hash[str] ? hash[str]+1:1
    }
    let i = 0,
        index = -1,
        count = 0;
    while (i < s.length) {
        let char = s[i];                               
        if (hash[char]){
            if (index == -1) {
                index = i;
            }
            count++;
            hash[char]--;
            if (count == p.length) {                   // 若是count等於0說明知足狀況 存儲i
                indexs.push(index);
                hash[s[index]]++;
                count = p.length-1;
                index++;
            }

        } else {
            if (index != -1 && hash[char] != undefined && (s.length - index) >= p.length) {
                while (index < i) {  // char溢出了 丟棄前面不爲char的字符
                    if (s[index] === char) {
                        index++;
                        break;
                    } else {   
                        count--;
                        hash[s[index]]++;
                    }   
                    index++;
                }
            } else {                                   // 遇到不在hash中的字符則初始化hash, index和count
                hash = Object.assign({}, storehash);
                count = 0;
                index = -1;
            }
        }

        i++;
    }
    return indexs
}
複製代碼
相關文章
相關標籤/搜索