สตริงย่อยทั่วไปที่ยิ่งใหญ่ที่สุด


30

สร้างโปรแกรมหรือฟังก์ชั่นที่รับรายการสตริงเป็นอินพุตและเอาต์พุตสตริงที่ยาวที่สุดที่เป็นสตริงย่อยของสตริงอินพุตทั้งหมด หากมีสตริงย่อยหลายรายการที่มีความยาวเท่ากันและไม่มีซับสตริงอีกต่อไปให้ส่งเอาต์พุตใด ๆ

  • นี่อาจหมายถึงการแสดงผลสตริงที่ว่างเปล่า
  • หากมีผลลัพธ์ที่ถูกต้องหลายอย่างคุณอาจส่งออกหนึ่งในนั้น คุณไม่จำเป็นต้องให้เอาต์พุตที่สอดคล้องกันสำหรับอินพุตที่กำหนดตราบใดที่เอาต์พุตนั้นถูกต้องเสมอ
  • จะมีอย่างน้อยหนึ่งสตริงในอินพุต แต่อาจไม่มีสตริงที่ไม่ว่างเปล่า
  • อักขระ ASCII ที่พิมพ์ได้ทั้งหมดอาจปรากฏในอินพุต คุณอาจสันนิษฐานว่าเป็นเพียงตัวอักษรที่ปรากฏขึ้น
  • คุณสามารถรับอินพุตหรือผลิตผลโดยวิธีการเริ่มต้นใดก็ได้
  • ไม่อนุญาตช่องโหว่มาตรฐาน
  • นี่คือ - ยิ่งมีจำนวนไบต์น้อยเท่าไหร่ก็ยิ่งดีเท่านั้น

กรณีทดสอบ:

[Inputs] -> [Valid outputs (choose one)]

["hello", "'ello"] -> ["ello"]
["very", "much", "different"] -> [""]
["empty", "", "STRING"] -> [""]
["identical", "identical"] -> ["identical"]
["string", "stRIng"] -> ["st", "ng"]
["this one", "is a substring of this one"] -> ["this one"]
["just one"] -> ["just one"]
["", "", ""] -> [""]
["many outputs", "stuptuo ynam"] -> ["m", "a", "n", "y", " ", "o", "u", "t", "p", "s"]
["many inputs", "any inputs", "ny iii", "yanny"] -> ["ny"]
["%%not&", "ju&#st", "[&]alpha_numeric"] -> ["&"]


2
@ Adámคำถามนั้นถามถึงลำดับย่อยที่ยาวที่สุดไม่ใช่สตริงย่อย
Doorknob

1
สตริงจะเป็นตัวอักษรและตัวเลขหรือตัวอักษรหรือพิมพ์ได้เท่านั้น
ศูนย์รวมแห่งความไม่รู้

@EmbodimentofIgnorance อักขระ ASCII ที่พิมพ์ได้ทั้งหมดสามารถปรากฏในอินพุต
ซาร่า J

2
@Shaggy โดยทั่วไปแล้วไม่มี หากทั้งสองสามารถแยกได้undefinedแสดงว่าไม่มีสตริงเอาต์พุตที่ถูกต้อง หากสตริงว่าง (หรือสตริงอื่น) เป็นเอาต์พุตที่ถูกต้องการอ้างว่าไม่มีเอาต์พุตที่ถูกต้องนั้นไม่ถูกต้อง
ซาร่า J

คำตอบ:


8

Python 2 , 82 ไบต์

f=lambda h,*t:h and max(h*all(h in s for s in t),f(h[1:],*t),f(h[:-1],*t),key=len)

ลองออนไลน์!

ใช้อินพุตกระจายเสียง จะหมดเวลาสำหรับอินพุตที่สตริงแรกยาว

แนวคิดคือใช้สตริงย่อยของสตริงแรกhเพื่อค้นหาสตริงที่ยาวที่สุดที่ปรากฏในสตริงที่เหลือtทั้งหมด hต้องการทำเช่นนั้นเราซ้ำสาขาในการลบตัวอักษรตัวแรกหรือสุดท้ายของ


Python 2 , 94 ไบต์

lambda l:max(set.intersection(*map(g,l)),key=len)
g=lambda s:s and{s}|g(s[1:])|g(s[:-1])or{''}

