อัลกอริทึม O (nlogn) - ค้นหาสามเว้นระยะเท่ากันภายในไบนารีสตริง


173

ฉันมีคำถามนี้ในการทดสอบอัลกอริทึมเมื่อวานและฉันไม่สามารถหาคำตอบได้ มันทำให้ฉันบ้ามากเพราะมันมีค่าประมาณ 40 คะแนน ฉันคิดว่าส่วนใหญ่ของชั้นเรียนไม่สามารถแก้ไขได้อย่างถูกต้องเพราะฉันไม่ได้คิดวิธีแก้ปัญหาใน 24 ชั่วโมงที่ผ่านมา

กำหนดสตริงไบนารี่ที่มีความยาว n โดยพลการให้หาสามตัวที่เว้นระยะเท่ากันภายในสตริงหากมีอยู่ เขียนอัลกอริทึมที่แก้ปัญหานี้ในเวลา O (n * log (n))

สตริงเช่นนี้มีสามอันที่ "เว้นระยะเท่ากัน": 11100000, 0100100100

แก้ไข: เป็นหมายเลขสุ่มดังนั้นจึงควรทำงานกับหมายเลขใดก็ได้ ตัวอย่างที่ฉันให้ไว้เพื่อแสดงคุณสมบัติ "เว้นระยะเท่ากัน" ดังนั้น 1001011 คือตัวเลขที่ถูกต้อง ด้วย 1, 4 และ 7 เป็นสิ่งที่เว้นระยะเท่ากัน


4
เป็นไปได้ดังต่อไปนี้: 10011010000 มันมีสาม 1s (แรก, สอง, ออก) เว้นระยะเท่ากัน แต่ก็ยังมี 1s เพิ่มเติม
แอนนา

5
โรเบิร์ตคุณต้องให้อาจารย์ของคุณตอบคำถามนี้และโพสต์ไว้ที่นี่ ปัญหานี้ทำให้ฉันติดกำแพง ฉันสามารถหาวิธีทำใน n ^ 2 แต่ไม่ใช่ n * log (n)
James McMahon

3
อืมฉันใช้เวลานานในขณะที่พยายามคิดออกเช่นนี้ยังไม่ได้คำตอบที่ดี บางทีคุณอาจเข้าใจผิดคำถาม? ตัวอย่างเช่นหากคำถามถามหาอัลกอริทึมที่ทำงานใน O (n log n) ที่กำหนดตำแหน่งของลำดับเว้นระยะเท่ากันของระยะห่าง k ในลำดับที่มีขนาดใหญ่กว่านี้สามารถทำได้อย่างง่ายดายโดยใช้การแปลงฟูเรียร์ที่รวดเร็ว
ldog

2
หากศาสตราจารย์ของคุณให้ทางออกโปรดโพสต์เป็นคำตอบ
ldog

5
เมื่อพิจารณาถึงความจริงที่ว่า Klaus Roth มีเหรียญฟิลด์สำหรับปี 1958 สำหรับการพิสูจน์ความหนาแน่นแต่ละ d> 0 มีจำนวนธรรมชาติ N ซึ่งแต่ละเซตย่อยของ {1, ... , N} อย่างน้อย d * องค์ประกอบ N ประกอบด้วยความก้าวหน้าทางเลขคณิตของความยาว 3 ฉันไม่แปลกใจเลยที่จนถึงขณะนี้ยังไม่มีใครพบอัลกอริทึมที่น่าเชื่อถือสำหรับปัญหานี้ ดูเพิ่มเติมen.wikipedia.org/wiki/Szemer%C3%A9di%27s_theorem
jp

คำตอบ:


128

ที่สุด! การติดตามลูกค้าเป้าหมายในคำตอบของ sdcvvcเรามี: อัลกอริทึม O (n log n) สำหรับปัญหา! มันง่ายเกินไปหลังจากที่คุณเข้าใจ ผู้ที่เดาว่า FFT นั้นถูกต้อง

ปัญหา: เราได้รับSความยาวสตริงไบนารี่nและเราต้องการหา 1s ที่เว้นระยะเท่ากันสามตัว ตัวอย่างเช่นSอาจเป็น110110010โดยที่n = 9 มีระยะห่าง 1 เท่า ๆ กันที่ตำแหน่ง 2, 5 และ 8

  1. สแกนSจากซ้ายไปขวาและทำรายการLตำแหน่ง 1 สำหรับS=110110010ด้านบนเรามีรายการ L = [1, 2, 4, 5, 8] ขั้นตอนนี้คือ O (n) ปัญหาคือตอนนี้เพื่อค้นหาความก้าวหน้าทางเลขคณิตของความยาว 3ในLคือเพื่อค้นหาa, b, cในLลักษณะที่ba = cbหรือa + c = 2b ที่เท่ากัน สำหรับตัวอย่างข้างต้นเราต้องการค้นหาความก้าวหน้า (2, 5, 8)

  2. ทำให้พหุนาม pกับเงื่อนไขx kสำหรับแต่ละkLใน สำหรับตัวอย่างข้างต้นเราทำพหุนามP (x) = (x + x 2 + x 4 + x 5 + x 8 ) ขั้นตอนนี้คือ O (n)

  3. ค้นหาพหุนามq= P 2โดยใช้จานแปลงฟูเรีย สำหรับตัวอย่างข้างต้นที่เราได้รับพหุนามQ (x) = x 16 + 2x 13 + 2x 12 + 3x 10 + 4x 9 + x 8 + 2x 7 + 4x 6 + 2x 5 + x 4 + 2x 3 + x 2 ขั้นตอนนี้คือ O (n log n)

  4. ละเว้นเงื่อนไขทั้งหมดยกเว้นผู้ที่สอดคล้องกับx 2kสำหรับบางkLใน สำหรับตัวอย่างข้างต้นที่เราได้รับข้อตกลงx 16 , 3x 10 , x 8 , x 4 , x 2 ขั้นตอนนี้คือ O (n) หากคุณเลือกที่จะทำทั้งหมด

นี่คือจุดสำคัญ: ค่าสัมประสิทธิ์ของการใด ๆx 2bสำหรับในLเป็นอย่างแม่นยำจำนวนคู่(A, C)ในLดังกล่าวที่A + c = 2b [CLRS, ตัวอย่าง 30.1-7] หนึ่งคู่นั้นคือ(b, b)เสมอ (ดังนั้นค่าสัมประสิทธิ์อย่างน้อย 1) แต่ถ้ามีคู่อื่น(a, c) , ค่าสัมประสิทธิ์อย่างน้อย 3 จาก(a, c )และ(c เป็น) สำหรับตัวอย่างข้างต้นเรามีค่าสัมประสิทธิ์x 10เป็น 3 อย่างแม่นยำเนื่องจาก AP (2,5,8) (สัมประสิทธิ์เหล่านี้x 2bจะเป็นตัวเลขคี่เสมอด้วยเหตุผลข้างต้น และสัมประสิทธิ์อื่น ๆ ใน q จะเท่ากันเสมอ)

ดังนั้นอัลกอริทึมคือการดูค่าสัมประสิทธิ์ของคำเหล่านี้x 2bและดูว่าหนึ่งในนั้นมีค่ามากกว่า 1 หรือไม่ถ้าไม่มีก็จะไม่มีระยะห่างเท่ากัน 1s หากมีเป็นในLที่ค่าสัมประสิทธิ์ของx 2bมีค่ามากกว่า 1 แล้วเรารู้ว่ามีบางคู่(A, C) - อื่น ๆ นอกเหนือ(ขข) - ที่A + c = 2b เพื่อหาคู่ที่เกิดขึ้นจริงเราก็ลองแต่ละใน(ที่สอดคล้องจะ2b-A ) และดูว่ามีความเป็น 1 ในตำแหน่งที่2b-Aใน ขั้นตอนนี้คือ O (n)LS

นั่นคือทั้งหมดที่คน


อาจมีใครถามว่า: เราจำเป็นต้องใช้ FFT หรือไม่ คำตอบมากมายเช่นbeta's , flybywireและrsp'sแนะนำว่าวิธีการตรวจสอบแต่ละคู่ของ 1s และดูว่ามี 1 ที่ตำแหน่ง "สาม" อาจทำงานใน O (n log n) ตามสัญชาตญาณ ว่าถ้ามี 1s มากเกินไปเราจะหาสามได้ง่ายและถ้ามีน้อยเกินไป 1 วินาทีการตรวจสอบทุกคู่ใช้เวลาน้อย แต่ในขณะที่สัญชาตญาณนี้ถูกต้องและวิธีการง่ายๆคือดีกว่า O (n 2 ) มันไม่ได้เป็นอย่างดี ในคำตอบของ sdcvvcเราสามารถใช้ชุด "Cantor-like set" ของสตริงความยาวn = 3 kโดยที่ 1s อยู่ในตำแหน่งที่มีตัวแทนสามคนเท่านั้นที่มี 0 วินาทีและ 2 วินาที (ไม่ใช่ 1 วินาที) สตริงดังกล่าวมี2 k = n (log 2) / (log 3) 0. n 0.63อยู่ในนั้นและไม่มีเว้นระยะเท่ากัน 1s ดังนั้นการตรวจสอบคู่ทั้งหมดจะเป็นไปตามลำดับของกำลังสองของจำนวน 1s: 4 k ≈ n 1.26ซึ่งน่าเสียดายที่มีขนาดใหญ่กว่า (n log n) ในความเป็นจริงกรณีที่เลวร้ายที่สุดคือแย่ลง: Leo Moser ในปี 1953 สร้างสตริง (ที่มีประสิทธิภาพ) ซึ่งมีn 1-c / √ (log n) 1s ในนั้น แต่ไม่มีเว้นระยะเท่ากัน 1s ซึ่งหมายความว่าในสตริงดังกล่าว วิธีการใช้Θ (n 2-2c / √ (บันทึก n) )- เพียงเล็ก ๆหน่อยดีกว่าΘ (n 2 )น่าแปลกใจ!


เกี่ยวกับจำนวนสูงสุดของ 1s ในสายของความยาว n ที่ไม่มี 3 คนเว้นระยะเท่ากัน (ซึ่งเราเห็นข้างต้นเป็นอย่างน้อยn 0.63จากง่ายต้นเสียงเหมือนก่อสร้างและอย่างน้อยn 1-C / √ (log n)ด้วย โมเซอร์ก่อสร้าง) - นี่คือOEIS A003002 นอกจากนี้ยังสามารถคำนวณได้โดยตรงจากOEIS A065825เช่น k ที่ A065825 (k) ≤ n <A065825 (k + 1) ฉันเขียนโปรแกรมเพื่อค้นหาสิ่งเหล่านี้และปรากฎว่าอัลกอริทึมโลภไม่ได้ให้สายอักขระที่ยาวที่สุด ตัวอย่างเช่นสำหรับn = 9 เราสามารถรับ 5 1s (110100011) ได้ แต่โลภให้เพียง 4 (110110000) สำหรับn= 26 เราสามารถรับ 11 1 วินาที (11001010001000010110001101) แต่โลภให้เพียง 8 (11011000011011000000000000) และสำหรับn = 74 เราสามารถรับ 22 1 วินาที (1100001011000100000000000000000000000000010100000000000000000000000000001101101011000000001) พวกเขาเห็นด้วยที่บางแห่งจนถึง 50 (เช่นทั้งหมด 38 ถึง 50) ในฐานะที่เป็นลำดับที่ OEIS บอกว่ามันก็ดูเหมือนว่า Jaroslaw Wroblewski มีความสนใจในคำถามนี้และเขาดูแลเว็บไซต์บนเหล่านี้ชุดที่ไม่ใช่ค่าเฉลี่ย ตัวเลขที่แน่นอนเป็นที่รู้จักกันมากถึง 194


27
ดีมาก. ประทับใจ ดูเหมือนว่าจะคาดหวังว่าจะมีใครซักคนในการทดสอบนี้
hughdbrown

4
ขั้นตอนที่ 1 การแปลปัญหาเพื่อค้นหา AP นั้นตรงไปตรงมา ขั้นตอนที่ 3 พหุนามสามารถคูณได้ในเวลา O (n log n) เป็นความจริง เคล็ดลับที่แท้จริงและสิ่งที่ทำให้ปัญหายากคือความคิดในการคิด 11011 ว่าพหุนามกับสัมประสิทธิ์ [1,1,0,1,1] ฯลฯ นี่เป็นความคิดที่ฉลาดและมีประโยชน์ซึ่งจะนำไปสู่ กลับไปที่ออยเลอร์ [ดูหนังสือที่น่ากลัวของ " การสร้างฟังก์ชั่นการทำงาน" สำหรับวิลฟ์ที่ทันสมัย: math.upenn.edu/~wilf/DownldGF.html ] ดังนั้นมันขึ้นอยู่กับว่านักเรียนได้สัมผัสกับการสร้างฟังก์ชั่นในหน่วยความจำล่าสุดหรือไม่ :-)
ShreevatsaR

2
ขออภัยการคำนวณของฉันผิดอย่างสมบูรณ์ ควรเป็น 110110010 ^ 2 = 12124214302200100 แต่ความคิดนั้นยืน เพิ่งทราบตำแหน่งของ 3
Guillermo Phillips

11
ที่น่าประทับใจมาก. มันเจ๋งจริงๆที่เห็นกระทู้ / คำถามนี้มารวมกันและหาทางแก้ไข ฉันเริ่มคิดว่ามันเป็นไปไม่ได้ นอกจากนี้ศาสตราจารย์คนนี้ก็ชั่วร้ายด้วย
KingNestor

1
@RexE: หาก p เป็นระดับ n-1 (มีคำศัพท์ n), q = p ^ 2 เป็นระดับ 2n-2 (มีคำไม่เกิน 2n-1) คุณได้รับ n ^ 2 อย่างไร (นอกจากนี้การคูณสองพหุนามองศา n ในเวลา O (n log n) โดยใช้ FFT เป็นการดำเนินการมาตรฐานที่ค่อนข้างดีโปรดคลิกที่ลิงก์ในคำตอบหรือดูบทความ Wikipedia )
ShreevatsaR

35

ปัญหาของคุณชื่อ AVERAGE ในบทความนี้ (1999):

ปัญหาคือ 3SUM-hard หากมีการลด sub-quadratic จากปัญหา 3SUM: เมื่อกำหนดชุด A ของ n จำนวนเต็มจะมีองค์ประกอบ a, b, c ใน A เช่นที่ + b + c = 0 หรือไม่ ไม่ทราบว่า AVERAGE เป็น 3SUM-hard หรือไม่ อย่างไรก็ตามมีการลดเวลาเชิงเส้นอย่างง่ายจาก AVERAGE เป็น 3SUM ซึ่งคำอธิบายที่เราละเว้น

Wikipedia :

เมื่อจำนวนเต็มอยู่ในช่วง [−u ... u], 3SUM สามารถแก้ไขได้ในเวลา O (n + u lg u) โดยการแทน S เป็นบิตเวกเตอร์และทำการแปลงโดยใช้ FFT

