老司机开车,教会女朋友什么是「马拉车算法」

戳蓝字“CSDN云计算”关注我们哦!
640?wx_fmt=jpeg

作者 | 李威

责编 | 阿秃


马拉车算法( Manacher‘s Algorithm )是小吴最喜欢的算法之一,因为,它真的很牛逼!
马拉车算法是用来 查找一个字符串的最长回文子串的线性方法 ,由一个叫 Manacher 的人在 1975 年发明的,这个方法的牛逼之处在于将时间复杂度提升到了 线性 。
事实上,马拉车算法在思想上和 KMP 字符串匹配算法有相似之处,都避免做了很多重复的工作。
如果你觉得马拉车算法的中文称呼有点俗,那么 KMP算法 就是带了一点颜色了,你总能在有关于 KMP算法 介绍的文章留言区看到它的中文俗称。
Manacher 算法本质上还是 中心扩散法 ,只不过它使用了类似 KMP 算法的技巧,充分挖掘了已经进行回文判定的子串的特点,提高算法的效率。
下面介绍 Manacher 算法的运行流程。
首先还是“中心扩散法”的思想:回文串可分为奇数回文串和偶数回文串,它们的区别是:奇数回文串关于它的“中点”满足“中心对称”,偶数回文串关于它“中间的两个点”满足“中心对称”。
为了避免对于回文串字符个数为奇数还是偶数的套路,首先对原始字符串进行预处理,方法也很简单:添加分隔符

第 1 步:预处理

第一步是对原始字符串进行预处理,也就是 添加分隔符
首先在字符串的首尾、相邻的字符中插入分隔符,例如 "babad" 添加分隔符 "#" 以后得到 "#b#a#b#a#d#"
对这一点有如下说明:
1、分隔符是一个字符,种类也只有一个,并且这个字符一定不能是原始字符串中出现过的字符;
2、加入了分隔符以后,使得“间隙”有了具体的位置,方便后续的讨论,并且新字符串中的任意一个回文子串在原始字符串中的一定能找到唯一的一个回文子串与之对应,因此对新字符串的回文子串的研究就能得到原始字符串的回文子串;
3、新字符串的回文子串的长度一定是奇数;
4、新字符串的回文子串一定以分隔符作为两边的边界,因此分隔符起到“哨兵”的作用。
640?wx_fmt=jpeg
五分钟学算法:原始字符串与新字符串的对应关系

第 2 步:计算辅助数组 p

辅助数组 p 记录了新字符串中以每个字符为中心的回文子串的信息。
手动的计算方法仍然是“中心扩散法”,此时记录以当前字符为中心,向左右两边同时扩散,记录能够扩散的最大步数。
以字符串 "abbabb" 为例,说明如何手动计算得到辅助数组 p ,我们要填的就是下面这张表。
char#a#b#b#a#b#b#
index0123456789101112
p












第 1 行数组 char :原始字符串加上分隔符以后的每个字符。
第 2 行数组 index :这个数组是新字符串的索引数组,它的值是从 0 开始的索引编号。
  • 我们首先填 p[0]

char#a#b#b#a#b#b#
index0123456789101112
p0











char[0] = '#' 为中心,同时向左边向右扩散,走 1 步就碰到边界了,因此能扩散的步数为 0,因此 p[0] = 0
  • 下面填写 p[1]
char[1] = 'a' 为中心,同时向左边向右扩散,走 1 步,左右都是 "#",构成回文子串,于是再继续同时向左边向右边扩散,左边就碰到边界了,最多能扩散的步数”为 1,因此 p[1] = 1
char#a#b#b#a#b#b#
index0123456789101112
p01











  • 下面填写 p[2]
char[2] = '#' 为中心,同时向左边向右扩散,走 1 步,左边是 "a",右边是 "b",不匹配,最多能扩散的步数为 0,因此 p[2] = 0


  • 下面填写 p[3]
char[3] = 'b' 为中心,同时向左边向右扩散,走 1 步,左右两边都是 “#”,构成回文子串,继续同时向左边向右扩散,左边是 "a",右边是 "b",不匹配,最多能扩散的步数为 1 ,因此 p[3] = 1
char#a#b#b#a#b#b#
index0123456789101112
p0101









  • 下面填写 p[4]
char[4] = '#' 为中心,同时向左边向右扩散,最多可以走 4 步,左边到达左边界,因此 p[4] = 4
char#a#b#b#a#b#b#
index0123456789101112
p01014








  • 继续填完 p 数组剩下的部分。
