จะหาค่าซ้ำ 5 ในเวลา O (n) ได้อย่างไร


15

สมมติว่าคุณมีอาร์เรย์ที่มีขนาดที่มีจำนวนเต็มตั้งแต่ถึงโดยรวมโดยมีการซ้ำห้าครั้ง ฉันต้องการที่จะนำเสนอขั้นตอนวิธีการที่สามารถหาตัวเลขที่ซ้ำในเวลา ฉันไม่สามารถคิดในสิ่งใดได้ตลอดชีวิตของฉัน ฉันคิดว่าการเรียงลำดับที่ดีที่สุดจะเป็นหรือไม่ จากนั้นภายในอาร์เรย์จะเป็นส่งผลให้ในlog) อย่างไรก็ตามฉันไม่แน่ใจว่าการเรียงลำดับจะมีความจำเป็นหรือไม่เนื่องจากฉันได้เห็นบางสิ่งที่ยุ่งยากด้วยรายการลิงก์คิวสแต็ก ฯลฯ1 n - 5 O ( n ) O ( n log n ) O ( n ) O ( n 2ล็อกn )n61n5O(n)O(nlogn)O(n)O(n2logn)


16
O(nlogn)+O(n)ไม่O(n2logn) ) มันO(nlogn) ) มันจะเป็นO(n2logn)ถ้าคุณเรียง n ครั้ง
คดีฟ้องร้องกองทุนโมนิก้า


1
@leftaroundabout อัลกอริธึมเหล่านี้คือO(kn)โดยที่nคือขนาดของอาเรย์และkคือขนาดของชุดอินพุต ตั้งแต่k=nconstantกลไกเหล่านี้ทำงานในO(n2)
โรมันกราฟ

4
@ RomanGräfปรากฏว่าสถานการณ์จริงคือสิ่งนี้: อัลกอริทึมทำงานในO(logkn)โดยที่kคือขนาดของโดเมน ดังนั้นสำหรับปัญหาเช่นเดียวกับ OP ของมันจะลงมาเหมือนกันไม่ว่าคุณจะใช้อัลกอริทึมดังกล่าวกับโดเมนที่มีขนาดnหรืออัลกอริทึมO(nlogn)ดั้งเดิมบนโดเมนที่มีขนาดไม่ จำกัด ทำให้รู้สึกเช่นกัน
leftaroundabout

5
สำหรับn=6จำนวนที่อนุญาตเท่านั้นคือ1ตามคำอธิบายของคุณ แต่แล้ว1จะต้องมีการทำซ้ำหกไม่ใช่ห้าครั้ง
อเล็กซ์ Reinking

คำตอบ:


22

คุณสามารถสร้างอาร์เรย์เพิ่มเติมขนาดn เริ่มตั้งองค์ประกอบทั้งหมดของอาร์เรย์ไป0 ห่วงแล้วผ่านการป้อนข้อมูลอาร์เรย์และการเพิ่มขึ้นB [ [ ผม] ]โดย 1 สำหรับแต่ละฉัน หลังจากนั้นคุณก็ตรวจสอบอาร์เรย์B : ห่วงมากกว่าและถ้าB [ [ ผม] ] > 1แล้ว[ ผม]ซ้ำแล้วซ้ำอีก คุณแก้มันในO ( n )Bn0AB[A[i]]iBAB[A[i]]>1A[i]O(n)เวลาที่ค่าใช้จ่ายของหน่วยความจำซึ่งเป็นและเนื่องจากจำนวนเต็มของคุณอยู่ระหว่าง1และn - 5O(n)1n5


26

วิธีการแก้ปัญหาในคำตอบ fade2black เป็นมาตรฐานหนึ่ง แต่จะใช้พื้นที่ คุณสามารถปรับปรุงสิ่งนี้เป็นพื้นที่O ( 1 )ดังนี้:O(n)O(1)

  1. ให้อาร์เรย์จะ[ 1 ] , ... , [ n ] สำหรับd = 1 , ... , 5 , คำนวณσ d = Σ n ฉัน= 1 [ ผม] dA[1],,A[n]d=1,,5σd=i=1nA[i]d
  2. คำนวณ (คุณสามารถใช้สูตรที่รู้จักกันดีในการคำนวณผลรวมหลังในO ( 1 ) ) โปรดทราบว่าτ d = m d 1 + + m d 5โดยที่m 1 , , m 5เป็นตัวเลขซ้ำτd=σdi=1n5idO(1)τd=m1d++m5dm1,,m5
  3. คำนวณพหุนาม ) ค่าสัมประสิทธิ์ของพหุนามนี้มีหน้าที่สมมาตรของม. 1 , ... , ม. 5ซึ่งสามารถคำนวณได้จากτ 1 , ... , τ 5ในO ( 1 )P(t)=(tm1)(tm5)m1,,m5τ1,,τ5O(1)
  4. ค้นหารากทั้งหมดของพหุนามโดยลองความเป็นไปได้n - 5ทั้งหมดP(t)n5