ลองออนไลน์!

วิธีการโดยตรงมากขึ้น ฟังก์ชั่นเสริมgสร้างชุดย่อยทั้งหมดของsและฟังก์ชั่นหลักจะใช้เวลาที่ยาวที่สุดในการแยก


8

Brachylog (v2), 3 9 ไบต์

{sᵛ}ᶠlᵒtw

ลองออนไลน์!

โปรแกรมเต็มรูปแบบ อินพุตจากอินพุตมาตรฐาน (เป็นรายการสตริงแบบ JSON), เอาต์พุตไปยังเอาต์พุตมาตรฐาน

คำอธิบาย

{sᵛ}ᶠlᵒtw
 s         Find a substring
  ᵛ          of every element {of the input}; the same one for each
{  }ᶠ      Convert generator to list
     lᵒt   Take list element with maximum length
        w  Output it

เห็นได้ชัดว่าคำสั่ง tiebreak sไม่ใช่สิ่งที่อยู่ในเกือบทุกอย่างใน Brachylog ดังนั้นเราต้องแทนที่มันด้วยตนเองเพื่อสร้างผลลัพธ์ที่ยาวที่สุด (นั่นเป็นเรื่องที่น่าผิดหวังเล็กน้อย: อักขระพิเศษสี่ตัวสำหรับการแทนที่รวมถึงอักขระการจัดกลุ่มสองตัวเพราะ Brachylog ไม่แยกวิเคราะห์สอง metapredicates ในแถว)

Brachylog sไม่คืนค่าสตริงย่อยดังนั้นเราจึงต้องการเคล็ดลับเล็กน้อยในการแก้ไข: แทนที่จะทำการส่งฟังก์ชั่น (ซึ่งเป็นสิ่งที่ทำตามปกติ) เราเขียนโปรแกรมเต็มรูปแบบแล้วส่งออกไปยังเอาต์พุตมาตรฐาน ด้วยวิธีนี้ถ้ามีสตริงย่อยทั่วไปเราแค่เอาท์พุทออกมาแล้วก็เสร็จแล้ว หากไม่มีสตริงย่อยทั่วไปโปรแกรมจะเกิดข้อผิดพลาด - แต่ยังคงพิมพ์อะไรไปยังเอาต์พุตมาตรฐานดังนั้นมันจะส่งออกสตริง null ตามที่ต้องการ


1
ฉันลองสิ่งนี้ด้วยอินพุต ["inpuabts จำนวนมาก", "inabputs ใด ๆ ", "ny iabii", "yanabny"] ผมคาดว่าผลABและny แต่มีเพียงผล ฉันกำลังทำอะไรผิดหรือเปล่า?
t-clausen.dk

1
ฮึดูเหมือนว่าฉันจำคำสั่งไทเบรคได้sผิดและการเอาชนะคำสั่งไทเบรกก็ค่อนข้างแพงไบท์ อย่างไรก็ตามการทำเช่นนั้นในตอนนี้เพราะมันเป็นสิ่งสำคัญสำหรับคำตอบที่ถูกต้อง อย่างใดกรณีทดสอบไม่ฉันพยายามสังเกตเห็นความแตกต่าง
ais523

1
@ ais523 คำสั่งsผลิตสารตั้งต้นคือโดยให้คำนำหน้าทั้งหมดของอินพุต (ยาวที่สุดก่อน) จากนั้นให้วางคำสั่งแรกและทำซ้ำ
Kroppeb

5

เจลลี่ , 12 6 ไบต์

Ẇ€f/ṫ0

ลองออนไลน์!

ขอบคุณ @JonathanAllan สำหรับการบันทึก 6 ไบต์!


ฉันเชื่อว่าẆ€œ&/Ṫḟ0จะทำงานและบันทึกสี่ไบต์เนื่องจากสตริงย่อยเรียงลำดับตามความยาวดังนั้นผลลัพธ์ที่กรองจะเป็น สิ่งที่เหลืออยู่ก็คือเมื่อไม่มีหางที่ตรงกันสร้างศูนย์และเนื่องจากเรารับประกันรายชื่อตัวละครเราจึงสามารถกรองเหล่านั้นออกได้
Jonathan Allan

