アルゴリズム-再帰とスタック、遅延計算
31237 ワード
文書ディレクトリ再帰 スタック スタックおよび再帰 両端キューの条件再帰 再帰
再帰とは何か、大まかに言えば、前のステップに依存した結果を計算することです.
前のステップの計算を完了してこそ、最初の明確な値まで、現在の計算操作を行うことができます.
leecode 230でお話しします
明らかに,中順に遍歴し,対応する配列のk−1 k−1 k−1番目の要素を取ればよい.
前順遍歴:r o o t→l e f t→r i g h t rootrightarrow leftrightarrow right root→left→right
中順遍歴:l e f t→r o o t→r i g h t leftrightarrow rootrightarrow right left→root→right
後順遍歴:l e f t→r i g h t→r o o t leftrightarrow rightrightarrow root left→right→root
このうち
再帰を示すだけでなく、いくつかの法則を教えてくれます.境界条件 再帰には、具体的な計算や操作、さらには直接的な答え(フィボナッチ数列)に対応する境界が必要です.法則伝達 各ステップの計算は常に次のステップに依存し、その関係を設定する必要があります.
依存は計算依存とプロセス依存に分けられ,フィボナッチは計算依存に属するが,この例はプロセス依存にすぎない.
具体的な操作では,以前の計算に依存しない.
スタック
まずスタックの特性を復習します:単口出入り.
leecode20
スタックと再帰
本質的には、
同時に、スタックポートのデータはスタックトップのデータとインタラクティブになり、積み重ねられ、一歩一歩近づくことができます.
依存する遅延計算は、スタックに押し込むことができ、計算の番になると、前置的な依存が準備されています.
ただ、肝心なのは、一つの問題に対して再帰的な考え方を抽象化できるかどうかです.
leecode739
直接解法は,繰返し計算が存在し,所定の数値が存在するのに,我々はなぜ何度も繰り返し計算するのか.
この考え方によれば,直接計算を行い,次のようなバージョンを得ることができる.
つかむべきものはすべてつかんで、唯一の肝心な点は再帰の思想を理解していないことです.
その後未知を添加するのは必ず温度が以前より小さい、すなわち、後ろを比較するには、前を比較しなければならない.
ここで採用した
コードの簡潔さについては、
データ構造の選択については,最初に
データ構造の選択を取り除くには、
両端キューの条件再帰
leecode 239を見てみましょう
暴力的なやり方は言わないで、私たちは両端の列の条件が再帰すると言っています.
最大値をフィルタします.
はい、シングル出口の繰り返しは、もちろん再帰をご利用いただけます
少し愚かなようですが、本質は同じで、特に非単一要素のフィルタリングでは、このようなやり方は絶対にもっと良いです.
この問題のポイントは2点にある.期限切れ つまりウィンドウの外、他のシーンでは、時間をウィンドウとすることが多いです.サイズ 値の大きさの判断は、言うまでもなく.
最も重要なのは、有効な最大値のフィルタリングです.そのためには、選挙値を保留しなければならない.
特に、あなたが残した選挙値は、有効で、必ず有効でなければなりません.
問題全体は,本質的に有効候補値の最大値フィルタリングを行い,重複ペアリングをどのように回避するかに重点を置いている.
単一の値を使用すると、増加または減少しない限り、タスクを完了できません.
しかし、出口は一つしかありません.私たちは底を漏らす必要があります.
ここでは、底漏れの機能を
最大値は、実際にはスタックの底にあり、リアルタイムの更新を保証し、その後は候補の有効最大値です.
後続の有効な最大値がスタックの最大値より大きいか、スタックの最大値が期限切れになっている場合にのみ、更新する必要はありません.
さらに重要なのは,スタック方向に秩序があり,フィルタリングの問題を考慮したことがないことである.
両端の列ですが、このようなシーンでは、
再帰とは何か、大まかに言えば、前のステップに依存した結果を計算することです.
前のステップの計算を完了してこそ、最初の明確な値まで、現在の計算操作を行うことができます.
leecode 230でお話しします
, kthSmallest k 。
:
k ,1 ≤ k ≤ 。
明らかに,中順に遍歴し,対応する配列のk−1 k−1 k−1番目の要素を取ればよい.
前順遍歴:r o o t→l e f t→r i g h t rootrightarrow leftrightarrow right root→left→right
中順遍歴:l e f t→r o o t→r i g h t leftrightarrow rootrightarrow right left→root→right
後順遍歴:l e f t→r i g h t→r o o t leftrightarrow rightrightarrow root left→right→root
このうち
とは、root
の位置に対応していますので、間違えないでくださいね.class Solution:
def kthSmallest(self, root: TreeNode, k: int) -> int:
container = []
def collect(node: TreeNode):
# ,
if node is None:
return
# ,
if (node.left is None) and (node.right is None):
container.append(node.val)
else:
#
collect(node.left)
#
container.append(node.val)
#
collect(node.right)
collect(root)
return container[k - 1]
再帰を示すだけでなく、いくつかの法則を教えてくれます.
依存は計算依存とプロセス依存に分けられ,フィボナッチは計算依存に属するが,この例はプロセス依存にすぎない.
具体的な操作では,以前の計算に依存しない.
スタック
まずスタックの特性を復習します:単口出入り.
class Stack(object):
def __init__(self):
self.container = []
def empty(self):
return len(self.container) == 0
def push(self, item):
self.container.append(item)
def pop(self):
if self.empty():
return None
return self.container.pop(-1)
def top(self):
return self.container[-1]
leecode20
'(',')','{','}','[',']' , 。
:
。
。
。
class Solution:
def isValid(self, s: str) -> bool:
mapping = {'}': '{', ']': '[', ')': '('}
stack = Stack()
for item in s:
#
if ' ' == item:
continue
if item in mapping:
#
if stack.empty():
return False
# ,
if mapping[item] == stack.top():
stack.pop()
# ,
else:
return False
else:
stack.push(item)
# ,
return stack.empty()
スタックと再帰
本質的には、
は
で実現されます.スタックには出口が1つしかないので、計算するたびに
のデータしかありません.同時に、スタックポートのデータはスタックトップのデータとインタラクティブになり、積み重ねられ、一歩一歩近づくことができます.
依存する遅延計算は、スタックに押し込むことができ、計算の番になると、前置的な依存が準備されています.
ただ、肝心なのは、一つの問題に対して再帰的な考え方を抽象化できるかどうかです.
leecode739
, 。 : , 。 , 0 。
, temperatures = [73, 74, 75, 71, 69, 72, 76, 73], [1, 1, 4, 2, 1, 1, 0, 0]。
直接解法は,繰返し計算が存在し,所定の数値が存在するのに,我々はなぜ何度も繰り返し計算するのか.
この考え方によれば,直接計算を行い,次のようなバージョンを得ることができる.
class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
result = [0 for _ in range(len(T))]
unknown = []
for item in enumerate(T):
#
if len(unknown) == 0:
unknown.append(item)
continue
#
last = -1
while -len(unknown) <= last < 0:
someday = unknown[last]
#
if item[1] > someday[1]:
result[someday[0]] = item[0] - someday[0]
del unknown[last]
else:
#
break
#
unknown.append(item)
return result
つかむべきものはすべてつかんで、唯一の肝心な点は再帰の思想を理解していないことです.
その後未知を添加するのは必ず温度が以前より小さい、すなわち、後ろを比較するには、前を比較しなければならない.
ここで採用した
-1
は,再帰の真髄ではなく,unknow
の除去,配列操作の必要性にすぎない.class Solution:
def dailyTemperatures(self, T: List[int]) -> List[int]:
result = [0 for _ in range(len(T))]
unknown = Stack()
for item in enumerate(T):
if unknown.empty():
unknown.push(item)
continue
while not unknown.empty():
top = unknown.top()
if item[1] > top[1]:
result[top[0]] = item[0] - top[0]
unknown.pop()
else:
break
unknown.push(item)
コードの簡潔さについては、
list
を使用してstack
をシミュレートしたためと言いますが、これはその一方にすぎません.list
シミュレーションstack
を使用すると、動作は増加するが、前の方法は、既知の未知をどのように除去するかをよりよく考えているだけである.データ構造の選択については,最初に
list
を選択するのは誤りであり,再帰的には当然stack
を用いるが,上は誤打に似ているだけである.データ構造の選択を取り除くには、
の違いが鍵であり、同じやり方で、思想が異なり、価値が異なる.なぜなら、思想は移行できるからだ.両端キューの条件再帰
leecode 239を見てみましょう
nums, k 。 k 。 。
。
暴力的なやり方は言わないで、私たちは両端の列の条件が再帰すると言っています.
最大値をフィルタします.
def max(*args):
maxValue = args[0]
for value in args[1:]:
if value > maxValue:
maxValue = value
はい、シングル出口の繰り返しは、もちろん再帰をご利用いただけます
def max(*args):
stack = Stack()
for value in args:
if stack.empty():
stack.push(value)
continue
if value > stack.top():
stack.pop()
stack.push(value)
return stack.pop()
少し愚かなようですが、本質は同じで、特に非単一要素のフィルタリングでは、このようなやり方は絶対にもっと良いです.
この問題のポイントは2点にある.
最も重要なのは、有効な最大値のフィルタリングです.そのためには、選挙値を保留しなければならない.
特に、あなたが残した選挙値は、有効で、必ず有効でなければなりません.
問題全体は,本質的に有効候補値の最大値フィルタリングを行い,重複ペアリングをどのように回避するかに重点を置いている.
単一の値を使用すると、増加または減少しない限り、タスクを完了できません.
list
を使用すると、私たちはすべての記録ではなく、特殊な操作が余計に見えます.stack
を考えると、有効な最大値を押し込むだけで、無効な最大値を除去することを保証すればいいだけです.しかし、出口は一つしかありません.私たちは底を漏らす必要があります.
class Stack(object):
def __init__(self, limit):
self.limit = limit
self.container = []
def max(self):
return self.container[0]
'''
,
'''
def valid(self, index):
if index - self.container[0][0] >= self.limit:
self.container.pop(0)
'''
,
'''
def push(self, item):
while len(self.container) > 0:
if self.container[-1][1]< item[1]:
self.container.pop(-1)
else:
break
self.container.append(item)
self.valid(item[0])
ここでは、底漏れの機能を
stack
内部に維持しました.つまり、valid
はデータの有効性を検証し、その方向は正反対です.class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
stack = Stack(k)
result = []
for item in enumerate(nums):
stack.push(item)
if item[0] < k - 1:
continue
result.append(stack.max()[1])
return result
最大値は、実際にはスタックの底にあり、リアルタイムの更新を保証し、その後は候補の有効最大値です.
後続の有効な最大値がスタックの最大値より大きいか、スタックの最大値が期限切れになっている場合にのみ、更新する必要はありません.
さらに重要なのは,スタック方向に秩序があり,フィルタリングの問題を考慮したことがないことである.
両端の列ですが、このようなシーンでは、
のstack
と見なすのが好きです.