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
46 changes: 46 additions & 0 deletions 0075.Sort-Colors/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# 75. Sort Colors

## step1
まず2回走査のアルゴリズムはすぐにかける。他の問題で見た気がする。5mぐらい。

> Follow up: Could you come up with a one-pass algorithm using only constant extra space?

値が三種類だけというのを利用すれば可能。

方針が立ったが、実装に時間がかかった。 2 を後ろにおくった時にまえに送られる値が 2 である可能性を考慮し忘れていた。15 mぐらい。

## step2
背景:Dutch National Flag
https://en.wikipedia.org/wiki/Dutch_national_flag_problem

変数名を書き直したが、どうだろうか

### 他の人のコード

https://github.com/huyfififi/coding-challenges/pull/49

レビューにあるzero, one, twoのポインタを使う実装がわかりやすかったので実装

4色以上の場合の実装も行う。自力でこれを一から書ける気がしない。

### in-place のソートアルゴリズム

Bubble sort: https://en.wikipedia.org/wiki/Bubble_sort

> It performs poorly in real-world use and is used primarily as an educational tool.
> Like insertion sort, bubble sort is adaptive, which can give it an advantage over algorithms like quicksort. This means that it may outperform those algorithms in cases where the list is already mostly sorted (having a small number of inversions), despite the fact that it has worse average-case time complexity. For example, bubble sort is O ( n ) {\displaystyle O(n)} on a list that is already sorted, while quicksort would still perform its entire O ( n log ⁡ n ) {\displaystyle O(n\log n)} sorting process.

Insertion sort: https://en.wikipedia.org/wiki/Insertion_sort

> Adaptive, i.e., efficient for data sets that are already substantially sorted: the time complexity is O(kn) when each element in the input is no more than k places away from its sorted position
> Stable; i.e., does not change the relative order of elements with equal keys
> In-place; i.e., only requires a constant amount O(1) of additional memory space

Selection sort: https://en.wikipedia.org/wiki/Selection_sort

> Heapsort has been described as "nothing but an implementation of selection sort using the right data structure."

バブルソートより計算量が少ない。(工夫しないと)安定ソートではない。

ヒープソートもin-placeで実装できる

41 changes: 41 additions & 0 deletions 0075.Sort-Colors/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
class Solution:
def sortColors(self, nums: list[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""

def move_to_front(target: int, start: int) -> int:
length = 0
for i in range(start, len(nums)):
if nums[i] == target:
nums[i], nums[length + start] = nums[length + start], nums[i]
length += 1

return length

length_zero = move_to_front(0, 0)
move_to_front(1, length_zero)


class Solution:
def sortColors(self, nums: list[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
length_zero = 0
i = 0
length_two = 0

while i <= len(nums) - 1 - length_two:
if nums[i] == 0:
nums[length_zero], nums[i] = nums[i], nums[length_zero]
length_zero += 1
i += 1
elif nums[i] == 2:
nums[i], nums[len(nums) - 1 - length_two] = (
nums[len(nums) - 1 - length_two],
nums[i],
)
length_two += 1
else:
i += 1
22 changes: 22 additions & 0 deletions 0075.Sort-Colors/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
class Solution:
def sortColors(self, nums: list[int]) -> None:
"""
Dutch National Flag: one pass, O(1) extra space.
"""
last_of_zero = 0
i = 0
last_of_one = len(nums) - 1

while i <= last_of_one:
if nums[i] == 0:
nums[last_of_zero], nums[i] = nums[i], nums[last_of_zero]
last_of_zero += 1
i += 1
elif nums[i] == 2:
nums[i], nums[last_of_one] = (
nums[last_of_one],
nums[i],
)
last_of_one -= 1
else:
i += 1
25 changes: 25 additions & 0 deletions 0075.Sort-Colors/step2_general.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import random


def sort_colors(nums: list[int], k: int) -> None:
starts = [0] * k

for i, val in enumerate(nums):
index_to_move = i
for color in range(k - 1, val - 1, -1):
nums[starts[color]], nums[index_to_move] = (
nums[index_to_move],
nums[starts[color]],
)
index_to_move = starts[color]
starts[color] += 1


k = 20

test_cases = [[random.randint(0, k - 1) for _ in range(20)] for _ in range(20)]

for test_case in test_cases:
colors = test_case.copy()
sort_colors(colors, k)
assert colors == sorted(test_case)
16 changes: 16 additions & 0 deletions 0075.Sort-Colors/step2_start_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class Solution:
def sortColors(self, nums: list[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
zero_start = 0 # i < zero_start -> nums[i] == 0
one_start = 0 # i < one_start and i >= zero_start -> nums[i] == 0

for two_start in range(len(nums)):
if nums[two_start] == 0:
nums[two_start], nums[zero_start] = nums[zero_start], nums[two_start]
zero_start += 1
one_start = max(zero_start, one_start)
if nums[two_start] == 1:
nums[two_start], nums[one_start] = nums[one_start], nums[two_start]
one_start += 1
20 changes: 20 additions & 0 deletions 0075.Sort-Colors/step3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Solution:
def sortColors(self, nums: list[int]) -> None:
"""
Dutch National Flag: one pass, O(1) extra space.
"""
end_of_zero = 0
i = 0
end_of_one = len(nums) - 1

while i <= end_of_one:
if nums[i] == 0:
nums[i], nums[end_of_zero] = nums[end_of_zero], nums[i]
end_of_zero += 1
i += 1
elif nums[i] == 2:
nums[i], nums[end_of_one] = nums[end_of_one], nums[i]
end_of_one -= 1
# swap前で nums[i] == 2 の場合のため i += 1は行わない
else:
i += 1