นอกจากนี้ฉันคิดว่าœ&/อาจถูกแทนที่ด้วยf/ที่นี่ประหยัดอีก
Jonathan Allan

ฉันส่งคำขอดึงไปที่ (หวังว่า) ทำให้ผลลัพธ์ของการลดรายการว่างเปล่าเป็นรายการว่างเปล่า (แทนที่จะเพิ่ม TypeError) หากสิ่งนั้นถูกผสานเข้าด้วยกันฉันเชื่อว่าคำตอบนี้อาจกลายเป็นหกไบต์Ẇ€f/ṛ/ได้
Jonathan Allan

@JanathanAllan ฟังดูดี ขอบคุณสำหรับเคล็ดลับอื่น ๆ - หวังว่าคุณจะมีความสุขสำหรับฉันที่จะรวมพวกเขา
Nick Kennedy

ใช่เหตุผลของฉันสำหรับความคิดเห็นเหล่านั้นคือเพื่อให้คุณสามารถรวมความคิดเห็นในโพสต์ของคุณ
Jonathan Allan

5

Ruby 2.6, 76 59 54 ไบต์

->a{*w=a;w.find{|r|w<<r.chop<<r[1..];a.all?{|s|s[r]}}}

ลองออนไลน์! - รุ่น Ruby 2.5 (56 ไบต์)

อย่างไร?

สร้างรายการการจับคู่ที่อาจเกิดขึ้นโดยเริ่มจากอาร์เรย์เดิม ทำซ้ำในรายการและหากสตริงไม่ตรงกันให้เพิ่ม 2 สตริงใหม่ลงในส่วนท้ายของรายการโดยตัดอักขระตัวแรกหรืออักขระตัวสุดท้ายออก ในตอนท้ายการแข่งขัน (ในที่สุดสตริงที่ว่างเปล่า) จะถูกพบ

ขอบคุณ Kirill L สำหรับ -2 ไบต์และฮิสโทแกรมอีก -2


4

R , 119 116 108 106 106 ไบต์

function(S,`?`=nchar,K=max(?S),s=Reduce(intersect,lapply(S,substring,0:K,rep(0:K,e=K+1))))s[which.max(?s)]

ลองออนไลน์!

ค้นหาสตริงย่อยทั้งหมดของแต่ละสตริงค้นหาจุดตัดของแต่ละรายการสตริงย่อยจากนั้นจึงส่งคืนสตริงที่ยาวที่สุด (หนึ่งใน)

-3 ไบต์ขอบคุณKirill L.

-8 ไบต์ใช้ lapply แทน Map

-2 ไบต์ต้องขอบคุณ Kirill L. อีกครั้งโดยลบเครื่องหมายวงเล็บ


ฉันไม่มีเวลาที่จะตรวจสอบ แต่ถ้าฉันไม่เข้าใจผิดเกิดขึ้น 2 ครั้งncharก็เพียงพอที่จะบันทึกบางสิ่งด้วยการประกาศว่าncharเป็นผู้ดำเนินการเอก
Kirill L.

@KirillL. yes, it is shorter by 2 bytes. Thanks! Aliasing list similarly gives us -3 bytes.
Giuseppe

You can also drop braces for another -2
Kirill L.

@KirillL. thanks! I'm a bit worried I'm going to start doing that with production code...
Giuseppe

that's the problem with golfing a language you use every day
MickyT

4

05AB1E, 14 9 8 bytes

€Œ.«ÃéθJ

-6 bytes thanks to @Adnan.

Try it online or verify all test cases.

Explanation:

€Œ       # Get the substring of each string in the (implicit) input-list
       # Right-reduce this list of list of strings by:
    Ã    #  Only keep all the strings that are present in both list of strings
     é   # Sort by length
      θ  # And pop and push its last item
         # The substrings exclude empty items, so if after the reduce an empty list remains,
         # the last item will also be an empty list,
       J # which will become an empty string after a join
         # (after which the result is output implicitly)

1
I think €Œ.«Ãõªéθ should work for 9 bytes.
Adnan

@Adnan Wait, we do have a reduce.. How did I miss that. :S I tried Å«Ã, but didn't realize I should have used .«Ã instead.. Thanks!
Kevin Cruijssen

