Liceum Klasa I 45 minut PP: I.2b | s. 342

Lekcja 17: Wyszukiwanie wzorca w tekscie metoda naiwna

Algorytm naiwny, przesuwane okno, zlozonosc obliczeniowa, implementacja w Pythonie

📋 Podstawa programowa: I.2b
algorytmyimplementacjapattern matchingstringwyszukiwanie wzorca
00:00
Wprowadzenie
5 min
00:05
Teoria
15 min
00:20
Cwiczenia
15 min
00:35
Podsumowanie
10 min
📚

Teoria

Problem wyszukiwania wzorca

Wyszukiwanie wzorca (pattern matching) to jeden z najwazniejszych problemow algorytmicznych w informatyce. Polega na znalezieniu wystapien pewnego krotszego tekstu (wzorca) wewnatrz dluzszego tekstu. Stosowany jest w edytorach tekstu (Ctrl+F), wyszukiwarkach, analizie DNA, filtrach antyspamowych i wielu innych dziedzinach.

Dane wejsciowe:

  • Tekst (T) - dlugi lancuch znakow dlugosci n
  • Wzorzec (W) - krotki lancuch znakow dlugosci m (m ≤ n)

Wynik: pozycje (indeksy) w tekscie T, na ktorych zaczyna sie wzorzec W.

Algorytm naiwny (brute force)

Algorytm naiwny jest najprostszym podejsciem do wyszukiwania wzorca. Polega on na "przesuwaniu" wzorca po tekscie o jedna pozycje i za kazdym razem sprawdzaniu, czy wzorzec pasuje do biezacego fragmentu tekstu.

Idea algorytmu naiwnego:
  1. Ustawiamy wzorzec na poczatku tekstu (pozycja 0)
  2. Porownujemy wzorzec z fragmentem tekstu znak po znaku
  3. Jesli wszystkie znaki sie zgadzaja - znalezlismy wystapienie!
  4. Przesuwamy wzorzec o jedna pozycje w prawo
  5. Powtarzamy kroki 2-4 az do konca tekstu

Wizualizacja dzialania

Przklad: szukamy wzorca "AB" w tekscie "AABABAB"

Tekst:   A A B A B A B
Wzorzec: A B             pozycja 0: A=A ok, A!=B - NIE
          A B            pozycja 1: A=A ok, B=B ok - TAK! (znaleziono na pozycji 1)
            A B          pozycja 2: B!=A - NIE
              A B        pozycja 3: A=A ok, B=B ok - TAK! (znaleziono na pozycji 3)
                A B      pozycja 4: B!=A - NIE
                  A B    pozycja 5: A=A ok, B=B ok - TAK! (znaleziono na pozycji 5)

Implementacja w Pythonie

def szukaj_naiwnie(tekst, wzorzec):
    """Wyszukiwanie wzorca metoda naiwna.
    Zwraca liste pozycji, na ktorych zaczyna sie wzorzec."""
    n = len(tekst)
    m = len(wzorzec)
    pozycje = []

    for i in range(n - m + 1):
        # Sprawdzamy, czy wzorzec pasuje na pozycji i
        pasuje = True
        for j in range(m):
            if tekst[i + j] != wzorzec[j]:
                pasuje = False
                break
        if pasuje:
            pozycje.append(i)

    return pozycje

# Test
tekst = "AABABAB"
wzorzec = "AB"
wynik = szukaj_naiwnie(tekst, wzorzec)
print(f"Wzorzec '{wzorzec}' znaleziony na pozycjach: {wynik}")
# Wzorzec 'AB' znaleziony na pozycjach: [1, 3, 5]

Zlozonosc obliczeniowa

Algorytm naiwny ma zlozonosc:

  • Przypadek optymistyczny: O(n) - gdy pierwszy znak wzorca nie pasuje, szybko przechodzimy dalej
  • Przypadek pesymistyczny: O(n * m) - gdy prawie caly wzorzec pasuje za kazdym razem, np. tekst "AAAAAAA" i wzorzec "AAAB"

Dla wiekszosci praktycznych zastosowan algorytm naiwny jest wystarczajaco szybki. Istnieja jednak szybsze algorytmy (KMP, Boyer-Moore, Rabin-Karp), ktore poznasz w przyszlosci.

Wazne: Petla zewnetrzna iteruje od 0 do n-m (wlacznie), a nie do n-1! Dlaczego? Bo wzorzec dlugosci m nie moze zaczynac sie dalej niz na pozycji n-m, gdyz "wystalalby" poza tekst.
✏️

