İki dizide farklılık gösteren bir element. Etkili nasıl bulabilirim?


22

Kodlama görüşmesi için hazırlanıyorum ve bu sorunu çözmenin en etkili yolunu bulamıyorum.

Diyelim ki sıralanmamış numaralardan oluşan iki dizimiz var. Dizi 2, Dizi 1'de bulunmayan bir sayı içerir. Her iki dizi de, aynı sırada veya aynı endekslerde olması gerekmez, rastgele yerleştirilmiş numaralara sahiptir. Örneğin:

Dizi 1 [78,11, 143, 84, 77, 1, 26, 35 .... n]

Dizi 2 [11,84, 35, 25, 77, 78, 26, 143 ... 21 ... n + 1]

Farklı olan sayıyı bulmak için en hızlı algoritma nedir? Çalışma süresi nedir? Bu örnekte, aradığımız sayı 21'dir.

Benim fikrim, Dizi 1'den geçmek ve bu değeri dizi 2'den silmek oldu. Tamamlanana kadar yineleyin. Bu, çalışma zamanı civarında olmalı , değil mi?O(nlogn)


@Jandvorak Yanıtlarınız için teşekkürler. Geç kaldım ve bunu gönderdikten sonra uykuya daldım. Dizi sıralanmaz ve tüm öğeler her iki dizideki rasgele dizinlerde görünür.
Konstantino Sparakis,

@KonstantinoSparakis: bu açıklama, her iki dizinin de aynı pozisyondaki unsurları içerdiğini varsayan cevapları geçersiz kılar.
Mario Cervera


@ Paparazi Sadece bir yazılım arayışı içerisindeydim, meta yazılım mühendisliğinde okuduğum bir çözümü bulacağım yerdi ama o zamanlar CS forumunu bilmiyordum. Modları, temizlemelerini söyledim.
Konstantino Sparakis,

@ Paparazzi bunu destekleyen bir meta gönderi var mı? Şahsen ben bu politikayı iyi uygulamak için hiçbir yol görmüyorum.
djechlin

Yanıtlar:


30