分析到这里,后面的数字不难填出,最后写成如下表格:
char#a#b#b#a#b#b#
index0123456789101112
p0101410501210
说明:有些资料将辅助数组 p 定义为回文半径数组,即 p[i] 记录了以新字符串第 i 个字符为中心的回文字符串的半径(包括第 i 个字符),与我们这里定义的辅助数组 p 有一个字符的偏差,本质上是一样的。
下面是辅助数组 p 的结论:辅助数组 p 的最大值是 5,对应了原字符串 "abbabb" 的  “最长回文子串” :"bbabb"。这个结论具有一般性,即:
辅助数组 `p` 的最大值就是“最长回文子串”的长度
因此,我们可以在计算辅助数组 p 的过程中记录这个最大值,并且记录最长回文子串。
简单说明一下这是为什么:
如果新回文子串的中心是一个字符,那么原始回文子串的中心也是一个字符,在新回文子串中,向两边扩散的特点是:“先分隔符,后字符”,同样扩散的步数因为有分隔符 # 的作用,在新字符串中每扩散两步,虽然实际上只扫到一个有效字符,但是相当于在原始字符串中相当于计算了两个字符。
因为最后一定以分隔符结尾,还要计算一个,正好这个就可以把原始回文子串的中心算进去
640?wx_fmt=jpeg
五分钟学算法:理解辅助数组的数值与原始字符串回文子串的等价性-1
如果新回文子串的中心是 #,那么原始回文子串的中心就是一个“空隙”。在新回文子串中,向两边扩散的特点是:“先字符,后分隔符”,扩散的步数因为有分隔符  # 的作用,在新字符串中每扩散两步,虽然实际上只扫到一个有效字符,但是相当于在原始字符串中相当于计算了两个字符。
因此,“辅助数组 p 的最大值就是“最长回文子串”的长度”这个结论是成立的,可以看下面的图理解上面说的 2 点。
640?wx_fmt=jpeg
五分钟学算法:理解辅助数组的数值与原始字符串回文子串的等价性-2
写到这里,其实已经能写出一版代码。(注:本文的代码是结合了 LeetCode 第 5 题「最长回文子串」进行讲解)

参考代码

public class Solution {

    public String longestPalindrome(String s) {
        int len = s.length();
        if (len < 2) {
            return s;
        }
        String str = addBoundaries(s, '#');
        int sLen = 2 * len + 1;
        int maxLen = 1;

        int start = 0;
        for (int i = 0; i < sLen; i++) {
            int curLen = centerSpread(str, i);
            if (curLen > maxLen) {
                maxLen = curLen;
                start = (i - maxLen) / 2;
            }
        }
        return s.substring(start, start + maxLen);
    }

    private int centerSpread(String s, int center) {
        // left = right 的时候,此时回文中心是一个空隙,回文串的长度是奇数
        // right = left + 1 的时候,此时回文中心是任意一个字符,回文串的长度是偶数
        int len = s.length();
        int i = center - 1;
        int j = center + 1;
        int step = 0;
        while (i >= 0 && j < len && s.charAt(i) == s.charAt(j)) {
            i--;
            j++;
            step++;
        }
        return step;
    }


    /**
     * 创建预处理字符串
     *
     * @param s      原始字符串
     * @param divide 分隔字符
     * @return 使用分隔字符处理以后得到的字符串
     */

    private String addBoundaries(String s, char divide) {
        int len = s.length();
        if (len == 0) {
            return "";
        }
        if (s.indexOf(divide) != -1) {
            throw new IllegalArgumentException("参数错误,您传递的分割字符,在输入字符串中存在!");
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            stringBuilder.append(divide);
            stringBuilder.append(s.charAt(i));
        }
        stringBuilder.append(divide);
        return stringBuilder.toString();
    }
}

复杂度分析

  • 时间复杂度:O(N2),这里 N 是原始字符串的长度。新字符串的长度是 2 * N + 1,不计系数与常数项,因此时间复杂度仍为 O(N2)
  • 空间复杂度:O(N)

科学家的工作

