栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

左神算法笔记09:Manacher算法、窗口最大值更新结构、单调栈

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

左神算法笔记09:Manacher算法、窗口最大值更新结构、单调栈

Manacher算法

解决的问题:
字符串str中,最长回文子串的长度如何求解
如何做到时间复杂度O(N)完成

伪代码

时间复杂度分析

代码实现
public class Manacher {
    public static char[] manacherString(String s) {
        char[] charArr = s.toCharArray();
        char[] res = new char[s.length() * 2 + 1];
        int index = 0;
        for (int i = 0; i < res.length; ++i) {
            res[i] = (i & 1) == 0 ? '#' : s.charAt(index++);
        }
        return res;
    }

    public static int maxLengthOfPalindrome(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }

        char[] str  = manacherString(s);
        //回文半径数组
        int[] pArr = new int[ str.length];
        // 整体最右回文右边界的下一个位置,最右的有效区是R-1位置,与讲解时不一样   L[...C...]R
        int R = -1;
        // 整体最右回文时的回文半径中心
        int C = -1;
        //扩出来的最大值
        int max = Integer.MIN_VALUE;

        //每个位置都求回文半径
        for (int i = 0; i <  str.length; ++i) {
            //不用验证也知道的i至少的回文区域,先给pArr[i],四种情况都对,可以验证
            //R <= i i在R外,至少不用验证的区域为1,对应情况1
            //R > i i在R内,至少不用验证的区域为为  i‘的位置对应的回文半径 和 R-i中 的最小值,对应 情况2 的1,2,3
            //i'的位置 = R - (R - C) * 2 + (R - i) = R - 2R + 2C + R - i = 2 * C - i
            pArr[i] = R > i ? Math.min(pArr[ 2 * C - i], R - i) : 1;

            //四种情况都往外扩,情况2的1 2 只会执行一次就会失败,这样写是为了省略代码,不需要if else判断多种情况
            while (i + pArr[i] <  str.length && i - pArr[i] > -1) {
                if (str[i + pArr[i]] == str[i - pArr[i]]) {
                    pArr[i]++;
                }
                else {
                    break;
                }
            }
            if (i + pArr[i] > R) {
                R = i + pArr[i];
                C = i;
            }
            max = Math.max(max, pArr[i]);
        }

        
        return max - 1;
    }

    public static void main(String []args) {
        String s1 = "123";
        String s2 = "ab43534c1234321ab";

        System.out.println("s1: " + maxLengthOfPalindrome(s1));
        System.out.println("s2: " + maxLengthOfPalindrome(s2));
    }
}
窗口最大值更新结构


使用双端队列存索引,每次窗口右边界右移时,先看当前元素是否能加入双端队列尾部,不可以则弹出尾部元素直到可以加入,从而维持一个单调队列
双端队列维持的是当右边界不动,左边界右移的时候,依次判断是否跟队头元素相同从而弹出最大值

平均时间复杂度为O(1)

public class GetMaxNumInWindow {
 
    public static int[] getMaxNumInWin(int[] arr, int win){
        if(arr == null || arr.length < win || win < 1){
            return null;
        }
 
        linkedList maxQueue = new linkedList<>();
        // 共有arr.length - win + 1个窗口,即共有arr.length - win + 1个最大值
        int[] res = new int[arr.length - win + 1];
        int index = 0;
        for(int i = 0; i < arr.length; i++){
            while(!maxQueue.isEmpty() && arr[maxQueue.peekLast()] <= arr[i]){
                
                maxQueue.pollLast();
            }
            maxQueue.addLast(i);
            if(maxQueue.peekFirst() == i - win){
                // 只有当窗口形成后才会有从双端队列头部失效一个数,即过期还是没过期
                maxQueue.pollFirst();
            }
            if(i >= win - 1){
                // 至少有一个窗口存在时,才有max
                res[index] = arr[maxQueue.peekFirst()];
            }
        }
        return res;
    }
}
单调栈

用途:想知道一个数左边比他大最近的是谁,右边比他大最近的是谁

应用

定义:正数数组中累积和与最小值的乘积,假设叫做指标A
给定一个数组,请返回子数组中,指标A最大的值

思路:以当前数字为最小值,求它的子数组,子数组选累加和最大的那个
由此可知是单调栈的做法

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/649054.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号