นี่เพียงพอที่จะแก้ปัญหาของคุณ :)

สิ่งที่สำคัญมากคือ O (n log n) มีความซับซ้อนในแง่ของจำนวนศูนย์และจำนวนไม่ใช่จำนวนของ (ซึ่งอาจให้เป็นอาร์เรย์เช่น [1,5,9,15]) การตรวจสอบว่าเซตมีการดำเนินการทางคณิตศาสตร์เงื่อนไขของจำนวน 1 เป็นเรื่องยากหรือไม่และเป็นไปตามที่ระบุไว้ในรายงานของปี 1999 ว่าไม่มีอัลกอริทึมที่เร็วกว่า O (n 2 ) เป็นที่ทราบกันหรือไม่ ทุกคนที่ไม่คำนึงถึงสิ่งนี้กำลังพยายามแก้ปัญหาที่เปิดอยู่

ข้อมูลที่น่าสนใจอื่น ๆ ส่วนใหญ่ไม่เกี่ยวข้อง:

ขอบเขตล่าง:

ขอบล่างที่ง่ายคือชุดคล้ายคันทอร์ (หมายเลข 1..3 ^ n-1 ที่ไม่มี 1 ในส่วนขยายไตรภาค) - ความหนาแน่นของมันคือ n ^ (log_3 2) (ประมาณ 0.631) ดังนั้นการตรวจสอบว่าชุดไม่ใหญ่เกินไปหรือไม่จากนั้นการตรวจสอบทุกคู่ไม่เพียงพอที่จะรับ O (n log n) คุณต้องตรวจสอบลำดับอย่างชาญฉลาด ดีกว่าขีด จำกัด ล่างจะยกมานี่ - มัน n 1-C / (เข้าสู่ระบบ (n)) ^ (1/2) ซึ่งหมายความว่าชุดคันทอร์ไม่เหมาะสมที่สุด

ขอบบน - อัลกอริทึมเก่าของฉัน:

เป็นที่ทราบกันดีว่าสำหรับ n ขนาดใหญ่เซตย่อยของ {1,2, ... , n} ที่ไม่ได้มีความก้าวหน้าทางเลขคณิตมีองค์ประกอบส่วนใหญ่ n / (log n) ^ (1/20) กระดาษบนอเนกประสงค์ในความก้าวหน้าทางเลขคณิตพิสูจน์เพิ่มเติม: ชุดไม่สามารถมีองค์ประกอบมากกว่า n * 2 28 * (บันทึกการเข้าสู่ระบบ n / log n) 1/2องค์ประกอบ ดังนั้นคุณสามารถตรวจสอบว่าขอบเขตนั้นสำเร็จหรือไม่และตรวจสอบคู่อย่างไร้เดียงสา นี่คืออัลกอริทึมO (n 2 * log log n / log n) เร็วกว่า O (n 2 ) น่าเสียดายที่ "บนอเนกประสงค์ ... " เปิดให้บริการบน Springer - แต่มีหน้าแรกและการแสดงนิทรรศการของ Ben Green มีอยู่ที่นี่หน้า 28, ทฤษฎีบท 24

อย่างไรก็ตามเอกสารมาจากปี 1999 - ปีเดียวกับที่ฉันพูดถึงครั้งแรกดังนั้นอาจเป็นเหตุผลว่าทำไมคนแรกไม่ได้พูดถึงผลที่ได้


2
คำตอบที่ยอดเยี่ยมคำตอบแรกที่กล่าวถึงสิ่งใด ๆ เกี่ยวกับปัญหานี้ ดังนั้นชุดที่คล้ายกันต้นเสียงจึงมี n ^ 0.63 1s ซึ่งหมายความว่าอัลกอริทึม "ตรวจสอบทุกคู่ของ 1s" เป็นอย่างน้อย n ^ 1.26 (log n log n) ในกรณีที่เลวร้ายที่สุด ขอบเขตล่างที่ยกมาในกระดาษ Szemeredi ของ (BTW the Moser กระดาษเขาพูดอยู่ที่นี่: books.google.co.th/books?id=Cvtwu5vVZF4C&pg=PA245 ) ดูเหมือนว่าจริง ๆ แล้วแปลว่า ^ (2-o (1)) แต่เราต้อง ระวังหน่อยเพราะเรามีตัวเลขที่ดึงมาจาก {1, ... , n} แต่ที่นี่คือผลรวมของตัวเลขในลำดับที่ n
ShreevatsaR

เอ้ออะไรคือลำดับไบนารีแบบ "Cantor-like" ที่มี n ^ (log_3 2) 1s ในนั้นและไม่มีสามเว้นระยะเท่ากัน 1s?
ShreevatsaR

ตัวอย่าง: 101000101000000000101000101 ความยาวของมันคือ 3 ^ n และมี 2 ^ n (ความหนาแน่น n ^ 0.63) ถ้าคุณเขียนที่ของ 1 เป็นเลขฐานสองมันจะเป็น {0,2,20,22,200,202,220,222} อีกวิธีที่เป็นไปได้ที่จะคิดว่ามันใช้ลำดับของวัตถุและกำจัด "กลาง" อย่างต่อเนื่องตามปกติในการก่อสร้างชุดคันทอร์: 111111111 -> 111000111 -> 101000101 เหตุผลที่มันไม่มีความก้าวหน้าทางคณิตศาสตร์คือ: ถ้า x , y, z ก่อตัวหนึ่งแล้ว y = (x + z) / 2 และ x และ z แตกต่างกันในบางสถานที่ขยายตัว รับสิ่งที่สำคัญที่สุด สมมติว่า x มี 0 และ z มี 2 ดังนั้นคุณต้องมี 1 ตรงนั้น ความขัดแย้ง.
sdcvvc

3
การวิจัยที่ยอดเยี่ยมอีกครั้ง! ฉันติดตามผลในบทความ 3SUM ปี 2008 และอ้างอิงถึงแบบฝึกหัดของ CLRS 30.1-7 หลังจากดูที่ฉันได้รับคำตอบ - อัลกอริทึม O (n log n) นั้นค่อนข้างง่าย! (กำลังสองฟังก์ชันพหุนาม / กำลังสร้าง) ฉันโพสต์คำตอบด้านล่าง (ตอนนี้เตะตัวเองโดยที่ไม่ได้คิดถึงมันก่อนหน้านี้ ... วิธีแก้ปัญหาง่าย ๆ มักจะทำให้เกิดปฏิกิริยานั้น: p)
ShreevatsaR

ดังนั้นคำตอบสำหรับคำถามสอบของเขาจึงเป็นเช่น "ปัญหานี้ลดลงได้สำหรับปัญหา 3-SUM และปัญหา 3-SUM นั้นไม่มีวิธีแก้ปัญหาย่อยกำลังสองดังนั้นปัญหานี้จึงไม่สามารถแก้ไขได้ใน O (n logn) " ใช่?
hughdbrown

8

นี่ไม่ใช่วิธีการแก้ปัญหา แต่เป็นแนวความคิดที่คล้ายกันกับสิ่งที่Olexiy คิด

ฉันกำลังเล่นกับการสร้างลำดับที่มีจำนวนสูงสุดและพวกเขาทั้งหมดน่าสนใจฉันได้ถึง 125 หลักและนี่คือตัวเลข 3 ตัวแรกที่พบโดยพยายามแทรกบิต '1' มากที่สุด:

  • 11011000011011000000000000001101100001101100000000000000000000000000000000000000000110110000110110000000000000011011000011011
  • 10110100010110100000000000010110100010110100000000000000000000000000000000000000000101101000101101000000000000101101000101101
  • 10011001010011001000000000010011001010011001000000000000000000000000000000000000010011001010011001000000000010011001010011001

ขอให้สังเกตว่าพวกเขาเป็นแฟร็กทัลทั้งหมด อาจมีบางอย่างในการคิดย้อนกลับบางทีถ้าสตริงไม่ใช่เศษส่วนของที่มีคุณสมบัติจากนั้นจะต้องมีรูปแบบการทำซ้ำ?

ขอบคุณเบต้าสำหรับคำที่ดีกว่าเพื่ออธิบายตัวเลขเหล่านี้

อัปเดต: ดูเหมือนว่ารูปแบบจะพังลงเมื่อเริ่มต้นด้วยสตริงเริ่มต้นที่ใหญ่พอเช่น: 10000000000001:

100000000000011
10000000000001101
100000000000011011
10000000000001101100001
100000000000011011000011
10000000000001101100001101
100000000000011011000011010000000001
100000000000011011000011010000000001001
1000000000000110110000110100000000010011
1000000000000110110000110100000000010011001
10000000000001101100001101000000000100110010000000001
10000000000001101100001101000000000100110010000000001000001
1000000000000110110000110100000000010011001000000000100000100000000000001
10000000000001101100001101000000000100110010000000001000001000000000000011
1000000000000110110000110100000000010011001000000000100000100000000000001101
100000000000011011000011010000000001001100100000000010000010000000000000110100001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001000001
100000000000011011000011010000000001001100100000000010000010000000000000110100001001000001000000110001000000001000000000000000000000000000000000000000010000001000000000000001100000000110010000000010010000000000001000000001000010000010010001001000001000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000011000001000000000000000000000100100000000000000000000000000000000000011001000000000000000000000010010000010000001
1000000000000110110000110100000000010011001000000000100000100000000000001101000010010000010000001100010000000010000000000000000000000000000000000000000100000010000000000000011000000001100100000000100100000000000010000000010000100000100100010010000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000110000010000000000000000000001001000000000000000000000000000000000000110010000000000000000000000100100000100000011
10000000000001101100001101000000000100110010000000001000001000000000000011010000100100000100000011000100000000100000000000000000000000000000000000000001000000100000000000000110000000011001000000001001000000000000100000000100001000001001000100100000100000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001100000100000000000000000000010010000000000000000000000000000000000001100100000000000000000000001001000001000000110000000000001

2
ศักดิ์สิทธิ์ * @ !! เหล่านี้เป็นผลไม้! หากสิ่งนี้ถือขึ้นมันจะทำให้ขอบเขตบนของจำนวน 1 และมันน้อยกว่า O (n)
Beta

fractals นั่นเป็นคำที่ดีกว่ามากในการอธิบาย ขอบคุณ
z -

น่าสนใจรูปแบบเหล่านี้คล้ายกับชุดประกอบของ Cantor ( en.wikipedia.org/wiki/Cantor_set ) อย่างใกล้ชิด หากเป็นเช่นนี้แล้วสัดส่วนของคนที่มีแนวโน้มที่จะเป็นศูนย์ ...
flybywire

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

3
การวิเคราะห์จำนวนของฉันในสตริงเมื่อเทียบกับขนาดโดยรวมของพวกเขาดูเหมือนจะบ่งบอกว่ามีความสัมพันธ์เชิงเส้นระหว่างจำนวนของคนและขนาดของสตริงทำให้ฉันเชื่อว่าไม่มีขอบเขตบนที่มีความสุขที่ทำให้เราบอกว่า จำนวนของคนในสตริงจะมากที่สุดเข้าสู่ระบบ (n) สำหรับสตริงที่กำหนด ดังนั้นวิธีแก้ปัญหาที่เกี่ยวข้องกับตำแหน่งของวัตถุและไม่ใช่ทั้งตัวสตริงเองก็จะเป็น O (n ^ 2) เช่นกัน หรือแม่นยำยิ่งขึ้น O (n + m ^ 2) โดยที่ m คือจำนวนของข้อความในสตริงและ n คือขนาดของสตริงและ m คือ big-theta (n)
Welbog

6

ฉันสงสัยว่าวิธีง่าย ๆ ที่ดูเหมือน O (n ^ 2) จะให้ผลที่ดีกว่าจริง ๆ เช่น O (n ln (n)) ลำดับที่ใช้เวลานานที่สุดในการทดสอบ (สำหรับ n ใด ๆ ที่ระบุ) คือลำดับที่ไม่มี trios และทำให้มีข้อ จำกัด ที่รุนแรงกับจำนวนของ 1 ที่สามารถอยู่ในลำดับ

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


2
ฮ่า ๆ ๆ ฉันไม่ได้นอนฟังการบรรยายเลย ฉันพูดคุยกับนักเรียนคนอื่น ๆ สองสามคนและไม่มีใครมีความคิดที่ชัดเจนเกี่ยวกับวิธีการแก้ปัญหา ส่วนใหญ่เขียน BS เกี่ยวกับการแบ่งและพิชิตในข้ออ้างเพื่อรับเครดิตบางส่วน
Robert Parker

3

รุ่น: 2009-10-17 23:00 น

ฉันใช้จำนวนมาก (เช่นสตริงจำนวน 20 ล้าน) และตอนนี้ฉันเชื่อว่าอัลกอริทึมนี้ไม่ใช่ O (n logn) อย่างไรก็ตามมันเป็นการใช้งานที่ยอดเยี่ยมและมีการปรับแต่งมากมายที่ทำให้มันทำงานได้อย่างรวดเร็ว มันประเมินการเตรียมการทั้งหมดของสตริงไบนารี่ 24 หรือน้อยกว่าหลักในภายใต้ 25 วินาที

ฉันได้อัปเดตรหัสเพื่อรวม0 <= L < M < U <= X-1ข้อสังเกตจากวันนี้ก่อนหน้า


เป็นต้นฉบับ

นี่คือในแนวคิดคล้ายกับคำถามอื่นผมตอบ รหัสนั้นยังดูค่าสามค่าในอนุกรมและพิจารณาว่า triplet ตรงตามเงื่อนไข นี่คือรหัส C # ดัดแปลงจากที่:

using System;
using System.Collections.Generic;

namespace StackOverflow1560523
{
    class Program
    {
        public struct Pair<T>
        {
            public T Low, High;
        }
        static bool FindCandidate(int candidate, 
            List<int> arr, 
            List<int> pool, 
            Pair<int> pair, 
            ref int iterations)
        {
            int lower = pair.Low, upper = pair.High;
            while ((lower >= 0) && (upper < pool.Count))
            {
                int lowRange = candidate - arr[pool[lower]];
                int highRange = arr[pool[upper]] - candidate;
                iterations++;
                if (lowRange < highRange)
                    lower -= 1;
                else if (lowRange > highRange)
                    upper += 1;
                else
                    return true;
            }
            return false;
        }
        static List<int> BuildOnesArray(string s)
        {
            List<int> arr = new List<int>();
            for (int i = 0; i < s.Length; i++)
                if (s[i] == '1')
                    arr.Add(i);
            return arr;
        }
        static void BuildIndexes(List<int> arr, 
            ref List<int> even, ref List<int> odd, 
            ref List<Pair<int>> evenIndex, ref List<Pair<int>> oddIndex)
        {
            for (int i = 0; i < arr.Count; i++)
            {
                bool isEven = (arr[i] & 1) == 0;
                if (isEven)
                {
                    evenIndex.Add(new Pair<int> {Low=even.Count-1, High=even.Count+1});
                    oddIndex.Add(new Pair<int> {Low=odd.Count-1, High=odd.Count});
                    even.Add(i);
                }
                else
                {
                    oddIndex.Add(new Pair<int> {Low=odd.Count-1, High=odd.Count+1});
                    evenIndex.Add(new Pair<int> {Low=even.Count-1, High=even.Count});
                    odd.Add(i);
                }
            }
        }