此时,计算机科学家 Manacher 出现了,他充分利用新字符串的回文性质,计算辅助数组 p。
上面的代码不太智能的地方是,对新字符串每一个位置进行中心扩散,会导致原始字符串的每一个字符被访问多次,一个比较极端的情况就是:#a#a#a#a#a#a#a#a#
事实上,计算机科学家 Manacher 就改进了这种算法,使得在填写新的辅助数组 p 的值的时候,能够参考已经填写过的辅助数组 p 的值,使得新字符串每个字符只访问了一次,整体时间复杂度由 O(N2改进到 O(N)
具体做法是:在遍历的过程中,除了循环变量 i 以外,我们还需要记录两个变量,它们是 maxRightcenter ,它们分别的含义如下:


maxRight


maxRight 表示记录当前向右扩展的最远边界,即从开始到现在使用“中心扩散法”能得到的回文子串,它能延伸到的最右端的位置 。
对于 maxRight 我们说明 3 点:
  1. “向右最远”是在计算辅助数组 p 的过程中,向右边扩散能走的索引最大的位置,注意:得到一个 maxRight 所对应的回文子串,并不一定是当前得到的“最长回文子串”,很可能的一种情况是,某个回文子串可能比较短,但是它正好在整个字符串比较靠后的位置;
  2. maxRight 的下一个位置可能是被程序看到的,停止的原因有 2 点:(1)左边界不能扩散,导致右边界受限制也不能扩散,maxRight 的下一个位置看不到;(2)正是因为看到了 maxRight 的下一个位置,导致 maxRight 不能继续扩散。
  3. 为什么 maxRight 很重要?因为扫描是从左向右进行的, maxRight 能够提供的信息最多,它是一个重要的分类讨论的标准,因此我们需要一个变量记录它。



center


center 是与 maxRight 相关的一个变量,它是上述 maxRight 的回文中心的索引值。对于 center 的说明如下:
center 的形式化定义:


640?wx_fmt=png
说明:x + p[x] 的最大值就是我们定义的 maxRighti 是循环变量,0<= x< i 表示是在 i 之前的所有索引里得到的最大值  maxRight,它对应的回文中心索引就是上述式子。


maxRight 与 center 的关系


maxRightcenter 是一一对应的关系,即一个  center 的值唯一对应了一个 maxRight 的值;因此 maxRightcenter 必须要同时更新
下面的讨论就根据循环变量 imaxRight 的关系展开讨论:
情况 1:当 i >= maxRight 的时候,这就是一开始,以及刚刚把一个回文子串扫描完的情况,此时只能够根据“中心扩散法”一个一个扫描,逐渐扩大 maxRight
情况 2:当 i < maxRight 的时候,根据新字符的回文子串的性质,循环变量关于 center 对称的那个索引(记为 mirror)的 p 值就很重要。
我们先看 mirror 的值是多少,因为 center 是中心,imirror 关于 center 中心对称,因此 (mirror + i) / 2 = center ,所以 mirror = 2 * center - i
根据 p[mirror] 的数值从小到大,具体可以分为如下 3 种情况:
情况 2(1)p[mirror] 的数值比较小,不超过 maxRight - i
说明:maxRight - i 的值,就是从 i 关于 center 的镜像点开始向左走(不包括它自己),到 maxRight 关于 center 的镜像点的步数
640?wx_fmt=jpeg
五分钟学算法:Manacher 算法分类讨论情况 2(1)
从图上可以看出,由于“以 center 为中心的回文子串”的对称性,导致了“以 i 为中心的回文子串”与“以 center 为中心的回文子串”也具有对称性,“以 i 为中心的回文子串”与“以 center 为中心的回文子串”不能再扩散了,此时,直接把数值抄过来即可,即 p[i] = p[mirror]
情况 2(2)p[mirror] 的数值恰好等于 maxRight - i
640?wx_fmt=jpeg
五分钟学算法:Manacher 算法分类讨论情况 2(2)
说明:仍然是依据“以 center 为中心的回文子串”的对称性,导致了“以 i 为中心的回文子串”与“以 center 为中心的回文子串”也具有对称性。
  1. 因为靠左边的 f 与靠右边的 g 的原因,导致“以 center 为中心的回文子串”不能继续扩散;
  2. 但是“以 i 为中心的回文子串” 还可以继续扩散。
因此,可以先把 p[mirror] 的值抄过来,然后继续“中心扩散法”,继续增加 maxRight
情况 2(3)p[mirror] 的数值大于 maxRight - i
640?wx_fmt=jpeg
五分钟学算法:Manacher 算法分类讨论情况 2(3)
说明:仍然是依据“以 center 为中心的回文子串”的对称性,导致了“以 i 为中心的回文子串”与“以 center 为中心的回文子串”也具有对称性。
下面证明,p[i] = maxRight - i ,证明的方法还是利用三个回文子串的对称性。
640?wx_fmt=jpeg
五分钟学算法:Manacher 算法分类讨论情况 2(3)的证明
① 由于“以 center 为中心的回文子串”的对称性, 黄色箭头对应的字符 ce 一定不相等;
② 由于“以 mirror 为中心的回文子串”的对称性, 绿色箭头对应的字符 cc 一定相等;
③ 又由于“以 center 为中心的回文子串”的对称性, 蓝色箭头对应的字符 cc 一定相等;
推出“以 i 为中心的回文子串”的对称性,  红色箭头对应的字符 ce 一定不相等。
因此,p[i] = maxRight - i,不可能再大。上面是因为我画的图,可能看的朋友会觉得理所当然。事实上,可以使用反证法证明:
如果“以 i 为中心的回文子串” 再向两边扩散的两个字符 ce 相等,就能够推出黄色、绿色、蓝色、红色箭头所指向的 8 个变量的值都相等,此时“以 center 为中心的回文子串” 就可以再同时向左边和右边扩散 1 格,与 maxRight 的最大性矛盾。
综合以上 3 种情况,当 i < maxRight 的时候,p[i] 可以参考 p[mirror] 的信息,以 maxRight - i 作为参考标准,p[i] 的值应该是保守的,即二者之中较小的那个值:
p[i] = min(maxRight - i, p[mirror]);

参考代码

public class Solution {

    public String longestPalindrome(String s) {
        // 特判
        int len = s.length();
        if (len < 2) {
            return s;
        }

        // 得到预处理字符串
        String str = addBoundaries(s, '#');
        // 新字符串的长度
        int sLen = 2 * len + 1;

        // 数组 p 记录了扫描过的回文子串的信息
        int[] p = new int[sLen];

        // 双指针,它们是一一对应的,须同时更新
        int maxRight = 0;
        int center = 0;

        // 当前遍历的中心最大扩散步数,其值等于原始字符串的最长回文子串的长度
        int maxLen = 1;
        // 原始字符串的最长回文子串的起始位置,与 maxLen 必须同时更新        
        int start = 0;

        for (int i = 0; i < sLen; i++) {
            if (i < maxRight) {
                int mirror = 2 * center - i;
                // 这一行代码是 Manacher 算法的关键所在,要结合图形来理解
                p[i] = Math.min(maxRight - i, p[mirror]);
            }

            // 下一次尝试扩散的左右起点,能扩散的步数直接加到 p[i] 中
            int left = i - (1 + p[i]);
            int right = i + (1 + p[i]);

            // left >= 0 && right < sLen 保证不越界
            // str.charAt(left) == str.charAt(right) 表示可以扩散 1 次
            while (left >= 0 && right < sLen && str.charAt(left) == str.charAt(right)) {
                p[i]++;
                left--;
                right++;

            }
            // 根据 maxRight 的定义,它是遍历过的 i 的 i + p[i] 的最大者
            // 如果 maxRight 的值越大,进入上面 i < maxRight 的判断的可能性就越大,这样就可以重复利用之前判断过的回文信息了
            if (i + p[i] > maxRight) {
                // maxRight 和 center 需要同时更新
                maxRight = i + p[i];
                center = i;
            }
            if (p[i] > maxLen) {
                // 记录最长回文子串的长度和相应它在原始字符串中的起点
                maxLen = p[i];
                start = (i - maxLen) / 2;
            }
        }
        return s.substring(start, start + maxLen);
    }


    /**
     * 创建预处理字符串
     *
     * @param s      原始字符串
     * @param divide 分隔字符
     * @return 使用分隔字符处理以后得到的字符串
     */

    private String addBoundaries(String s, char divide) {
        int len = s.length();
        if (len == 0) {
            return "";
        }
        if (s.indexOf(divide) != -1) {
            throw new IllegalArgumentException("参数错误,您传递的分割字符,在输入字符串中存在!");
        }
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < len; i++) {
            stringBuilder.append(divide);
            stringBuilder.append(s.charAt(i));
        }
        stringBuilder.append(divide);
        return stringBuilder.toString();
    }
}

