Some operations are cheap most of the time and only rarely expensive. Applying the worst case to every single operation gives an overly pessimistic estimate. Amortized analysis takes the total cost of a sequence of operations and divides it by their number.

Cost of each append: most cost 1, a few cost 2, 3, 5, 9; the average is about 2
Cost of each append: most cost 1, a few cost 2, 3, 5, 9; the average is about 2

The dynamic array: list.append

A list is stored in an array. When the space runs out, a new, bigger array is allocated and all items are copied, which costs O(n). But if the capacity is doubled each time, copies are rare: 1 + 2 + 4 + ... + n/2 < n. The total cost of n appends is n (the appends themselves) + < n (copying) = O(n), so one append costs O(1) amortized.

python
class DynArray:
    def __init__(self):
        self.cap = 1
        self.size = 0
        self.data = [None]
        self.copies = 0

    def append(self, x):
        if self.size == self.cap:          # full: allocate twice as much
            self.cap *= 2
            new = [None] * self.cap
            for i in range(self.size):
                new[i] = self.data[i]
                self.copies += 1
            self.data = new
        self.data[self.size] = x
        self.size += 1