Yinelenen işlev olarak 2 ** n - 1 nasıl yazılır?


49

Ben n alır ve 2 n - 1 döndüren bir işleve ihtiyacım var . Kulağa yeterince basit geliyor, ancak işlev özyinelemeli olmalıdır. Şimdiye kadar sadece 2 n var :

def required_steps(n):
    if n == 0:
        return 1
    return 2 * req_steps(n-1)

Alıştırma şunları söylüyor: "n parametresinin her zaman pozitif bir tam sayı ve 0'dan büyük olduğunu varsayabilirsiniz"


4
Sadece kayıt için, kayma ve çıkarma ile normal bir insan gibi yapmak çok daha verimli olmalıdır. Python tamsayıları rasgele genişliktedir, bu nedenle 1 << ntaşamaz. Bu (1<<n) - 1, birden fazla adımda ayrışmanın bir yolunu icat etme alıştırması gibi görünüyor , belki de her biti bir kerede bazı cevapların gösterdiği gibi ayarlıyor.
Peter Cordes

8
def fn(n): if n == 0: return 1; return (2 << n) - fn(0); # technically recursive
MooseBoys

3
@Voo: Carl değil, ama lütfen içerdiği her şeyi listeleyinC:\MyFolder
Flater

1
@Voo: Bağımlılık olsun ya da olmasın, tamamen özyineleme kavramını öğretmeye odaklanan bir egzersiz için önemsizdir. Öğrencilerin kullanabileceği temel bir dizi sınıf / yöntem yapabilirim. Alıştırma noktasının tamamen dışında bir şeye odaklanıyorsunuz. Dosya sistemi navigasyonunu kullanmak iyi bir örnektir, çünkü öğrenciler genellikle klasörlerin ve dosyaların doğal olarak tekrarlayan doğasını anlarlar (yani, klasörler süresiz olarak iç içe yerleştirilebilir)
Flater

1
@Voo Hayır Tekrarlı bir veri yapısı göstererek özyineleme öğretebileceğini söylüyorum. Bunu neden kavramaya çalıştığına dair hiçbir fikrim yok.
flater

Yanıtlar:


54

2**n -1ayrıca tek bir özyinelemeli işlev haline getirilebilen 1 + 2 + 4 + ... + 2 n-1'dir (ikincisi olmadan 2'nin gücünden 1 çıkarmak).

İpucu : 1 + 2 * (1 + 2 * (...))

Aşağıdaki çözüm, önce ipucunu denemek isteyip istemediğinize bakmayın.


Bu n, sıfırdan büyük olduğu garanti edilirse çalışır (aslında sorun bildiriminde vaat edildiği gibi):

def required_steps(n):
    if n == 1: # changed because we need one less going down
        return 1
    return 1 + 2 * required_steps(n-1)

Daha sağlam bir sürüm sıfır ve negatif değerleri de işleyebilir:

def required_steps(n):
    if n < 0:
        raise ValueError("n must be non-negative")
    if n == 0:
        return 0
    return 1 + 2 * required_steps(n-1)

(Tamsayı olmayanlar için bir kontrol ekleme alıştırması olarak bırakılmıştır.)


4
ama required_steps(0)şimdi sonsuz özyinelemeye neden oluyor
Teşekkürler

7
2^0 - 1== 0. ifBu dava için bir tane daha ekleyin .
h4z3

9
@ user633183 Evet, toplam fonksiyonun ne olduğunu biliyorum. Yapıyor musun? Çünkü hiçbir zaman tam bir işlev olmayacak. Diğer cevaplar toplam fonksiyonlar değildir. Ve evet, onları tam işlevler haline getirmek için daha fazla kod gerekli olacaktır. - Dediğim gibi, alanımız yok. Alanımızın ne olduğunu varsaymalıyız? Sadece olsa bile int, n <0 olduğunda ne yapacağımızı bilmiyoruz. Hesaplamak? Bir hata mı attı? Dönüş 0? Bu durumda, sadece kısmi bir işlev yapabiliriz (sonucun ne olduğunu bildiğimiz şeyler için tanımlayın).
h4z3

4
OP'ın kodunda temel durumdur 0ve kullanımları n - 1subproblem için. Doğal Sayılar alanı iyi bir uyum gibi görünüyor.
Teşekkürler

4
Çok teşekkür ederim! Benim düşünceme göre, bu benim özel sorunum için en iyi çözüm. N için olası değerleri belirtmedim, gerçekten üzgünüm! Bunun çok önemli olduğunu biliyorum ... egzersiz şöyle diyor: "n parametresinin her zaman pozitif bir tamsayı ve 0'dan büyük olduğunu
varsayabilirsiniz

37

