Tento návod vás provede procesem, jak v jazyce Python vygenerovat a zobrazit Pascalův trojúhelník pro zadaný počet řádků.
Nejprve si objasníme, jak se Pascalův trojúhelník konstruuje. Poté se podíváme na implementaci funkce v Pythonu a následně prozkoumáme možnosti její optimalizace.
🚀 Začněme!
Co je Pascalův trojúhelník a jak se tvoří?
Zobrazení Pascalova trojúhelníku pro konkrétní počet řádků je oblíbenou úlohou při programovacích pohovorech.
V Pascalově trojúhelníku s počtem řádků n obsahuje řádek číslo i právě i prvků.
První řádek tedy obsahuje jediný prvek, a to číslo 1. Každý prvek v dalších řádcích se získá jako součet dvou čísel, která se nacházejí přímo nad ním.
Následující obrázek ilustruje, jak se vytváří Pascalův trojúhelník s pěti řádky.
Pascalův trojúhelník pro numRows = 5 (zdroj: autor)
Všimněte si, že prázdná místa nad čísly lze pro výpočet považovat za nuly.
📝Pro procvičení si zkuste sami sestrojit Pascalův trojúhelník pro n = 6 a n = 7 podle výše uvedeného postupu.
Nyní se podívejme na kód. Úryvky kódu můžete zkoušet přímo ve vašem prohlížeči s pomocí Wdzwdz Python IDE.
Python funkce pro výpis Pascalova trojúhelníku
V této části vytvoříme funkci v Pythonu, která zobrazí Pascalův trojúhelník pro libovolný počet řádků.
Zamyslíme se nad dvěma klíčovými body:
- Jak matematicky vyjádřit prvky v Pascalově trojúhelníku?
- Jak efektivně zobrazit Pascalův trojúhelník s ohledem na správné mezery a formátování?
Podívejme se na ně detailněji.
#1. Jaký je matematický vzorec pro každý prvek v Pascalově trojúhelníku?
Ukazuje se, že hodnoty v Pascalově trojúhelníku lze vypočítat pomocí vzorce pro kombinace, známého jako nCr. Jak si možná vzpomínáte ze středoškolské matematiky, nCr vyjadřuje, kolika způsoby můžeme vybrat r prvků z celkového počtu n prvků.
Vzorec pro nCr je následující:
Vzorec nCr (zdroj: autor)
Nyní si ukážeme, jak pomocí vzorce nCr vyjádříme prvky v Pascalově trojúhelníku.
Pascalův trojúhelník s využitím nCr (zdroj: autor)
Tímto způsobem jsme našli matematické vyjádření prvků v matici.
#2. Jak upravit mezery při vypisování struktury?
V Pascalově trojúhelníku s počtem řádků `numRows` má řádek číslo 1 jeden prvek, řádek číslo 2 dva prvky, a tak dále. Aby se struktura vypsala jako trojúhelník, potřebujeme `numRows – i` mezer na začátku řádku číslo `i`. K tomu můžeme použít funkci `range` v Pythonu spolu s cyklem `for`.
Protože funkce `range` ve výchozím nastavení vylučuje koncový bod, musíme přidat + 1, abychom dosáhli požadovaného počtu úvodních mezer.
Nyní, když už umíme vyjádřit prvky a upravovat mezery při výpisu Pascalova trojúhelníku, můžeme definovat funkci `pascal_tri`.
Analýza definice funkce
Jaké vlastnosti by měla mít funkce `pascal_tri`?
- Funkce `pascal_tri` by měla přijímat jako parametr počet řádků (`numRows`).
- Měla by zobrazit Pascalův trojúhelník s počtem řádků `numRows`.
Pro výpočet faktoriálu použijeme funkci faktoriálu z vestavěného matematického modulu v Pythonu.
▶️ Spusťte následující kód pro import funkce faktoriálu a její využití.
from math import factorial
Následující úryvek kódu obsahuje definici funkce.
def pascal_tri(numRows): '''Zobrazí Pascalův trojúhelník s daným počtem řádků.''' for i in range(numRows): # Cyklus pro získání mezer na začátku řádku for j in range(numRows-i+1): print(end=" ") # Cyklus pro získání prvků řádku i for j in range(i+1): # nCr = n!/((n-r)!*r!) print(factorial(i)//(factorial(j)*factorial(i-j)), end=" ") # Každý řádek se zobrazí na novém řádku print("\n")
Funkce funguje takto:
- Funkce `pascal_tri` má jeden povinný parametr `numRows`, který udává počet řádků.
- Celkem bude vytištěno `numRows` řádků. Pro každý řádek `i` přidáme `numRows – i` úvodních mezer před první prvek na řádku.
- K výpočtu jednotlivých prvků používáme vzorec nCr. Pro řádek `i` jsou prvky `iCj`, kde `j = {0,1,2,..,i}`.
- Všimněte si, že používáme operátor `//`, který provádí celočíselné dělení, protože chceme, aby byly všechny prvky celá čísla.
- Po výpočtu všech prvků v řádku se přejde na nový řádek.
🔗 Jelikož jsme přidali dokumentační řetězec, můžete použít vestavěnou funkci `help()` v Pythonu, nebo atribut `__doc__` pro přístup k dokumentačnímu řetězci funkce. Následující úryvek ukazuje, jak se to dělá.
help(pascal_tri) # Výstup Help on function pascal_tri in module __main__: pascal_tri(numRows) Zobrazí Pascalův trojúhelník s daným počtem řádků. pascal_tri.__doc__ # Výstup Zobrazí Pascalův trojúhelník s daným počtem řádků.
Nyní zkusme funkci zavolat s počtem řádků jako argumentem.
pascal_tri(3) # Výstup 1 1 1 1 2 1
První 3 řádky Pascalova trojúhelníku se zobrazí podle očekávání.
Výpis Pascalova trojúhelníku s využitím rekurze
V předchozí části jsme definovali matematické vyjádření každého prvku v Pascalově trojúhelníku. Nevyužili jsme však vztahu mezi prvky ve dvou po sobě jdoucích řádcích.
Ve skutečnosti se předchozí řádek využívá k výpočtu prvků v následujícím řádku. Nemůžeme toho využít k rekurzivní implementaci funkce `pascal_tri`?
Ano, můžeme!
Při rekurzivní implementaci funkce opakovaně volá sama sebe, dokud není dosaženo základního případu. Při vytváření Pascalova trojúhelníku začínáme prvním řádkem s jedním prvkem 1 a poté vytváříme další řádky.
Volání funkce `pascal_tri(numRows)` tedy volá `pascal_tri(numRows-1)` a tak dále, dokud není dosaženo základního případu `pascal_tri(1)`.
Vezměme si příklad, kdy potřebujete zobrazit první 3 řádky Pascalova trojúhelníku. Následující obrázek ilustruje, jak se rekurzivní volání ukládají do zásobníku a jak se z volání rekurzivní funkce vrací řádky Pascalova trojúhelníku.
Zásobník volání během rekurzivních volání (zdroj: autor)
▶️ Spusťte následující úryvek kódu pro rekurzivní generování řádků Pascalova trojúhelníku.
def pascal_tri(numRows): '''Zobrazí Pascalův trojúhelník s daným počtem řádků.''' if numRows == 1: return [[1]] # dosaženo základního případu! else: res_arr = pascal_tri(numRows-1) # rekurzivní volání pascal_tri # Použije předchozí řádek k výpočtu aktuálního řádku cur_row = [1] # každý řádek začíná 1 prev_row = res_arr[-1] for i in range(len(prev_row)-1): # součet 2 prvků přímo nad cur_row.append(prev_row[i] + prev_row[i+1]) cur_row += [1] # každý řádek končí 1 res_arr.append(cur_row) return res_arr
Několik poznámek:
- Jako datovou strukturu jsme použili vnořený seznam, kde každý řádek v Pascalově trojúhelníku je seznam sám o sobě: `[[řádek 1], [řádek 2],…,[řádek n]]`.
- Volání funkce `pascal_tri(numRows)` vyvolává řadu rekurzivních volání s argumenty `numRows – 1`, `numRows – 2` až po 1. Tato volání jsou vkládána do zásobníku.
- Když `numRows == 1`, dosáhli jsme základního případu a funkce vrací `[[1]]`.
- Nyní se vrácený seznam využívá u funkcí v zásobníku volání k výpočtu dalšího řádku.
- Pokud je aktuální řádek `cur_row`, pak `cur_row[i] = předchozí_řádek[i] + předchozí_řádek[i+1]` – součet 2 prvků přímo nad aktuálním indexem.
Jelikož je vrácené pole vnořený seznam (seznam seznamů), musíme upravit mezery a zobrazit prvky, jak je to znázorněno v následujícím úryvku kódu.
tri_array = pascal_tri(5) for i,row in enumerate(tri_array): for j in range(len(tri_array) - i + 1): print(end=" ") # mezery na začátku for j in row: print(j, end=" ") # zobrazení prvků print("\n") # nový řádek
Výstup je správný, jak můžeme vidět níže!
# Výstup 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
Python funkce pro zobrazení Pascalova trojúhelníku pro numRows ≤ 5
Obě metody, které jsme se naučili, fungují pro výpis Pascalova trojúhelníku pro libovolný počet řádků `numRows`.
Existují ale situace, kdy potřebujeme zobrazit Pascalův trojúhelník s menším počtem řádků. Pokud je počet řádků, které potřebujeme zobrazit maximálně 5, můžeme použít přímou metodu.
Podívejte se na obrázek níže. Všimněte si, jak se mocniny čísla 11 shodují s prvky v Pascalově trojúhelníku. Důležité je, že to funguje pouze do 4. mocniny čísla 11. To znamená, že 11 umocněné na {0, 1, 2, 3, 4} dá prvky v řádcích 1 až 5 Pascalova trojúhelníku.
Pojďme přepsat definici funkce tak, jak je uvedeno níže:
def pascal_tri(numRows): '''Zobrazí Pascalův trojúhelník s daným počtem řádků.''' for i in range(numRows): print(' '*(numRows-i), end='') # výpočet mocniny 11 print(' '.join(str(11**i)))
Funkce `pascal_tri` pracuje takto:
- Stejně jako v předchozích příkladech upravíme mezery.
- Pak použijeme operátor umocňování (**) v Pythonu k výpočtu mocnin čísla 11.
- Protože mocniny 11 jsou ve výchozím nastavení celá čísla, převedeme je na řetězec pomocí `str()`. Nyní máme mocniny 11 jako řetězce.
- Řetězce v Pythonu jsou iterovatelné, takže jimi můžeme procházet a přistupovat k jednotlivým znakům.
- Dále můžeme použít metodu `join()` se syntaxí: `
.join( )` ke spojení prvků v ` ` s použitím ` ` jako oddělovače. - Zde potřebujeme jednu mezeru mezi znaky, takže `
` bude ‚ ‚, a ` ` je řetězec: mocnina 11.
Ověřme, že funkce funguje správně.
pascal_tri(5) # Výstup 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1
Jako další příklad zavoláme funkci `pascal_tri` s argumentem 4.
pascal_tri(4) # Výstup 1 1 1 1 2 1 1 3 3 1
Doufám, že nyní rozumíte tomu, jak snadno zobrazit Pascalův trojúhelník pro `numRows` v rozsahu 1 až 5.
Závěr
Co jsme se naučili:
- Jak sestrojit Pascalův trojúhelník pro zadaný počet řádků. Každé číslo v daném řádku je součtem dvou čísel, která se nacházejí přímo nad ním.
- Jak vytvořit funkci v Pythonu pomocí vzorce nCr = n!/(n-r)!.r! pro výpočet prvků Pascalova trojúhelníku.
- Pak jsme se naučili rekurzivní implementaci funkce.
- A nakonec jsme se naučili nejefektivnější metodu pro konstrukci Pascalova trojúhelníku pro počet řádků do 5 – pomocí mocnin čísla 11.
Pokud chcete vylepšit své dovednosti v Pythonu, podívejte se na násobení matic, ověření, zda je číslo prvočíslo a řešení problémů s řetězcovými operacemi. Přeji vám šťastné kódování!