SORU
14 Kasım 2014, Cuma


Nasıl iki liste dairesel Python ile aynı olup olmadığını kontrol etmek için

Örneğin, bir listem var:

a[0] = [1, 1, 1, 0, 0]
a[1] = [1, 1, 0, 0, 1]
a[2] = [0, 1, 1, 1, 0]
# and so on

Farklı gibi görünüyor, ama eğer başlangıç ve bitiş bağlı olduğu tahmin ediliyor, o zamandaireselaynı.

Sorun, var olan her liste 55 uzunluğa sahiptir ve sadece üç birler ve sıfırlar 52 içerir. Dairesel koşul olmadan, 26,235 (3 seçmek 55) listeleri vardır. Bu durum ancak, 'döngüsel', dairesel aynı listelerinin çok sayıda var

Şu anda takip ederek dairesel kimliğini Gözden geçirdim

def is_dup(a, b):
    for i in range(len(a)):
        if a == list(numpy.roll(b, i)): # shift b circularly by i
            return True
    return False

Bu işlev, en kötü ihtimalle 55 döngüsel shift işlemleri gerektirir. Ve birbirleri ile karşılaştırılmak 26,235 listeleri vardır. Kısacası, 55 * 26,235 * (26,235 - 1) / 2 = 18,926,847,225 hesaplamaları lazım. Yaklaşık 20 Giga!

Herhangi bir iyi bir yol daha az hesaplamaları ile ilgisi var mı? Ya da destekleyen herhangi bir veri türleridairesel?

CEVAP
14 Kasım 2014, Cuma


Öncelikle, bu listenin uzunluğu bakımından O(n) yapılabilir Eğer 2 kez ([1, 2, 3]) [1, 2, 3, 1, 2, 3] olacak listenizi çoğaltmak istersen o zaman yeni bir liste kesinlikle tüm olası döngüsel listeleri düzenleyecek dikkat edin.

Tüm aradığınız listesi başlangıç listesinden 2 kez içinde olup olmadığını kontrol etmektir. Python şu şekilde (uzunlukları aynı olduğunu varsayarsak) bunu elde edebilirsiniz.

list1 = [1, 1, 1, 0, 0]
list2 = [1, 1, 0, 0, 1]
print ' '.join(map(str, list2)) in ' '.join(map(str, list1 * 2))

Benim oneliner ilgili bir açıklama: list * 2 kendisi ile ilgili bir liste birleştirir, map(str, [1, 2]) dize için tüm numaraları dönüştürmek ve ' '.join() bir dizeye 14* *dizi '1 2 111' dönüştürür.

Yorumlarda bazı kişiler tarafından işaret olarak, oneliner Olası bazı yanlış pozitif sonuç verebilir, tüm olası kenar taleplerini karşılamak için:

def isCircular(arr1, arr2):
    if len(arr1) != len(arr2):
        return False

    str1 = ' '.join(map(str, arr1))
    str2 = ' '.join(map(str, arr2))
    if len(str1) != len(str2):
        return False

    return str1 in str2   ' '   str2

P. S. 1zaman karmaşıklığı hakkında konuşurken, eğer alt O(n) zaman bulunabilir O(n) elde edilebileceğini fark değer. Her zaman böyle değildir ve dil (although potentially it can be done in linear zaman örneğin KMP) uygulamasına bağlıdır.

P. S. 2ve bu gerçek yüzünden korkuyor dizeleri ameliyat olan insanlar cevap değil iyi olduğunu düşünüyorum. Önemli olan ne karmaşıklık ve hız. Bu algoritma Olası O(n) ve O(n^2) etki alanı içinde her şeyi daha iyi yapar O(n) uzayda çalışır. Kendiniz görmek için, (rasgele bir liste oluşturur ilk öğe açılır ve sonunda böylece döngüsel bir listesini oluşturmak için ekler. küçük bir kriter çalıştırabilirsiniz Kendi manipülasyonlar yapmak) için ücretsiz

from random import random
bigList = [int(1000 * random()) for i in xrange(10**6)]
bigList2 = bigList[:]
bigList2.append(bigList2.pop(0))

# then test how much time will it take to come up with an answer
from datetime import datetime
startTime = datetime.now()
print isCircular(bigList, bigList2)
print datetime.now() - startTime    # please fill free to use timeit, but it will give similar results

Benim makinede 0.3 saniye. Çok uzun değil. Şimdi O(n^2) çözümler ile bu karşılaştırmak için deneyin. Karşılaştırma sırasında, Avustralya (büyük olasılıkla bir yolcu gemisi tarafından) BİZE gelen seyahat edebilirsiniz

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • kev5124

    kev5124

    9 Kasım 2008
  • michaeljacksonVEVO

    michaeljacks

    2 EYLÜL 2009
  • stokelycalm

    stokelycalm

    28 Aralık 2010