Ich machte this Kurs auf Algorithmen von MIT. In der allerersten Vorlesung stellt der Professor folgendes Problem vor: -2D-Peak-Finding-Algorithmus in O (n) Worst-Case-Zeit?
Ein Peak in einem 2D-Array ist ein Wert, so dass alle 4 Nachbarn kleiner oder gleich sind, d. für
a[i][j]
ein lokales Maximum zu sein, finden
a[i+1][j] <= a[i][j]
&& a[i-1][j] <= a[i][j]
&& a[i][j+1] <= a[i][j]
&& a[i+1][j-1] <= a[i][j]
Jetzt gegeben einen NxN 2D-Array, einen Spitzen in der Anordnung.
Diese Frage kann in O(N^2)
Zeit gelöst werden, indem man über alle Elemente iteriert und einen Peak zurückgibt.
Jedoch kann es optimiert werden, um in O(NlogN)
Zeit gelöst werden, indem Sie eine teilen und erobern Lösung wie erklärt here.
Aber sie haben gesagt, dass es einen O(N)
Zeitalgorithmus gibt, der dieses Problem löst. Bitte schlagen Sie vor, wie wir dieses Problem in O(N)
Zeit lösen können.
PS (Für diejenigen, die Python kennen) Der Kurs Mitarbeiter hat einen Ansatz here (Problem 1-5. Peak-Finding Proof) erklärt und auch einige Python-Code in ihren Problem-Sets zur Verfügung gestellt. Aber der erklärte Ansatz ist absolut nicht offensichtlich und sehr schwer zu entziffern. Der Python-Code ist gleichermaßen verwirrend. Daher habe ich den Hauptteil des folgenden Codes für diejenigen kopiert, die Python kennen und wissen, welcher Algorithmus aus dem Code verwendet wird.
def algorithm4(problem, bestSeen = None, rowSplit = True, trace = None):
# if it's empty, we're done
if problem.numRow <= 0 or problem.numCol <= 0:
return None
subproblems = []
divider = []
if rowSplit:
# the recursive subproblem will involve half the number of rows
mid = problem.numRow // 2
# information about the two subproblems
(subStartR1, subNumR1) = (0, mid)
(subStartR2, subNumR2) = (mid + 1, problem.numRow - (mid + 1))
(subStartC, subNumC) = (0, problem.numCol)
subproblems.append((subStartR1, subStartC, subNumR1, subNumC))
subproblems.append((subStartR2, subStartC, subNumR2, subNumC))
# get a list of all locations in the dividing column
divider = crossProduct([mid], range(problem.numCol))
else:
# the recursive subproblem will involve half the number of columns
mid = problem.numCol // 2
# information about the two subproblems
(subStartR, subNumR) = (0, problem.numRow)
(subStartC1, subNumC1) = (0, mid)
(subStartC2, subNumC2) = (mid + 1, problem.numCol - (mid + 1))
subproblems.append((subStartR, subStartC1, subNumR, subNumC1))
subproblems.append((subStartR, subStartC2, subNumR, subNumC2))
# get a list of all locations in the dividing column
divider = crossProduct(range(problem.numRow), [mid])
# find the maximum in the dividing row or column
bestLoc = problem.getMaximum(divider, trace)
neighbor = problem.getBetterNeighbor(bestLoc, trace)
# update the best we've seen so far based on this new maximum
if bestSeen is None or problem.get(neighbor) > problem.get(bestSeen):
bestSeen = neighbor
if not trace is None: trace.setBestSeen(bestSeen)
# return when we know we've found a peak
if neighbor == bestLoc and problem.get(bestLoc) >= problem.get(bestSeen):
if not trace is None: trace.foundPeak(bestLoc)
return bestLoc
# figure out which subproblem contains the largest number we've seen so
# far, and recurse, alternating between splitting on rows and splitting
# on columns
sub = problem.getSubproblemContaining(subproblems, bestSeen)
newBest = sub.getLocationInSelf(problem, bestSeen)
if not trace is None: trace.setProblemDimensions(sub)
result = algorithm4(sub, newBest, not rowSplit, trace)
return problem.getLocationInSelf(sub, result)
#Helper Method
def crossProduct(list1, list2):
"""
Returns all pairs with one item from the first list and one item from
the second list. (Cartesian product of the two lists.)
The code is equivalent to the following list comprehension:
return [(a, b) for a in list1 for b in list2]
but for easier reading and analysis, we have included more explicit code.
"""
answer = []
for a in list1:
for b in list2:
answer.append ((a, b))
return answer
Warum abstimmen, um die Frage zu schließen? –
Nur ein zufälliger Peak oder alle Peaks? – Andrey
Nur eine zufällige Spitze –