Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions 300/memo.md
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]
- これを足すことで親に移る
- 自分では書けない
13 changes: 13 additions & 0 deletions 300/sol1.py
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)
15 changes: 15 additions & 0 deletions 300/sol2.py
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 = []
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3か月くらい後にこのコードを読むと、tails が何を表していて、なぜ問題が解けるのか読み解くのに苦労しそうです。何らかコメントでサポートできると良いと思います。

Copy link
Copy Markdown
Owner Author

@tom4649 tom4649 Mar 28, 2026

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)
とコメントを追加しました

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)
56 changes: 56 additions & 0 deletions 300/sol3.py
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))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

こちらのコメントをご参照ください。
hemispherium/LeetCode_Arai60#10 (comment)

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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
45 changes: 45 additions & 0 deletions 300/sol4.py
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
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ans は設問に対する回答というニュアンスを感じました。変数に格納される値の意味や役割に寄せた命名のほうが良いと思います。 max_length はいかがでしょうか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The 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
6 changes: 6 additions & 0 deletions bisect_test.py
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