-
Notifications
You must be signed in to change notification settings - Fork 0
300.longest increasing subsequence #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # 300. Longest Increasing Subsequence | ||
| - sol1: 愚直な解法。素直に解くことができた | ||
| - O(n**2) | ||
| - O(nlogn)の解法を思いつくことはできない | ||
| - https://github.com/mamo3gr/arai60/blob/300_longest-increasing-subsequence/300_longest-increasing-subsequence/memo.md | ||
| - この方針だけ読んで考えてたが無理 | ||
| - コードを読んでやっと理解 | ||
|
|
||
| bisectの使い方 | ||
|
|
||
| https://docs.python.org/3/library/bisect.html | ||
|
|
||
| ```python | ||
| from bisect import bisect_left, bisect_right | ||
|
|
||
| a = [1, 3, 5] | ||
| print(bisect_left(a, 2)) # 1 | ||
| print(bisect_left(a, 3)) # 1 | ||
| print(bisect_right(a, 3)) # 2 | ||
| ``` | ||
|
|
||
| https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0 | ||
| > 日本語で長々と書くと、「lengths[i] とは、仮に nums[i] がシーケンスの最後であると仮定した場合に可能な、最も長いシーケンスの長さ」ですよね。 | ||
| - 自分のsol1もlength_of_isなのでこの指摘が当てはまる | ||
|
|
||
| https://discord.com/channels/1084280443945353267/1200089668901937312/1209563502407065602 | ||
|
|
||
| https://github.com/mamo3gr/arai60/blob/300_longest-increasing-subsequence/300_longest-increasing-subsequence/memo.md | ||
|
|
||
| - セグ木を使った解法、Binary Indexed Treeを使った解法 | ||
|
|
||
| https://github.com/mamo3gr/arai60/blob/300_longest-increasing-subsequence/300_longest-increasing-subsequence/memo.md | ||
| - 色々まとめてくれている | ||
|
|
||
| - セグメントツリー | ||
| - https://github.com/naoto-iwase/leetcode/pull/36 | ||
| - ほとんど写経で書いてみる | ||
| - 1-indexedにすることで、k%2==1: 右の子、k%2==0:左の子となる | ||
| - 座標圧縮を行う | ||
| - 自分より小さい数字であることを(座標圧縮した)indexで処理し、自分より前の数字であることをnumsの順番のループで処理 | ||
| - 自力ではかけない | ||
|
|
||
| - BITを使った解法: LLMに書かせたが自分では読んでいない。(sol4) | ||
| - https://algo-logic.info/binary-indexed-tree/ | ||
| - 和の区間を最初からに限定することで、メモリと計算効率を上昇 | ||
| - bit演算で親や子への移動が可能 | ||
| - index & -index = lowbit[index] | ||
| - これを足すことで親に移る | ||
| - 自分では書けない |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| class Solution: | ||
| def lengthOfLIS(self, nums: List[int]) -> int: | ||
| # Length of increasing subsequence | ||
| len_is = [1] * len(nums) | ||
| for i, num in enumerate(nums): | ||
| for j in range(i): | ||
| if num > nums[j]: | ||
| len_is[i] = max( | ||
| len_is[i], | ||
| len_is[j] + 1, | ||
| ) | ||
|
|
||
| return max(len_is) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| from bisect import bisect_left | ||
|
|
||
|
|
||
| class Solution: | ||
| def lengthOfLIS(self, nums: List[int]) -> int: | ||
| # tails[i] is the smallest ending element of all increasing subsequences of length (i + 1) | ||
| tails = [] | ||
| for n in nums: | ||
| pos_insert_n = bisect_left(tails, n) | ||
| if pos_insert_n >= len(tails): | ||
| tails.append(n) | ||
| continue | ||
| tails[pos_insert_n] = n | ||
|
|
||
| return len(tails) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| from bisect import bisect_left | ||
|
|
||
|
|
||
| class SegTree: | ||
| def __init__(self, size): | ||
| n = 1 | ||
| while n < size: | ||
| n *= 2 | ||
| self.offset = n | ||
| self.data = [0] * 2 * n | ||
|
|
||
| def _to_leaf_index(self, index): | ||
| return index + self.offset - 1 | ||
|
|
||
| def update(self, index, value): | ||
| k = self._to_leaf_index(index) | ||
| self.data[k] = max(self.data[k], value) | ||
| k //= 2 | ||
| while k >= 1: | ||
| self.data[k] = max(self.data[2 * k], self.data[2 * k + 1]) | ||
| k //= 2 | ||
|
|
||
| def query(self, first_index, last_index): | ||
| if first_index > last_index: | ||
| return 0 | ||
| l, r = self._to_leaf_index(first_index), self._to_leaf_index(last_index) | ||
| result = 0 | ||
| while l <= r: | ||
| if l % 2 == 1: | ||
| result = max(result, self.data[l]) | ||
| l += 1 | ||
| if r % 2 == 0: | ||
| result = max(result, self.data[r]) | ||
| r -= 1 | ||
| l //= 2 | ||
| r //= 2 | ||
| return result | ||
|
|
||
|
|
||
| class Solution: | ||
| def lengthOfLIS(self, nums: List[int]) -> int: | ||
| nums_sorted = sorted(set(nums)) | ||
|
|
||
| def num_to_rank(n): | ||
| return bisect_left(nums_sorted, n) + 1 | ||
|
|
||
| seg_tree = SegTree(len(nums)) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. こちらのコメントをご参照ください。
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. segment_treeの方が良さそうですね。極力省略しない、なかなか身につかないので気をつけます |
||
|
|
||
| max_len = 0 | ||
| for n in nums: | ||
| rank = num_to_rank(n) | ||
| max_len_with_smaller = seg_tree.query(1, rank - 1) | ||
| seg_tree.update(rank, max_len_with_smaller + 1) | ||
| max_len = max(max_len, max_len_with_smaller + 1) | ||
|
|
||
| return max_len | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # Generated by LLM | ||
| from bisect import bisect_left | ||
| from typing import List | ||
|
|
||
|
|
||
| class BITMax: | ||
| def __init__(self, size: int): | ||
| self.n = size | ||
| self.bit = [0] * (size + 1) | ||
|
|
||
| def update(self, index: int, value: int) -> None: | ||
| while index <= self.n: | ||
| if value > self.bit[index]: | ||
| self.bit[index] = value | ||
| index += index & -index | ||
|
|
||
| def query(self, index: int) -> int: | ||
| result = 0 | ||
| while index > 0: | ||
| if self.bit[index] > result: | ||
| result = self.bit[index] | ||
| index -= index & -index | ||
| return result | ||
|
|
||
|
|
||
| class Solution: | ||
| def lengthOfLIS(self, nums: List[int]) -> int: | ||
| if not nums: | ||
| return 0 | ||
|
|
||
| coords = sorted(set(nums)) | ||
|
|
||
| def to_rank(x: int) -> int: | ||
| return bisect_left(coords, x) + 1 | ||
|
|
||
| bit = BITMax(len(coords)) | ||
| ans = 0 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ans は設問に対する回答というニュアンスを感じました。変数に格納される値の意味や役割に寄せた命名のほうが良いと思います。 max_length はいかがでしょうか?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Geminiに伝えておきます |
||
| for x in nums: | ||
| r = to_rank(x) | ||
| best_prev = bit.query(r - 1) | ||
| cur = best_prev + 1 | ||
| bit.update(r, cur) | ||
| if cur > ans: | ||
| ans = cur | ||
| return ans | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| from bisect import bisect_left, bisect_right | ||
|
|
||
| a = [1, 3, 5] | ||
| print(bisect_left(a, 2)) # 1 | ||
| print(bisect_left(a, 3)) # 1 | ||
| print(bisect_right(a, 3)) # 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
3か月くらい後にこのコードを読むと、
tailsが何を表していて、なぜ問題が解けるのか読み解くのに苦労しそうです。何らかコメントでサポートできると良いと思います。Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
# tails[i] is the smallest ending element of all increasing subsequences of length (i + 1)とコメントを追加しました