        static int FindSpacedOnes(string s)
        {
            // List of indexes of 1s in the string
            List<int> arr = BuildOnesArray(s);
            //if (s.Length < 3)
            //    return 0;

            //  List of indexes to odd indexes in arr
            List<int> odd = new List<int>(), even = new List<int>();

            //  evenIndex has indexes into arr to bracket even numbers
            //  oddIndex has indexes into arr to bracket odd numbers
            List<Pair<int>> evenIndex = new List<Pair<int>>(), 
                oddIndex = new List<Pair<int>>(); 
            BuildIndexes(arr, 
                ref even, ref odd, 
                ref evenIndex, ref oddIndex);

            int iterations = 0;
            for (int i = 1; i < arr.Count-1; i++)
            {
                int target = arr[i];
                bool found = FindCandidate(target, arr, odd, oddIndex[i], ref iterations) || 
                    FindCandidate(target, arr, even, evenIndex[i], ref iterations);
                if (found)
                    return iterations;
            }
            return iterations;
        }
        static IEnumerable<string> PowerSet(int n)
        {
            for (long i = (1L << (n-1)); i < (1L << n); i++)
            {
                yield return Convert.ToString(i, 2).PadLeft(n, '0');
            }
        }
        static void Main(string[] args)
        {
            for (int i = 5; i < 64; i++)
            {
                int c = 0;
                string hardest_string = "";
                foreach (string s in PowerSet(i))
                {
                    int cost = find_spaced_ones(s);
                    if (cost > c)
                    {
                        hardest_string = s;
                        c = cost;
                        Console.Write("{0} {1} {2}\r", i, c, hardest_string);
                    }
                }
                Console.WriteLine("{0} {1} {2}", i, c, hardest_string);
            }
        }
    }
}

ความแตกต่างหลักคือ:

  1. การค้นหาโซลูชันอย่างละเอียด
    รหัสนี้สร้างชุดข้อมูลเพื่อค้นหาอินพุตที่ยากที่สุดในการแก้ปัญหาสำหรับอัลกอริทึมนี้
  2. การแก้ปัญหาทั้งหมดกับการแก้ไขที่ยากที่สุด
    รหัสสำหรับคำถามก่อนหน้านี้สร้างโซลูชันทั้งหมดโดยใช้ตัวสร้างหลาม รหัสนี้จะแสดงที่ยากที่สุดสำหรับความยาวแต่ละรูปแบบ
  3. อัลกอริทึมการให้คะแนน
    รหัสนี้จะตรวจสอบระยะทางจากองค์ประกอบกลางถึงขอบซ้ายและขวา รหัสหลามทดสอบว่าผลรวมนั้นสูงกว่าหรือต่ำกว่า 0
  4. การบรรจบกับผู้สมัคร
    รหัสปัจจุบันทำงานจากกลางสู่ขอบเพื่อค้นหาผู้สมัคร รหัสในปัญหาก่อนหน้านี้ทำงานจากขอบเข้าหากลาง การเปลี่ยนแปลงครั้งล่าสุดนี้ให้การปรับปรุงประสิทธิภาพขนาดใหญ่
  5. การใช้พูลคู่และคี่
    จากการสังเกตในตอนท้ายของการเขียนนี้รหัสค้นหาคู่ของคู่เลขคี่เพื่อหา L และ U ทำให้ M คงที่ สิ่งนี้จะลดจำนวนการค้นหาโดยการคำนวณข้อมูลล่วงหน้า ดังนั้นรหัสใช้สองระดับของการอ้อมในวงหลักของ FindCandidate และต้องใช้สองสายในการ FindCandidate สำหรับแต่ละองค์ประกอบกลาง: หนึ่งครั้งสำหรับตัวเลขคู่และอีกครั้งสำหรับคี่

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

ผลลัพธ์ล้าสมัย: ถูกลบออก


แก้ไข: 2009-10-16 18:48

ในข้อมูลของ yx ซึ่งได้รับความเชื่อมั่นในการตอบกลับอื่น ๆ ซึ่งเป็นตัวแทนของข้อมูลที่ยากต่อการคำนวณฉันได้รับผลลัพธ์เหล่านี้ ... ฉันลบสิ่งเหล่านี้ พวกเขาล้าสมัย

ฉันจะชี้ให้เห็นว่าข้อมูลนี้ไม่ใช่วิธีที่ยากที่สุดสำหรับอัลกอริทึมของฉันดังนั้นฉันคิดว่าการสันนิษฐานว่าแฟร็กทัลของ yx นั้นยากที่สุดในการแก้นั้นผิดพลาด ฉันคาดว่ากรณีที่แย่ที่สุดสำหรับอัลกอริทึมเฉพาะจะขึ้นอยู่กับอัลกอริทึมนั้นและจะไม่สอดคล้องกันในอัลกอริทึมที่แตกต่างกัน


แก้ไข: 2009-10-17 13:30 น

ข้อสังเกตเพิ่มเติมเกี่ยวกับเรื่องนี้

ขั้นแรกให้แปลงสตริงของ 0 และ 1 เป็นอาร์เรย์ของดัชนีสำหรับแต่ละตำแหน่งของ 1 บอกว่าความยาวของอาเรย์นั้นคือ X แล้วเป้าหมายคือการค้นหา

0 <= L < M < U <= X-1

ดังนั้น

A[M] - A[L] = A[U] - A[M]

หรือ

2*A[M] = A[L] + A[U]

เนื่องจาก A [L] และ A [U] รวมเป็นเลขคู่พวกเขาจึงไม่สามารถ (คู่คี่) หรือ (คี่แม้แต่คู่) การค้นหาการแข่งขันสามารถปรับปรุงได้โดยแบ่ง A [] เป็นคี่และคู่และค้นหาการแข่งขันใน A [M] ในกลุ่มคี่และคู่

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


แก้ไข 2009-10-18 00:45

การเพิ่มประสิทธิภาพอื่นเกิดขึ้นกับฉันในหลอดเลือดดำเดียวกับการแยกผู้สมัครเข้าคู่และคี่ เนื่องจากดัชนีทั้งสามจะต้องเพิ่มหลายตัวของ 3 (a, a + x, a + 2x - mod 3 เป็น 0 โดยไม่คำนึงถึง a และ x) คุณสามารถแยก L, M และ U ออกเป็นค่า mod 3 :

M  L  U
0  0  0
   1  2
   2  1
1  0  2
   1  1
   2  0
2  0  1
   1  0
   2  2

ในความเป็นจริงคุณสามารถรวมสิ่งนี้เข้ากับการสังเกตคู่ / คี่และแยกพวกมันออกเป็นค่า mod 6:

M  L  U
0  0  0
   1  5
   2  4
   3  3
   4  2
   5  1

และอื่น ๆ สิ่งนี้จะช่วยเพิ่มประสิทธิภาพการทำงานเพิ่มเติม แต่ไม่ใช่การเร่งความเร็วอัลกอริธึม


2

ยังไม่สามารถหาวิธีแก้ปัญหาได้ :( แต่มีความคิดบางอย่าง

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


จำนวนของ 1 ถูก จำกัด โดย O (n) อย่างแน่นอน มันไม่สามารถเป็น O (n ** 2) ใช่ไหมจำนวนของ 1 เติบโตเร็วกว่าข้อมูลใช่ไหม คำถามสำคัญคือขีด จำกัด สูงสุดนั้นต่ำกว่านั้นหรือไม่
hughdbrown

ผมใช้ o ขนาดเล็กไม่ใหญ่หนึ่ง
Olexiy

2

สิ่งนี้อาจช่วย ....

ปัญหานี้จะลดลงดังต่อไปนี้:

ให้ลำดับของจำนวนเต็มบวกหาการเรียงลำดับที่ต่อเนื่องกันแบ่งเป็นคำนำหน้าและคำต่อท้ายเช่นว่าผลรวมของคำนำหน้าของการเรียงจะเท่ากับผลรวมของคำต่อท้ายของการประกอบ

ตัวอย่างเช่นกำหนดลำดับของ[ 3, 5, 1, 3, 6, 5, 2, 2, 3, 5, 6, 4 ]เราจะพบ subsequence ของ[ 3, 6, 5, 2, 2]ด้วยคำนำหน้าของ[ 3, 6 ]กับผลรวมของคำนำหน้า9และคำต่อท้ายของกับผลรวมของคำต่อท้าย[ 5, 2, 2 ]9

การลดมีดังนี้:

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

ตัวอย่างเช่นกำหนดลำดับของเราจะพบว่าการลดลงของ[ 0, 1, 1, 0, 0, 1, 0, 0, 0, 1 0 ] [ 1, 3, 4]จากการลดลงนี้เราคำนวณความต่อเนื่องของ[ 1, 3, 4], คำนำหน้า[ 1, 3]ด้วย4, ผลรวมของ, และคำต่อท้ายของ[ 4 ]ด้วยผลรวมของ4กับผลรวมของ

การลดลงนี้อาจคำนวณได้ O(n)ได้

น่าเสียดายที่ฉันไม่แน่ใจว่าจะไปจากที่นี่


1
มันเป็นสัญกรณ์ขนาดกะทัดรัด แต่ก็ไม่ได้ช่วยให้เวลาซับซ้อน ชุดของ "คำนำหน้า" พาร์ทิชัน isomorphic เพื่อค้นหาทุกคู่ในทุกเหตุการณ์ที่เกิดขึ้น - "1" ซึ่งก็คือ O (n ^ 2)
p00ya

เห็นได้ชัดว่ามีอัลกอริธึมที่เกี่ยวข้องกับผลรวมของลำดับที่ต่อเนื่องกัน น่าเสียดายที่พวกเขาทั้งหมดดูเหมือนจะจัดการกับการหาลำดับที่ต่อเนื่องกันกับผลรวมสูงสุดใน O (n)
yfeldblum

@ p00ya นี้ไม่ถูกต้อง การใช้ algorhitm นี้เวลา coplexity ขึ้นอยู่กับจำนวนสูงสุดของจำนวน false ซึ่งโดย assupton บนสตริง Cantor ที่สร้างขึ้นคือ ((3/2) ^ (log (n) / log (3))) และความซับซ้อนของพื้นที่กลายเป็นสิ่งนี้ แต่ความซับซ้อนของเวลากลายเป็นทวีคูณโดย n ตรวจสอบคำตอบที่สองของฉัน (ไม่ใช่ลบ): D
Luka Rahne

@ralu: ภายใต้การสันนิษฐานของคุณว่าสตริงที่สร้างขึ้นคันทอร์เป็นกรณีที่เลวร้ายที่สุดซึ่งเป็นสิ่งที่ผิด สำหรับบันทึกจำนวนคู่แน่นอน O (n ^ 2); แต่ฉันเดาว่าฉันหมายถึงว่ามันเป็นโอเมก้าขนาดใหญ่ (n ^ 2) ซึ่งไม่ถูกต้องเนื่องจากผลลัพธ์เหล่านี้ (ดูลิงก์ NrootN โดยเฉพาะ) แนะนำให้ขีด จำกัด ล่างในคู่ของโอเมก้าใหญ่ (n ^ (2 / 1.52) )) โดยการพิสูจน์หรือโอเมก้าขนาดใหญ่ (n ^ (4/3)) โดยการคาดเดา
p00ya

1

สำหรับประเภทปัญหาง่าย ๆ (เช่นคุณค้นหาสาม "1" ด้วยเท่านั้น (เช่นศูนย์หรือมากกว่า) "0"ระหว่างมัน) มันค่อนข้างง่าย: คุณสามารถแยกลำดับที่ทุก "1" และมองหาองค์ประกอบสองตัวที่อยู่ติดกัน ความยาวเท่ากัน (ลำดับที่สองไม่ใช่ลำดับสุดท้ายแน่นอน) เห็นได้ชัดว่านี้สามารถทำได้ในO (n)เวลา

สำหรับรุ่นที่ซับซ้อนมากขึ้น (เช่นคุณค้นหาดัชนีiและช่องว่างg > 0 เช่นนั้นs[i]==s[i+g]==s[i+2*g]=="1") ฉันไม่แน่ใจว่าหากมีวิธีการแก้ปัญหาO (n log n) อยู่เนื่องจากอาจมีO (n²) triplets คุณสมบัตินี้ (คิดว่าเป็นสตริงของทั้งหมดมีประมาณสามn² / 2เช่นสาม) แน่นอนคุณกำลังมองหาเพียงหนึ่งในสิ่งเหล่านี้ แต่ฉันยังไม่มีความคิดวิธีการหา ...


ใช่เรากำลังพูดถึงปัญหาที่ยากขึ้น อย่างไรก็ตามโซลูชัน n * log (n) อาจเป็นไปได้
Olexiy

1
ที่จริงมี n เลือก 3 ซึ่งก็คือ O (n ^ 3) สามเท่าที่เป็นไปได้ผมคิดว่าเมื่อคุณพูดประมาณ n ^
2/2

@gmatt: n เลือก 2 ก็เพียงพอแล้ว ถ้าเรากำหนดตำแหน่ง 1 ใน 2 ให้ครบจะกำหนดตำแหน่งที่สามและเป็นเวลาคงที่เพื่อดูว่ามีตำแหน่ง 1 ในตำแหน่งนั้นหรือไม่
ShreevatsaR

@ShreevatsaR: ใช่แล้วฉันคิดว่าฉันกำลังคิดถึงคดีที่ไม่มีข้อ จำกัด
ldog

1
@gmatt: อันที่จริงเรากำลังมองหา Tuples (i, g) ตามที่นิยามไว้ข้างต้นด้วยข้อ จำกัด ที่ 0 <= i <(n-3) และ 0 <g <(ni-1) / 2 ดังนั้นการประมาณ n ^
2/2

1

เป็นคำถามที่สนุก แต่เมื่อคุณรู้ว่ารูปแบบที่แท้จริงระหว่างสองสิ่งนั้นไม่สำคัญอัลกอริทึมจะกลายเป็น:

  • สแกนหา '1'
  • เริ่มต้นจากการสแกนตำแหน่งถัดไปเพื่อหา '1' อีกตัว (ไปยังจุดสิ้นสุดของอาร์เรย์ลบด้วยระยะทางจาก '1' แรกในปัจจุบันมิฉะนั้นตัวที่ 3 '1' จะไม่อยู่ในขอบเขต)
  • หากที่ตำแหน่งของ '2' 1 บวกกับระยะทางจาก 1 'a' 1 'ที่สาม' ที่พบเรามีช่องว่างเท่ากัน

ในรหัสแฟชั่น JTest (หมายเหตุรหัสนี้ไม่ได้เขียนว่ามีประสิทธิภาพมากที่สุดและฉันได้เพิ่ม println เพื่อดูว่าเกิดอะไรขึ้น)