复杂度分析

  • 时间复杂度:O(N),由于 Manacher 算法只有在遇到还未匹配的位置时才进行匹配,已经匹配过的位置不再匹配,因此对于字符串 S 的每一个位置,都只进行一次匹配,算法的复杂度为 O(N)
  • 空间复杂度:O(N)

后记

Manacher 算法我个人觉得没有必要记住,如果真有遇到,查资料就可以了。

640?wx_fmt=png

福利
扫描添加小编微信,备注“姓名+公司职位”,入驻【CSDN博客】,加入【云计算学习交流群】,和志同道合的朋友们共同打卡学习!


640?wx_fmt=jpeg

推荐阅读:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/520616.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实时计算 Flink性能调优

自动配置调优 实时计算 Flink新增自动调优功能autoconf。能够在流作业以及上下游性能达到稳定的前提下&#xff0c;根据您作业的历史运行状况&#xff0c;重新分配各算子资源和并发数&#xff0c;达到优化作业的目的。更多详细说明请您参阅自动配置调优。 首次智能调优 创建…

神作!3万程序员在学,这本深度学习宝典刷爆IT圈!

深度学习在过去5年处于爆发式增长状态&#xff0c;在人工智能领域占据主导地位。据Gartner统计&#xff0c;深度学习的专家职位从2014年之后才开始出现&#xff0c;不过到2018年&#xff0c;市面上大概就有40,000多深度学习专家的职位空缺。而且这些需求大多来自Facebook、Appl…

