我的后缀是什么类型?


10

介绍

因此,我一直在浪费时间来研究后缀排序算法,以手工和代码方式评估新的想法。但是我总是很难记住后缀的类型!能告诉我我的后缀是哪种类型?

最左边是什么?

许多后缀排序算法(SAIS,KA,我自己的daware)将后缀分为不同的类型,以便对其进行排序。有两种基本类型:S型L型后缀。S型后缀是字典顺序以下(后缀小号比下面后缀和小光伏)L型,如果它是按字典顺序更大(大号 arger)。甲最左边的S型LMS型)就是:甲S型,其由preceeded后缀L型后缀。

这些LMS类型后缀的特殊之处在于,一旦我们对它们进行了排序,就可以在线性时间内对所有其他后缀进行排序!那不是很棒吗?

挑战

给定一个字符串,假定它以小于该字符串中任何其他字符的特殊字符终止(例如,甚至小于空字节)。为每个后缀输出对应的char类型。

您可以自由选择使用哪种类型的字符哪个,但我更喜欢L, S and *L-, S- and LMS-type,只要它们是所有可打印的(0x20 - 0x7E)。

给定字符串mmiissiissiippi输出(使用时L, S and *):

 LL*SLL*SLL*SLLL

例如,第一个L是由于在mmiissiissiippi$字典上大于miissiissiippi$$代表所添加的最小字符)的事实:

L - mmiissiissiippi$ > miissiissiippi$
L - miissiissiippi$  > iissiissiippi$
* - iissiissiippi$   < issiissiippi     and preceeded by L
S - issiissiippi$    < ssiissiippi$
L - ssiissiippi$     > siissiippi$
L - siissiippi$      > iissiippi$
* - iissiippi$       < issiippi$        and preceeded by L
S - issiippi$        < ssiippi$
L - ssiippi$         > siippi$
L - siippi$          > iippi$
* - iippi$           < ippi$            and preceeded by L
S - ippi$            < ppi$
L - ppi$             > pi$
L - pi$              > i$
L - i$               > $

其他示例:

"hello world" -> "L*SSL*L*LLL"
"Hello World" -> "SSSSL*SSLLL"
"53Ab§%5qS"   -> "L*SSL*SLL"

目标

我不是来惹恼Peter Cordes的(我有一段时间会在stackoverflow上这样做);我很懒,所以这当然是!以字节为单位的最短答案将获胜。


编辑:字符的顺序由其字节值给出。这意味着比较应该像C一样strcmp

Edit2:如注释中所述,每个输入字符应为单个字符。虽然我认为这可以理解为“返回字符串”,但似乎至少有1个答案会返回单个字符的列表。为了不使现有答案无效,我将允许您返回一个单字符列表(或打印时仅产生1个字符的整数)。


线性时间提示:

  1. 它可以在2个并行的正向迭代中或单个向后的迭代中完成。
  2. 每个后缀的状态仅取决于前两个字符和第二个字符的类型。
  3. 反向扫描输入,您可以像这样确定L或S:$t=$c<=>$d?:$t(PHP 7),$c当前字符$d是前一个和$t前一个类型。
  4. 看到我的PHP答案。明天我将颁发赏金。

这是我的第一个问题:) 沙盒有两个投票,也没有任何评论,因此我认为它已经准备好发布了。随时提出建议!
克里斯多夫(Christoph)

输入中可以显示什么字符?
Martin Ender

@MartinEnder您的字符串支持的所有字符,例如c++样式字符串甚至为空字节。将其视为二进制数据。
克里斯多夫(Christoph)

什么*意思
Leaky Nun

@LeakyNun *表示相应的后缀类型left most s-typeA S-type suffix that is preceeded by a L-type suffix.
克里斯托夫(Christoph)

Answers:


7

Haskell64 53 48 42字节

(0!)
k!(x:y)|x:y>y=1:2!y|2>1=k:0!y
_![]=[]

在线尝试!

取消高尔夫,使用Char代替Int

