## Exercice 1

liste = [2, 0, 5, [7, 6, 17], 4]
liste[1] = 8  # on remplace le 0 par 8
liste[3][2] = 22  # on remplace le 17 par 22 (liste[3] est [7, 6, 17])
print(liste)


## Exercice 2

# 1)

carres = []
for i in range(1, 1001):
    carres.append(i**2)

# 2)

carres = []
i = 1
while i <= 1000:
    carres.append(i**2)
    i += 1


## Exercice 3

# En itérant sur un range :

def produit(L):
    p = 1
    for i in range(len(L)):
        p = p * L[i]
    return p

# En itérant directement sur la liste :

def produit(L):
    p = 1
    for x in L:
        p = p * x
    return p


## Exercice 4

# En itérant sur un range :

def pairs_et_impairs(L):
    pairs = []
    impairs = []
    for i in range(len(L)):
        if L[i] % 2 == 0:
            pairs.append(L[i])
        else:
            impairs.append(L[i])
    return pairs, impairs

# En itérant directement sur la liste :

def pairs_et_impairs(L):
    pairs = []
    impairs = []
    for x in L:
        if x % 2 == 0:
            pairs.append(x)
        else:
            impairs.append(x)
    return pairs, impairs

# Avec des listes par compréhension :

def pairs_et_impairs(L):
    return [x for x in L if x % 2 == 0], [x for x in L if x % 2 == 1]


## Exercice 5

# 1) Il suffit de remplacer > par <.

# 2) La fonction effectue toujours n-1 comparaisons si on itère sur un range
# (n si on itère sur la liste).
# Si le plus grand élément est en première position, seule l'affectation
# m = L[0] est effectuée.
# Si la liste est strictement croissante, la fonction effectue n affectations
# car m est modifié à chaque itération.


## Exercice 6

def meilleur_eleve(notes):
    i_meilleur = 0 # indice du meilleur élève
    for i in range(1, len(notes)):
        if notes[i][1] > notes[i_meilleur][1]:
            i_meilleur = i
    return notes[i_meilleur][0]
    

## Exercice 7

# Il y a plusieurs méthodes :

L1 = [7*k for k in range(1, 15)]  # 100 // 7 = 14
print(L1)

L2 = [k for k in range(1, 101) if k % 7 == 0]
print(L2)


## Exercice 8

# 1)

def indice(x, L):
    for i in range(len(L)):  # On est obligé d'itérer sur un range ici.
        if L[i] == x:
            return i
    return False

# 2)

def compter(x, L):
    nb = 0
    for y in L:
        if y == x:
            nb = nb + 1
    return nb

# 3)

def concatener(L1, L2):
    L = []
    for x in L1:
        L.append(x)
    for x in L2:
        L.append(x)
    return L

# 4)

def remplacer(L, x1, x2):
    LL = []
    for x in L:
        if x == x1:
            LL.append(x2)
        else:
            LL.append(x)
    return LL

# 5)

def decouper(L, i, j):
    LL = []
    for k in range(i, j+1):
        LL.append(L[k])
    return LL

# 6)

def echanger(L, i, j):   # cette fonction ne modifie pas L, comme demandé
    LL = []
    for k in range(len(L)):
        if k == i:
            LL.append(L[j])
        elif k == j:
            LL.append(L[i])
        else:
            LL.append(L[k])
    return LL

# 7)

def enlever(x, L):
    LL = []
    for y in L:
        if y != x:
            LL.append(y)
    return LL


## Exercice 9

# Noter qu'on ne peut renvoyer True qu'à la fin, après avoir entièrement parcouru
# la liste.

def est_triee(L):
    for i in range(1, len(L)):
        if L[i] < L[i-1]:
            return False
    return True


## Exercice 10

def supprimer_doublons(L):
    LL = []
    for x in L:
        if x not in LL:
            LL.append(x)
    return LL


## Exercice 11

# 1)

def chiffres(n):
    L = []
    while n > 0:
        L.append(n % 10)
        n = n // 10
    return L[::-1]  # Il faut remettre la liste dans le bon ordre.

# 2)

for n in range(10**5):
    s = 0
    for x in chiffres(n):
        s += x
    if n == s**3:
        print(n)

# ou :

for n in range(10**5):
    if n == sum(chiffres(n))**3:
        print(n)

# Pour démontrer qu'il n'y a pas de solution supérieure à 10**5 il faudrait faire un
# raisonnement mathématique.

# 3)

for n in range(10**5):
    s = 0
    for x in chiffres(n):
        s += x**3
    if n == s:
        print(n)

# ou :

for n in range(10**5):
    if sum(x**3 for x in chiffres(n)) == n:
        print(n)


## Exercice 12

# Une solution naïve en O(n^2) :

def nombre_manquant(L):
    for i in range(len(L)+1):
        if i not in L:   # ce test est en O(n)
            return i


## Exercice 13

def decomposition(n):
    dec = []
    k = 2
    while n != 1:
        val = 0
        while n % k == 0:
            val += 1
            n = n // k
        if val != 0:
            dec.append([k, val])
        k += 1
    return dec
