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
7 changes: 7 additions & 0 deletions swejp75/01 - 242. Valid Anagram.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
### Solution 1

```python
class Solution:
def isAnagram(self, s: str, t: str) -> bool:
return Counter(s) == Counter(t)
```
14 changes: 14 additions & 0 deletions swejp75/02 - 300. Longest Increasing Subsequence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
### Solution 1

```python
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
min_tails_for_length = []
for num in nums:
idx = bisect_left(min_tails_for_length, num)
if idx == len(min_tails_for_length):
min_tails_for_length.append(num)
else:
min_tails_for_length[idx] = num
return len(min_tails_for_length)
```
53 changes: 53 additions & 0 deletions swejp75/03 - 11. Container with Most Water.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
### Solution 1

```python
class Solution:
def maxArea(self, height: List[int]) -> int:
max_area = 0
left = 0
right = len(height) - 1
while left < right:
area = (right - left) * min(height[left], height[right])
max_area = max(max_area, area)
if height[left] < height[right]:
left += 1
else:
right -= 1
return max_area
```

#### 解法についての補足メモ(Geminiとの会話)

Q. その瞬間よさそうだからって短いほうを内側に進めて全体最適のものを見逃しちゃう可能性はないのかにょ?

A.

1. 「見逃す」可能性があるケースを考えてみるにょ

今、左端の壁 i が右端の壁 j より短い(h[i]<h[j])とするにょ。 このとき、もし「 i を動かしたことで見逃してしまう正解」があるとしたら、それは i と「 j より内側にあるどこかの壁 k 」の組み合わせのはずだにょ。

つまり、(i,k) (ただし i<k<j)の面積が、今の (i,j) の面積より大きくなることがあるか?を考えればいいんだにょ。

2. 数学的な「詰み」の証明

面積の公式をもう一度見てみるにょ。
Area(i,j)=(j−i)×h[i](左が短いので高さは h[i])

次に、内側にある壁 k との面積 Area(i,k) を計算してみるにょ。

- 横幅: (k−i) は (j−i) より必ず短くなるにょ。
- 高さ: min(h[i],h[k]) は、相手の h[k] がどんなに高くても、ボトルネックである h[i] 以下にしかならないにょ。

ということは...
Area(i,k)=(短くなった横幅)×( h[i] 以下の高さ)
Area(i,k)<Area(i,j)

となり、i を使った組み合わせの中では、今の j とのペアが最強だということが確定しちゃうんだにょ!

3. だから安心して i を捨てていいんだにょ!

「 i を始点とする可能性」は、今の j と計算した時点ですべて出し切った(これ以上 i を使って記録更新はできない)ことが分かったにょ。

だから、**「 i を含む全ての組み合わせ」をこれ以上探す必要はない(=見逃す心配はない)**として、ポインタを内側に進めていいんだにょ!

全探索(O(n²))という広大な砂漠の中から、**「ここには絶対に宝物はないにょ!」**というエリアを数学の力でゴッソリ削り落としているのが、この 2 ポインタ法なんだにょ。
16 changes: 16 additions & 0 deletions swejp75/04 - 238. Product of Array Except Self.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Solution 1

```python
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
result = [1] * len(nums)
cumprod_left = 1
for i in range(len(nums)):
result[i] *= cumprod_left
cumprod_left *= nums[i]
cumprod_right = 1
for i in reversed(range(len(nums))):
result[i] *= cumprod_right
cumprod_right *= nums[i]
return result
```
16 changes: 16 additions & 0 deletions swejp75/05 - 152. Maximum Product Subarray.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
### Solution 1

最初正の値と負の値を分けて保存していたのだが、場合分けが結構面倒になってしまったので単純に最小値と最大値として保存する方式にしてみた。

```python
class Solution:
def maxProduct(self, nums: List[int]) -> int:
current_max = current_min = result = nums[0]
for i in range(1, len(nums)):
num = nums[i]
values = num, current_max * num, current_min * num
current_max = max(values)
current_min = min(values)
result = max(result, current_max)
return result
```
21 changes: 21 additions & 0 deletions swejp75/06 - 443. String Compression.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
### Solution 1

```python
class Solution:
def compress(self, chars: List[str]) -> int:
writer = 0
reader = 0
while reader < len(chars):
char = chars[reader]
count = 0
while reader < len(chars) and chars[reader] == char:
count += 1
reader += 1
chars[writer] = char
writer += 1
if count >= 2:
for digit in str(count):
chars[writer] = digit
writer += 1
return writer
```
11 changes: 11 additions & 0 deletions swejp75/07 - 49. Group Anagrams.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
### Solution 1

```python
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
group_to_strings = defaultdict(list)
for s in strs:
group = "".join(sorted(s))
group_to_strings[group].append(s)
return list(group_to_strings.values())
```
54 changes: 54 additions & 0 deletions swejp75/08 - 215. Kth Largest Element in an Array.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
### Solution 1

min heapを使った解法。Arai60の問題に引っ張られて最初にこの解法で書いたがarrayでこれをやるのは結構不自然かも。
こんなことをやるんだったら配列をソートしてk-1番目を出力した方がいい気がする。

```python
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
min_heap = []
for num in nums:
if len(min_heap) < k:
heapq.heappush(min_heap, num)
else:
if num < min_heap[0]:
continue
heapq.heappushpop(min_heap, num)
return min_heap[0]
```

### Solution 2

3-partition quick select
普通のquick selectは以下と未満の判別をしないので都合が悪い(全部同じ要素、みたいな配列が入ってくるとkをスキップしてしまう)