ขั้นตอนวิธีการนี้จะถือว่ารูปแบบเครื่อง RAM ซึ่งดำเนินการทางคณิตศาสตร์พื้นฐานเกี่ยวกับคำบิตใช้เวลาO ( 1 )เวลาO(logn)O(1)


อีกวิธีในการกำหนดโซลูชันนี้เป็นไปตามบรรทัดต่อไปนี้:

  1. คำนวณและอนุมานปี1 = m 1 + + ม. 5โดยใช้สูตรที่Y 1 = x 1 - Σ n - 5 ฉัน= 1ฉันx1=i=1nA[i]y1=m1++m5y1=x1i=1n5i
  2. คำนวณในO ( n )โดยใช้สูตร x 2 = ( A [ 1 ] ) A [ 2 ] + ( A [ 1 ] + A [ 2] ] ) A [ 3 ] + ( A [ 1x2=1i<jA[i]A[j]O(n)
    x2=(A[1])A[2]+(A[1]+A[2])A[3]+(A[1]+A[2]+A[3])A[4]++(A[1]++A[n1])A[n].
  3. ลดใช้สูตร y 2 = x 2 - 1 i < j n - 5 i j - ( n - 5 i = 1 i ) y 1 .y2=1i<j5mimj
    y2=x21i<jn5ij(i=1n5i)y1.
  4. คำนวณและอนุมานy 3 , y 4 , y 5ตามเส้นที่คล้ายกันx3,x4,x5y3,y4,y5
  5. ค่าของคือ (ถึงเครื่องหมาย) สัมประสิทธิ์ของพหุนามP ( t )จากวิธีแก้ปัญหาก่อนหน้าy1,,y5P(t)

วิธีนี้แสดงให้เห็นว่าถ้าเราแทนที่ 5 ด้วยเราจะได้รับ (ฉันเชื่อว่า) O ( d 2 n )อัลกอริทึมโดยใช้พื้นที่O ( d 2 )ซึ่งดำเนินการทางคณิตศาสตร์O ( d n )ในจำนวนเต็มของบิตยาวO ( d log n ) , รักษาได้มากที่สุดO ( d )ของสิ่งเหล่านี้ในเวลาที่กำหนด (สิ่งนี้ต้องการการวิเคราะห์อย่างรอบคอบของการคูณที่เราดำเนินการซึ่งส่วนใหญ่เกี่ยวข้องกับตัวถูกดำเนินการที่มีความยาวเพียงตัวเดียวO ( บันทึกndO(d2n)O(d2)O(dn)O(dlogn)O(d) .) เป็นไปได้ว่าสิ่งนี้สามารถปรับปรุงเป็นเวลา O ( d n )และพื้นที่ O ( d )โดยใช้เลขคณิตแบบแยกส่วนO(logn)O(dn)O(d)


การตีความของและτ d , P ( t ) , m ฉันและอื่น ๆ ? ทำไมวันที่{ 1 , 2 , 3 , 4 , 5 } ? σdτdP(t)mid{1,2,3,4,5}
โฟมบินได้ใน

3
ข้อมูลเชิงลึกที่อยู่เบื้องหลังการแก้ปัญหาเป็นเคล็ดลับข้อสรุปซึ่งจะปรากฏในการออกกำลังกายจำนวนมาก (ตัวอย่างเช่นคุณจะพบองค์ประกอบที่ขาดหายไปจากอาร์เรย์ของความยาวมีทั้งหมด แต่หนึ่งของตัวเลข1 , ... , n ?) กลวิธีการรวมสามารถใช้ในการคำนวณf ( m 1 ) + + f ( m 5 )สำหรับฟังก์ชันโดยพลการfและคำถามคือfใดที่จะเลือกเพื่อให้สามารถอนุมานm 1 , , mn11,,nf(m1)++f(m5)ff . คำตอบของฉันใช้เทคนิคที่คุ้นเคยจากทฤษฎีเบื้องต้นของฟังก์ชันสมมาตร m1,,m5
Yuval Filmus

1
@hoffmale จริง ) O(d2)
Yuval Filmus

1
@hoffmale แต่ละคนจะใช้เวลาคำเครื่อง d
Yuval Filmus

1
@BurnsBA ปัญหาของวิธีนี้คือใหญ่กว่า( n - 4 ) ( n - 5 )(n5)# . การดำเนินงานในจำนวนมากช้ากว่า (n4)(n5)2
Yuval Filmus

8

นอกจากนี้ยังมีเวลาเชิงเส้นและอัลกอริทึมพื้นที่คงที่ตามการแบ่งซึ่งอาจมีความยืดหยุ่นมากขึ้นหากคุณพยายามที่จะใช้สิ่งนี้กับตัวแปรของปัญหาที่วิธีการทางคณิตศาสตร์ไม่ทำงาน สิ่งนี้ต้องการการกลายพันธุ์อาเรย์พื้นฐานและมีปัจจัยคงที่ที่แย่กว่าวิธีการทางคณิตศาสตร์ โดยเฉพาะอย่างยิ่งฉันเชื่อว่าค่าใช้จ่ายในแง่ของจำนวนทั้งหมดของค่าและจำนวนของการทำซ้ำdคือO ( n log d )และO ( d )ตามลำดับแม้ว่าการพิสูจน์ว่าจะใช้เวลามากกว่าที่ฉันมีอยู่ในขณะนี้ .ndO(nlogd)O(d)


ขั้นตอนวิธี

เริ่มต้นด้วยรายการคู่โดยที่คู่แรกคือช่วงที่อยู่เหนือทั้งอาร์เรย์หรือหากทำดัชนีไว้[(1,n)]

ทำซ้ำขั้นตอนต่อไปนี้จนกว่ารายการจะว่างเปล่า:

  1. ใช้และลบคู่ใด ๆออกจากรายการ(i,j)
  2. ค้นหาขั้นต่ำและสูงสุด, และสูงสุด , ของ subarray ที่แสดงminmax
  3. หากระบบย่อยจะประกอบด้วยองค์ประกอบที่เท่ากันเท่านั้น ให้ผลองค์ประกอบยกเว้นหนึ่งและข้ามขั้นตอนที่ 4 ถึง 6min=max
  4. หากระบบย่อยจะไม่มีรายการซ้ำ ข้ามขั้นตอนที่ 5 และ 6maxmin=ji
  5. แบ่งพาร์ติชันย่อยรอบเช่นนั้นองค์ประกอบถึงบางดัชนีkมีขนาดเล็กกว่าตัวคั่นและองค์ประกอบด้านบนดัชนีนั้นไม่ได้min+max2k
  6. เพิ่มและ( k + 1 , j )ลงในรายการ(i,k)(k+1,j)

การวิเคราะห์ความซับซ้อนของเวลา

ขั้นตอนที่ 1 ถึง 6 ใช้เวลาเนื่องจากการค้นหาขั้นต่ำและสูงสุดและการแบ่งพาร์ติชันสามารถทำได้ในเวลาเชิงเส้นO(ji)

ทุกคู่ในรายการเป็นคู่แรก( 1 , n )หรือลูกของบางคู่ที่ subarray ที่สอดคล้องกันมีองค์ประกอบที่ซ้ำกัน มีมากที่สุดd log 2 n + 1 parentsผู้ปกครองดังกล่าวเนื่องจากการสำรวจเส้นทางแต่ละช่วงแบ่งครึ่งซึ่งสามารถทำซ้ำได้ดังนั้นจึงมีจำนวนสูงสุด2 d log 2 n + 1 รวมเมื่อรวมคู่กับ subarrays ที่ไม่มี ที่ซ้ำกัน ในแต่ละครั้งขนาดของรายการไม่เกิน2 d(i,j)(1,n)dlog2n+12dlog2n+12d.

พิจารณางานเพื่อค้นหาสิ่งใดสิ่งหนึ่งที่ซ้ำกัน นี้ประกอบด้วยลำดับของคู่มากกว่าช่วงชี้แจงลดลงดังนั้นการทำงานทั้งหมดคือผลรวมของลำดับเรขาคณิตหรือ ) นี้ก่อให้เกิดข้อพิสูจน์ที่ชัดเจนว่าการทำงานรวมสำหรับdซ้ำกันจะต้องเป็นO ( n d )ซึ่งเป็นเส้นตรงในnO(n)dO(nd)n

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


ขอบคุณสำหรับคำอธิบาย ตอนนี้ฉันเข้าใจ. อัลกอริทึมสวยมาก!
DW

5

ปล่อยให้นี่เป็นคำตอบเพราะต้องการพื้นที่มากกว่าความคิดเห็นที่ให้

คุณทำผิดพลาดใน OP เมื่อคุณแนะนำวิธีการ เรียงลำดับรายการแล้ว transversing มันเวลาไม่O ( n 2บันทึกn )เวลา เมื่อคุณทำสองสิ่ง (ที่ใช้O ( f )และO ( g )ตามลำดับ) ตามลำดับดังนั้นความซับซ้อนของเวลาที่เกิดขึ้นคือO ( f + g ) = O ( สูงสุดf , g ) (ภายใต้สถานการณ์ส่วนใหญ่)O(nlogn)O(n2logn)O(f)O(g)O(f+g)=O(maxf,g)

เพื่อที่จะเพิ่มความซับซ้อนของเวลาคุณจะต้องใช้สำหรับการวนซ้ำ ถ้าคุณมีห่วงความยาวและคุ้มค่าในวงแต่ละคนที่คุณทำฟังก์ชั่นที่ใช้O ( กรัม)แล้วคุณจะได้รับO ( กรัม)เวลาfO(g)O(fg)

ดังนั้นในกรณีของคุณคุณเรียงลำดับในและจากนั้นในแนวขวางO ( n )ที่เกิดขึ้นในO ( n log n + n ) = O ( n log n ) ถ้าเปรียบเทียบของขั้นตอนวิธีการเรียงลำดับแต่ละคนที่คุณต้องทำคำนวณที่ใช้O ( n ) , แล้วมันจะใช้เวลาO ( n 2บันทึกn )แต่นั่นไม่ใช่กรณีที่นี่O(nlogn)O(n)O(nlogn+n)=O(nlogn)O(n)O(n2logn)


ในกรณีที่คุณอยากรู้เกี่ยวกับการอ้างสิทธิ์ของฉันที่เป็นสิ่งสำคัญที่จะต้องทราบว่านั่นไม่จริงเสมอไป แต่ถ้าf O ( g )หรือg O ( f ) (ซึ่งเก็บไว้สำหรับโฮสต์ทั้งหมดของฟังก์ชั่นทั่วไป) มันจะถือ เวลาที่พบมากที่สุดก็ไม่ถือไม่ได้คือเมื่อพารามิเตอร์เพิ่มเติมได้มีส่วนร่วมและคุณได้รับการแสดงออกเช่นO ( 2 n + n log n )O(f+g)=O(maxf,g)fO(g)gO(f)O(2cn+nlogn)


3

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

for idx from n-4 to n
    while arr[arr[idx]] != arr[idx]
        swap(arr[arr[idx]], arr[idx])

สิ่งนี้จะใส่arr[idx]ที่ตำแหน่งซ้ำ ๆarr[idx]จนกว่าคุณจะพบตำแหน่งนั้นแล้วซึ่ง ณ จุดนั้นจะต้องซ้ำกัน โปรดทราบว่าจำนวนรวมของการแลกเปลี่ยนถูก จำกัด โดยเนื่องจากการสลับแต่ละครั้งทำให้เงื่อนไขการออกถูกต้องn


คุณจะต้องให้เหตุผลบางอย่างที่whileวงภายในทำงานในเวลาคงที่โดยเฉลี่ย มิฉะนั้นนี่ไม่ใช่ขั้นตอนวิธีเชิงเส้น
David Richerby

@DavidRicherby มันไม่ได้ใช้เวลาคงที่โดยเฉลี่ย แต่วงรอบนอกจะทำงานเพียง 5 ครั้งดังนั้นก็โอเค โปรดทราบว่าจำนวนรวมของการแลกเปลี่ยนจะถูก จำกัด ด้วยเนื่องจากการสลับแต่ละครั้งทำให้เงื่อนไขการออกถูกต้องดังนั้นแม้ว่าจำนวนของค่าที่ซ้ำกันเพิ่มขึ้นเวลาทั้งหมดยังคงเป็นแบบเชิงเส้น (aka. ใช้ขั้นตอนnมากกว่าn d ) nnnd
Veedrac

อุ๊ปส์ฉันไม่ได้สังเกตว่าวงรอบนอกทำงานเป็นจำนวนคงที่ตลอดเวลา! (แก้ไขเพื่อรวมบันทึกย่อของคุณเกี่ยวกับจำนวนของการแลกเปลี่ยนและดังนั้นฉันจึงสามารถย้อนกลับ downvote ของฉัน.)
David Richerby

1

ลบค่าที่คุณมีจากผลรวม .i=1ni=(n1)n2

ดังนั้นหลังจากเวลา (สมมติว่าเลขคณิตคือ O (1) ซึ่งไม่ใช่จริง ๆ แต่ลองทำท่า) คุณมีผลรวมσ 1จาก 5 จำนวนเต็มระหว่าง 1 ถึง n:Θ(n)σ1

x1+x2+x3+x4+x5=σ1

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

i=1ni2

x12+x22+x32+x42+x52=σ2

x.

Caveats: Arithmetic is not really O(1). Also, you need a bit of space to represent your sums; but not as much as you would imagine - you can do most everything modularly, as long as you have, oh, log(5n6) bits; that should do it.


Doesn't @YuvalFilmus propose the same solution?
fade2black

@fade2black: Oh, yes, it does, sorry, I just saw the first line of his solution.
einpoklum

0

Easiest way to solve the problem is to create array in which we will count the apperances for each number in the original array, and then traverse all number from 1 to n5 and check if the number appears more than once, the complexity for this solution in both memory and time is linear, or O(N)


1
This is the same @fade2black's answer (although a bit easier on the eyes)
LangeHaare

0

Map an array to 1 << A[i] and then XOR everything together. Your duplicates will be the numbers where corresponding bit is off.


มีห้ารายการที่ซ้ำกันดังนั้นเคล็ดลับ xor จะไม่แตกในบางกรณี
Evil

1
เวลาทำงานของสิ่งนี้คือ O(n2). bitvector แต่ละอันนั้นn บิตยาวดังนั้นคุณต้องใช้การดำเนินการ bitvector O(n) เวลาและคุณทำการดำเนินการเวกเตอร์หนึ่งบิตต่อองค์ประกอบของอาร์เรย์เดิมรวมเป็น O(n2) เวลา.
DW

@DW แต่เนื่องจากเครื่องที่เราใช้ตามปกติได้รับการแก้ไขที่ 32 หรือ 64 บิตและสิ่งเหล่านี้จะไม่เปลี่ยนแปลงในเวลาทำงาน (นั่นคือค่าคงที่) ทำไมพวกเขาไม่ควรได้รับการปฏิบัติเช่นนั้นและคิดว่า การดำเนินการบิตอยู่ใน O(1) แทน O(n)?
code_dredd

1
@ray, I think you answered your own question. Given that the machines we normally use are fixed at 64-bits, the running time to do an operation on a n-bit vector is O(n), not O(1). It takes something like n/64 instructions to do some operation on all n bits of a n-bit vector, and n/64 is O(n), not O(1).
D.W.

@DW สิ่งที่ฉันได้จากมาก่อนหน้านี้ ความคิดเห็นคือเวกเตอร์บิตที่อ้างถึงองค์ประกอบเดียวในnอาร์เรย์ขนาดเล็กที่มีเวกเตอร์บิตเป็น 64 บิตซึ่งจะเป็นค่าคงที่ฉันหมายถึง เห็นได้ชัดว่าการประมวลผลขนาดของอาร์เรย์n จะทำ O(kn) เวลาถ้าเราคิดว่ามี k- บิตต่อองค์ประกอบและ nจำนวนองค์ประกอบในอาร์เรย์ แต่k=64ดังนั้นการดำเนินการสำหรับองค์ประกอบอาร์เรย์ที่มีจำนวนบิตคงที่ควรเป็น O(1) แทน O(k) และอาร์เรย์ O(n) แทน O(kn). คุณกำลังรักษาk เพื่อความสมบูรณ์ / ความถูกต้องหรือฉันหายไปอย่างอื่น?
code_dredd

-2
DATA=[1,2,2,2,2,2]

from collections import defaultdict

collated=defaultdict(list):
for item in DATA:
    collated[item].append(item)
    if len(collated) == 5:
        return item.

# n time

4
ยินดีต้อนรับสู่เว็บไซต์ เราเป็นไซต์วิทยาการคอมพิวเตอร์ดังนั้นเราจึงมองหาอัลกอริธึมและคำอธิบายไม่ใช่การทิ้งโค้ดที่ต้องการความเข้าใจในภาษาและไลบรารีเฉพาะ โดยเฉพาะอย่างยิ่งการอ้างสิทธิ์ของคุณที่รหัสนี้ทำงานในเวลาเชิงเส้นถือว่าที่collated[item].append(item)ทำงานในเวลาคงที่ เป็นเรื่องจริงเหรอ?
David Richerby

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