1
Actually, I think €Œ.«ÃéθJ should work for 8.
Adnan

4

Zsh, 126 ... 96 bytes

-3 bytes from arithmetic for, -6 bytes from implicit "$@" (thanks roblogic), -5 bytes from removing unneeded { }, -1 byte from short form of for, -1 byte by using repeat, -1 byte by concatenating for s ($b) with its body, -13 bytes by changing the repeat loop out for some eval jank.

for l
eval a=\( \$l\[{1..$#l},{1..$#l}\] \)&&b=(${${b-$a}:*a})
for s ($b)(($#x<$#s))&&x=$s
<<<$x

Try it online! Try it online! Try it online!

We read all possible substrings into the arraya, and then set b to the intersection of the arrays a and b. The construct ${b-$a} will only substitue $a on the first iteration: Unlike its sibling expansion ${b:-$a}, it will not substitute when b is set but empty.

for l;                              # implicit "$@"

# === OLD ===
{
    a= i=                           # empty a and i
    repeat $[$#l**2]                # compound double loop using div/mod
        a+=($l[++i/$#l+1,i%$#l+1])  # append to a all possible substrings of the given line
#               1+i/$#l             # 1,1,1...,  1,1,2,2,2,... ...,  n,n
#                       1+i%$#l     # 1,2,3...,n-1,n,1,2,3,... ...,n-1,n
#       a+=( $l[       ,     ] )    # append that substring to the array
# === NEW ===
    eval a=\( \
        \$l\[{1..$#l},{1..$#l}\] \  # The {bracket..expansions} are not escaped
    \) &&
# ===     ===
    b=( ${${b-$a}:*a} )
#         ${b-$a}                   # if b is unset substitute $a
#       ${       :*a}               # take common elements of ${b-$a} and $a
#   b=(               )             # set b to those elements
}
for s ($b)                          # for every common substring
    (( $#x < $#s )) && x=$s         # if the current word is longer, use it
<<<$x                               # print to stdout

How does this bit work? a+=( $l[1+i/$#l,1+i%$#l] )
roblogic

1
@roblogic I think I explained it better now, check the edit. The idea is to loop to n^2 and use / and % instead of using 2 nested for loops
GammaFunction

1
you might be able to cut for l in "$@" to simply for l; - it's a bash trick
roblogic

i gotta say, zsh is so much more elegant than bash. There's nothing analogous to this nice array comparison AFAIK b=(${${b-$a}:*a})}
roblogic

1
There's some neat things you can do with it, and it isn't all that popular. That translates into me adding a zsh answer to most questions I come across. :P If you want to learn zsh, I recommend man zshexpn and man zshparam especially. I always have them open when writing an answer.
GammaFunction

3

Haskell, 80 bytes

import Data.List
f(x:r)=last$sortOn(0<$)[s|s<-inits=<<tails x,all(isInfixOf s)r]

Try it online!

Get all suffixes (tails) of the first word x in the list and take all prefixes (inits) of those suffixes to get all substrings s of x. Keep each s that isInfixOf all strings in the remaining list r. Sort those substrings by length (using the (0<$) trick) and return the last.


3

Retina 0.8.2, 48 bytes

M&!`(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)
O#$^`
$.&
1G`

Try it online! Explanation:

M&!`(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)

For each suffix of the first string, find the longest prefix that's also a substring of all of the other strings. List all of those suffix prefixes (i.e. substrings). If there are no matching substrings, we just end up with the empty string, which is what we want anyway.

O#$^`
$.&

Sort the substrings in reverse order of length.

1G`

Keep only the first, i.e. the longest substring.


Let n is number of argument strings. Then (?=(.*\n.*\1)*.*$) should be (?=(.*\n.*\1){n-1}.*$), isn't it? Test case: ["very", "different", "much"] -> [""]
mazzy

1
@mazzy I don't see the problem: Try it online!
Neil

it is not a problem. with {n} you could remove start and end patterns and keep (.+)(?=(.*\n.*\1){n} if Retina allows to write n shorter than (?<=^.*).*$
mazzy

@mazzy I can't in Retina 0.8.2, and in Retina 1 I'd have to mess around with eval, which would probably be longer anyway.
Neil

3

TSQL query, 154 bytes

USE master
DECLARE @ table(a varchar(999)collate Latin1_General_CS_AI,i int identity)
INSERT @ values('string'),('stRIng');

SELECT top 1x FROM(SELECT
distinct substring(a,f.number,g.number)x,i
FROM spt_values f,spt_values g,@ WHERE'L'=g.type)D
GROUP BY x ORDER BY-sum(i),-len(x)

Try it online

Made case sensitive by declaring the column 'a' with collation containing CS (case sensitive).

Splitting all strings from 2540 starting positions(many identical) but the useful values range between 1 and 2070 and ending 0 to 22 characters after starting position, the end position could be longer by changing the type to 'P' instead of 'L', but would cripple performance.

These distinct strings within each rownumber are counted. The highest count will always be equal to the number of rows in the table variable '@'. Reversing the order on the same count will leave the substring with most matches on top of the results followed by reversed length of the substring will leave longest match with most matches on top. The query only select the top 1 row.

In order to get all answers, change the first part of the query to

SELECT top 1with ties x FROM


3

C# (Visual C# Interactive Compiler), 320 257 bytes

l=>(string.Join(",",l.Select(s=>new int[s.Length*s.Length*2].Select((i,j)=>string.Concat(s.Skip(j/-~s.Length).Take(j%-~s.Length))))
.Aggregate((a,b)=>a.Intersect(b)).GroupBy(x=>x.Length).OrderBy(x =>x.Key).LastOrDefault()?.Select(y=>y)??new List<string>()));

Try it online!

Props to @Expired Data and @dana


You can just return the string from a function. So in Interactive compiler it might look something like this: 294 bytes
Expired Data

1
Here's the solution golfed down some bytes 215 bytes
Expired Data

@ExpiredData ah perfect this is the example I needed :)
Innat3

186
dana


3

Perl 6, 62 60 bytes

{~sort(-*.comb,keys [∩] .map(*.comb[^*X.. ^*]>>.join))[0]}

Try it online!

I'm a little annoyed the Perl 6 can't do set operations on lists of lists, which is why there's an extra .comb and >> in there.

Another annoying thing is that max can't take an function for how to compare items, meaning I have to use sort instead. As pointed out in the comments, max can take an argument, however it ends up longer since I have to take into account max returning negative infinity when there are common substrings (Try it online!).


3
max can take such a function (arity 1 though), either by position when called in OO mode, or a named :by argument in procedural mode.
Ven

2

Japt v2.0a0 -hF, 8 bytes

Îã f@eøX

Thanks to Shaggy for saving 3 bytes

Try it

Îã              //Generate all substrings of the first string
 f@             //Filter; keep the substrings that satisfy the following predicate:
   e            //    If all strings of the input...
    øX          //    Contain this substring, then keep it
-h              //Take last element
-F              //If last element is undefined, default to empty string

You shouldn't need to sort by length at the end, saving 3 bytes. Also, -F defaults to the empty string.
Shaggy

2

Japt -h, 8 bytes

(I could knock off the last 3 bytes and use the -Fh flag instead but I'm not a fan of using -F)

mã rf iP

Try it or run all test cases

mã rf iP     :Implicit input of array
m            :Map
 ã           :  Substrings
   r         :Reduce by
    f        :  Filter, keeping only elements that appear in both arrays
      i      :Prepend
       P     :  An empty string
             :Implicit output of last element


1

Python 2, 103 bytes

lambda b:max(reduce(set.__and__,[{d[f:e]for e in range(len(d)+2)for f in range(e)}for d in b]),key=len)

Try it online!

This is an anonymous lambda that transforms each element into the set of all substrings, then reduces it by set intersection (set.__and__) and then returns the max element by length.


1 byte shorter with set.intersection.
ovs




1

Charcoal, 30 bytes

≔⊟θη≔⁰ζFLη«≔✂ηζ⊕ι¹ε¿⬤θ№κεPε≦⊕ζ

Try it online! Link is to verbose version of code. This algorithm is more efficient as well as shorter than generating all substrings. Explanation:

≔⊟θη

Pop the last string from the input list into a variable.

≔⁰ζ

Zero out the substring start index.

FLη«

Loop over all possible substring end indices. (Actually this loops from 0 excluding the length, so the value is adjusted later.)

≔✂ηζ⊕ι¹ε

Obtain the current substring.

¿⬤θ№κε

Check whether this substring is contained in all of the other input strings.

Pε

If it is then overprint any previously output substring.

≦⊕ζ

Otherwise try incrementing the substring start index.


1

Bash, 295 .. 175 bytes

Not pretty but at least it works. Try it Online

-37 by general cleaning up ; -52 by plagiarising from the zsh answer ; -26 by replacing array with a loop ; -2 thanks to GammaFunction ; -3 removed i=0 from for loop

for l;{ d=${#l}
for((;i<d**2;i++)){ a="${l:i/d:1+i%d}" k=
for n;{ [[ $n =~ $a ]]&&((k++));}
((k-$#))||b+=("$a");};}
for e in "${b[@]}";do((${#e}>${#f}))&&f="$e";done
echo "$f"

Here's the original ungolfed script with comments


1
Save 2 more: You can replace ((k==$#))&& with ((k-$#))||. This also lets you use k= instead of setting it to 0.
GammaFunction

1
I think "Not pretty but at least it works" is the MO for bash scripts :)
joeytwiddle

0

Red, 266 174 bytes

func[b][l: length? s: b/1 n: 1 until[i: 1 loop n[t: copy/part at s i l r: on foreach u
next b[r: r and(none <> find/case u t)]if r[return t]i: i + 1]n: n + 1 1 > l: l - 1]""]

Try it online!

Changed the recursion to iteration and got rid of the sorting.



0

JavaScript (Node.js), 106 bytes

a=>(F=(l,n,w=a[0].substr(n,l))=>l?n<0?F(--l,L-l):a.some(y=>y.indexOf(w)<0)?F(l,n-1):w:"")(L=a[0].length,0)

Try it online!

a=>(                      // Main function
 F=(                      //  Helper function to run through all substrings in a[0]
  l,                      //   Length
  n,                      //   Start position
  w=a[0].substr(n,l)      //   The substring
 )=>
 l?                       //   If l > 0:
  n<0?                    //    If n < 0:
   F(--l,L-l)             //     Check another length
  :a.some(                //    If n >= 0: 
   y=>y.indexOf(w)<0      //     Check whether there is any string not containing the substring
                          //     (indexOf used because of presence of regex special characters)
  )?                      //     If so:
   F(l,n-1)               //      Check another substring
  :w                      //     If not, return this substring and terminate
                          //     (This function checks from the longest substring possible, so
                          //      it is safe to return right here)
 :""                      //   If l <= 0: Return empty string (no common substring)
)(
 L=a[0].length,           //  Starts from length = the whole length of a[0]
 0                        //  And start position = 0
)

0

Gaia, 15 bytes

eḋ¦&⊢⟨:l¦:⌉=¦⟩∇

Try it online!

e		| eval as code
 ḋ¦		| find all non-empty substrings
   &⊢		| Reduce by set intersection
              ∇	| and return the first element where
      ⟨:l¦:⌉=¦⟩	| the length is equal to the max length

0

PowerShell, 165 163 87 bytes

-76 bytes thanks to Nail for the awesome regexp.

"$($args-join'
'|sls "(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)"-a -ca|% m*|sort Le*|select -l 1)"

Try it online!

Less golfed:

$multilineArgs = $args-join"`n"
$matches = $multilineArgs|sls "(?<=^.*)(.+)(?=(.*\n.*\1)*.*$)" -AllMatches -CaseSensitive|% matches
$longestOrNull = $matches|sort Length|select -Last 1
"$longestOrNull"




0

Pyth, 16 bytes

eolN.U@bZm{s./dQ

Try it online!

       m     Q    # Map Q (parsed input) over the following function (lambda d:
          ./d     # Partitions of d (all substrings)
         s        # Reduce on + (make one list)
        {         # deduplicate
    .U            # reduce the result on the following lambda, with starting value result[0]
      @bZ         # lambda b,Z: Intersection between b and Z
                  # Result so far: all common substrings in random order
 o                # sort the resulting sets by the following lambda function:
  lN              # lambda N: len(N)
e                 # last element of that list
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.