ค้นหาสตริงต้นฉบับโดยไม่มีการทำซ้ำโดยไม่ต้องทำซ้ำ ๆ


25

บางครั้งมันเกิดขึ้นที่ในขณะที่พิมพ์ประโยคหนึ่งฉันก็ว้าวุ่นใจและท้ายที่สุดฉันก็พิมพ์คำที่เหมือนกันสองคำสองเท่าของคำสองครั้งติดต่อกัน

เพื่อให้แน่ใจว่าบุคคลอื่นจะไม่ใส่ใจกับสิ่งนี้งานของคุณคือการเขียนโปรแกรมที่ช่วยแก้ปัญหานี้!

งาน

รับสายป้อนข้อมูล (หากเป็นเรื่องเกี่ยวกับภาษาของคุณคุณอาจสมมติว่าเป็นอินพุตแบบ ASCII เท่านั้นที่ไม่มี linefeeds) strที่มีที่อยู่ตรงกลางของสตริงย่อยที่เกิดขึ้นสองครั้งติดต่อกันทันทีส่งคืนสตริงด้วยหนึ่งอินสแตนซ์นี้ ลบซับสตริงออกแล้ว

ในกรณีที่มีความเป็นไปได้หลายทางให้ส่งคืนคำตอบที่สั้นที่สุดเท่าที่จะทำได้ (นั่นคือเลือกสตริงย่อยที่ซ้ำกันที่ยาวที่สุดต่อเนื่องกันแล้วเอาอันนั้นออก)

ในกรณีของสตริงย่อยที่มีการทำซ้ำหลายรายการติดต่อกันนานเท่ากันให้ลบอันแรก (นั่นคืออันแรกที่พบเมื่ออ่านผ่านสตริงจากด้านหน้าไปด้านหลัง) หนึ่ง

คุณอาจสมมติว่าอินพุตถูกต้อง (เช่นมีซับสตริงการทำซ้ำติดต่อกันเสมอ) ซึ่งอาจช่วยให้กอล์ฟลงได้


ตัวอย่าง

  1. การป้อนข้อมูล: hello hello world-> hello worldขาออก
  2. การป้อนข้อมูล: foofoo-> fooขาออก (ดังนั้น: ใช่สตริงอาจประกอบด้วยส่วนที่ซ้ำกันสองครั้งเท่านั้น)
  3. การป้อนข้อมูล: aaaaa-> เอาท์พุท: aaaเป็นที่ยาวที่สุดทำซ้ำ substring aaติดต่อกันอยู่ที่นี่
  4. อินพุต: Slartibartfast-> นี่ไม่ใช่อินพุตที่ถูกต้องเนื่องจากไม่มีสตริงย่อยที่ซ้ำกันติดต่อกันดังนั้นคุณไม่จำเป็นต้องจัดการกับกรณีนี้
  5. อินพุต: the few the bar-> นี่เป็นอีกอินพุตที่ไม่ถูกต้องเนื่องจากส่วนที่ทำซ้ำควรเป็นไปตามส่วนเดิมทันที ในกรณีนี้theและtheถูกคั่นด้วยอย่างอื่นในระหว่างดังนั้นข้อมูลนี้ไม่ถูกต้อง
  6. การป้อนข้อมูล: ababcbc-> abcbcขาออก ทั้งสองเป็นไปได้สตริงซ้ำติดต่อกันยาวนานที่สุดเป็นและab bcตามที่abพบก่อนหน้านี้ในสายนี้เป็นคำตอบที่ถูกต้อง
  7. อินพุต: Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo. ผลลัพธ์: Buffalo buffalo buffalo buffalo Buffalo buffalo. (การเปลี่ยนที่ดำเนินการควรเป็นแบบตรงตามตัวพิมพ์ใหญ่ - เล็ก)
  8. การป้อนข้อมูล: Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice couple of words twice in succession.-> Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice in succession.ขาออก สตริงย่อยการทำซ้ำที่ยาวที่สุดต่อเนื่องกันเท่านั้นที่จะถูกลบออก

รหัสของคุณควรสั้นที่สุดเนื่องจากเป็นดังนั้นคำตอบที่สั้นที่สุดในหน่วยไบต์จะชนะ โชคดี!


@manatwork เมื่อถ่ายประโยคแรกที่เป็นเป็นนำเข้าส่งออกที่ควรจะเป็นSometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice couple of words twice in succession. Sometimes it happens that while typing a sentence, I am distracted and I end up typing the same couple of words twice in succession.เฉพาะการทำซ้ำที่พบที่ยาวที่สุดเท่านั้นที่จะถูกลบ
Qqwy

1
ฉันขอแนะนำให้เพิ่มการทดสอบที่มีการเปลี่ยนได้สองแบบโดยที่การทดสอบที่สองนั้นยาวกว่าการทดสอบแรก ฉันสงสัยว่าคำตอบส่วนใหญ่จะไม่ผ่านที่หนึ่ง :)
aross