计算机软件中汇编程序是一种,计算机系统软件中的汇编程序是一种()。

摘要&#xff1a;疼痛&#xff0c;计算机系件中热、痛皮色不红、不&#xff0c;为E&#xff0c;缓者则痛得暖。下列和间关于直接经验接经验&#xff0c;编程的说错误法有。形式认识这种属于&#xff0c;计算机系件中香味人闻果的一个到苹&#xff0c;莱果的颜色看到。...疼痛&a…

取某个单元格的值_vba中如何进行单元格复制,Copy方法使用介绍,一定要学

NO.1在Excel操作过程当中&#xff0c;除了给表格输入内容就数单元格复制最常用了&#xff0c;通常快捷方法有Ctrlc&#xff0c;Ctrlv。不用说&#xff0c;这种方法对于操作十分方便&#xff0c;那么如何利用代码来实现复制功能呢&#xff01;因为在编程过程中&#xff0c;会用到…

Visual Studio Code(VScode)设置为中文界面

安装插件重启即可&#xff1a; 名称: Chinese (Simplified) Language Pack for Visual Studio Code

重磅!阿里云发布业界首款SaaS化防火墙

近日&#xff0c;阿里云发布了业界首款SaaS化防火墙&#xff0c;一键开启&#xff0c;无需复杂网络接入配置&#xff0c;适用于所有在云上部署了重要业务资产的客户&#xff0c;特别是企业级客户。 对于用户来说&#xff0c;即开即用&#xff0c;操作简单&#xff0c;无需传统…

阿里云全球首推流量型独享虚拟主机新规格,网络访问速度最高提升400%

近日&#xff0c;为了提升用户网站访问体验&#xff0c;阿里云虚拟主机宣布推出流量型独享虚拟主机新规格&#xff0c;流量型独享虚拟主机新规格可以提供高速流量包&#xff0c;提高访问速度。在高速流量包用尽后&#xff0c;网站也不会关停&#xff0c;可自动降为低带宽模式&a…

阿里云文件存储的高性能架构演进之路

10月27日下午&#xff0c;2018中国计算机大会上举办了主题“数据中心计算”的技术论坛&#xff0c;一起探讨解决数据中心所面临的挑战。论坛上&#xff0c;阿里云分布式存储团队高级技术专家田磊磊进行了《阿里云文件存储的高性能架构演进之路》的报告。 专家简介 田磊磊&…

阿里巴巴黄贵谈存储新硬件带来数据库的机遇

10月27日下午&#xff0c;2018中国计算机大会上举办了主题“存储软硬件之国产化挑战与机遇”的技术论坛&#xff0c;共同探讨存储软硬件栈上的关键系统与技术的国产化发展道路。论坛上&#xff0c;阿里数据库资深技术专家黄贵针对存储软硬件国产化进行了《存储新硬件给数据库自…

项目实战Git团队操作_图形化版本

文章目录一、分支思路1. Git命令常用理解记忆2. 分支换分规则3. 线上发布准备二、 实战前期准备2.1. 在远程仓库创建kernel_system项目2.2. 将远程仓库克隆到本地2.3. 本地准备操作三、场景实战模拟提交3.1. Git合并某个分支的某/多次提交到指定分支3.2. Git合并分支3.3. 回滚/…

