web-dev-qa-db-fra.com

Comment calculer efficacement une ligne dans le triangle de Pascal?

Je suis intéressé à trouver la nième rangée du triangle Pascal (pas un élément spécifique mais la rangée entière elle-même). Quel serait le moyen le plus efficace de le faire?

J'ai réfléchi à la manière conventionnelle de construire le triangle en résumant les éléments correspondants dans la rangée au-dessus qui prendrait:

1 + 2 + .. + n = O(n^2)

Une autre façon pourrait être d'utiliser la formule de combinaison d'un élément spécifique:

c(n, k) = n! / (k!(n-k)!)

pour chaque élément de la ligne qui, je suppose, prendrait plus de temps, la méthode précédente dépendait de la méthode utilisée pour calculer la combinaison. Des idées?

31
none
>>> 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]

Ceci utilise l'identité suivante:

C(n,k+1) = C(n,k) * (n-k) / (k+1)

Vous pouvez donc commencer par C(n,0) = 1, puis calculer le reste de la ligne en utilisant cette identité, en multipliant à chaque fois l'élément précédent par (n-k) / (k+1).

88
Omri Barel

Une seule ligne peut être calculée comme suit:

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

Notez que vous pouvez calculer la valeur suivante à partir de la valeur précédente, en multipylant simplement un nombre puis en le divisant par un autre nombre. 

Cela peut être fait en une seule boucle. Échantillon de 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
11
Knoothe

L'approche la plus efficace serait:

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;
}
9
DarkZeros

Un moyen facile de le calculer consiste à remarquer que l'élément de la ligne suivante peut être calculé comme la somme de deux éléments consécutifs de la ligne précédente.

[1, 5, 10, 10, 5, 1]
[1, 6, 15, 20, 15, 6, 1]

Par exemple, 6 = 5 + 1, 15 = 5 + 10, 1 = 1 + 0 et 20 = 10 + 10. Cela donne un algorithme simple pour calculer la ligne suivante à partir de la précédente.

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)
2
Salvador Dali

voici un exemple rapide implémenté dans go-lang qui calcule à partir des bords extérieurs d'une ligne et se dirige vers le milieu en assignant deux valeurs avec un seul calcul ...

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

la sortie de 20 itérations prend environ 1/4 milliseconde à exécuter ...

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]
2
Darryl West

En programmation Scala: je l'aurais fait aussi simple que cela:

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

Je l'appellerais à l'intérieur de ceci: 

for (row <- 0 to 10) {
    for (col <- 0 to row)
        print(Pascal(col, row) + " ")
    println()
}

résultant à:

. 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

Pour expliquer pas à pas:

Étape 1:Nous nous assurons que si notre colonne est la première, nous retournons toujours la figure 1.

Étape 2:Depuis chaque X-ème ligne, il y a X nombre de colonnes. Alors on dit ça; la dernière colonne X est supérieure ou égale à X-ème ligne, puis retourne le chiffre 1.

Étape 3:Sinon, nous obtenons la somme du pascal répété de la colonne juste avant celle en cours et de la ligne juste avant celle en cours; et le Pascal de cette colonne et la ligne juste avant celle en cours.

Bonne chance.

2
MrOnyancha

Voici un autre moyen simple et optimal de concevoir dynamiquement un triangle Pascal à l'aide de VBA. 

`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`
0
Vikas Kulhari

En Ruby, le code suivant affichera la ligne spécifique du triangle de Pascals souhaitée:

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

Où appeler row(0) renvoie [1] et row(5) renvoie [1, 5, 10, 10, 5, 1]

0
GMarx

Le moyen le plus efficace de calculer une ligne dans le triangle de Pascal est la convolution. Nous avons d’abord choisi la deuxième ligne (1,1) comme noyau, puis pour obtenir la ligne suivante, nous avons seulement besoin de convoluer une ligne courante avec le noyau.

Donc, la convolution du noyau avec la deuxième ligne donne la troisième ligne [1 1]*[1 1] = [1 2 1], la convolution avec la troisième ligne donne la quatrième [1 2 1]*[1 1] = [1 3 3 1] et ainsi de suite

C'est une fonction de Julia-lang (très similaire à 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
0
kon kon

J'ai utilisé Ti-84 Plus CE

L'utilisation de -> dans la ligne 6 est le bouton de valeur de magasin

Forloop syntax is 
:For(variable, beginning, end [, increment])
:Commands
:End

nCr syntax is 
:valueA nCr valueB

Les index de liste commencent à 1, c'est pourquoi je le règle sur 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

C’est le moyen le plus rapide auquel je puisse penser pour faire cela dans la programmation (avec un ti 84), mais si vous voulez pouvoir calculer la ligne à l’aide de crayon et de papier, dessinez simplement le triangle, ce qui est pénible!

0
user7960773

Voici une solution O(n) de complexité d'espace en Python:

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