@aross test case 8 นั้นแน่นอน :)
Qqwy

ถ้าฉันและรหัสทดสอบของฉันผิดพลาดมีเพียงสายเดียวซ้ำอยู่ในนั้น
aross

@aross มีสองเท่าpในhappens
Qqwy

คำตอบ:


8

Perl 6 , 40 ไบต์

{.subst: m:ex/(.*))>$0/.max(*.chars),''}

ลองมัน

{
  .subst:             # substitute


    m                 # match
    :exhaustive
    /
      ( .* )          # any number of chars

      )>              # don't include the following in what is returned

      $0              # the first match again
    /.max( *.chars ), # find the first longest submatch


    ''                # substitute it with nothing
}

8

เรติน่า , 35 33 ไบต์

จำนวนไบต์ถือว่าการเข้ารหัส ISO 8859-1

(?=(.+)(\1.*))
$2¶$`
O$#`
$.&
G1`

ลองออนไลน์!

คำอธิบาย

เนื่องจากเอ็นจิ้น regex มองหาแมตช์จากซ้ายไปขวาจึงไม่สำคัญที่จะค้นหาแมตช์ที่ยาวที่สุดโดยไม่คำนึงถึงตำแหน่ง มันสามารถทำได้กับกลุ่มสมดุลของ. NET แต่ผลที่ได้ค่อนข้างยาว:

1`((.)+)\1(?<=(?!.*((?>(?<-2>.)+).+)\3)^.*)
$1

ดังนั้นฉันจึงคิดว่าฉันจะพยายามหลีกเลี่ยงสิ่งนั้นด้วยการใช้คุณสมบัติ Retina อื่น ๆ

(?=(.+)(\1.*))
$2¶$`

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

ในตอนท้ายเราจะมีหนึ่งบรรทัดสำหรับแต่ละการแข่งขันโดยมีการลบซ้ำที่เกี่ยวข้อง ในตอนท้ายก็จะมีการป้อนข้อมูลเต็มรูปแบบอีกครั้งโดยไม่มีการแทนที่ใด ๆ

ตอนนี้เรามีการทดแทนที่เป็นไปได้ทั้งหมดเราต้องการผลลัพธ์ที่สั้นที่สุด (ซึ่งสอดคล้องกับการลบซ้ำที่ยาวที่สุด)

O$#`
$.&

ดังนั้นก่อนอื่นเราต้องจัดเรียงเส้นตามความยาว