为什么程序员总是打扮成这样一幅鬼样子

1几千年来&#xff0c;时尚像病毒一样不断进化&#xff0c;横扫世界。它遇神杀神&#xff0c;遇佛杀佛。遇到程序员后&#xff0c;含羞自尽。因为程序员是时尚休止符。因为他们习惯以不变应万变。夏季三大件&#xff1a;格子衫沙滩裤人字拖。冬季三大件&#xff1a;冲锋衣牛仔裤…

基础计算机b卷,计算机应用基础B卷.doc

计算机应用基础B卷.doc (6页)本资源提供全文预览&#xff0c;点击全文预览即可全文预览,如果喜欢文档就下载吧&#xff0c;查找使用更方便哦&#xff01;9.9 积分&#xfeff;《计算机应用基础》模拟试卷B (闭卷)一、单项选择题(本大题共40个小题&#xff0c;每题2分&#xff0…

阿里云大数据总监:计算让城市更智能

10月25日&#xff0c;2018中国计算机大会上举办了主题是智慧城市下个十年&#xff1a;智在“数”还是“术”的技术论坛。目前&#xff0c;城市已经具备了丰富多样的大数据积累&#xff0c;成体系的数据管理标准&#xff0c;开放自由的数据流动环境等重要基础&#xff0c;但对于…

多维度创新打造领先阿里云技术生态

10月26日&#xff0c;2018中国计算机大会上举办了主题是“云计算生态与发展”的技术论坛。论坛上&#xff0c;阿里云技术战略架构师陈绪博士从构建目标、构建基石、构建要点三个方面详细陈述了阿里云开放的技术生态。目前阿里云正在全力打造一个由阿里云引导、驱动、赋能的多赢…

Facebook陷入史上最大危机;华为5G设备欧洲大卖,美国指责欧盟;红帽宣布OpenShift可用于AWS中国……...

关注并标星星CSDN云计算 速递、最新、绝对有料。这里有企业新动、这里有业界要闻&#xff0c;打起十二分精神&#xff0c;紧跟fashion你可以的&#xff01;每周两次&#xff0c;打卡即read更快、更全了解泛云圈精彩newsgo go go新加坡加入微信计划 &#xff08;图片来源网络&am…

阿里云高级总监谈超大规模超高性能分布式快存储系统

新型硬件&#xff08;如NVRAM、RDMA、GPU/TPU等&#xff09;及其构建的异构复杂环境&#xff0c;与既有硬件环境的巨大差异&#xff0c;导致传统的算法、数据结构甚至是涉及原则和经验法则等难以为继&#xff0c;对计算智能与大数据处理带来新的挑战和机遇。 10月27日下午&…

最新量子通信芯片曝光!大小仅为现有装置的千分之一

近日&#xff0c;新加坡南洋理工大学&#xff08;NTU-Singapore&#xff09;的Liu Ai Qun教授和Kwek Leong Chuan副教授领导的研究小组在《自然光子学》发表一项令人吃惊的研究成果&#xff1a;他们研究出一种量子通信芯片&#xff0c;大小约为3mm&#xff0c;其体积是目前量子…

如何提高阿里云上应用的可用性(一)

如今&#xff0c;开发并上线一款应用十分方便。因为云计算提供了从最基础的计算资源如服务器网络、数据库服务、中间件PaaS平台到各种应用支撑的云管理服务&#xff0c;同时开源社区的迅猛发展也提供了从数据库、缓存到应用全生命流程中各种必须的组件&#xff0c;所以越来越多…

运营商服务器系统,浪潮服务器助力运营商三大支撑系统上云

【IT168 资讯】继浙江移动、广东移动、福建电信业务系统云化应用改造项目后&#xff0c;浪潮服务器再次中标河南某运营商云资源池项目&#xff0c;中标金额达三千多万。三百多台浪潮双路、四路服务器用于支撑该运营商的BOSS计费系统、CRM系统、经营分析系统、网管应用系统、OA、…

如何提高阿里云上应用的可用性(二)

在单体应用时代&#xff0c;最大的问题是如何解决数据库瓶颈&#xff0c;而微服务之下&#xff0c;一个大应用被拆分成了几十个甚至上百个微服务&#xff0c;数据访问的压力被传导到了服务之间的网络&#xff0c;服务强弱依赖&#xff0c;服务雪崩等各种问题随之而来&#xff0…