Farklı çalışma süreleriyle bu sorunu çözmenin dört ana yolunu görüyorum:

  • n,O(n2) çözümü: önerdiğiniz çözüm bu olurdu. Dizilerin sıralanmadığından, silme işleminin doğrusal zaman alacağını unutmayın. Sen yürütmek silme; bu nedenle, bu algoritma ikinci dereceden zaman alır.n

  • O ( nO(nlogn) çözümü: dizileri önceden sıralar; daha sonra, farklı öğeyi tanımlamak için doğrusal bir arama yapın. Bu çözümde, çalışma süresi sıralama işlemi tarafından belirlenir, bu nedenle üst sınır.O(nlogn)

Bir soruna bir çözüm belirlediğinizde daima kendinize sormalısınız: daha iyisini yapabilir miyim? Bu durumda, veri yapılarını akıllıca kullanarak yapabilirsiniz. Yapmanız gereken tek şey bir diziyi yinelemek ve diğer dizide tekrarlanan arama yapmaktır. Hangi veri yapısı (beklenen) sabit sürede arama yapmanızı sağlar? Doğru tahmin ettiniz: bir karma tablo .

  • çözüm (beklenen): ilk diziyi yineler ve elemanları bir karma tabloda saklar; daha sonra, ikinci dizide doğrusal bir tarama gerçekleştirin ve karma tablosundaki her öğeye bakın. Hash tablosunda bulunmayan öğeyi döndür. Bu doğrusal zaman çözümü, bir karma işlevine geçirebileceğiniz her tür öğe için işe yarar (örneğin, dizelerin dizileri için benzer şekilde çalışır).O(n)

Üst sınır garantileri istiyorsanız ve diziler kesinlikle tam sayılardan oluşuyorsa, en iyi çözüm, muhtemelen, Tobi Alafin tarafından önerilen çözümdür (bu çözüm size, ikinci dizide farklılık gösteren öğenin dizinini vermese de ) :

  • çözümü (garantili): ilk dizinin elemanlarını toplar. Ardından, ikinci dizinin öğelerini toplayın. Son olarak, çıkarma işlemini gerçekleştirin. Bu çözümün,bitsel XOR operatörüsayesinde, değerleri sabit uzunlukta bit dizeleri olarak gösterilebilecek herhangi bir veri türüne genelleştirilebileceğini unutmayın. Bu tamamenIlmari Karonen'incevabındaaçıklanmıştır. O(n)

Son olarak, bir başka olasılık (aynı tam sayı dizisi varsayımı altında), sayma sıralama gibi bir doğrusal zaman sıralama algoritmasını kullanmak olacaktır. Bu, sıralama tabanlı çözümün çalışma süresini O'dan ( n) azaltır. ila O ( n ) .O(nlogn)O(n)


4
Ancak, sayılar yeterince büyük olursa toplama toplamı doğrusal değildir.
Sarge Borsch,

9
Toplama algoritması ile ilgili güzel bir şey, yalnızca tamsayılarla değil en çok uint64abelyalı bir grupla çalışmasıdır (En önemlisi ; cc sarge).
John Dvorak

6
@Abdul şu ki, eğer tamsayılarınız çok büyükse, eklemek için aldıklarını söyleyemezsiniz . Ben karmaşıklığı büyür inanıyoruz O ( n ln n ) bu hesaba eğer. Normal ekleme yerine XOR kullanmak, yine de, girişte keyfi olarak çok sayıda sayı olmasına izin verir. O(n)O(nlnn)
John Dvorak

2
@JanDvorak Hayır, değil. Abelian grubunda tanımlanan işlemin sürekli zaman alacağını varsayıyorsunuz. Bu sadece kabul edilemez.
UTF-8

2
Znd

16

Θ(n)

  • Toplam , örneğin herhangi bir değeri için bu ve b , bir B tanımlandığı gibidir ve aynı tipte (ya da operatörü olan bir kısmı uygun bir süper tip, en azından hala tanımlandığı gibidir);abab
  • birleştirici , öyle ki ;a(bc)=(ab)c
  • değişmeli , bu şekilde ; veab=ba
  • cancellative bir ters operatör vardır, öyle ki tatmin olduğu ( bir b ) b = bir . Teknik olarak, bu ters işlemin, her biri O ( n ) süresinden daha fazla zaman almadığı iki toplam n elemanının "çıkarılması" gerektiği sürece, sabit zaman olması gerekmez .(ab)b=anO(n)

(Tür yalnızca sınırlı sayıda farklı değer alabiliyorsa, bu özellikler onu bir Abelian grubuna dönüştürmek için yeterlidir , olmasa da en azından değişmeli bir iptal grubu olacaktır .)

Bu tür bir işlem kullanılarak , biz dizi "toplamı" tanımlayabilir a = ( bir 1 , bir 2 , ... , bir n ) olarak ( a=(a1,a2,,an) Başka bir dizi göz önüne alındığında b = ( b , 1 , b 2 , ... , B , n , b , n + 1 ) , tüm elemanlarını ihtiva eden bir artı bir ilave eleman x , biz, böylece var (

(a)=a1a2an.
b=(b1,b2,,bn,bn+1)ax , ve bu fazladan bilgiyi hesaplayarak bulabiliriz: x = ( (b)=(a)x
x=(b)(a).

Daha genel olarak, bit ucundaki XOR yöntemini değişken uzunluktaki dizgelere uygulayabiliriz, uçtaki dolguyu tersine çevirerek çıkarmak için bir yolumuz olduğu sürece bunları gerektiği kadar aynı uzunlukta geçirerek uygulayabiliriz.

Bazı durumlarda, bu önemsizdir. Örneğin, C tarzı boş bayt dizileri sonlandırılmış, kendi uzunluklarını dolaylı olarak kodlar, bu nedenle onlar için bu yöntemi uygulamak önemsizdir: iki dizeyi XORing yaparken, uzunluk eşleşmesi için kısa olanı boş baytlarla doldurun ve arkadaki boştaki boşlukları kırpın son sonuç. Ara XOR-sum dizeleri Not edebilirsiniz açıkça onların boyunu saklamak gerekir böylece boş karakter içermediğini olsa da, bayt (ama sadece birisi veya ikisi en fazla gerekir).

1001232bayt uzunluğunda, her dizenin uzunluğunu 32-bit bir tamsayı olarak kodlayabilir ve dizeye hazırlayabilirdik. Veya bazı önek kodlarını kullanarak rastgele dize uzunluklarını bile kodlayabilir ve bunları dizelere hazırlayabiliriz. Diğer olası kodlamalar da mevcuttur.

Θ(n)

Potansiyel olarak zor olan tek şey, iptali işe yaraması için, iki dizideki giriş değerlerinin verilebilmesi halinde zor olabilecek (gerçekten, potansiyel olarak hesaplama bile mümkün olmayan), her değer için benzersiz bir kanonik bit temsili temsili seçmemiz gerektiğidir. farklı eşdeğer temsillerde. Ancak bu, bu yöntemin belirgin bir zayıflığı değildir; Bu sorunun çözülmesi için herhangi başka bir yöntem de, girişin eşdeğeri belirlenemeyen değerler içermesine izin verilirse, başarısız olmak için de yapılabilir.


Vay bu çok ilginç al. Thank you @IlmariKaronen
Konstantino Sparakis

14

Bunu Tobi'nin cevabı üzerine yorum olarak gönderirdim, ancak henüz itibarım yok.

Her listenin toplamını hesaplamaya alternatif olarak (özellikle büyük listeler ise veya toplandığında veri türünüzü taşabilecek çok büyük sayılar içeriyorsa) bunun yerine xor kullanabilirsiniz.

Sadece her listenin xor-sum değerini (yani x [0] ^ x [1] ^ x [2] ... x [n]) hesaplayın ve sonra bu iki değeri x. Bu size yabancı öğenin değerini verecektir (ancak dizini değil).

Bu hala O (n) 'dir ve taşma ile ilgili sorunlardan kaçınır.


3
XOR'u da kullanırdım, çünkü biraz daha düzgün görünüyor, ama adil olmak gerekirse, taşma, bunu uyguladığınız dil, kaydırma yoluyla taşma işlemini desteklediği sürece sorun değil.
Martin Ender,

14

Öğe = Toplam (Dizi2) - Toplam (Dizi1)

Ben içtenlikle bu en optimum algoritmadır şüpheliyim. Ancak sorunu çözmenin başka bir yolu ve sorunu çözmenin en basit yoludur. Umarım yardımcı olur.

Eklenen öğelerin sayısı birden fazla ise, bu işe yaramaz.

Cevabım, en iyi, en kötü ve ortalama durum için aynı çalışma süresi karmaşıklığına sahip,

EDIT
Biraz düşündükten sonra, cevabım senin çözümün olduğunu düşünüyorum.

nn11=n12=n+11=n

2n121=1

2n1+1=2n

Θ(n)

EDIT:
Veri tipleri ile ilgili bazı problemlerden dolayı, reffu tarafından önerilen bir XOR toplamı daha uygun olacaktır.


Değerler yüzüyorsa bu yöntemin doğru bir cevap vermeyebileceğini unutmayın; Tamsayılı değerler için çalışacaktır, ancak a) tamsayılı türünüz taşma üzerinde iyi tanımlanmış sarma davranışına sahipse veya b) toplamları taşmaları mümkün olmayan genişlikte bir değişkende saklarsanız.
Ilmari Karonen

Ruby'nin "BigNum" sınıfı bununla baş edebilir.
Tobi Alafin,

Diziniz örneğin dizeler içeriyorsa veya anlamlı bir şekilde eklenemeyen herhangi bir şey varsa, kesinlikle işe yaramaz.
gnasher729

Evet, farkettim. Peki ya 'XOR'? Yüzer için işe yarar mı?
Tobi Alafin

Evet ve ayrıca işaretçiler ve genel olarak sabit sayıdaki bitlerden oluşan her şey. Birçok dil bunu desteklemiyor, ancak bu temel bir sorun değil. Modüler toplama / çıkarma aynı durumlarda işe yarayacaktır.
Harold

1

Bu dizi 2'nin dizi 1 alarak ve bir öğeyi rastgele bir konuma sokarak oluşturulduğunu varsayalım veya dizi 1 dizi 2 alarak ve rastgele bir öğeyi silerek yaratıldı.

Tüm dizi elemanının farklı olması garanti edilirse, zaman O (ln n) 'dir. Öğeleri n / 2 konumundaki karşılaştırırsınız. Eşitleri varsa, fazladan eleman n / 2 + 1'den dizinin sonuna kadardır, aksi takdirde 0 ile n / 2 arasındadır. Ve bunun gibi.

Dizi öğelerinin farklı olmaları garanti edilmezse: Dizi 1'de n sayısı 1 ve dizi 2'de herhangi bir yere 2 sayısı girmiş olabilirsiniz. Bu durumda, 2 sayısının hiç bakmadan nerede olduğunu bilemezsiniz. dizi elemanları Bu nedenle O (n).

PS. Gereksinimler değiştiğinden, kullanılabilir olup olmadığını öğrenmek için kütüphanenizi kontrol edin. MacOS / iOS'ta bir NSCountedSet yaratırsınız, dizi 2'deki tüm sayıları ekler, dizi 1'deki tüm sayıları kaldırır ve geriye kalan şey, ek bir tane olduğu iddiasına güvenmeksizin dizi 2'deki her şeydir, ancak dizi 1'deki değildir öğe.


Bu cevap çok açıktı, ancak soru varsayımınızı geçersiz kılan yeni bir gereksinimle düzenlendi.
Mario Cervera

Yeni cevabın doğru görünüyor. Zaman karmaşıklığı nedir.
Tobi Alafin

İlk önce kodu yazmak için gereken zaman nedir. Çok önemsiz. NSCountedSet karma kullanır, bu yüzden zaman karmaşıklığı "genellikle doğrusaldır".
gnasher729

-1

en kısa, en uzun var;

Hızlı referanslama için bir haritaya en kısa olanı ve geçerli değer haritaya girene kadar en uzundaki döngüyü dönüştürün.

Javascript'te buna benzer bir şey:

if (arr1.length> arr2.length) {shortest = arr2; en uzun = arr1; } else {shortest = arr1; en uzun = arr2; }

var map = shortest.reduce (function (obj, value) {obj [değer] = doğru; return obj;}, {});

değişken fark = longest.find (function (value) {return !!! map [değer];});


Açıklama içermeyen kodlar burada iyi bir cevap sayılmaz. Ayrıca neden kullandın !!! ?
Evil

-1

Zaman karmaşıklığında O (N) çözümü Uzay karmaşıklığı açısından O (1)

Problem cümlesi: dizi2'nin dizi1'in tüm elemanlarını ve dizi1'de bulunmayan bir başka eleman içerdiğini varsayarsak.

Çözüm şudur: dizi 1'de bulunmayan öğeyi bulmak için xor'u kullanırız, bu nedenle adımlar şunlardır: 1. Dizi1'den başlayın ve tüm öğeleri xor yapın ve bir değişkende saklayın. 2. dizi2'yi alın ve dizi1'in xorunu saklayan değişkenle tüm öğelerin xor değerini yapın. 3. İşlemi yaptıktan sonra değişkenimiz sadece dizi2'de bulunan elemanı içerecektir. Yukarıdaki algoritma, aşağıdaki xor "a xor a = 0" "a xor 0 = a" özelliği nedeniyle çalışır. Umarım bu sorunu çözer. Ayrıca yukarıda önerilen çözümler de iyidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.