Özyinelemeli bir yaklaşımla bir sorunu çözmek için, belirli bir girdiyle işlevi farklı bir girdiyle aynı işlev açısından nasıl tanımlayabileceğinizi öğrenmeniz gerekir. Bu durumda, çünkü f(n) = 2 * f(n - 1) + 1şunları yapabilirsiniz:

def required_steps(n):
    return n and 2 * required_steps(n - 1) + 1

Böylece:

for i in range(5):
    print(required_steps(i))

çıktılar:

0
1
3
7
15

9

Gerçekten özyinelemeli parçayı başka bir işleve çıkarabilirsiniz

def f(n):
    return required_steps(n) - 1

Veya bir bayrak ayarlayabilir ve ne zaman çıkarılacağını belirleyebilirsiniz

def required_steps(n, sub=True):
    if n == 0: return 1
    return 2 * required_steps(n-1, False) - sub

>>> print(required_steps(10))
1023

0

Sonuç için ek bir parametre kullanarak, r-

def required_steps (n = 0, r = 1):
  if n == 0:
    return r - 1
  else:
    return required_steps(n - 1, r * 2)

for x in range(6):
  print(f"f({x}) = {required_steps(x)}")

# f(0) = 0
# f(1) = 1
# f(2) = 3
# f(3) = 7
# f(4) = 15
# f(5) = 31

Ayrıca bitsel sola kaydırma kullanarak da yazabilirsiniz, <<-

def required_steps (n = 0, r = 1):
  if n == 0:
    return r - 1
  else:
    return required_steps(n - 1, r << 1)

Çıktı aynı


2
Basit bir çarpma egzersizi için bitsel işlemlere gerek yoktur .. hiç okunamaz. Ayrıca, elseher iki işlevde de maddeye gerek yok
rafaelc

Tek fark değişiyor r * 2için r << 1ve o "hiç okunamayan" dir? 😂
Teşekkürler

2
2. bir parametreyi icat etmek, bunu sadece sol nzamanları değiştiren ve sonra 1 çıkaran bir döngüye dönüştürür. Her şey verimsiz bir egzersiz olmasına rağmen, gerekli olandan daha da zarif görünmektedir (1<<n) - 1.
Peter Cordes

1
@PeterCordes: bir akümülatör parametresine durumunu Hareketli olan bir kuyruk-yinelemeli çağrı içine yinelemeli çağrı transforme standart bir yol. Şimdi maalesef Python Uygun Kuyruk Aramalar, hatta Uygun Kuyruk Özyinelemeyi desteklemez, ama bu başka dillerde uygulamak, böylece öğrenmek için yararlı bir teknik değildir anlamına gelmez do Uygun Kuyruk Aramalar uygulamak veya en azından Uygun Kuyruk Özyineleme.
Jörg W Mittag

1
@ JörgWMittag Evet, ancak bu durumda bir döngü olarak daha doğal olacağı gerçeğini gizlemek zor . Belki de sadece montaj dili ve performansı için çok fazla zaman harcıyorum, ancak bir döngü yazabildiğinizde kuyruk özyineleme kullanarak bir "döngü" yazmak zorunlu bir dilde anlamsız görünüyor. Ya da belki de bu cevap hakkında beni rahatsız eden şey, sadece nasıl ayrışacağının seçimidir: her seferinde bir vardiyaya ve daha sonra temel taban olarak son bir çıkarma. Muhtemelen her ikisinin bir kombinasyonu.
Peter Cordes

0

İlk aşamada, yani daha sonra orijinal n değerini ve hatırlamak için bir yer tutucu var n == N, dönüş2^n-1

n = 10
# constant to hold initial value of n
N = n
def required_steps(n, N):
    if n == 0:
        return 1
    elif n == N:
        return 2 * required_steps(n-1, N) - 1
    return 2 * required_steps(n-1, N)

required_steps(n, N)

-1

"-1" ofsetini almanın bir yolu, varsayılan değerde bir argüman kullanarak ilk işlev çağrısından geri dönüşte uygulamak ve sonra özyinelemeli çağrılar sırasında ofset bağımsız değişkenini açıkça sıfıra ayarlamaktır.

def required_steps(n, offset = -1):
    if n == 0:
        return 1
    return offset + 2 * required_steps(n-1,0)

-1

Daha önce verilen tüm müthiş cevapların üstünde, aşağıda iç işlevlerle uygulanmasını gösterecektir.

def outer(n):
    k=n
    def p(n):
        if n==1:
            return 2
        if n==k:
            return 2*p(n-1)-1
        return 2*p(n-1)
    return p(n)

n=5
print(outer(n))

Temel olarak, k'ye küresel bir n değeri atar ve uygun karşılaştırmalar ile tekrar eder.

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.