G1`

แล้วเราจะเก็บบรรทัดแรกเท่านั้น


ว้าวเทคนิคการเปลี่ยนที่ฉลาดจริงๆ!
Leo

6

เยลลี่ , 22 19 ไบต์

-2 ไบต์ด้วยเดนนิส (หลีกเลี่ยงการกลับรายการอาร์กิวเมนต์, ลบส่วนเพิ่มที่ซ้ำซ้อนอย่างละเอียด)

ẋ2³wȧ+¥J
ẆÇ€LÐṀḢṬœp

ลองออนไลน์!

โปรแกรมเต็มรูปแบบ (พบข้อผิดพลาดที่ÐṀไม่ทำหน้าที่ด้วย arity ที่ถูกต้องมากกว่าสีย้อมซึ่งจะได้รับการแก้ไขในไม่ช้า แต่ฉันไม่แน่ใจว่ามันจะทำให้รหัสสั้นลงได้ที่นี่)

อย่างไร?

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

ẋ2³wȧ+¥J - Link 1, removal indices for given slice if valid, else 0: slice, x
ẋ2       - repeat x twice, say y
  ³      - program input: s
   w     - index of first occurrence of y in s (1-based) or 0, say i
       J - range(length(x)): [1,2,3,...,length(x)]
      ¥  - last two links as a dyad
    ȧ    -     and (non-vectorising)
     +   -     addition: [1+i,2+i,3+i,...,length(x)+i] or 0
         - note: no need to decrement these since the last index will be the 1st index
         - of the repetition (thanks to Dennis for spotting that!)

ẆÇ€LÐṀḢṬœp - Main link: string, s
Ẇ          - all sublists of s (order is short to long, left to right, e.g. a,b,c,ab,bc,abc)
 Ç€        - call the last link (1) as a monad for €ach
    ÐṀ     - filter by maximal
   L       -     length
      Ḣ    - head: get the first (and hence left-most) one
       Ṭ   - untruth: make a list with 1s at the indexes given and 0s elsewhere
        œp - partition s at truthy indexes of that, throwing away the borders
           - implicit print

6

JavaScript (ES6), 81 74 ไบต์

f=
s=>s.replace(/(?=(.+)\1)/g,(_,m)=>r=m[r.length]?m:r,r='')&&s.replace(r,'')
<input oninput=o.textContent=f(this.value)><pre id=o>

แก้ไข: บันทึกแล้ว 7 ไบต์โดยขโมยm[r.length]เคล็ดลับของ @ Arnauld


5

PowerShell , 87 ไบต์

param($s)([regex](([regex]'(.+)\1'|% *hes $s|sort L*)[-1]|% Gr*|% V*)[1])|% Re* $s '' 1

ลองออนไลน์!(กรณีทดสอบทั้งหมด)

คำอธิบาย

เริ่มต้นจากภายในโดยทั่วไปเราวิ่งMatchesด้วย(.+)\1 regex เพื่อส่งคืนวัตถุที่ตรงกันทั้งหมดสำหรับสตริงที่ระบุ regex ตรงกับลำดับของอักขระที่ตามมาด้วยตัวเอง

จากนั้นวัตถุที่ตรงกับผลลัพธ์จะถูกไพพ์ไปsortที่เรียงลำดับตามLengthคุณสมบัติของพวกมัน(ย่อมาจาก wildcard) ซึ่งจะส่งผลให้มีการจับคู่เรียงตามความยาวเพิ่มขึ้นเพื่อจัดทำดัชนี[-1]เพื่อรับองค์ประกอบสุดท้าย (ยาวที่สุด) ค่าของการจับคู่นั้นคือการจับคู่ไม่ใช่กลุ่มดังนั้นจึงรวมถึงการทำซ้ำดังนั้นเราจึงเรียก Group object ( |% Gr*) จากนั้นค่าของ ( |% V*) นั้นเพื่อให้ได้สตริงซ้ำที่ใหญ่ที่สุด สิ่งที่เป็นวัตถุกลุ่มเป็นอาร์เรย์จริง ๆ เพราะกลุ่ม 0 มักจะจับคู่เสมอ แต่ฉันต้องการกลุ่มจริง (1) ดังนั้นค่าผลลัพธ์ที่ได้คือค่าsจึงจะได้รับการจัดทำดัชนีองค์ประกอบที่สอง ค่านี้ถูกส่งไปยังวัตถุ regex เองแล้ววิธีจริงเรียกว่ากับสตริงเดิมแทนที่ไม่มีอะไรและมีเพียง นัดแรกถูกแทนที่ ( )[1]Replace|% Re* $s '' 1


5

Haskell , 101 ไบต์

หน้าที่หลักคือจะใช้เวลาและผลตอบแทนfString

l=length
a=splitAt
f s|i<-[0..l s-1]=[p++t|n<-i,(p,(r,t))<-fmap(a$l s-n).(`a`s)<$>i,r==take(l r)t]!!0

ลองออนไลน์!

เมื่อผมเริ่มนี้ผมนำเข้าData.Listและใช้งานmaximum, tails, และinits อย่างใดที่ได้กลายเป็นนี้ แต่ฉันก็ยังสามารถโกนได้ 11 ไบต์เท่านั้น ...isPrefixOf

หมายเหตุ

  • splitAt/ aแยกสตริงที่ดัชนีที่กำหนด
  • s เป็นสตริงอินพุต
  • iคือรายการของตัวเลข[0 .. length s - 1]ที่-1คือการทำงานรอบที่splitAtแยกในตอนท้ายถ้าให้ดัชนีมีขนาดใหญ่เกินไป
  • nคือlength sลบเป้าหมายความยาวปัจจุบันสำหรับส่วนที่ทำซ้ำมันถูกเลือกด้วยวิธีนี้ดังนั้นเราจึงไม่ต้องใช้สองรายการตัวเลขและ / หรือไวยากรณ์รายการลดน้อยลง
  • p, rและtมีการแยก threeway ของsกับrส่วนที่ตั้งใจซ้ำแล้วซ้ำอีก fmapมีใช้(,) String Functorเพื่อหลีกเลี่ยงตัวแปรสำหรับการแยกกลาง
  • !!0 เลือกองค์ประกอบแรกของรายการการแข่งขัน


4

Mathematica, 63 60 59 ไบต์

4 ไบต์บันทึกไว้เนื่องจากมาร์ตินเอนเดอร์

#&@@StringReplaceList[#,a__~~a__->a]~SortBy~{StringLength}&

ฟังก์ชั่นไม่ระบุชื่อ รับสตริงเป็นอินพุตและส่งคืนสตริงเป็นเอาต์พุต


ดูเหมือนจะใช้งานไม่ได้กับตัวอย่างที่ 6 - ~SortBy~StringLengthเรียงลำดับสตริงตามตัวอักษรหากความยาวเท่ากัน ...
ไม่ใช่ต้นไม้

1
@ LegionMammal978 การแก้ไขที่สั้นกว่าคือเก็บSortByและตัดStringLengthในรายการเพื่อรับการเรียงที่เสถียร
Martin Ender

3

JavaScript (ES6), 70 ไบต์

s=>s.replace(s.match(/(.+)(?=\1)/g).reduce((p,c)=>c[p.length]?c:p),'')

กรณีทดสอบ


ล้มเหลวในแต่การใช้ที่ดีของaaaabaaab reduce
Neil

2

นี่ควรเป็นความคิดเห็น แต่ฉันมีชื่อเสียงไม่เพียงพอที่จะแสดงความคิดเห็น ฉันแค่อยากจะบอก @Neil ว่าโค้ดของเขาจะลดลงเหลือ 77 ไบต์ คุณไม่จำเป็นต้องใช้การยืนยันล่วงหน้าใน regex นี่คือรุ่นที่ลดลง:

s=>s.replace(/(.+)\1/g,(_,m)=>(n=m.length)>l&&(l=n,r=m),l=0)&&s.replace(r,'')

2
สวัสดีและยินดีต้อนรับสู่ PPCG! คุณสามารถส่งเป็นคำตอบ JavaScript ของคุณเอง! หากคุณต้องการฉันสามารถแก้ไขโพสต์และแสดงให้เห็นว่าควรมีลักษณะอย่างไร
NoOneIsHere

2
ฉันต้องใช้การยืนยันล่วงหน้าเพื่อจัดการกับกรณีของการแข่งขันที่ทับซ้อนกัน aababเป็นตัวอย่างสั้น ๆ ที่ข้อเสนอแนะของคุณล้มเหลว
Neil

0

C #, 169 ไบต์

(s)=>{var x="";for(int i=0;i<s.Length-2;i++){for(int l=1;l<=(s.Length-i)/2;l++){var y=s.Substring(i,l);if(s.Contains(y+y)&l>x.Length)x=y;}}return s.Replace(x+x,x);}

คำอธิบาย

(s) => {                // Anonymous function declaration    
    var x = "";         // String to store the longest repeating substring found
    for (int i = 0; i < s.Length - 2; i++) {               // Loop through the input string
        for (int l = 1; l <= (s.Length - i) / 2; l++) {    // Loop through all possible substring lengths
            var y = s.Substring(i, l);
            if (s.Contains(y + y) & l > x.Length) x = y;   // Check if the substring repeats and is longer than any previously found
        }
    }
    return s.Replace(x + x, x);    // Perform the replacement
}

นี่คือวิธีการบังคับแบบเดรัจฉาน: ลองสตริงย่อยที่เป็นไปได้ทั้งหมดจนกว่าเราจะพบสตริงย่อยซ้ำที่ยาวที่สุด Regex ไม่ต้องสงสัยมีประสิทธิภาพมากขึ้น แต่การจัดการกับ Regex ใน C # มีแนวโน้มที่จะค่อนข้างละเอียด


ยินดีต้อนรับสู่ PPCG! คำตอบทั้งหมดจะต้องเป็นโปรแกรมเต็มรูปแบบหรือฟังก์ชั่นที่เรียกใช้ได้ไม่แน่ใจว่าตัวอย่างที่มีอินพุตในตัวแปร hardcoded นอกจากนี้โปรดแสดงเวอร์ชันของรหัสที่คุณนับด้วยการลบช่องว่างที่ไม่จำเป็นออกทั้งหมด คุณสามารถรวมเวอร์ชันที่อ่านได้มากขึ้นด้วยการเยื้องนอกเหนือจากเวอร์ชันที่สมบูรณ์
Martin Ender

0

PHP, 84 82 ไบต์

หมายเหตุ: ใช้การเข้ารหัส IBM-850

for($l=strlen($argn);--$l&&!$r=preg_filter("#(.{0$l})\g-1#",~█╬,$argn,1););echo$r;

ทำงานแบบนี้:

echo 'hello hello world' | php -nR 'for($l=strlen($argn);--$l&&!$r=preg_filter("#(.{0$l})\g-1#",~█╬,$argn,1););echo$r;';echo
> hello world

คำอธิบาย

for(
  $l=strlen($argn);   # Set $l to input length.
  --$l   &&           # Decrement $l each iteration until it becomes 0.
  !$r=preg_filter(    # Stop looping when preg_filter has a result
                      # (meaning a successful replace).
    "#(.{0$l})\g-1#", # Find any character, $l times (so the longest
                      # match is tried first), repeated twice.
    ~█╬,              # Replace with $1: first capture group, removing the
                      # duplicate.
    $argn,
    1                 # Only replace 1 match.
  );
);
echo$r;               # Print the result of the (only) successful
                      # search/replace, if any.

การปรับแต่ง

  • บันทึก 2 ไบต์เนื่องจากไม่มีความยาวขั้นต่ำของสตริงย่อยซ้ำ
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.