suffixes :: String -> String
suffixes = go 'S'
 where
   go :: Char -> String -> String
   go _ "" = ""
   go lorstar s | s > tail s = 'L' : go '*' (tail s)
                | otherwise  = lorstar : go 'S' (tail s)

允许使用匿名函数,因此z=可以将其删除。
与Orjan约翰森

我只是看不懂Haskell。您介意给我一个简短的解释吗?
克里斯多夫(Christoph)

1
@Christoph:该go函数接受两个参数。第一个是代表应该用来描述S情况的字符。第二个是字符串。它以递归方式遍历该字符串,并在每个步骤中删除第一个字符(就是tail这样)。诀窍是将第一个参数设置为*上一个结果为时的LS否则为。这样,在应使用an *或an 的情况下,S可以直接使用第一个参数。希望有道理。
bartavelle

真是个好主意!我希望看到更多聪明的主意:)
Christoph

@ØrjanJohansen我应该如何在TIO中准备结果?
bartavelle

6

果冻 25 23 21 20  19 字节

Ṛ;\UỤỤIṠµI2n×ịØDṚ;0

使用以下命令打印字符列表的完整程序:

L: 0
S: 8
*: 9

(作为链接,它返回一个列表,其中所有项目都是除最后一个零(零)之外的字符。)

在线尝试!或查看测试套件(转换为LS*)。

怎么样?

Ṛ;\UỤỤIṠµI2n×ịØDṚ;0 - Link: list of characters, s  e.g. "cast"
Ṛ                   - reverse                           "tsac"
  \                 - cumulative reduce by:
 ;                  -   concatenation                   ["t","ts","tsa","tsac"]
   U                - upend (reverse each)              ["t","st","ast","cast"] (suffixes)
    Ụ               - sort indexes by value             [3,4,2,1] (lexicographical order)
     Ụ              - sort indexes by value             [4,3,1,2] (order of that)
      I             - incremental differences           [-1,-2,1] (change)
       Ṡ            - sign                              [-1,-1,1] (comparisons)
        µ           - monadic chain separation, call that x
         I          - incremental differences           [0,2] (only (-1,1) produce 2s)
          2         - literal 2                         2
           n        - not equal?                        [1,0] (indexes of * will be 0)
            ×       - multiply by x (vectorises)        [-1,0,1] (make indexes of *s 0)
              ØD    - decimal yield                     "0123456789"
             ị      - index into (1-indexed & modular)  ['8','9','0']
                Ṛ   - reverse                           ['0','9','8']
                 ;0 - concatenate a zero                ['0','9','8',0]
                    - implicit print                     0980
                    -                              i.e. "L*SL"

您介意为我补充一点说明吗?
克里斯多夫(Christoph)

2
我当然会做-我首先在考虑打高尔夫的可能性……
Jonathan Allan


@LeakyNun你是如何解决的?您正在使用中的错误有,我认为+对字符串似乎vectorise但潜在的结果是不实际果冻iterables但字符串(例如,尝试(!)+@/L€+@/L€€或...)
乔纳森·艾伦

@JonathanAllan是的,+产生实际的字符串。这是一个未记录的功能,或您所说的错误。
Leaky Nun


3

JavaScript(ES6),51 45字节

f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)

@Neil节省了6个字节。

该练习的递归解决方案。

f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)

console.log(f('mmiissiissiippi')); //LL*SLL*SLL*SLLL   002100210021000
console.log(f('hello world'));     //L*SSL*L*LLL       02110202000
console.log(f('Hello World'));     //SSSSL*SSLLL       11110211000
console.log(f('53Ab§%5qS'));       //L*SSL*SLL         021102100


保存6个字节:f=(c,d)=>c&&(d<(d=c<(c=c.slice(1))))+d+f(c,d)
尼尔(Neil)

谢谢,@ Neil,我知道那里必须有一个优化。
瑞克·希区柯克

2

JavaScript(ES6),52个字节

f=
s=>s.replace(/./g,_=>(c<(c=s<(s=s.slice(1))))+c,c=1)
<input oninput=o.textContent=f(this.value)><pre id=o>

@ L3viathan的答案的端口。


