Search a 2D Matrix
Otrzymujesz siatkę liczb całkowitych matrix o m wierszach i n kolumnach oraz liczbę całkowitą target. Każdy wiersz jest posortowany rosnąco, a pierwsza wartość w każdym wierszu jest większa od ostatniej wartości w wierszu powyżej. Zwróć true, jeśli target znajduje się w siatce, a w przeciwnym razie false, w czasie O(log(m × n)).
Funkcja
- matrixinteger-2d-array
- siatka, podana jako lista wierszy, uporządkowana wiersz po wierszu
- targetinteger
- wartość, której należy szukać
- Zwracaboolean
- true, jeśli target znajduje się w siatce, w przeciwnym razie false
Ograniczenia
1 ≤ m, n ≤ 100, gdziem = matrix.lengthin = matrix[i].length- Każdy wiersz ma tę samą długość
n. -104 ≤ matrix[i][j], target ≤ 104- Każdy wiersz jest uporządkowany ściśle rosnąco, a pierwsza wartość każdego wiersza jest większa od ostatniej wartości poprzedniego wiersza.
Przykłady
- Wejście
- matrix = [[2, 5, 9, 14], [17, 21, 26, 30], [33, 38, 45, 52]]target = 26
- Wyjście
- true
- Wyjaśnienie
- Czytając wiersz po wierszu, 12 wartości tworzy jedną posortowaną listę. Wyszukiwanie binarne na pozycjach od 0 do 11 sprawdza 21 na pozycji 5 (za mała), 33 na pozycji 8 (za duża), a następnie znajduje 26 na pozycji 6.
- Wejście
- matrix = [[2, 5, 9, 14], [17, 21, 26, 30], [33, 38, 45, 52]]target = 16
- Wyjście
- false
- Wyjaśnienie
- 16 byłoby po 14, ostatniej wartości wiersza 0, i przed 17, pierwszą wartością wiersza 1. Nic między nimi nie ma, więc 16 nie znajduje się w siatce.
Pytanie dodatkowe
Załóżmy, że wiersze mogą mieć różną długość, ale nadal są posortowane od początku do końca. Jak zamienić pozycję na wiersz i kolumnę oraz jaki byłby koszt wyszukiwania?
Podpowiedzi
Otwieraj je po kolei. Każda zdradza trochę więcej.
Odczytuj macierz wiersz po wierszu, od lewej do prawej, jakby była jedną długą listą. Co zauważasz w kolejności wartości na tej liście?
Obie reguły razem oznaczają, że cała macierz, odczytywana wiersz po wierszu, jest jedną posortowaną listą
m × nwartości. Możesz przeszukać ją binarnie, nie tworząc jej.Wyszukiwanie binarne w pozycjach od
0dom × n - 1. Pozycjapznajduje się w wierszup / ni kolumniep % n(dzielenie całkowite), więc każdy krok odczytuje jedną komórkę i odrzuca połowę pozostałych pozycji.
Rozwiązanie
Obie reguły porządkowania sprawiają, że siatka, odczytywana wiersz po wierszu, tworzy jedną posortowaną listę m × n wartości. Wykonaj wyszukiwanie binarne na tej liście według pozycji, a następnie przekształć każdą pozycję z powrotem w wiersz i kolumnę za pomocą jednego dzielenia. Siatka o wymiarach 100 na 100 wymaga wtedy najwyżej 14 porównań zamiast 10000.
Sprawdź każdą komórkę
Intuicja
Porównaj każdą komórkę z target i zwróć true w przypadku dopasowania, a false po sprawdzeniu ostatniej komórki. Odczytuje każdą komórkę, więc działa poprawnie dla każdej siatki, posortowanej lub nie. Nie wykorzystuje kolejności, więc siatka 100 na 100 wymaga maksymalnie 10000 porównań.
Algorytm
- Dla każdego wiersza
matrixsprawdzaj kolejno każdą wartość. - Jeśli wartość jest równa
target, zwróćtrue. - Po pętlach zwróć
false.
def searchMatrix(matrix, target):
for row in matrix:
for value in row:
if value == target:
return True
return FalseIdź od prawego górnego rogu
Intuicja
Zaczynając od komórki w prawym górnym rogu, każda wartość po lewej stronie jest mniejsza, a każda wartość poniżej jest większa. Jeśli wartość w komórce jest większa niż target, to kolumna poniżej niej również jest większa: przejdź w lewo i wyeliminuj tę kolumnę. Jeśli jest mniejsza, to wiersz po jej lewej stronie również jest mniejszy: przejdź w dół i wyeliminuj ten wiersz.
W pierwszym przykładzie 14 jest mniejsze niż 26, więc przejdź w dół do 30. 30 jest większe, więc przejdź w lewo do 26 — to szukana wartość. Każdy krok eliminuje wiersz lub kolumnę, więc wykonasz najwyżej m + n kroków: 200 w siatce o wymiarach 100 na 100. Wystarczy, że wiersze i kolumny są posortowane, więc to podejście nie wykorzystuje połowy informacji, jakie daje ta siatka.
Algorytm
- Zacznij od wiersza
0i ostatniej kolumny. - Gdy wiersz i kolumna znajdują się w siatce, odczytaj komórkę.
- Jeśli jest równa
target, zwróćtrue. - Jeśli jest większa, przesuń się o jedną kolumnę w lewo; jeśli jest mniejsza, przesuń się o jeden wiersz w dół.
- Gdy wyjdziesz poza siatkę, zwróć
false.
def searchMatrix(matrix, target):
# Start at the top-right corner: left is smaller, down is larger.
r, c = 0, len(matrix[0]) - 1
while r < len(matrix) and c >= 0:
value = matrix[r][c]
if value == target:
return True
if value > target:
c -= 1 # every value below in this column is larger still
else:
r += 1 # every value to the left in this row is smaller still
return FalseWyszukiwanie binarne w spłaszczonej siatce
Intuicja
Ponumeruj komórki wierszami: wiersz 0 zawiera pozycje od 0 do n - 1, wiersz 1 zawiera pozycje od n do 2n - 1 i tak dalej. Każdy wiersz jest posortowany i zaczyna się powyżej miejsca, w którym kończył się poprzedni wiersz, więc wartości rosną wraz z pozycją. To posortowana lista, do której można zastosować wyszukiwanie binarne.
Nie tworzysz listy. Pozycja p znajduje się w wierszu p / n i kolumnie p % n, przy użyciu dzielenia całkowitego. W pierwszym przykładzie n = 4, więc pozycja 6 to wiersz 1, kolumna 2, która zawiera 26. Każde porównanie zmniejsza o połowę liczbę pozycji, w których może znajdować się target: dla 10000 komórek potrzeba najwyżej 14 porównań i dwóch indeksów dodatkowej pamięci.
Algorytm
- Niech
minoznaczają liczbę wierszy i kolumn, alo = 0,hi = m × n - 1. - Dopóki
lo ≤ hi, wybierzmidpośrodku między nimi. - Odczytaj
value = matrix[mid / n][mid % n]. - Jeśli
valuejest równetarget, zwróćtrue. Jeśli jest mniejsze, ustawlo = mid + 1; w przeciwnym razie ustawhi = mid - 1. - Po zakończeniu pętli zwróć
false.
def searchMatrix(matrix, target):
rows, cols = len(matrix), len(matrix[0])
# Read row by row, the cells form one sorted list of rows * cols values.
# Position p of that list is matrix[p // cols][p % cols].
lo, hi = 0, rows * cols - 1
while lo <= hi:
mid = (lo + hi) // 2
value = matrix[mid // cols][mid % cols]
if value == target:
return True
if value < target:
lo = mid + 1
else:
hi = mid - 1
return False
Pułapki i przypadki brzegowe
- Dzielenie przez liczbę wierszy zamiast kolumn. Pozycja
pznajduje się w wierszup / n; gdy w jej miejsce użyjeszm, kod działa dla kwadratowych siatek, ale zawodzi dla siatki z 3 wierszami i 4 kolumnami. - W wersji z dwoma wyszukiwaniami brak obsługi sytuacji, gdy
targetjest mniejszy niżmatrix[0][0]. Żaden wiersz nie zaczyna się od tej wartości ani od mniejszej, a indeks wiersza-1trafia do drugiego wyszukiwania. - Używanie pętli z warunkiem
lo < hiprzy włącznie uwzględnionymhi. Siatka 1 na 1 zawierającatargetzwracafalse, ponieważ pętla nigdy się nie wykonuje. - W Lua i R zapomnienie o przesunięciu indeksów do numeracji od 1: pozycja
pto wierszp / n + 1, kolumnap % n + 1.
Najczęstsze pytania3
Jaka jest złożoność czasowa wyszukiwania w macierzy 2D?
Wyszukiwanie binarne w spłaszczonej siatce działa w czasie O(log(m × n)) i używa O(1) pamięci: dla 10000 komórek wymaga najwyżej 14 porównań. Ponieważ log(m × n) = log m + log n, jest równoważne wyszukiwaniu wiersza, a następnie elementu w tym wierszu.
Czy użyć marszu od prawego górnego rogu, czy wyszukiwania binarnego?
Przejście po narożnikach wymaga O(m + n) kroków i zakłada jedynie, że wiersze i kolumny są posortowane, więc rozwiązuje również wariant, w którym wiersz może zaczynać się poniżej końca wiersza powyżej. Gdy każdy wiersz zaczyna się powyżej miejsca, w którym kończy się poprzedni, jak tutaj, wyszukiwanie binarne jest szybsze.
Czy dwa wyszukiwania binarne — jedno dla wiersza, a drugie w jego obrębie — również są poprawne?
Tak. Wyszukaj binarnie w pierwszej kolumnie ostatni wiersz, którego pierwsza wartość jest nie większa niż target, a następnie wyszukaj binarnie w tym wierszu. Złożoność wynosi O(log m + log n), czyli tyle samo. Pojedyncze wyszukiwanie wykonuje tę samą pracę przy użyciu jednej pętli i mniejszej liczby przypadków brzegowych.
Podobne zadania
Zadania oparte na tych samych pomysłach. Rozwiązanie dwóch lub trzech utrwala schemat.
def searchMatrix(matrix, target):
# Wpisz kod tutajTest #1
Test #2
Argumenty
matrix = [[2, 5, 9, 14], [17, 21, 26, 30], [33, 38, 45, 52]] target = 26
Oczekiwany wynik
true