import java.util.Random;

import junit.framework.TestCase;

public class AlgorithmTest extends TestCase {

 /**
  * Constructor for GetNumberTest.
  *
  * @param name The test's name.
  */
 public AlgorithmTest(String name) {
  super(name);
 }

 /**
  * @see TestCase#setUp()
  */
 protected void setUp() throws Exception {
  super.setUp();
 }

 /**
  * @see TestCase#tearDown()
  */
 protected void tearDown() throws Exception {
  super.tearDown();
 }

 /**
  * Tests the algorithm.
  */
 public void testEvenlySpacedOnes() {

  assertFalse(isEvenlySpaced(1));
  assertFalse(isEvenlySpaced(0x058003));
  assertTrue(isEvenlySpaced(0x07001));
  assertTrue(isEvenlySpaced(0x01007));
  assertTrue(isEvenlySpaced(0x101010));

  // some fun tests
  Random random = new Random();

  isEvenlySpaced(random.nextLong());
  isEvenlySpaced(random.nextLong());
  isEvenlySpaced(random.nextLong());
 }

 /**
  * @param testBits
  */
 private boolean isEvenlySpaced(long testBits) {
  String testString = Long.toBinaryString(testBits);
  char[] ones = testString.toCharArray();
  final char ONE = '1';

  for (int n = 0; n < ones.length - 1; n++) {

   if (ONE == ones[n]) {
    for (int m = n + 1; m < ones.length - m + n; m++) {

     if (ONE == ones[m] && ONE == ones[m + m - n]) {
      System.out.println(" IS evenly spaced: " + testBits + '=' + testString);
      System.out.println("               at: " + n + ", " + m + ", " + (m + m - n));
      return true;
     }
    }
   }
  }

  System.out.println("NOT evenly spaced: " + testBits + '=' + testString);
  return false;
 }
}

4
ถ้าฉันไม่เข้าใจผิดนี่เป็น O (n²) เพราะวงรอบนอกวิ่ง n คูณและวงด้านในวิ่งเฉลี่ย n / 2 ครั้ง
StriplingWarrior

ลูปภายนอกรัน n ครั้งและลูปภายในเรียกใช้ n / 4 โดยเฉลี่ย แต่เริ่มจากตำแหน่งที่ตามหลัง '1' เท่านั้น ในการเข้าใกล้พฤติกรรม n ^ 2 จำนวนของ '1 จะต้องสูงซึ่งส่งผลให้เกิดผลลัพธ์ที่แท้จริงก่อนดังนั้นจึงหยุดการประมวลผล ดังนั้นพฤติกรรม n ^ 2 จะไม่เกิดขึ้น วิธีการตรวจสอบ O ขึ้นอยู่กับคุณสมบัติที่รู้จักของข้อมูลหนีฉันในขณะนี้
rsp

น่าเสียดายที่มันไม่ได้เกี่ยวกับรันไทม์ชีวิตจริงโดยเฉลี่ย และวิธีการของคุณคือ O (n²) (เช่นเดียวกับของฉันเพราะวิธีการของคุณเป็นเช่นเดียวกับของฉัน)
DaClown

ฉันไม่ได้พูดถึงพฤติกรรมโดยเฉลี่ย แต่เป็นพฤติกรรมสูงสุด ฉันจะไม่แปลกใจถ้ามันสามารถพิสูจน์ได้ว่าเอนโทรปีสูงสุดที่ล้มเหลวในการทดสอบมี log n '1 ในสตริง
rsp

จะเกิดอะไรขึ้นถ้าคุณอัปเดตดัชนีในลูปด้านนอกด้วย 1 แรกที่พบในลูปภายในเช่นถ้า (คน [m] == ONE) {n = m} นั่นช่วย O ใหญ่ได้ไหม?
steamer25

1

ฉันคิดถึงวิธีการแบ่งและพิชิตที่อาจใช้การได้

ก่อนอื่นในการประมวลผลล่วงหน้าคุณต้องใส่ตัวเลขทั้งหมดน้อยกว่าครึ่งหนึ่งของขนาดอินพุต ( n / 3) ลงในรายการ

รับสาย: 0000010101000100(โปรดทราบว่าตัวอย่างนี้ถูกต้อง)

แทรกช่วงเวลาทั้งหมด (และ 1) จาก 1 ถึง (16/2) ลงในรายการ: {1, 2, 3, 4, 5, 6, 7}

จากนั้นแบ่งครึ่ง:

100000101 01000100

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

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

ดังนั้นดำเนินการตามตัวอย่างด้านบน:

1000 0101 0100 0100

10 00 01 01 01 00 01 00

1 0 0 0 0 1 0 1 0 1 0 0 0 1 0 0

ในขั้นตอนการรวมกันครั้งแรกเรามีแปดชุดสองตอนนี้ ในตอนแรกเรามีความเป็นไปได้ของเซต แต่เราเรียนรู้ว่าการเว้นวรรค 1 นั้นเป็นไปไม่ได้เพราะศูนย์อื่นอยู่ที่นั่น ดังนั้นเราจึงคืนค่า 0 (สำหรับดัชนี) และ {2,3,4,5,7} เนื่องจากข้อเท็จจริงที่ว่าการเว้นวรรคด้วย 1 เป็นไปไม่ได้ ในวินาทีเราไม่มีอะไรเลยและส่งคืน -1 ในสามเรามีการแข่งขันโดยไม่มีการเว้นระยะห่างในดัชนี 5 ดังนั้นกลับ 5, {1,2,3,4,5,7} ในคู่ที่สี่เราคืนค่า 7, {1,2,3,4,5,7} ในวันที่ห้าส่งคืน 9, {1,2,3,4,5,7} ในวันที่หกส่งคืน -1 ในวันที่เจ็ดส่งคืน 13, {1,2,3,4,5,7} ในแปดกลับ -1

เมื่อรวมกันอีกครั้งเป็นสี่ชุดเรามี:

1000: Return (0, {4,5,6,7}) 0101: Return (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6 , 7}) 0100: Return (9, {3,4,5,6,7}) 0100 : Return (13, {3,4,5,6,7})

รวมกันเป็นชุดแปด:

10000101: ส่งคืน (0, {5,7}), (5, {2,3,4,5,6,7}), (7, {1,2,3,4,5,6,7}) 01000100: ส่งคืน (9, {4,7}), (13, {3,4,5,6,7})

รวมกันเป็นชุดสิบหก:

10000101 01000100

ในขณะที่เราก้าวหน้าไปเรายังคงตรวจสอบความเป็นไปได้ทั้งหมด จนถึงขั้นตอนนี้เราได้ทิ้งสิ่งที่เกินกว่าจุดสิ้นสุดของสตริง แต่ตอนนี้เราสามารถตรวจสอบความเป็นไปได้ทั้งหมด

โดยทั่วไปเราจะตรวจสอบ 1 รายการแรกด้วยระยะห่างระหว่าง 5 และ 7 และพบว่าพวกเขาไม่เข้าแถวถึง 1 (โปรดทราบว่าการตรวจสอบแต่ละครั้งเป็นค่าคงที่ไม่ใช่เวลาเชิงเส้น) จากนั้นเราจะตรวจสอบรายการที่สอง (ดัชนี 5) ด้วยระยะห่างระหว่าง 2, 3, 4, 5, 6 และ 7 - หรือเราจะหยุดที่ 2 ตั้งแต่ ที่ตรงกันจริง ๆ

วุ้ย นั่นเป็นอัลกอริทึมที่ค่อนข้างยาว

ฉันไม่รู้ 100% ถ้าเป็นO (n log n)เนื่องจากขั้นตอนสุดท้าย แต่ทุกอย่างจนถึงมีO (n log n)เท่าที่ฉันสามารถบอกได้ ฉันจะกลับไปหาสิ่งนี้ในภายหลังและพยายามปรับขั้นตอนสุดท้าย

แก้ไข: เปลี่ยนคำตอบของฉันเพื่อสะท้อนความคิดเห็นของ Welbog ขออภัยสำหรับข้อผิดพลาด ฉันจะเขียนรหัสเทียมในภายหลังเช่นกันเมื่อฉันมีเวลามากขึ้นในการถอดรหัสสิ่งที่ฉันเขียนอีกครั้ง ;-)


ฉันไม่ทำตามอัลกอริทึมของคุณ แต่ +1 สำหรับการลองอัลกอริทึมที่จริง ๆ แล้วพยายามเป็น O (n log n)
ldog

ขอบคุณ ฉันจะพยายามอธิบายให้ดีขึ้นเมื่อฉันมีเวลามากขึ้น (อาจจะเขียนรหัสเทียมหรือบางอย่าง)
Platinum Azure

ทำไมคุณดูที่ความเป็นไปได้ของช่องว่างของช่วงเวลาเท่านั้น? คุณจะเสนอให้จับคู่สตริง100010001อย่างไร หากฉันเข้าใจวิธีการของคุณอย่างถูกต้องจะไม่สามารถจับคู่ได้เพราะคำตอบที่ถูกต้อง(0,{4})ไม่สามารถคำนวณได้ เนื่องจากคุณไม่จำเป็นต้องมีช่วงเวลาในรายการของคุณจึงเป็นเรื่องง่ายที่จะเกิดสตริงทางพยาธิวิทยาที่ขยายรายการที่เป็นไปได้ที่คุณต้องตรวจสอบให้สูงกว่า O (n log (n))
Welbog

สาบานได้ว่าตอนแรกฉันจะทำทวีคูณ แต่ฉันเปลี่ยนคำตอบตรงกลางและไม่ได้เปลี่ยนทุกอย่าง ขอโทษ จะแก้ไขในไม่ช้า
Platinum Azure

3
ฉันไม่คิดว่ามันเป็น O (n log n) ในขั้นตอนการรวมครั้งแรกคุณปฏิบัติต่อชุด (n / 2) ซึ่งแต่ละชุดอาจส่งคืนชุดของช่องว่างที่เป็นไปได้ O (n) สิ่งนี้เองที่ทำให้ O (n ^ 2) น่าเสียดาย
MartinStettner

1

ฉันจะคาดเดาคร่าวๆของฉันที่นี่และปล่อยให้คนที่ดีกว่าด้วยการคำนวณความซับซ้อนเพื่อช่วยฉันในการคำนวณอัลกอริทึมของฉันใน O-notation อย่างชาญฉลาด

  1. รับสตริงไบนารี 0000010101000100 (ตัวอย่าง)
  2. ครอบตัดหัวและส่วนท้ายของศูนย์ -> 00000 101010001 00
  3. เราได้รับ 101010001 จากการคำนวณครั้งก่อน
  4. ตรวจสอบว่าบิตกลางเป็น 'หนึ่ง' ถ้าเป็นจริงพบถูกต้องสามเว้นระยะเท่ากัน 'คน' (เฉพาะในกรณีที่จำนวนบิตเป็นเลขคี่)
  5. ถ้าจำนวนบิตที่ถูกตัดส่วนที่เหลือยังคงเป็นเลขแม้แต่ส่วนหัวและส่วนท้าย 'หนึ่ง' จะไม่สามารถเป็นส่วนหนึ่งของระยะห่างเท่า ๆ กัน 'หนึ่ง'
  6. เราใช้ 1010100001 เป็นตัวอย่าง (โดยมี 'ศูนย์' พิเศษเพื่อกลายเป็นคร็อปที่มีเลขคู่) ในกรณีนี้เราต้องทำการครอบตัดอีกครั้งจากนั้นจะกลายเป็น -> 10101 00001
  7. เราได้รับ 1,0101 จากการคำนวณครั้งก่อนและตรวจสอบบิตกลางและเราพบบิตที่เว้นระยะเท่ากันอีกครั้ง

ฉันไม่รู้ว่าจะคำนวณความซับซ้อนของสิ่งนี้ได้ทุกคนสามารถช่วยได้ไหม

แก้ไข: เพิ่มรหัสเพื่อแสดงความคิดของฉัน

edit2: พยายามรวบรวมรหัสของฉันและพบข้อผิดพลาดที่สำคัญแก้ไข

char *binaryStr = "0000010101000100";

int main() {
   int head, tail, pos;
   head = 0;
   tail = strlen(binaryStr)-1;
   if( (pos = find3even(head, tail)) >=0 )
      printf("found it at position %d\n", pos);
   return 0;
}

int find3even(int head, int tail) {
   int pos = 0;
   if(head >= tail) return -1;
   while(binaryStr[head] == '0') 
      if(head<tail) head++;
   while(binaryStr[tail] == '0') 
      if(head<tail) tail--;
   if(head >= tail) return -1;
   if( (tail-head)%2 == 0 && //true if odd numbered
       (binaryStr[head + (tail-head)/2] == '1') ) { 
         return head;
   }else {
      if( (pos = find3even(head, tail-1)) >=0 )
         return pos;
      if( (pos = find3even(head+1, tail)) >=0 )
         return pos;
   }
   return -1;
}

@ recursive ฉันคิดว่ามันจะทำงานเมื่อถึง call find3even (head + 1, tail) ซึ่งจะครอบตัดมันให้กลายเป็น 111 ที่ head = 4 คุณช่วยตรวจสอบอีกครั้งสำหรับฉันได้ไหม?
andycjw

@ recursive โปรดตรวจสอบรหัสที่ฉันเพิ่มเพื่ออธิบายรหัสหลอกที่ฉันทำไว้ก่อนหน้านี้ซึ่งไม่เข้มงวดและรัดกุมมาก
andycjw

นี่คือ nlogn - สำหรับ n bits เราคาดว่าจะมีการทำซ้ำ logn เพื่อตรวจสอบ n * c bits โดยที่ C เป็นค่าคงที่
Ron Warholic

ใช่ดูเหมือนว่าจะล้มเหลวใน 111001 และ 100111 เป็นกรณีที่ง่ายที่สุด 1 ที่เว้นระยะเท่ากันไม่จำเป็นต้องอยู่ตรงกลาง
Dean J

สามารถจัดการกับกรณีเหล่านั้นได้อย่างถูกต้อง 111001 มีจำนวนบิตเท่ากันดังนั้นจึงถูกแบ่งเป็น 111 และ 001 ทันทีเนื่องจาก 111 มีจำนวนบิตแปลกและบิตกลางเป็นหนึ่งที่ส่งคืนได้สำเร็จ
Ron Warholic

1

ฉันมากับสิ่งนี้:

