2 ** n-1を再帰関数として記述する方法は?


49

nを受け取り、2 n -1を返す関数が必要です。簡単に聞こえますが、関数は再帰的でなければなりません。これまでのところ、私は2 nしかありません:

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

演習では、「パラメータnは常に正の整数であり、0より大きいと想定できます。


4
参考までに、シフトと減算を行う通常の人と同じように行う方がはるかに効率的です。Python整数は任意の幅であるため1 << n、オーバーフローできません。これは、(1<<n) - 1複数のステップに分解する方法を発明するための練習のようです。おそらく、いくつかの回答が示すように、各ビットを一度に1つずつ設定します。
Peter Cordes

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

3
@Voo:カールではありませんが、含まれているすべてをリストしてくださいC:\MyFolder
Flater

1
@Voo:再帰の概念を教えることだけに焦点を当てた演習では、依存関係は関係ありません。生徒が使用できる基本的な模擬クラス/メソッドのセットを作成できました。あなたは、演習のポイントから完全に外れていることに焦点を当てています。ファイルシステムナビゲーションの使用は良い例です。学生は一般的に、フォルダーとファイルの本質的に再発する性質を理解しているためです(つまり、フォルダーは無限に互いに入れ子にできる)
Flater

1
@Vooいいえ再帰的なデータ構造を表示することで、再帰を教えることができると言っています。なぜあなたはこれを理解するのに苦労するのか分かりません。
Flater

回答:


54

2**n -11 + 2 + 4 + ... + 2 n-1個(2の累乗から1を減算する第1せず)は、単一の再帰関数に作製することができます。

ヒント:1 + 2 *(1 + 2 *(...))

以下の解決策、最初にヒントを試したいかどうかを調べないでください。


これnは、ゼロより大きいことが保証されている場合に機能します(問題のステートメントで実際に約束されていたとおり)。

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

より堅牢なバージョンでは、ゼロと負の値も処理されます。

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)

(非整数のチェックの追加は、演習として残します。)


4
しかし、required_steps(0)今では無限再帰が発生します
ありがとう

7
2^0 - 1==0 if。その場合は、さらに追加します。
h4z3

9
@ user633183はい、私は合計機能が何であるかを知っています。あなたは?完全な機能にはならないからです。他の答えも総機能ではありません。そして、はい、それらを完全な機能にするために、より多くのコードが必要になるでしょう。-先ほど言ったように、ドメインはありません。私たちのドメインは何であると想定すべきですか?ただintであっても、n <0の場合はどうすればよいかわかりません。計算?エラーを投げますか?0を返しますか?この場合、部分的な機能しか実行できません(結果が何であるかを知るためにそれを定義します)。
h4z3

4
OPのコードのベースケースはある0と用途n - 1サブ問題のために。Natural Numbersのドメインは適しているようです。
ありがとう

4
どうもありがとうございます!私の控えめな意見では、これは私の特定の問題に対する最良の解決策です。私はnの可能な値を述べていません、本当に申し訳ありません!私はちょっと重要である知っている...運動状態を:「あなたは、パラメータnは常に正の整数であり、0よりも大きいと仮定することができます」
Kajice

37

再帰的アプローチの問題を解決するには、異なる入力を持つ同じ関数の観点から、特定の入力を持つ関数を定義する方法を見つける必要があります。この場合、なのでf(n) = 2 * f(n - 1) + 1、次のことができます。

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

そのため:

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

出力:

0
1
3
7
15

9

本当に再帰的な部分を別の関数に抽出できます

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

または、フラグを設定して、いつ減算するかを定義できます

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

結果に追加のパラメーターを使用する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

ビットごとの左シフトを使用してそれを書くこともできます<<-

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

出力は同じです


2
単純な乗算の演習ではビット単位の演算を行う必要はありません。まったく読めません。また、elseどちらの関数にも句は必要ありません
rafaelc '14年

唯一の違いはへの変更r * 2r << 1あり、それは「まったく読めない」ですか?😂
ありがとう

2
2番目のパラメーターを作成すると、これが左にシフトしてnから1を引くループに変わるだけです。全体が非効率対の演習ですが、必要以上にエレガントではないようです(1<<n) - 1
Peter Cordes

1
@PeterCordes:状態をアキュムレータパラメータに移動することは再帰呼び出しを末尾再帰呼び出しに変換する標準的な方法です。さて、残念ながら、Pythonは適切な末尾再帰ではなく、さらに適切なテール再帰をサポートしていませんが、それは、これはあなたが他の言語でそれを適用することができるように学ぶための有用な技術ではないことを意味するわけではない適切な末尾再帰を実装しますまたは少なくとも適切なテール再帰。
イェルクWミッターク

1
@JörgWMittagはい、しかし、この場合、ループとしてより自然であるという事実を偽ることは困難です。たぶん、私がアセンブリ言語とパフォーマンスに多くの時間を費やしているだけなのかもしれませんが、テール再帰を使用して「ループ」を書くことは、ループを書くことができるだけの命令型言語では無意味に思えます。あるいは、この答えについて私を悩ませているのは、分解方法の選択だけです。一度に1つずつシフトし、最後にベースケースとして減算します。おそらく両方の組み合わせです。
Peter Cordes

0

nの元の値を記憶するプレースホルダーを用意し、最初のステップ、つまりn == 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」のオフセットを取得する1つの方法は、デフォルト値の引数を使用して最初の関数呼び出しからの戻り値に適用し、再帰呼び出し中にオフセット引数を明示的にゼロに設定することです。

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

-1

以前に与えられたすべての素晴らしい答えの上に、内部関数を使用したその実装を以下に示します。

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))

基本的に、それはnのグローバル値をkに割り当て、適切な比較でそれを繰り返します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.