Algorithm 列表的最大后缀

Algorithm 列表的最大后缀,algorithm,Algorithm,这个问题是试图找到给定列表的字典最大后缀 假设我们有一个数组/列表[e1;e2;e3;e4;e5] 那么[e1;e2;e3;e4;e5]的所有后缀都是: [e1;e2;e3;e4;e5] [e2;e3;e4;e5] [e3;e4;e5] [e4;e5] [e5] 然后,我们的目标是在上述5列表中找到词典编纂的最大值 例如,[1;2;3;1;0]的所有后缀都是 [1;2;3;1;0] [2;3;1;0] [3;1;0] [1;0] [0]. 从上面的示例中,词典的最大后缀是[3;1;0]

这个问题是试图找到给定列表的字典最大后缀


假设我们有一个数组/列表[e1;e2;e3;e4;e5]

那么[e1;e2;e3;e4;e5]的所有后缀都是:

[e1;e2;e3;e4;e5]
[e2;e3;e4;e5]
[e3;e4;e5]
[e4;e5]
[e5]

然后,我们的目标是在上述5列表中找到词典编纂的最大值


例如,[1;2;3;1;0]的所有后缀都是

[1;2;3;1;0]
[2;3;1;0]
[3;1;0]
[1;0]
[0].

从上面的示例中,词典的最大后缀是
[3;1;0]


简单的算法只是逐个比较所有后缀,并始终记录最大值。时间复杂度是
O(n^2)
,因为比较两个列表需要
O(n)

但是,所需的时间复杂度为O(n),并且不应使用后缀树(也不使用后缀数组)

请注意,列表中的元素可能不是不同的

int max_后缀(const vector&a)
{
int n=a.size(),
i=0,
j=1,
K
while(jj)
互换(i,j);
}
返回i;
}
我的解决办法是对这个问题的解决办法稍加修改


在上面的代码中,每次它进入循环时,都会保持
i
,以及所有
a[p…n](0想象在一个两人游戏中,两个对手a和B在寻找给定字符串s的最大后缀时相互对抗。谁首先找到最大后缀,谁将赢得游戏。在第一轮中,a选择后缀s[i…],B选择后缀s[j..]

i: _____X
j: _____Y
Matched length = k
法官比较两个后缀,发现在k次比较后不匹配,如上图所示

在不失去普遍性的情况下,我们假设X>Y,那么B在这一轮中输了。因此他必须选择一个不同的后缀,以便(可能)在下一轮中击败a。如果B很聪明,他不会选择从位置j,j+1,…,j+k开始的任何后缀,因为s[j…]已经被s[i…]打败,他知道s[j+1…]将被s[i+1…]打败,而s[j+1…][j+2..]将被s[i+2..]等击败。因此,B应该为下一轮选择后缀s[j+k+1..。另外一个观察是,B也不应该选择与A相同的后缀,因为第一个找到最大后缀的人赢得了比赛。如果j+k+1恰好等于i,B应该跳到下一个位置

最后,在多轮之后,A或B将耗尽选择并输掉比赛,因为A和B的选择数量都是有限的,有些选择在每轮之后都会被淘汰。 发生这种情况时,获胜者持有的当前后缀是max后缀(请记住,输家用尽了所有选择。一个选择被放弃是因为它不可能是最大后缀,或者它目前由另一个人持有。因此输家在某轮中放弃实际最大后缀的唯一原因是他的对手持有它。一旦玩家持有最大后缀,他将永远不会输掉并放弃它)

< C++中的程序几乎是对这个游戏的直译。

int maxSuffix(const std::string& s) {
    std::size_t i = 0, j = 1, k;
    while (i < s.size() && j < s.size()) {
        for (k = 0; i + k < s.size() && j + k < s.size() && s[i + k] == s[j +k]; ++k) { } //judge

        if (j + k >= s.size()) return i; //B is finally lost
        if (i + k >= s.size()) return j; //A is finally lost

        if (s[i + k] > s[j + k]) { //B is lost in this round so he needs a new choice
            j = j + k + 1;
            if (j == i) ++j;
        } else {                   //A is lost in this round so he needs a new choice
            i = i + k + 1;
            if (i == j) ++i;
        }
    }
    return j >= s.size() ? i : j;
}
int-maxSuffix(常量std::string&s){
标准:尺寸i=0,j=1,k;
而(i=s.size())返回i;//B最终丢失
如果(i+k>=s.size())返回j;//A最终丢失
如果(s[i+k]>s[j+k]){//B在这一轮中输了,那么他需要一个新的选择
j=j+k+1;
如果(j==i)+j;
}否则{//A在这一轮中输了,所以他需要一个新的选择
i=i+k+1;
如果(i==j)+i;
}
}
返回j>=s.size()?i:j;
}
运行时间分析:最初每个玩家有n个选择。在每轮比赛后,裁判进行k次比较,并且从A或B中至少排除k次可能的选择。因此,游戏结束时,比较的总数以2n为界


上面的讨论是在字符串的上下文中进行的,但对任何只支持顺序访问的容器都应该稍作修改。

您能解释一下
字典最大后缀吗
?似乎您只需要从列表中的最大元素开始获取子列表。@UmNyobe字典是按字典顺序排列的。是的,它将从max元素开始,但是如果有多个max元素呢?我的意思是列表中的元素可能不明显。@JacksonTale
在数学和计算机科学中,一个算法[…]
,所以它属于这两个元素。我想他们会比我们更有效……感觉很像O(n)如果你把一个虚构的字符粘贴在结尾并反转比较操作的方向,你可能会考虑,因为这不是一个“软件算法”,而不是试图在最合适的堆栈交换上启动另一个谩骂,只是一个建议:
int maxSuffix(const std::string& s) {
    std::size_t i = 0, j = 1, k;
    while (i < s.size() && j < s.size()) {
        for (k = 0; i + k < s.size() && j + k < s.size() && s[i + k] == s[j +k]; ++k) { } //judge

        if (j + k >= s.size()) return i; //B is finally lost
        if (i + k >= s.size()) return j; //A is finally lost

        if (s[i + k] > s[j + k]) { //B is lost in this round so he needs a new choice
            j = j + k + 1;
            if (j == i) ++j;
        } else {                   //A is lost in this round so he needs a new choice
            i = i + k + 1;
            if (i == j) ++i;
        }
    }
    return j >= s.size() ? i : j;
}