1
@RickHitchcock糟糕,我以某种方式设法移植c=1c=0...
Neil


1

Haskell77 75字节,线性时间

f(a:b:c)|let g"L"|a<b="SL";g"S"|a>b="L*";g d=d++d;d:e=f$b:c=g[d]++e
f _="L"

在线尝试!

怎么运行的

这使用递归,从字符串的开头一次剥离一个字符。(Haskell字符串类型是一个单链接字符列表,因此每个步骤都是固定时间。)

  • 对于字符串abc,其中ab是单个字符,而c是任何(可能为空)字符串,
    • 如果fbc)= L e并且a < b ; fabc)= SL e ;
    • 如果fbc)= S ea > b ; fabc)= L * e ;
    • ˚FABC)= LL È,如果˚FBC)= L Ë一个b ;
    • ˚FABC)= SS È,如果˚FBC)= S Ë一个b
  • 对于单字符字符串afa)=L。

1
您能提供一个解释吗?
R. Kap

请提供说明,以便我可以验证它是否可以线性运行。
克里斯托夫(Christoph)

@Christoph添加了。
Anders Kaseorg

@AndersKaseorg感谢您添加!遗憾的是,与其他Haskell答案相比,这似乎很冗长。可以通过不使用进一步打高尔夫球S, L and *吗?
克里斯多夫(Christoph)

1
@Christoph需要清楚的[1,1,2,0,1,1,2,0,1,1,2,0,1,1,1]是,它是一个单数字列表,而不是一个单字符列表。就我而言,我认为输出数字列表不会为我节省任何字节。
Anders Kaseorg

1

Python 2中65 55个字节

递归版本,基于L3viathan的answer012用作LS*

def g(s,d=2):c=s<s[1:];return s and`c+(d<c)`+g(s[1:],c)

在线尝试!

Python 3中65 59个字节

递归的解决方案使用LS以及*

f=lambda s:s and('LS'[s<s[1:]]+f(s[1:])).replace('LS','L*')

贯穿从前面的字符串,并且替换的所有实例LSL*

在线尝试!


1
blah if s else''s and blah保存六个字节。在Python 2中,str(blah)`blah`在第二个解决方案上另存了三个字节。
Anders Kaseorg

1

PHP,82字节,线性时间

for($a=$argn;a&$c=$a[$i-=1];$d=$c)$a[$i]=2+$t=$d<=>$c?:$t;echo strtr($a,[13=>12]);

从右到左遍历输入,并用类型替换每个字符。

$t=$d<=>$c?:$t

计算给定当前字符和上一个字符(-1或1)的类型。如果相等,则类型不变。


+1的想法strtr
约尔格Hülsermann

1

PHP,70字节

L = 1,S = 0,* = 2

多字节支持需要最后测试用例与§+3字节mb_substr,而不是substr

for(;$s=&$argn;$s=$u)$r.=$l=($l&1)+(1&$l^($s>$u=substr($s,1)));echo$r;

在线尝试!

PHP,71字节

L = 1,S = 0,* = 2

for(;$s=&$argn;$s=$u)$r.=+($s>$u=substr($s,1));echo strtr($r,[10=>12]);

在线尝试!

PHP,74字节

for(;$s=&$argn;$s=$u)$r.=SL[$s>$u=substr($s,1)];echo strtr($r,[LS=>"L*"]);

在线尝试!


$s=&$argn挺聪明的!我很确定还有一个更好的答案;)希望有人提出来:)
Christoph

@Christoph我有一种想念的感觉。我有尝试存储最后LS在varibale *,但它是长
约尔格Hülsermann

@Christoph表示您喜欢吗?我真的看不出为什么最后一个测试用例是错误的,请在线尝试!
约尔格Hülsermann

@Christoph好吧,我已经知道了为什么它不适用于我必须使用的最后一个测试用例,mb_substr而不是substr如果输入不在简单的ascii范围内。是否有必要支持最后一个测试用例?
约尔格Hülsermann

1
@Christoph谢谢在这种情况下,我忽略了与过去的测试用例§
约尔格Hülsermann
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.