```python
class Solution:
def findKthLargest(self, nums: List[int], k: int) -> int:
if k > len(nums):
raise ValueError("invalid k for the list")
nums = nums[:]
left = 0
right = len(nums) - 1
while True:
pivot = nums[random.randint(left, right)]
l = left
r = right
idx = left
while idx <= r:
if nums[idx] > pivot:
nums[l], nums[idx] = nums[idx], nums[l]
l += 1
idx += 1
elif nums[idx] == pivot:
idx += 1
else:
nums[idx], nums[r] = nums[r], nums[idx]
r -= 1
if l <= k - 1 <= r:
return pivot
elif k - 1 < l:
right = l - 1
elif r < k - 1:
left = r + 1
```
15 changes: 15 additions & 0 deletions swejp75/09 - 560. Subarray Sum Equals K.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### Solution 1

```python
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
result = 0
cumsum_to_count = defaultdict(int)
cumsum_to_count[0] += 1
cumsum = 0
for num in nums:
cumsum += num
result += cumsum_to_count[cumsum - k]
cumsum_to_count[cumsum] += 1
return result
```
39 changes: 39 additions & 0 deletions swejp75/10 - 125. Valid Palindrome.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
### Solution 1

```python
class Solution:
def isPalindrome(self, s: str) -> bool:
s = "".join([char for char in s if char.isalnum()])
s = s.lower()
left = 0
right = len(s) - 1
while left < right:
if s[left] != s[right]:
return False
left += 1
right -= 1
return True
```

### Solution 2

追加メモリを使わないバージョン。

```python
class Solution:
def isPalindrome(self, s: str) -> bool:
left = 0
right = len(s) - 1
while left < right:
if not s[left].isalnum():
left += 1
continue
if not s[right].isalnum():
right -= 1
continue
if s[left].lower() != s[right].lower():
return False
left += 1
right -= 1
return True
```
15 changes: 15 additions & 0 deletions swejp75/11 - 283. Move Zeroes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
### Solution 1

```python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
non_zero = 0
for i in range(len(nums)):
if nums[i] != 0:
if non_zero != i:
nums[non_zero], nums[i] = nums[i], nums[non_zero]
non_zero += 1
```
86 changes: 86 additions & 0 deletions swejp75/12 - 15. 3Sum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
### Solution 1

最初にやろうとした方針のコード。
(ちなみにこれはLeetcode上ではTLEになる。概念上の計算量自体はO(N^2)だと思うのだが、おそらくオーバーヘッドが結構ある)

```python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
three_sum_groups = set()
two_sum_to_pairs = defaultdict(set)
for i in range(len(nums)):
for pair in two_sum_to_pairs[-nums[i]]:
group = tuple(sorted((*pair, nums[i])))
three_sum_groups.add(group)
del two_sum_to_pairs[-nums[i]]
for j in range(i):
pair = tuple(sorted((nums[i], nums[j])))
two_sum_to_pairs[nums[i] + nums[j]].add(pair)
return [list(group) for group in three_sum_groups]
```

### Solution 2

配列をソートした後、一つのiを固定し、合計が目標値になるような組み合わせを2ポインタのone-passで見つける。
すでに見た一つ目の数字や二つ目の数字はスキップする。

```python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums = sorted(nums)
result = []
i = 0
while i < len(nums):
j = i + 1
k = len(nums) - 1
while j < k:
if nums[j] + nums[k] < -nums[i]:
j += 1
continue
if nums[j] + nums[k] > -nums[i]:
k -= 1
continue
result.append([nums[i], nums[j], nums[k]])
current_j_num = nums[j]
while j < k and nums[j] == temp:
j += 1
current_i_num = nums[i]
while i < len(nums) and nums[i] == temp:
i += 1
return result
```

### Solution 3

こんなやり方もあるみたい(gemini出力コード)

```python
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
res = []
# 1. 各数字の出現回数をカウント
count = Counter(nums)
# 2. ユニークな数字だけをソートして取り出す
unique_nums = sorted(count.keys())

for i, num1 in enumerate(unique_nums):
# ケース1: 同じ数字を3つ使う (0, 0, 0)
if num1 == 0:
if count[num1] >= 3:
res.append([0, 0, 0])
# ケース2: 同じ数字を2つ使う (x, x, y)
elif count[num1] >= 2:
target = -2 * num1
if target in count and target != num1:
res.append([num1, num1, target])

# ケース3: 3つとも異なる数字を使う (num1 < num2 < num3)
# 重複を避けるため、num2 は num1 より大きい範囲から選ぶ
for num2 in unique_nums[i+1:]:
num3 = -(num1 + num2)
# num3 が num2 より大きく、かつ存在すればOK
if num3 > num2 and num3 in count:
res.append([num1, num2, num3])

return res
```
23 changes: 23 additions & 0 deletions swejp75/13 - 88. Merge Sorted Array.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
### Solution 1

頭から読んでnums1に作っていくとnums1をどこかに保存しておく必要がある。
後ろから読むと保存しなくてよさそう。

```python
class Solution:
def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
"""
Do not return anything, modify nums1 in-place instead.
"""
w = len(nums1) - 1
r1 = len(nums1) - len(nums2) - 1
r2 = len(nums2) - 1
while w >= 0:
if r2 < 0 or r1 >= 0 and nums1[r1] > nums2[r2]:
nums1[w] = nums1[r1]
r1 -= 1
else:
nums1[w] = nums2[r2]
r2 -= 1
w -= 1
```
Loading