swift 查找给定子字符串的所有位置 朴素字符串匹配、KMP字

2020-02-28  本文已影响0人  一直都是流年

思路:
使用朴素字符串搜索,依次扫描整个字符串

/// 查找所有的子字符串所在位置
/// - Parameter string: 给定的模式P
func findAllIndex(_ string:String) -> [NSRange]{
    var ranges:[NSRange] = []
    if string.elementsEqual(""){
        return ranges
    }
    let zero = self.startIndex
    let target = Array(string)
    let total = Array(self)
    
    let lenght = string.count
    var startPoint = 0
    
    while total.count >= startPoint + string.count{
        if total[startPoint] == target[0]{
            let startIndex = self.index(zero, offsetBy: startPoint)
            let endIndex = self.index(startIndex, offsetBy: lenght)
            let child = self[startIndex..<endIndex]
            if child.elementsEqual(string){
                ranges.append(NSRange.init(location: startPoint, length: lenght))
                startPoint += lenght
            }else{
                startPoint += 1
            }
        }else{
            startPoint += 1
        }
    }
    
    return ranges
}

使用KMP算法实现:

/// KMP字符串查询
/// - Parameter p: 查询的模式
func kmpFindAllIndex(_ p:String) -> [NSRange]{
    var ranges:[NSRange] = []
    let n = self.count
    let m = p.count
    let π = computePrefix(p)
    var q = 0
    
    for i in 0..<n{
        while q > 0 && !p.getCharacter(q).elementsEqual(self.getCharacter(i)){
            q = π[q]
        }
        
        if p.getCharacter(q).elementsEqual(self.getCharacter(i)){
            q += 1
        }
        
        if q == m{
            ranges.append(NSRange.init(location: i, length: m))
            q = π[q]
        }
    }
    return ranges
}


/// 计算KMP对应的前缀函数π数组
/// - Parameter p: 模式P
func computePrefix(_ p:String) -> [Int]{
    let m = p.count
    var π:[Int] = [Int](repeatElement(0, count: m + 1))
    π[0] = 0
    var k = 0
    for q in 1..<m{
        while k > 0 && !p.getCharacter(k).elementsEqual(p.getCharacter(q)){
            k = π[k]
        }
        if p.getCharacter(k).elementsEqual(p.getCharacter(q)){
            k += 1
        }
        π[q] = k
    }
    
    return π
}


/// 获取单个字符
/// - Parameter index: <#index description#>
func getCharacter(_ index:Int) -> String{
    return getChildsString(index, 1)
}

/// 获取特定位置,长度 字符串
/// - Parameters:
///   - start: 开始位置
///   - length: 长度
func getChildsString(_ start:Int,_ length:Int) -> String{
    let startIndex = self.index(self.startIndex, offsetBy: start)
    let endIndex = self.index(startIndex, offsetBy: length)
    return String(self[startIndex..<endIndex])
}
上一篇下一篇

猜你喜欢

热点阅读