Funkce len() vrací počet prvků pole, ve vašem případě tedy 3. Prvky pole jsou indexované od nuly, tedy první prvek pole má index 0, tj. words[0] == "dog", words[1] == "cat", words[2] == "hint". Index posledního prvku v poli je tedy o jedničku menší, než počet prvků v poli.
Indexování prvků pole od nuly je zvyk z doby, kdy se přistupovalo přímo k paměti. Adresa prvku pole pak byla adresa pole + index * velikost prvku pole.
Ale zrovna v tom vašem případě by se stejného výsledku dalo dosáhnout i bez odečítání jedničky, stačilo by místo operátoru menší nebo rovno použít ostře menší:
words = ["dog","cat","hint"]
counter = 0
length = len(words)
while counter < length:
word = words[counter]
print(word + "!")
counter = counter + 1