Zadania

Latwe

Zadanie 1: Reczne sledzenie algorytmu

Prześledz recznie dzialanie algorytmu naiwnego dla tekstu "ABCABCABC" i wzorca "CAB". Zapisz kazdy krok porownania i wskazz pozycje, na ktorych znaleziono wzorzec.

Pokaz rozwiazanie
Tekst:   A B C A B C A B C
Wzorzec: C A B              poz 0: A!=C - NIE
          C A B             poz 1: B!=C - NIE
            C A B           poz 2: C=C, A=A, B=B - TAK! (pozycja 2)
              C A B         poz 3: A!=C - NIE
                C A B       poz 4: B!=C - NIE
                  C A B     poz 5: C=C, A=A, B=B - TAK! (pozycja 5)
                    C A B   poz 6: A!=C - NIE

Wzorzec "CAB" znaleziony na pozycjach: [2, 5]
Srednie

Zadanie 2: Implementacja z licznikiem porownan

Zmodyfikuj algorytm naiwny tak, aby zliczal laczna liczbe porownan znakow. Przetestuj dla tekstu "AAAAAAAAAB" i wzorca "AAAB". Ile porownan wykonano?

Pokaz rozwiazanie
def szukaj_z_licznikiem(tekst, wzorzec):
    n = len(tekst)
    m = len(wzorzec)
    pozycje = []
    porownania = 0

    for i in range(n - m + 1):
        pasuje = True
        for j in range(m):
            porownania += 1
            if tekst[i + j] != wzorzec[j]:
                pasuje = False
                break
        if pasuje:
            pozycje.append(i)

    return pozycje, porownania

tekst = "AAAAAAAAAB"
wzorzec = "AAAB"
poz, por = szukaj_z_licznikiem(tekst, wzorzec)
print(f"Pozycje: {poz}")
print(f"Liczba porownan: {por}")
# Pozycje: [6]
# Liczba porownan: 28
Srednie

Zadanie 3: Wyszukiwanie bez rozrozniana wielkosci liter

Zmodyfikuj algorytm naiwny tak, aby ignorewal roznice miedzy wielkimi i malymi literami. Przetestuj dla tekstu "Ala ma kota a Kot ma Ale" i wzorca "ala".

Pokaz rozwiazanie
def szukaj_bez_wielkosci(tekst, wzorzec):
    tekst_lower = tekst.lower()
    wzorzec_lower = wzorzec.lower()
    n = len(tekst_lower)
    m = len(wzorzec_lower)
    pozycje = []

    for i in range(n - m + 1):
        if tekst_lower[i:i+m] == wzorzec_lower:
            pozycje.append(i)

    return pozycje

tekst = "Ala ma kota a Kot ma Ale"
wzorzec = "ala"
wynik = szukaj_bez_wielkosci(tekst, wzorzec)
print(f"Znaleziono na pozycjach: {wynik}")
# Znaleziono na pozycjach: [0]
# (Uwaga: "Ale" to nie "ala" - inny koncowy znak)
Trudne

Zadanie 4: Zamiana wzorca

Napisz funkcje zamien_wzorzec(tekst, stary, nowy), ktora znajduje wszystkie wystapienia tekstu "stary" i zastepuje je tekstem "nowy" (bez uzycia wbudowanej metody replace).

Pokaz rozwiazanie
def zamien_wzorzec(tekst, stary, nowy):
    wynik = ""
    n = len(tekst)
    m = len(stary)
    i = 0

    while i < n:
        # Sprawdzamy czy na pozycji i zaczyna sie stary wzorzec
        if i <= n - m and tekst[i:i+m] == stary:
            wynik += nowy
            i += m  # przeskakujemy caly stary wzorzec
        else:
            wynik += tekst[i]
            i += 1

    return wynik

# Test
tekst = "Ala ma kota i kota ma Ala"
print(zamien_wzorzec(tekst, "kota", "psa"))
# Ala ma psa i psa ma Ala
🎥

Materialy wideo

Searching for a pattern in text. Naive algorithm.
Informatyka w liceum
Algorithms on texts - searching for a pattern in text
Dziwne... u mnie działa - (ScratchSPWZ)
🎧

Podcasty

✔️

Quiz - sprawdz sie!

📜

Podstawa programowa

← Lekcja 16: Porownywanie tekstow Lekcja 18: Szyfr Cezara →