算法学习记录(二十三)

98 阅读1分钟

问:

  1. 求字符串的最大回文子串
  2. 剑指 Offer 59 - I. 滑动窗口的最大值

解:

  1. Manacher
function Manacher(str) {
    // 用#扩充处理字符串,使得它可以统计偶数回文子串
    str = handleStr(str)
    // 所有回文子串的最右边界
    let rightBorder = -1
    // 最右边界的子串的中点
    let center = -1
    // 所有字符的回文半径
    const everyLength = []
    let max = -1
    for (let i = 0; i < str.length; i++) {
        // 当前位置的最小可跳过判断的回文半径
        everyLength[i] = i < rightBorder ? Math.min(everyLength[2 * center - i], rightBorder - i) : 1
        // 当前位置为中心,回文半径不越界
        while (i + everyLength[i] < str.length && i - everyLength[i] > -1) {
            if (str[everyLength[i] + i] === str[i- everyLength[i]]) {
                everyLength[i]++
            } else {
                break
            }
        }
        // 取所有回文子串的最右边界
        if (i + everyLength[i] > rightBorder) {
            rightBorder = everyLength[i] + i
            center = i
        }
        // 回文半径最大值
        max = Math.max(everyLength[i], max)
    }
    // 字符被扩充过,所以回文半径-1就是真实字符串的回文直径
    return max - 1
    function handleStr(str) {
        const strArr = str.split('')
        strArr.push('')
        strArr.unshift('')
        return strArr.join('#')
    }
}
  1. 创建一个队列,遍历数组,若当前值不大于队列的最后一位就放进去,否则弹出队列的最后一位,直到遇到符合条件的值或者直到弹空为止。当遍历次数小于size时先不计算窗口最大值,因为这个窗口还不完整。当窗口完整创建后,队列的第一位就是最大值。放入结果数组,若窗口最左值是最大值,那么就移除队列中这个值,因为窗口右移就不再包含这个值。
function slidingWindow(arr, size) {
    const res = []
    const queue = []
    let left = 0
    let right = 0
    while (right < arr.length) {
        while (queue.length && queue[queue.length - 1] < arr[right]) {
            queue.pop()
        }
        queue[queue.length] = arr[right]
        right++
        if (right < size) continue
        res[res.length] = queue[0]
        if (arr[left] === queue[0]) {
            queue.shift()
        }
        left++
    }
    return res
}