Pascal三角形のn番目の行(特定の要素ではなく、行全体)を見つけることに興味があります。それを行う最も効率的な方法は何ですか?
私は、上の行の対応する要素を合計して三角形を構築する従来の方法について考えました:
1 + 2 + .. + n = O(n^2)
別の方法は、特定の要素の組み合わせ式を使用することです。
c(n, k) = n! / (k!(n-k)!)
行の各要素については、組み合わせの計算方法によっては前者の方法よりも時間がかかると思います。何か案は?
_>>> def Pascal(n):
... line = [1]
... for k in range(n):
... line.append(line[k] * (n-k) / (k+1))
... return line
...
>>> Pascal(9)
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1]
_
これは、次のIDを使用します。
_C(n,k+1) = C(n,k) * (n-k) / (k+1)
_
そのため、C(n,0) = 1
から始めて、この識別情報を使用して残りの行を計算し、そのたびに前の要素に_(n-k) / (k+1)
_を掛けます。
単一の行は次のように計算できます。
First compute 1. -> N choose 0
Then N/1 -> N choose 1
Then N*(N-1)/1*2 -> N choose 2
Then N*(N-1)*(N-2)/1*2*3 -> N choose 3
.....
単一の数値で乗算し、別の数値で除算するだけで、前の値から次の値を計算できることに注意してください。
これは単一のループで実行できます。サンプルpython。
def comb_row(n):
r = 0
num = n
cur = 1
yield cur
while r <= n:
r += 1
cur = (cur* num)/r
yield cur
num -= 1
最も効率的なアプローチは次のとおりです。
std::vector<int> Pascal_row(int n){
std::vector<int> row(n+1);
row[0] = 1; //First element is always 1
for(int i=1; i<n/2+1; i++){ //Progress up, until reaching the middle value
row[i] = row[i-1] * (n-i+1)/i;
}
for(int i=n/2+1; i<=n; i++){ //Copy the inverse of the first part
row[i] = row[n-i];
}
return row;
}
簡単な計算方法は、次の行の要素が前の行の2つの連続した要素の合計として計算できることに注意することです。
[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]
例えば 6 = 5 + 1
、15 = 5 + 10
、1 = 1 + 0
および20 = 10 + 10
。これにより、前の行から次の行を計算する簡単なアルゴリズムが得られます。
def Pascal(n):
row = [1]
for x in xrange(n):
row = [l + r for l, r in Zip(row + [0], [0] + row)]
# print row
return row
print Pascal(10)
go-langで実装された高速な例は、行の外側の端から計算し、1つの計算で2つの値を中央に割り当てる方法です...
package main
import "fmt"
func calcRow(n int) []int {
// row always has n + 1 elements
row := make( []int, n + 1, n + 1 )
// set the edges
row[0], row[n] = 1, 1
// calculate values for the next n-1 columns
for i := 0; i < int(n / 2) ; i++ {
x := row[ i ] * (n - i) / (i + 1)
row[ i + 1 ], row[ n - 1 - i ] = x, x
}
return row
}
func main() {
for n := 0; n < 20; n++ {
fmt.Printf("n = %d, row = %v\n", n, calcRow( n ))
}
}
20回の反復の出力は、実行に約1/4ミリ秒かかります...
n = 0, row = [1]
n = 1, row = [1 1]
n = 2, row = [1 2 1]
n = 3, row = [1 3 3 1]
n = 4, row = [1 4 6 4 1]
n = 5, row = [1 5 10 10 5 1]
n = 6, row = [1 6 15 20 15 6 1]
n = 7, row = [1 7 21 35 35 21 7 1]
n = 8, row = [1 8 28 56 70 56 28 8 1]
n = 9, row = [1 9 36 84 126 126 84 36 9 1]
n = 10, row = [1 10 45 120 210 252 210 120 45 10 1]
n = 11, row = [1 11 55 165 330 462 462 330 165 55 11 1]
n = 12, row = [1 12 66 220 495 792 924 792 495 220 66 12 1]
n = 13, row = [1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1]
n = 14, row = [1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1]
n = 15, row = [1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1]
n = 16, row = [1 16 120 560 1820 4368 8008 11440 12870 11440 8008 4368 1820 560 120 16 1]
n = 17, row = [1 17 136 680 2380 6188 12376 19448 24310 24310 19448 12376 6188 2380 680 136 17 1]
n = 18, row = [1 18 153 816 3060 8568 18564 31824 43758 48620 43758 31824 18564 8568 3060 816 153 18 1]
n = 19, row = [1 19 171 969 3876 11628 27132 50388 75582 92378 92378 75582 50388 27132 11628 3876 969 171 19 1]
In Scala Programming:私はこれと同じくらい簡単にしたでしょう:
def Pascal(c: Int, r: Int): Int = c match {
case 0 => 1
case `c` if c >= r => 1
case _ => Pascal(c-1, r-1)+Pascal(c, r-1)
}
私はこれを内部で呼び出します:
for (row <- 0 to 10) {
for (col <- 0 to row)
print(Pascal(col, row) + " ")
println()
}
結果:
. 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1 1 10 45 120 210 252 210 120 45 10 1
ステップごとに説明するには:
ステップ1:列が最初の列である場合、必ず図1が返されるようにします。
ステップ2:各X番目の行にはX個の列があります。だから私たちはそう言う。最後の列XがX番目の行以上である場合、図1を返します。
ステップ3:それ以外の場合は、現在の行の直前の列と行の直前の繰り返しパスカルの合計を取得します現在のものの前。その列のパスカルと現在の行の直前の行。
がんばろう。
Rソリューションのシェーンの 優秀な仕事 に基づいて作りましょう。 (ありがとう、シェーン!。三角形を生成するための彼のコード:
pascalTriangle <- function(h) {
lapply(0:h, function(i) choose(i, 0:i))
}
これにより、三角形をリストとして保存できます。その後、必要な行にインデックスを付けることができます。ただし、インデックス作成時に1を追加してください!たとえば、下の行を取得します。
pt_with_24_rows <- pascalTriangle(24)
row_24 <- pt_with_24_rows[25] # add one
row_24[[1]] # prints the row
だから、最後に、私は ガルトン委員会 問題を持っていると信じています。私は、中央にクラスター化されたBeanの割合を見つけるというarbitrary意的な課題があります。たとえば、ビン10から15(25個のうち)です。
sum(row_24[[1]][10:15])/sum(row_24[[1]])
0.7704771であることがわかります。いいね!
VBAを使用してPascal三角形を動的に設計する別の最良かつ簡単な方法を次に示します。
`1
11
121
1331
14641`
`Sub Pascal()
Dim book As Excel.Workbook
Dim sht As Worksheet
Set book = ThisWorkbook
Set sht = book.Worksheets("sheet1")
a = InputBox("Enter the Number", "Fill")
For i = 1 To a
For k = 1 To i
If i >= 2 And k >= 2 Then
sht.Cells(i, k).Value = sht.Cells(i - 1, k - 1) + sht.Cell(i- 1, k)
Else
sht.Cells(i, k).Value = 1
End If
Next k
Next i
End Sub`
Rubyでは、次のコードにより、Pascals Triangleの特定の行が印刷されます。
_def row(n)
Pascal = [1]
if n < 1
p Pascal
return Pascal
else
n.times do |num|
nextNum = ((n - num)/(num.to_f + 1)) * Pascal[num]
Pascal << nextNum.to_i
end
end
p Pascal
end
_
row(0)
を呼び出すと_[1]
_が返され、row(5)
を呼び出すと_[1, 5, 10, 10, 5, 1]
_が返されます
パスカルの三角形の行を計算する最も効率的な方法は、畳み込みを使用することです。最初に2番目の行(1,1)をカーネルとして選択し、次に次の行を取得するために、現在の行をカーネルと畳み込むだけで済みます。
そのため、カーネルと2行目の畳み込みは3行目[1 1]*[1 1] = [1 2 1]
、3行目の畳み込みは4番目の[1 2 1]*[1 1] = [1 3 3 1]
等々
これはJulia-langの関数です(matlabに非常に似ています):
function binomRow(n::Int64)
baseVector = [1] #the first row is equal to 1.
kernel = [1,1] #This is the second row and a kernel.
row = zeros(n)
for i = 1 : n
row = baseVector
baseVector = conv(baseVector, kernel) #convoltion with kernel
end
return row::Array{Int64,1}
end
Ti-84 Plus CEを使用しました
6行目の–>の使用は、値の保存ボタンです。
Forloop syntax is
:For(variable, beginning, end [, increment])
:Commands
:End
nCr syntax is
:valueA nCr valueB
リストインデックスは1から始まるため、R + 1に設定します。
N= row
R= column
PROGRAM: Pascal
:ClrHome
:ClrList L1
:Disp "ROW
:Input N
:For(R,0,N,1)
:N nCr R–>L1(R+1)
:End
:Disp L1
これは、プログラミングでこれを行うために考えることができる最速の方法です(TI 84を使用)が、ペンと紙を使用して行を計算できるようにする場合は、三角形を描画するだけで、要因の実行が苦痛です!
PythonのO(n) space-complexityソリューション:
def generate_Pascal_nth_row(n):
result=[1]*n
for i in range(n):
previous_res = result.copy()
for j in range(1,i):
result[j] = previous_res[j-1] + previous_res[j]
return result
print(generate_Pascal_nth_row(6))