def IsSymetric(number):
    number = number.strip('0')

    if len(number) < 3:
        return False
    if len(number) % 2 == 0:
        return IsSymetric(number[1:]) or IsSymetric(number[0:len(number)-2])
    else:
        if number[len(number)//2] == '1':
            return True
        return IsSymetric(number[:(len(number)//2)]) or IsSymetric(number[len(number)//2+1:])
    return False

นี่คือแรงบันดาลใจจาก andycjw

  1. ตัดทอนศูนย์
  2. ถ้าเป็นเช่นนั้นให้ทดสอบสองสตริงย่อย 0 - (len-2) (ข้ามอักขระสุดท้าย) และจาก 1 - (len-1) (ข้ามอักขระตัวแรก)
  3. ถ้าไม่ถึงแม้ว่าถ่านตรงกลางจะเป็นมากกว่าที่เราจะประสบความสำเร็จ อื่นแบ่งสตริงใน midle โดยไม่มีองค์ประกอบ midle และตรวจสอบทั้งสองส่วน

สำหรับความซับซ้อนนี่อาจเป็น O (nlogn) เช่นเดียวกับในการเรียกซ้ำแต่ละครั้งเราจะหารด้วยสอง

หวังว่ามันจะช่วย


ดูเหมือนว่าคุณกำลังแปลงปัญหาด้วยองค์ประกอบ N เป็น 2 ปัญหากับองค์ประกอบ N-1 การแบ่งครึ่งจะหมายถึงการแปลงเป็น 2 ปัญหาด้วยองค์ประกอบ N / 2
RHSeeger

นั่นเป็นเพียงกรณีของความยาวเท่ากัน ดังนั้นหาก len คือ 8 อัลกอริทึมจะสร้างสตริงที่มีความยาว: 7, 7, 3, 3, 3, 3 ความสูงของต้นไม้เรียกซ้ำคือ 3 และเท่ากับ lg (8)
Beku

1

ตกลงฉันจะเอาปัญหาแทงอีก ฉันคิดว่าฉันสามารถพิสูจน์ได้ว่าอัลกอริทึม O (n log (n)) ที่คล้ายกับที่กล่าวถึงแล้วโดยใช้ต้นไม้ไบนารีแบบสมดุลเพื่อจัดเก็บระยะทางระหว่าง 1 ของ วิธีการนี้ได้แรงบันดาลใจจากการสังเกตของผู้พิพากษาเกี่ยวกับการลดปัญหาลงในรายการระยะทางระหว่าง 1 ของ

เราสามารถสแกนสตริงอินพุตเพื่อสร้างต้นไม้ไบนารีแบบสมดุลรอบตำแหน่ง 1 ซึ่งแต่ละโหนดจะเก็บตำแหน่งของ 1 และแต่ละขอบจะมีป้ายกำกับด้วยระยะห่างจาก 1 ไปยังโหนดที่อยู่ติดกัน ตัวอย่างเช่น:

10010001 gives the following tree

      3
     / \
  2 /   \ 3
   /     \
  0       7

สิ่งนี้สามารถทำได้ใน O (n log (n)) ตั้งแต่สำหรับสตริงที่มีขนาด n การแทรกแต่ละครั้งจะใช้ O (log (n)) ในกรณีที่แย่ที่สุด

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

ฉันคิดถึงอะไรเหรอ?


"เนื่องจากจำนวนเส้นทางในทรีย่อยจะเป็นสัดส่วนกับ log (n)" ทำไมไม่ n? โดยทั่วไปนี่เป็นวิธีที่มีแนวโน้ม
sdcvvc

@sdcwc: มันเป็นสัดส่วนในการ log (n) และไม่ใช่ n เพราะในทรีย่อยแต่ละทรีมีครึ่งโหนดและจำนวนของพา ธ ไปยังรูทของทรีย่อยจะเหมือนกับจำนวนโหนดในทรีย่อย (ยกเว้น ราก).
Jeremy Bourque

0

ดูเหมือนว่าจะเป็นปัญหาที่สนุกดังนั้นฉันจึงตัดสินใจลองทำดู

ฉันตั้งสมมติฐานว่า 111000001 จะพบ 3 คนแรกและประสบความสำเร็จ โดยพื้นฐานแล้วจำนวนศูนย์ต่อจาก 1 คือสิ่งสำคัญเนื่องจาก 0111000 เท่ากับ 111000 ตามคำจำกัดความของคุณ เมื่อคุณพบสองกรณีของ 1 กรณีที่ 1 ถัดไปที่พบจะจบไตรภาค

นี่คือใน Python:

def find_three(bstring):
    print bstring
    dict = {}
    lastone = -1
    zerocount = 0
    for i in range(len(bstring)):
        if bstring[i] == '1':
            print i, ': 1'
            if lastone != -1:
                if(zerocount in dict):
                    dict[zerocount].append(lastone)
                    if len(dict[zerocount]) == 2:
                        dict[zerocount].append(i)
                        return True, dict
                else:
                    dict[zerocount] = [lastone]
            lastone = i
            zerocount = 0
        else:
            zerocount = zerocount + 1
    #this is really just book keeping, as we have failed at this point
    if lastone != -1:
        if(zerocount in dict):
            dict[zerocount].append(lastone)
        else:
            dict[zerocount] = [lastone]
    return False, dict

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


@ recursive จะไม่เว้นระยะเท่ากัน
James McMahon

คุณหมายถึงอะไรโดยเว้นระยะเท่ากัน? ดูที่ดัชนี 0, 3 และ 6 ทุกอันและแยกกันสองอัน
recursive

โอ้ฉันเห็นแล้วว่าฉันเข้าใจแล้วศูนย์รวมอยู่ในระยะห่างเท่านั้น
James McMahon

คำถามนี้พูดถึง "1001011" ซึ่งใช้ไม่ได้ มีคำตอบก่อนหน้านี้ (ถูกลบแล้ว) ถูกโพสต์ทันทีหลังจากถามคำถามซึ่งแก้ไขปัญหา (อื่น ๆ ) เช่นเดียวกับคำถามนี้ :-)
ShreevatsaR

ฉันกำลังดูเรื่องนี้ในที่ทำงานวันนี้และฉันไม่เข้าใจว่า Rob หมายถึงอะไรกับการแก้ไขของเขา ฉันแก้ไขคำถามเพื่อความชัดเจน ฉันควรจะรู้ว่าฉันหายไปบางสิ่งบางอย่างเมื่อฉันมีเวลาง่าย ๆ กับมัน
James McMahon

0

ฉันถือว่าเหตุผลนี้เป็น nlog (n) เนื่องจากต่อไปนี้:

  • ในการค้นหา 1 ซึ่งเป็นจุดเริ่มต้นของ triplet คุณต้องตรวจสอบอักขระ (n-2) หากคุณยังไม่พบจุดนั้นคุณจะไม่ (ตัวอักษร n-1 และ n ไม่สามารถเริ่ม triplet ได้) (O (n))
  • ในการค้นหา 1 วินาทีที่เป็นส่วนหนึ่งของ triplet (เริ่มต้นด้วยอันแรก) คุณต้องตรวจสอบ m / 2 (m = nx โดยที่ x คือออฟเซ็ตของอักขระ 1 ตัวแรก) นี่เป็นเพราะหากคุณยังไม่พบอันดับที่ 1 ตามเวลาที่คุณอยู่ครึ่งทางจากจุดแรกจนถึงจุดสิ้นสุดคุณจะไม่ ... เนื่องจากช่วงที่ 1 ต้องอยู่ห่างกันเป็นวินาทีเดียว(O (เข้าสู่ระบบ (n)))
  • มันเป็น O (1) ในการค้นหา 1 อันสุดท้ายเนื่องจากคุณรู้ว่าดัชนีนั้นจะต้องเป็นไปตามเวลาที่คุณค้นหาครั้งแรกและครั้งที่สอง

ดังนั้นคุณมี n, log (n) และ 1 ... O (nlogn)

แก้ไข:โอ๊ะฉันไม่ดี สมองของฉันตั้งไว้ว่า n / 2 เป็น logn ... ซึ่งเห็นได้ชัดว่าไม่ใช่ (เพิ่มเป็นสองเท่าในรายการที่ยังคงเพิ่มจำนวนการวนซ้ำในวงวนด้านในเป็นสองเท่า) นี่ยังอยู่ที่ n ^ 2 ไม่ใช่การแก้ปัญหา อย่างน้อยฉันก็ต้องเขียนโค้ด :)


การดำเนินการใน Tcl

proc get-triplet {input} {
    for {set first 0} {$first < [string length $input]-2} {incr first} {
        if {[string index $input $first] != 1} {
            continue
        }
        set start [expr {$first + 1}]
        set end [expr {1+ $first + (([string length $input] - $first) /2)}]
        for {set second $start} {$second < $end} {incr second} {
            if {[string index $input $second] != 1} {
                continue
            }
            set last [expr {($second - $first) + $second}]
            if {[string index $input $last] == 1} {
                return [list $first $second $last]
            }
        }
    }
    return {}
}

get-triplet 10101      ;# 0 2 4
get-triplet 10111      ;# 0 2 4
get-triplet 11100000   ;# 0 1 2
get-triplet 0100100100 ;# 1 4 7

0

ฉันคิดว่าฉันได้พบวิธีการแก้ปัญหา แต่ฉันไม่สามารถสร้างหลักฐานที่เป็นทางการได้ โซลูชันที่ฉันทำถูกเขียนขึ้นใน Java และใช้ตัวนับ 'n' เพื่อนับจำนวนรายการ / อาร์เรย์ที่เข้าถึง ดังนั้น n ควรน้อยกว่าหรือเท่ากับ stringLength * log (stringLength) หากถูกต้อง ฉันลองใช้ตัวเลข 0 ถึง 2 ^ 22 และใช้งานได้

มันเริ่มต้นด้วยการวนซ้ำสตริงการป้อนข้อมูลและการทำรายการของดัชนีทั้งหมดที่ถือหนึ่ง นี่เป็นเพียง O (n)

จากรายการของดัชนีจะเลือก firstIndex และ secondIndex ซึ่งมากกว่าครั้งแรก ดัชนีทั้งสองนี้ต้องเก็บไว้เนื่องจากอยู่ในรายการดัชนี จากจุดที่สามอินเด็กซ์สามารถคำนวณได้ ถ้า inputString [thirdIndex] เป็น 1 ดังนั้นมันจะหยุด

public static int testString(String input){
//n is the number of array/list accesses in the algorithm
int n=0;

//Put the indices of all the ones into a list, O(n)
ArrayList<Integer> ones = new ArrayList<Integer>();
for(int i=0;i<input.length();i++){
    if(input.charAt(i)=='1'){
        ones.add(i);
    }
}

//If less than three ones in list, just stop
if(ones.size()<3){
    return n;
}

int firstIndex, secondIndex, thirdIndex;
for(int x=0;x<ones.size()-2;x++){
    n++;
    firstIndex = ones.get(x);

    for(int y=x+1; y<ones.size()-1; y++){
        n++;
        secondIndex = ones.get(y);
        thirdIndex = secondIndex*2 - firstIndex;

        if(thirdIndex >= input.length()){
            break;
        }

        n++;
        if(input.charAt(thirdIndex) == '1'){
            //This case is satisfied if it has found three evenly spaced ones
            //System.out.println("This one => " + input);
            return n;
        }
    }
}

return n;

}

หมายเหตุเพิ่มเติม: ตัวนับ n ไม่เพิ่มขึ้นเมื่อวนซ้ำสตริงการป้อนข้อมูลเพื่อสร้างรายการดัชนี การดำเนินการนี้เป็น O (n) ดังนั้นจึงไม่มีผลต่อความซับซ้อนของอัลกอริทึม


คุณยังดูเหมือนจะมีสองลูปของ O (n), ซ้อนกัน, ซึ่งทำให้ O (n ^ 2)
RHSeeger

อาร์เรย์ของดัชนีไม่ได้มีขนาดเท่ากับสตริงอินพุต สิ่งนี้ทำให้ฉันยากที่จะเขียนหลักฐานจริงหรือพิสูจน์ว่าไม่ถูกต้อง ฉันสงสัยว่ามีความคิดทางคณิตศาสตร์พื้นฐานที่ทำให้งานนี้
Robert Parker

1
ฉันคิดว่าเคล็ดลับสำหรับปัญหานี้คือแม้ว่าอัลกอริธึมของคุณจะเป็น O (n ^ 2) กรณีที่แย่ที่สุดของสตริงที่คุณจะได้รับจะส่งผลให้เกิดการวนซ้ำ O (nlogn) ไม่เช่นนั้นคุณจะพบวิธีแก้ปัญหา
z -

2
การทดสอบสูงสุด 2 ^ 22 ไม่ได้ทดสอบความซับซ้อนจริง ๆ 2 ^ 22 มีเพียง 22 บิตเท่านั้นซึ่งหมายความว่า N ของคุณคือ 22 ลองใช้กับค่าสองสามค่าที่ N คือไม่กี่ล้าน
Peter Recore

1
ลองใช้อัลกอริทึมนี้กับหนึ่งในสตริง "เลวร้าย" สูงสุดที่กำหนดในคำตอบของ yx และคุณจะพบว่านี่เป็นO(n^2)อัลกอริทึม
Welbog

0

หนึ่งในปัญหานี้คือการคิดถึงปัจจัยและการเปลี่ยนแปลง

ด้วยการเลื่อนคุณเปรียบเทียบสตริงของวัตถุและเลขศูนย์กับรุ่นที่เลื่อนของตัวเอง จากนั้นคุณจับคู่คนที่ตรงกัน ใช้ตัวอย่างนี้เลื่อนสอง:

1010101010
  1010101010
------------
001010101000

1 ของผลลัพธ์ (bitwise ANDed) ต้องเป็นตัวแทนของ 1 ทั้งหมดที่เว้นระยะเท่ากันโดยสอง ตัวอย่างเดียวกันเลื่อนโดยสาม:

1010101010
   1010101010
-------------
0000000000000

ในกรณีนี้ไม่มี 1 ซึ่งเว้นระยะเท่ากันสามส่วน

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

10000010 
  10000010 (Shift by two)
    10000010
      10000010 (We have a match)

10000010
   10000010 (Shift by three)
      10000010 (We have a match)

ดังนั้นการเปลี่ยนแปลงเพียงอย่างเดียวที่คุณจำเป็นต้องตรวจสอบคือ 2,3,5,7,11,13 ฯลฯ จนถึงจุดที่สำคัญที่สุดที่อยู่ใกล้กับรากที่สองของขนาดของสตริงของตัวเลข

แก้ไขได้เกือบ?

ฉันคิดว่าฉันใกล้ทางออกแล้ว โดยทั่วไป:

  1. สแกนสตริงสำหรับ 1 ของ สำหรับโน้ตแต่ละอันจะยังเหลืออยู่หลังจากรับโมดูลัสของตำแหน่ง โมดูลัสช่วงจาก 1 ถึงครึ่งขนาดของสตริง นี่เป็นเพราะขนาดการแยกที่ใหญ่ที่สุดที่เป็นไปได้คือครึ่งหนึ่งของสตริง สิ่งนี้ทำใน O (n ^ 2) แต่. ต้องทำการตรวจสอบเฉพาะรุ่นที่สำคัญเท่านั้นดังนั้น O (n ^ 2 / log (n))
  2. เรียงลำดับรายการโมดูลัส / ส่วนที่เหลือตามลำดับโมดูลัสที่ใหญ่ที่สุดก่อนซึ่งสามารถทำได้ในเวลา O (n * log (n))
  3. ค้นหาโมดูลัส / ส่วนที่เหลือสามลำดับติดต่อกันซึ่งเหมือนกัน
  4. ยังไงก็เถอะดึงตำแหน่งของคน!

ฉันคิดว่าคำตอบที่ใหญ่ที่สุดคืออัลกอริธึมเรียงลำดับที่เร็วที่สุดคือ O (n * log (n))

ไม่ถูกต้อง

ขั้นตอนที่ 1 ผิดเนื่องจากเพื่อนร่วมงานคนหนึ่งชี้ให้เห็น ถ้าเรามี 1 ของที่ตำแหน่ง 2,12 และ 102 จากนั้นรับโมดูลัส 10 พวกเขาทั้งหมดจะมีส่วนที่เหลือเหมือนกันและยังไม่เว้นระยะห่างเท่ากัน! ขอโทษ


นี่เป็นวิธีการที่น่าสนใจแจ้งให้เราทราบหากคุณคิดวิธีแก้ปัญหาที่สมบูรณ์
James McMahon

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

0

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

ลองพิจารณาวิธีแก้ปัญหาที่เสนอดังต่อไปนี้ซึ่งเป็นวิธีการที่หลาย ๆ คนแนะนำรวมถึงตัวฉันเองในคำตอบก่อนหน้านี้ :)

  1. ตัดแต่งเลขศูนย์นำหน้าและต่อท้าย
  2. สแกนสตริงที่ค้นหา 1
  3. เมื่อพบ 1:
    1. สมมติว่ามันเป็น 1 ตรงกลางของการแก้ปัญหา
    2. สำหรับแต่ละก่อนหน้า 1 ใช้ตำแหน่งที่บันทึกไว้เพื่อคำนวณตำแหน่งที่คาดหวังของ 1 ขั้นสุดท้าย
    3. หากตำแหน่งที่คำนวณได้อยู่หลังจุดสิ้นสุดของสตริงมันไม่สามารถเป็นส่วนหนึ่งของการแก้ปัญหาได้ดังนั้นให้วางตำแหน่งจากรายการผู้สมัคร
    4. ตรวจสอบการแก้ไข
  4. หากไม่พบวิธีแก้ไขให้เพิ่ม 1 ปัจจุบันไปยังรายการผู้สมัคร
  5. ทำซ้ำจนกว่าจะไม่พบ 1 รายการ

ตอนนี้ให้พิจารณาสตริงอินพุตสตริงดังต่อไปนี้ซึ่งจะไม่มีวิธีแก้ไข:

101
101001
1010010001
101001000100001
101001000100001000001

โดยทั่วไปนี่คือการต่อข้อมูลของสตริง k ของรูปแบบ j 0 ตามด้วย 1 สำหรับ j จากศูนย์ถึง k-1

k=2  101
k=3  101001
k=4  1010010001
k=5  101001000100001
k=6  101001000100001000001

โปรดทราบว่าความยาวของสตริงย่อยคือ 1, 2, 3 และอื่น ๆ ดังนั้นขนาดของปัญหาที่ n มีสตริงของความยาว 1 ถึง k ดังนั้น n = k (k + 1) / 2

k=2  n= 3  101
k=3  n= 6  101001
k=4  n=10  1010010001
k=5  n=15  101001000100001
k=6  n=21  101001000100001000001

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

k=2  n= 3  p= 1  101
k=3  n= 6  p= 3  101001
k=4  n=10  p= 6  1010010001
k=5  n=15  p=10  101001000100001
k=6  n=21  p=15  101001000100001000001

ความสัมพันธ์ระหว่าง n และ p คือ n = p + k

กระบวนการผ่านสตริงใช้เวลา O (n) ทุกครั้งที่พบ 1 จะทำการเปรียบเทียบสูงสุด (k-1) ตั้งแต่ n = k (k + 1) / 2, n> k ** 2 ดังนั้น sqrt (n)> k สิ่งนี้ทำให้เรามี O (n sqrt (n)) หรือ O (n ** 3/2) อย่างไรก็ตามโปรดทราบว่าอาจไม่แน่นนักเนื่องจากจำนวนการเปรียบเทียบเปลี่ยนจาก 1 เป็นสูงสุด k มันไม่ได้เป็น k ตลอดเวลา แต่ฉันไม่แน่ใจว่าจะคำนึงถึงเรื่องนี้อย่างไรในคณิตศาสตร์

มันยังคงไม่ใช่ O (n log (n)) นอกจากนี้ฉันไม่สามารถพิสูจน์อินพุตเหล่านั้นเป็นกรณีที่เลวร้ายที่สุดแม้ว่าฉันจะสงสัยว่ามันเป็น ฉันคิดว่าการบรรจุที่หนาแน่นกว่าของ 1 ต่อหน้าจะส่งผลให้มีการบรรจุสปอร์เซอร์แบบคู่ในตอนท้าย

เนื่องจากบางคนอาจยังพบว่ามีประโยชน์นี่คือรหัสของฉันสำหรับการแก้ปัญหานั้นใน Perl:

#!/usr/bin/perl

# read input as first argument
my $s = $ARGV[0];

# validate the input
$s =~ /^[01]+$/ or die "invalid input string\n";

# strip leading and trailing 0's
$s =~ s/^0+//;
$s =~ s/0+$//;

# prime the position list with the first '1' at position 0
my @p = (0);

# start at position 1, which is the second character
my $i = 1;

print "the string is $s\n\n";

while ($i < length($s)) {
   if (substr($s, $i, 1) eq '1') {
      print "found '1' at position $i\n";
      my @t = ();
      # assuming this is the middle '1', go through the positions
      # of all the prior '1's and check whether there's another '1'
      # in the correct position after this '1' to make a solution
      while (scalar @p) {
         # $p is the position of the prior '1'
         my $p = shift @p;
         # $j is the corresponding position for the following '1'
         my $j = 2 * $i - $p;
         # if $j is off the end of the string then we don't need to
         # check $p anymore
         next if ($j >= length($s));
         print "checking positions $p, $i, $j\n";
         if (substr($s, $j, 1) eq '1') {
            print "\nsolution found at positions $p, $i, $j\n";
            exit 0;
         }
         # if $j isn't off the end of the string, keep $p for next time
         push @t, $p;
      }
      @p = @t;
      # add this '1' to the list of '1' positions
      push @p, $i;
   }
   $i++;
}

print "\nno solution found\n";

ลำดับ "ไม่ใช่วิธีแก้ปัญหา" ของคุณผิด ดัชนีของแต่ละ 1 คือลำดับของตัวเลขสามเหลี่ยม 1, 3, 6, 10, 15 ... ฯลฯ และประกอบด้วยตัวเลข 6, 36 และ 66 ซึ่งเป็นรูปแบบการดำเนินการทางคณิตศาสตร์
46499 Jason S

0

ในขณะที่การสแกน 1s เพิ่มตำแหน่งของพวกเขาไปยังรายการ เมื่อเพิ่ม 1 วินาทีที่สองและต่อเนื่องให้เปรียบเทียบกับแต่ละตำแหน่งในรายการจนถึงตอนนี้ ระยะห่างเท่ากับ currentOne (กลาง) - ก่อนหน้าหนึ่งซ้าย (ซ้าย) บิตทางด้านขวาคือ currentOne + Spacing ถ้ามันคือ 1 จบ

รายการของคนที่เพิ่มขึ้นผกผันกับช่องว่างระหว่างพวกเขา เพียงแค่ระบุว่าหากคุณมีจำนวน 0 จำนวนมากระหว่าง 1s (เช่นในกรณีที่เลวร้ายที่สุด) รายการ 1s ที่คุณรู้จักจะเติบโตค่อนข้างช้า

using System;
using System.Collections.Generic;

namespace spacedOnes
{
    class Program
    {
        static int[] _bits = new int[8] {128, 64, 32, 16, 8, 4, 2, 1};

        static void Main(string[] args)
        {
            var bytes = new byte[4];
            var r = new Random();
            r.NextBytes(bytes);
            foreach (var b in bytes) {
                Console.Write(getByteString(b));
            }
            Console.WriteLine();
            var bitCount = bytes.Length * 8;
            var done = false;
            var onePositions = new List<int>();
            for (var i = 0; i < bitCount; i++)
            {
                if (isOne(bytes, i)) {
                    if (onePositions.Count > 0) {
                        foreach (var knownOne in onePositions) {
                            var spacing = i - knownOne;
                            var k = i + spacing;
                            if (k < bitCount && isOne(bytes, k)) {
                                Console.WriteLine("^".PadLeft(knownOne + 1) + "^".PadLeft(spacing) + "^".PadLeft(spacing));
                                done = true;
                                break;
                            }
                        }
                    }
                    if (done) {
                        break;
                    }
                    onePositions.Add(i);
                }
            }
            Console.ReadKey();
        }

        static String getByteString(byte b) {
            var s = new char[8];
            for (var i=0; i<s.Length; i++) {
                s[i] = ((b & _bits[i]) > 0 ? '1' : '0');
            }
            return new String(s);
        }

        static bool isOne(byte[] bytes, int i)
        {
            var byteIndex = i / 8;
            var bitIndex = i % 8;
            return (bytes[byteIndex] & _bits[bitIndex]) > 0;
        }
    }
}

0

ฉันคิดว่าฉันจะเพิ่มหนึ่งความคิดเห็นก่อนโพสต์วิธีแก้ปัญหาที่ไร้เดียงสาที่ 22 ให้กับปัญหา สำหรับวิธีการแก้ปัญหาแบบไร้เดียงสาเราไม่จำเป็นต้องแสดงให้เห็นว่าจำนวนของ 1 ในสตริงเป็นอย่างมาก O (log (n)) แต่ค่อนข้างจะเป็น O (sqrt (n * log (n))

Solver:

def solve(Str):
    indexes=[]
    #O(n) setup
    for i in range(len(Str)):
        if Str[i]=='1':
            indexes.append(i)

    #O((number of 1's)^2) processing
    for i in range(len(indexes)):
        for j in range(i+1, len(indexes)):
                            indexDiff = indexes[j] - indexes[i]
            k=indexes[j] + indexDiff
            if k<len(Str) and Str[k]=='1':
                return True
    return False

โดยพื้นฐานแล้วมันค่อนข้างคล้ายกับแนวคิดและการนำไปใช้ของ flybywire แต่มองไปข้างหน้าแทนที่จะมองย้อนกลับไป

ตัวสร้างสตริงโลภ:

#assumes final char hasn't been added, and would be a 1 
def lastCharMakesSolvable(Str):
    endIndex=len(Str)
    j=endIndex-1
    while j-(endIndex-j) >= 0:
        k=j-(endIndex-j)
        if k >= 0 and Str[k]=='1' and Str[j]=='1':
            return True
        j=j-1
    return False



def expandString(StartString=''):
    if lastCharMakesSolvable(StartString):
        return StartString + '0'
    return StartString + '1'

n=1
BaseStr=""
lastCount=0
while n<1000000:
    BaseStr=expandString(BaseStr)
    count=BaseStr.count('1')
    if count != lastCount:
        print(len(BaseStr), count)
    lastCount=count
    n=n+1

(ในการป้องกันของฉันฉันยังอยู่ในขั้นตอนของการทำความเข้าใจ 'งูหลาม')

นอกจากนี้ผลลัพธ์ที่มีประโยชน์จากการสร้างสายโลภก็มีการกระโดดที่สอดคล้องกันหลังจากการกดปุ่ม 2 ในจำนวน 1 ... ซึ่งฉันไม่เต็มใจที่จะรอการเป็นพยานในการกดปุ่ม 2096

strlength   # of 1's
    1    1
    2    2
    4    3
    5    4
   10    5
   14    8
   28    9
   41    16
   82    17
  122    32
  244    33
  365    64
  730    65
 1094    128
 2188    129
 3281    256
 6562    257
 9842    512
19684    513
29525    1024

0

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

  1. กำหนดจำนวนคงที่ของพื้นที่kและสตริงSค้นหาสำหรับ K-เว้นระยะแฝดใช้เวลาO(n)- เราก็ทดสอบทุกถ้า0<=i<=(n-2k) S[i]==S[i+k]==S[i+2k]การทดสอบใช้เวลาO(1)และการที่เราทำมันn-kครั้งที่เป็นค่าคงที่ดังนั้นต้องใช้เวลาkO(n-k)=O(n)

  2. ให้เราสมมติว่ามีสัดส่วนผกผันระหว่างจำนวน1ช่องว่างและจำนวนช่องว่างสูงสุดที่เราต้องการค้นหา นั่นคือถ้ามีหลายคน1ต้องมี triplet และจะต้องค่อนข้างหนาแน่น หากมีเพียงไม่กี่1รายการ triplet (ถ้ามี) อาจค่อนข้างเบาบาง กล่าวอีกนัยหนึ่งฉันสามารถพิสูจน์ได้ว่าถ้าฉันมีเพียงพอ1triplet นั้นต้องมีอยู่และยิ่ง1ฉันมีมากขึ้นจะต้องพบ triplet ที่หนาแน่นมากขึ้น สิ่งนี้สามารถอธิบายได้โดยหลักการของ Pigeonhole - หวังว่าจะอธิบายอย่างละเอียดในภายหลัง

  3. บอกว่ามีขอบเขตด้านkบนตามจำนวนช่องว่างที่เป็นไปได้ที่ฉันต้องค้นหา ตอนนี้สำหรับแต่ละ1ที่ตั้งอยู่ในS[i]ที่เราจำเป็นต้องตรวจสอบ1ในS[i-1]และS[i+1], S[i-2]และS[i+2]... และS[i-k] S[i+k]นี้จะใช้เวลาO((k^2-k)/2)=O(k^2)สำหรับแต่ละ1ในS- เนื่องจากการเกาส์ซีรีส์สรุปสูตร โปรดทราบว่าสิ่งนี้แตกต่างจากส่วนที่ 1 - ฉันมีkขอบเขตเป็นส่วนบนของจำนวนช่องว่างไม่ใช่พื้นที่คงที่

O(n*log(n))เราจำเป็นต้องพิสูจน์ นั่นก็คือเราจะต้องแสดงให้เห็นว่าเป็นสัดส่วนk*(number of 1's)log(n)

ถ้าเราสามารถทำเช่นนั้นขั้นตอนวิธีการเป็นที่น่ารำคาญ - สำหรับแต่ละ1ในSที่มีดัชนีจะiเพียงแค่มองหา1's kจากแต่ละด้านขึ้นอยู่กับระยะทาง หากทั้งสองถูกพบในระยะทางเดียวกันกลับและi kส่วนที่ยุ่งยากก็คือการค้นหาkและพิสูจน์ความถูกต้อง

ฉันขอขอบคุณความคิดเห็นของคุณที่นี่ - ฉันพยายามค้นหาความสัมพันธ์ระหว่างkและจำนวนของ1บนกระดานไวท์บอร์ดของฉันจนไม่ประสบความสำเร็จ


0

อัสสัมชั:

ผิดพูดคุยเกี่ยวกับจำนวน log (n) ของขีด จำกัด บนของคน

แก้ไข:

ตอนนี้ฉันพบว่าการใช้หมายเลขคันทอร์ (ถ้าถูกต้อง) ความหนาแน่นในชุดคือ (2/3) ^ Log_3 (n) (ฟังก์ชั่นแปลก) และฉันเห็นด้วยความหนาแน่นของ log (n) / n นั้นแข็งแกร่ง

หากนี่คือขีด จำกัด สูงสุดมี algorhitm ที่แก้ปัญหานี้อย่างน้อย O (n * (3/2) ^ (log (n) / log (3))) ความซับซ้อนของเวลาและ O ((3/2) ^ ( log (n) / log (3))) ความซับซ้อนของพื้นที่ (ตรวจสอบคำตอบของผู้พิพากษาสำหรับ algorhitm)

นี่ยังดีกว่า O (n ^ 2)

ฟังก์ชั่นนี้ ((3/2) ^ (บันทึก (n) / บันทึก (3))) ดูเหมือนจริง ๆ ว่า n * log (n) ตั้งแต่แรกเห็น

ฉันจะรับสูตรนี้ได้อย่างไร

Applaying หมายเลข Cantors บนสตริง
สมมติว่าความยาวของสตริงเป็น 3 ^ p == n
ในแต่ละขั้นตอนในการสร้างสตริงของคันทอร์คุณจะต้องรักษา 2/3 ของจำนวนที่เท่ากัน ใช้ p นี้

นั่นหมายถึง (n * ((2/3) ^ p)) -> ((3 ^ p)) * ((2/3) ^ p)) จำนวนที่เหลือและหลังจากการทำให้เข้าใจง่าย 2 ^ p นี่หมายถึง 2 ^ p อันในสตริง 3 ^ p -> (3/2) ^ p แทน p = log (n) / log (3) และรับ
((3/2) ^ (log (n) / log (3)))


เท็จ: ชุดคันทอร์มีความหนาแน่น n ^ log_3 (2)
sdcvvc

0

วิธีการแก้ปัญหา O (n) ง่ายๆด้วยพื้นที่ O (n ^ 2)? (ใช้สมมติฐานที่ว่าผู้ปฏิบัติงานระดับบิตทั้งหมดทำงานใน O (1))

อัลกอริทึมโดยทั่วไปทำงานในสี่ขั้นตอน:

ขั้นที่ 1: สำหรับแต่ละบิตในหมายเลขเดิมของคุณค้นหาว่าอยู่ไกลแค่ไหน แต่พิจารณาเพียงทิศทางเดียว (ฉันพิจารณาบิตทั้งหมดในทิศทางของบิตนัยสำคัญน้อยที่สุด)

ขั้นตอนที่ 2: กลับลำดับของบิตในอินพุต;

ขั้นตอนที่ 3: เรียกใช้ขั้นตอนที่ 1 อีกครั้งบนอินพุตที่กลับด้าน

ขั้นตอนที่ 4: เปรียบเทียบผลลัพธ์จากระยะ 1 และระยะ 3 หากบิตใดมีระยะห่างเท่ากันเหนือและใต้เราจะต้องมีการเข้าชม

โปรดทราบว่าไม่มีขั้นตอนในอัลกอริทึมด้านบนใช้เวลานานกว่า O (n) ^ _ ^

ในฐานะที่เป็นประโยชน์เพิ่มเติมอัลกอริทึมนี้จะหาทุกเว้นระยะเท่ากันจากจำนวนทุก ตัวอย่างเช่นหากคุณได้รับผลลัพธ์ของ "0x0005" ดังนั้นจะมีช่องว่างห่างเท่ากันที่ทั้ง 1 และ 3 หน่วย

ฉันไม่ได้ลองปรับรหัสด้านล่างให้เหมาะสม แต่เป็นรหัส C # ที่สามารถทำงานได้

using System;

namespace ThreeNumbers
{
    class Program
    {
        const int uint32Length = 32;

        static void Main(string[] args)
        {
            Console.Write("Please enter your integer: ");
            uint input = UInt32.Parse(Console.ReadLine());

            uint[] distancesLower = Distances(input);
            uint[] distancesHigher = Distances(Reverse(input));

            PrintHits(input, distancesLower, distancesHigher);
        }

        /// <summary>
        /// Returns an array showing how far the ones away from each bit in the input.  Only 
        /// considers ones at lower signifcant bits.  Index 0 represents the least significant bit 
        /// in the input.  Index 1 represents the second least significant bit in the input and so 
        /// on.  If a one is 3 away from the bit in question, then the third least significant bit 
        /// of the value will be sit.
        /// 
        /// As programed this algorithm needs: O(n) time, and O(n*log(n)) space.  
        /// (Where n is the number of bits in the input.)
        /// </summary>
        public static uint[] Distances(uint input)
        {
            uint[] distanceToOnes = new uint[uint32Length];
            uint result = 0;

            //Sets how far each bit is from other ones. Going in the direction of LSB to MSB
            for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
            {
                distanceToOnes[arrayIndex] = result;
                result <<= 1;

                if ((input & bitIndex) != 0)
                {
                    result |= 1;
                }
            }

            return distanceToOnes;
        }

        /// <summary>
        /// Reverses the bits in the input.
        /// 
        /// As programmed this algorithm needs O(n) time and O(n) space.  
        /// (Where n is the number of bits in the input.)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static uint Reverse(uint input)
        {
            uint reversedInput = 0;
            for (uint bitIndex = 1; bitIndex != 0; bitIndex <<= 1)
            {
                reversedInput <<= 1;
                reversedInput |= (uint)((input & bitIndex) != 0 ? 1 : 0);
            }

            return reversedInput;
        }

        /// <summary>
        /// Goes through each bit in the input, to check if there are any bits equally far away in 
        /// the distancesLower and distancesHigher
        /// </summary>
        public static void PrintHits(uint input, uint[] distancesLower, uint[] distancesHigher)
        {
            const int offset = uint32Length - 1;

            for (uint bitIndex = 1, arrayIndex = 0; bitIndex != 0; bitIndex <<= 1, ++arrayIndex)
            {
                //hits checks if any bits are equally spaced away from our current value
                bool isBitSet = (input & bitIndex) != 0;
                uint hits = distancesLower[arrayIndex] & distancesHigher[offset - arrayIndex];

                if (isBitSet && (hits != 0))
                {
                    Console.WriteLine(String.Format("The {0}-th LSB has hits 0x{1:x4} away", arrayIndex + 1, hits));
                }
            }
        }
    }
}

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


0

ด้านล่างเป็นทางออก อาจมีข้อผิดพลาดเล็กน้อยที่นี่และที่นั่น แต่ความคิดคือเสียง

แก้ไข: ไม่ใช่บันทึก * (n)

รหัส PSEUDO:

foreach character in the string
  if the character equals 1 {         
     if length cache > 0 { //we can skip the first one
        foreach location in the cache { //last in first out kind of order
           if ((currentlocation + (currentlocation - location)) < length string)
              if (string[(currentlocation + (currentlocation - location))] equals 1)
                 return found evenly spaced string
           else
              break;
        }
     }
     remember the location of this character in a some sort of cache.
  }

return didn't find evenly spaced string

รหัส C #:

public static Boolean FindThreeEvenlySpacedOnes(String str) {
    List<int> cache = new List<int>();

    for (var x = 0; x < str.Length; x++) {
        if (str[x] == '1') {
            if (cache.Count > 0) {
                for (var i = cache.Count - 1; i > 0; i--) {
                    if ((x + (x - cache[i])) >= str.Length)
                        break;

                    if (str[(x + (x - cache[i]))] == '1')
                        return true;                            
                }
            }
            cache.Add(x);                    
        }
    }

    return false;
}

มันทำงานอย่างไร:

iteration 1:
x
|
101101001
// the location of this 1 is stored in the cache

iteration 2:
 x
 | 
101101001

iteration 3:
a x b 
| | | 
101101001
//we retrieve location a out of the cache and then based on a 
//we calculate b and check if te string contains a 1 on location b

//and of course we store x in the cache because it's a 1

iteration 4:
  axb  
  |||  
101101001

a  x  b  
|  |  |  
101101001


iteration 5:
    x  
    |  
101101001

iteration 6:
   a x b 
   | | | 
101101001

  a  x  b 
  |  |  | 
101101001
//return found evenly spaced string

1
อัลกอริทึมของคุณใช้งานได้ แต่คุณต้องพิสูจน์ว่ามันน้อยกว่า O (n ^ 2) การวิเคราะห์เล็กน้อยจะนำคุณไปสู่ ​​O (n ^ 2) สำหรับแต่ละ 1 คุณจะไป 1s ทั้งหมดที่อยู่ก่อนหน้ามัน การทำให้ฟังก์ชั่นความซับซ้อนเป็น 1 +2 +3 + ... + (k / 2-1) = O (k ^ 2) [โดยที่ k คือจำนวน 1 วินาที]
แอนนา

ฉันตรวจสอบและแน่นอนกรณีสถานการณ์ที่เลวร้ายที่สุดโดยไม่มีวิธีแก้ปัญหามีขนาดใหญ่กว่านั้น O (n * log (n))
Niek H.

0

เห็นได้ชัดว่าเราต้องตรวจสอบอย่างน้อยสามกลุ่มในเวลาเดียวกันดังนั้นเราจำเป็นต้องบีบอัดเช็คอย่างใด ฉันมีอัลกอริทึมแบบผู้สมัคร แต่การวิเคราะห์ความซับซ้อนของเวลาเกินกว่าขีดความสามารถของฉัน * เวลา

สร้างต้นไม้ที่แต่ละโหนดมีลูกสามคนและแต่ละโหนดมีจำนวน 1 ทั้งหมดที่ใบของมัน สร้างรายการที่เชื่อมโยงมากกว่า 1 เช่นกัน กำหนดแต่ละโหนดด้วยราคาที่ได้รับอนุญาตตามสัดส่วนของช่วงที่ครอบคลุม ตราบใดที่เวลาที่เราใช้ในแต่ละโหนดอยู่ในงบประมาณเราจะมีอัลกอริทึม O (n lg n)

-

เริ่มต้นที่รูท หากกำลังสองของจำนวนรวมของด้านล่างต่ำกว่าต้นทุนที่อนุญาตให้ใช้อัลกอริธึมไร้เดียงสา มิฉะนั้นจะคืนเงินให้กับบุตรหลานของตน

ตอนนี้เราได้ส่งคืนภายในงบประมาณหรือเรารู้ว่าไม่มีทริปเปิลที่ถูกต้องทั้งหมดในเด็กคนใดคนหนึ่ง ดังนั้นเราจะต้องตรวจสอบสามจุดระหว่างโหนด

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

-

เหตุผลที่ฉันคิดว่าอัลกอริทึมจะทำงานได้เนื่องจากลำดับที่ไม่มีทริปเปิลที่ถูกต้องปรากฏขึ้นเพื่อสลับกันระหว่างจำนวนของ 1 และ 0 จำนวนมาก มันแยกพื้นที่การค้นหาในบริเวณใกล้เคียงได้อย่างมีประสิทธิภาพและต้นไม้จำลองการแยกนั้น

เวลาทำงานของอัลกอริทึมไม่ชัดเจนเลย มันขึ้นอยู่กับคุณสมบัติที่ไม่น่าสนใจของลำดับ หาก 1 ของเบาบางจริงๆแล้วอัลกอริทึมไร้เดียงสาจะทำงานภายใต้งบประมาณ หาก 1 ของมีความหนาแน่นสูงก็ควรจะพบการแข่งขันทันที แต่ถ้าความหนาแน่นเป็น 'ถูกต้อง' (เช่นใกล้ ~ n ^ 0.63 ซึ่งคุณสามารถทำได้โดยการตั้งค่าบิตทั้งหมดที่ตำแหน่งที่ไม่มีเลข '2' ในฐาน 3) ฉันไม่รู้ว่ามันจะทำงานหรือไม่ คุณจะต้องพิสูจน์ว่าเอฟเฟกต์การแยกนั้นแข็งแกร่งพอ


0

ไม่มีคำตอบทางทฤษฎีที่นี่ แต่ฉันเขียนโปรแกรม Java อย่างรวดเร็วเพื่อสำรวจพฤติกรรมเวลาทำงานเป็นฟังก์ชันของ k และ n โดยที่ n คือความยาวบิตทั้งหมดและ k คือจำนวน 1 ฉันมีผู้ตอบคำถามสองสามคนที่พูดว่าอัลกอริทึม "ปกติ" ที่ตรวจสอบตำแหน่งบิตทั้งหมดและค้นหาบิตที่ 3 แม้ว่าจะต้องใช้ O (k ^ 2) ในกรณีที่แย่ที่สุด ความเป็นจริงเพราะกรณีที่เลวร้ายที่สุดต้องการ bitstrings เบาบางคือ O (n ln n)

อย่างไรก็ตามนี่คือโปรแกรมด้านล่าง เป็นโปรแกรมสไตล์ Monte-Carlo ที่รันการทดลอง NTRIALS จำนวนมากสำหรับค่าคงที่ n และสร้างการสุ่มบิตเซ็ตสำหรับช่วงค่า k โดยใช้กระบวนการ Bernoulli ที่มีความหนาแน่นของข้อ จำกัด ระหว่างข้อ จำกัด ที่สามารถระบุได้และบันทึกเวลาทำงาน ของการค้นหาหรือการล้มเหลวในการค้นหา triplet ของที่เว้นระยะเท่ากันเวลาที่วัดในขั้นตอนไม่ได้อยู่ในเวลา CPU ฉันวิ่งไปที่ n = 64, 256, 1024, 4096, 16384 * (ยังคงทำงานอยู่) ก่อนอื่นทำการทดสอบกับการทดสอบ 500,000 ครั้งเพื่อดูว่าค่า k ใดใช้เวลาในการรันนานที่สุดจากนั้นทดสอบอีกครั้งกับการทดสอบ 5000000 ครั้ง การโฟกัสแบบหนาแน่นเพื่อดูว่าค่าเหล่านั้นเป็นอย่างไร เวลาทำงานที่ยาวนานที่สุดเกิดขึ้นกับความหนาแน่นน้อยมาก (เช่นสำหรับ n = 4096 พีคเวลาทำงานอยู่ในช่วง k = 16-64 โดยมีค่าสูงสุดสำหรับรันไทม์เฉลี่ยที่ 4212 ขั้นตอน @ k = 31 จำนวนรันไทม์สูงสุดที่ 5101 ขั้นตอน @ k = 58) ดูเหมือนว่าจะมีค่า N ที่ใหญ่มากสำหรับขั้นตอน O (k ^ 2) ที่แย่ที่สุดในกรณีที่จะใหญ่กว่าขั้นตอน O (n) ที่คุณสแกนบิตสตริงเพื่อหาดัชนีตำแหน่งของ 1

package com.example.math;

import java.io.PrintStream;
import java.util.BitSet;
import java.util.Random;

public class EvenlySpacedOnesTest {
    static public class StatisticalSummary
    {
        private int n=0;
        private double min=Double.POSITIVE_INFINITY;
        private double max=Double.NEGATIVE_INFINITY;
        private double mean=0;
        private double S=0;

        public StatisticalSummary() {}
        public void add(double x) {
            min = Math.min(min, x);
            max = Math.max(max, x);
            ++n;
            double newMean = mean + (x-mean)/n;
            S += (x-newMean)*(x-mean);
            // this algorithm for mean,std dev based on Knuth TAOCP vol 2
            mean = newMean;
        }
        public double getMax() { return (n>0)?max:Double.NaN; }
        public double getMin() { return (n>0)?min:Double.NaN; }
        public int getCount() { return n; }
        public double getMean() { return (n>0)?mean:Double.NaN; }
        public double getStdDev() { return (n>0)?Math.sqrt(S/n):Double.NaN; } 
        // some may quibble and use n-1 for sample std dev vs population std dev    
        public static void printOut(PrintStream ps, StatisticalSummary[] statistics) {
            for (int i = 0; i < statistics.length; ++i)
            {
                StatisticalSummary summary = statistics[i];
                ps.printf("%d\t%d\t%.0f\t%.0f\t%.5f\t%.5f\n",
                        i,
                        summary.getCount(),
                        summary.getMin(),
                        summary.getMax(),
                        summary.getMean(),
                        summary.getStdDev());
            }
        }
    }

    public interface RandomBernoulliProcess // see http://en.wikipedia.org/wiki/Bernoulli_process
    {
        public void setProbability(double d);
        public boolean getNextBoolean();
    }

    static public class Bernoulli implements RandomBernoulliProcess
    {
        final private Random r = new Random();
        private double p = 0.5;
        public boolean getNextBoolean() { return r.nextDouble() < p; }
        public void setProbability(double d) { p = d; }
    }   
    static public class TestResult {
        final public int k;
        final public int nsteps;
        public TestResult(int k, int nsteps) { this.k=k; this.nsteps=nsteps; } 
    }

    ////////////
    final private int n;
    final private int ntrials;
    final private double pmin;
    final private double pmax;
    final private Random random = new Random();
    final private Bernoulli bernoulli = new Bernoulli();
    final private BitSet bits;
    public EvenlySpacedOnesTest(int n, int ntrials, double pmin, double pmax) {
        this.n=n; this.ntrials=ntrials; this.pmin=pmin; this.pmax=pmax;
        this.bits = new BitSet(n);
    }

    /*
     * generate random bit string
     */
    private int generateBits()
    {
        int k = 0; // # of 1's
        for (int i = 0; i < n; ++i)
        {
            boolean b = bernoulli.getNextBoolean();
            this.bits.set(i, b);
            if (b) ++k;
        }
        return k;
    }

    private int findEvenlySpacedOnes(int k, int[] pos) 
    {
        int[] bitPosition = new int[k];
        for (int i = 0, j = 0; i < n; ++i)
        {
            if (this.bits.get(i))
            {
                bitPosition[j++] = i;
            }
        }
        int nsteps = n; // first, it takes N operations to find the bit positions.
        boolean found = false;
        if (k >= 3) // don't bother doing anything if there are less than 3 ones. :(
        {       
            int lastBitSetPosition = bitPosition[k-1];
            for (int j1 = 0; !found && j1 < k; ++j1)
            {
                pos[0] = bitPosition[j1];
                for (int j2 = j1+1; !found && j2 < k; ++j2)
                {
                    pos[1] = bitPosition[j2];

                    ++nsteps;
                    pos[2] = 2*pos[1]-pos[0];
                    // calculate 3rd bit index that might be set;
                    // the other two indices point to bits that are set
                    if (pos[2] > lastBitSetPosition)
                        break;
                    // loop inner loop until we go out of bounds

                    found = this.bits.get(pos[2]);
                    // we're done if we find a third 1!
                }
            }
        }
        if (!found)
            pos[0]=-1;
        return nsteps;
    }

    /*
     * run an algorithm that finds evenly spaced ones and returns # of steps.
     */
    public TestResult run()
    {
        bernoulli.setProbability(pmin + (pmax-pmin)*random.nextDouble());
        // probability of bernoulli process is randomly distributed between pmin and pmax

        // generate bit string.
        int k = generateBits();
        int[] pos = new int[3];
        int nsteps = findEvenlySpacedOnes(k, pos);
        return new TestResult(k, nsteps); 
    }

    public static void main(String[] args)
    {
        int n;
        int ntrials;
        double pmin = 0, pmax = 1;
        try {
            n = Integer.parseInt(args[0]);
            ntrials = Integer.parseInt(args[1]);
            if (args.length >= 3)
                pmin = Double.parseDouble(args[2]);
            if (args.length >= 4)
                pmax = Double.parseDouble(args[3]);
        }
        catch (Exception e)
        {
            System.out.println("usage: EvenlySpacedOnesTest N NTRIALS [pmin [pmax]]");
            System.exit(0);
            return; // make the compiler happy
        }

        final StatisticalSummary[] statistics;
        statistics=new StatisticalSummary[n+1];
        for (int i = 0; i <= n; ++i)
        {
            statistics[i] = new StatisticalSummary();
        }

        EvenlySpacedOnesTest test = new EvenlySpacedOnesTest(n, ntrials, pmin, pmax);
        int printInterval=100000;
        int nextPrint = printInterval;
        for (int i = 0; i < ntrials; ++i)
        {
            TestResult result = test.run();
            statistics[result.k].add(result.nsteps);
            if (i == nextPrint)
            {
                System.err.println(i);
                nextPrint += printInterval;
            }
        }
        StatisticalSummary.printOut(System.out, statistics);
    }
}

0
# <algorithm>
def contains_evenly_spaced?(input)
  return false if input.size < 3
  one_indices = []
  input.each_with_index do |digit, index|
    next if digit == 0
    one_indices << index
  end
  return false if one_indices.size < 3
  previous_indexes = []
  one_indices.each do |index|
    if !previous_indexes.empty?
      previous_indexes.each do |previous_index|
        multiple = index - previous_index
        success_index = index + multiple
        return true if input[success_index] == 1
      end
    end
    previous_indexes << index
  end
  return false
end
# </algorithm>

def parse_input(input)
  input.chars.map { |c| c.to_i }
end

ฉันมีปัญหากับสถานการณ์กรณีเลวร้ายที่สุดที่มีตัวเลขหลายล้านหลัก การคลุมเครือจาก/dev/urandomหลักจะช่วยให้คุณ O (n) แต่ฉันรู้ว่ากรณีที่เลวร้ายที่สุดนั้นเลวร้ายยิ่งกว่านั้น ฉันไม่สามารถบอกได้ว่าแย่ลงแค่ไหน สำหรับขนาดเล็กnมันเป็นเรื่องไม่สำคัญที่จะค้นหาปัจจัยที่เกี่ยวข้อง3*n*log(n)แต่ก็ยากที่จะแยกความแตกต่างจากลำดับการเติบโตอื่น ๆ สำหรับปัญหาเฉพาะนี้

ทุกคนที่ทำงานกับอินพุตกรณีที่แย่ที่สุดสามารถสร้างสตริงที่มีความยาวมากกว่าพูดหนึ่งแสน


ในขณะที่ฉันชี้ให้เห็นในคำตอบของฉันมันง่ายที่จะสร้างสตริงที่ไม่ดี (แม้ว่าจะไม่ใช่กรณีที่เลวร้ายที่สุด) ของจำนวนตัวเลขใด ๆ : ใส่ 1s ตรงตำแหน่ง p ที่ไม่ประกอบด้วย "1" ในการเป็นตัวแทนของพวกเขา ตำแหน่ง 2, 6, 8, 18, 20, 24, 26, 54, 56, 60 ... : ดูสูตรได้ที่ research.att.com/~njas/sequences/ ...... ) สำหรับ 3 ^ 13 ≈ 1 ล้านนี้มี 2 ^ 13 ≈ 8000 1 วินาที เวลาที่ทำงานบนสตริงดังกล่าวจะเป็น≈ n ^ (1.26) - ซึ่งอาจยังยากที่จะแยกความแตกต่างจาก O (n log n) สำหรับ n ขนาดเล็กเช่นนั้น ลองและดู
ShreevatsaR

-2

การปรับอัลกอริทึมของ Rabin-Karp อาจเป็นไปได้สำหรับคุณ ความซับซ้อนของมันคือ 0 (n) ดังนั้นจึงสามารถช่วยคุณได้

ดูhttp://en.wikipedia.org/wiki/Rabin-Karp_string_search_algorithm


3
Rabin-Karp ใช้การแฮ็กสตริงเพื่อค้นหาสตริงย่อยที่แน่นอนดังนั้นจึงไม่สามารถช่วยแก้ไขปัญหาได้
โรเบิร์ตปาร์กเกอร์

-3

นี่อาจเป็นทางออกหรือไม่? ฉันไม่แน่ใจว่ามันเป็น O (nlogn) แต่ในความคิดของฉันมันดีกว่า O (n²) เพราะวิธีเดียวที่จะไม่หาทริปเปิลจะเป็นการกระจายตัวของจำนวนเฉพาะ

มีห้องพักสำหรับการปรับปรุงครั้งที่สองที่พบ 1 อาจเป็นครั้งแรกต่อไป 1 ยังไม่มีการตรวจสอบข้อผิดพลาด

#include <iostream>

#include <string>

int findIt(std::string toCheck) {
    for (int i=0; i<toCheck.length(); i++) {
        if (toCheck[i]=='1') {
            std::cout << i << ": " << toCheck[i];
            for (int j = i+1; j<toCheck.length(); j++) {
                if (toCheck[j]=='1' && toCheck[(i+2*(j-i))] == '1') {
                    std::cout << ", " << j << ":" << toCheck[j] << ", " << (i+2*(j-i)) << ":" << toCheck[(i+2*(j-i))] << "    found" << std::endl;
                    return 0;
                }
            }
        }
    }
    return -1;
}

int main (int agrc, char* args[]) {
    std::string toCheck("1001011");
    findIt(toCheck);
    std::cin.get();
    return 0;
}

1
ในทางเทคนิคนี่คือ O (n ^ 2) โดยเฉลี่ยแล้ววงด้านในจะวนซ้ำมากกว่าครึ่งในแต่ละครั้งที่เรียกใช้ ดังนั้นจึงสามารถเขียนเป็น O (n * (n / 2)) และนั่นสามารถทำให้เป็น O (n ^ 2) ได้อย่างง่ายดาย
Robert Parker

หืมดูเหมือนว่าคุณพูดถูก นี่ไม่ใช่ปัญหาง่าย ๆ เพียงแค่ค้นหา 1 ทั้งหมดที่ใช้ O (n) ไม่มากพอสำหรับการค้นหาเพิ่มเติม / เปรียบเทียบกับความซับซ้อน O (logn)
DaClown

-3

ฉันคิดว่าอัลกอริทึมนี้มีความซับซ้อน O (n log n) (C ++, DevStudio 2k5) ตอนนี้ฉันไม่ทราบรายละเอียดของวิธีการวิเคราะห์อัลกอริทึมเพื่อกำหนดความซับซ้อนดังนั้นฉันจึงเพิ่มข้อมูลการรวบรวมตัวชี้วัดลงในโค้ด รหัสจะนับจำนวนการทดสอบที่ทำตามลำดับของ 1 และ 0 สำหรับอินพุตที่กำหนด (หวังว่าฉันจะไม่ทำอัลกอริทึม) เราสามารถเปรียบเทียบจำนวนการทดสอบจริงกับค่า O และดูว่ามีความสัมพันธ์กันหรือไม่

#include <iostream>
using namespace std;

bool HasEvenBits (string &sequence, int &num_compares)
{
  bool
    has_even_bits = false;

  num_compares = 0;

  for (unsigned i = 1 ; i <= (sequence.length () - 1) / 2 ; ++i)
  {
    for (unsigned j = 0 ; j < sequence.length () - 2 * i ; ++j)
    {
      ++num_compares;
      if (sequence [j] == '1' && sequence [j + i] == '1' && sequence [j + i * 2] == '1')
      {
        has_even_bits = true;
        // we could 'break' here, but I want to know the worst case scenario so keep going to the end
      }
    }
  }

  return has_even_bits;
}

int main ()
{
  int
    count;

  string
    input = "111";

  for (int i = 3 ; i < 32 ; ++i)
  {
    HasEvenBits (input, count);
    cout << i << ", " << count << endl;
    input += "0";
  }
}

โปรแกรมนี้แสดงจำนวนการทดสอบสำหรับแต่ละความยาวสตริงสูงสุด 32 อักขระ นี่คือผลลัพธ์:

 n  Tests  n log (n)
=====================
 3     1     1.43
 4     2     2.41
 5     4     3.49
 6     6     4.67
 7     9     5.92
 8    12     7.22
 9    16     8.59
10    20    10.00
11    25    11.46
12    30    12.95
13    36    14.48
14    42    16.05
15    49    17.64
16    56    19.27
17    64    20.92
18    72    22.59
19    81    24.30
20    90    26.02
21   100    27.77
22   110    29.53
23   121    31.32
24   132    33.13
25   144    34.95
26   156    36.79
27   169    38.65
28   182    40.52
29   196    42.41
30   210    44.31
31   225    46.23

ฉันได้เพิ่มค่า 'n log n' เช่นกัน เขียนสิ่งเหล่านี้โดยใช้เครื่องมือสร้างกราฟที่คุณเลือกเพื่อดูความสัมพันธ์ระหว่างผลลัพธ์ทั้งสอง การวิเคราะห์นี้ขยายไปถึงค่าทั้งหมดของ n หรือไม่? ฉันไม่รู้


ฉันเห็นด้วยไม่ใช่ความสัมพันธ์ที่สมบูรณ์แบบ อย่างไรก็ตามเส้นโค้งอยู่ใกล้กับ n log n มากกว่าที่จะเป็น n ^ 2
Skizz

3
ลองปั๊มขนาดอินพุตให้ใหญ่ขึ้นเป็นล้านหรือมากกว่า ที่อินพุตขนาดเล็กเส้นโค้งมักจะมีลักษณะคล้ายกับส่วนโค้งของอัลกอริธึมซึ่งเห็นได้ชัดว่าดีกว่าเมื่อขนาดอินพุตถูกปั๊มขึ้น
Nick Larsen

คู่สำหรับวงที่มีวงในด้านที่ล้อมรอบด้วยด้านนอกทำให้รูปสามเหลี่ยมซึ่งยังคงเป็น O (n ^ 2) ในความซับซ้อน ลองนึกภาพทั้งหมด (i, j) แบบที่ i ใน [0, n] และ j ใน [0, n-2 * i] คุณมีรูปสามเหลี่ยมและพื้นที่ของรูปสามเหลี่ยมมีแนวโน้มเป็นกำลังสอง
Matthieu M.

เพื่อความแม่นยำการทดสอบ = (n ^ 2-2n) / 4 สำหรับคู่ n; เห็นได้ชัดว่ากำลังสอง
คุณปู่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.