Skip to content
Merged
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
30 changes: 30 additions & 0 deletions longest-substring-without-repeating-characters/radiantchoi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
# 문자열 전체를 순회, 서브스트링이란 서로 붙어 있는 문자열
# 글자를 볼 때 현재 모아둔 글자 모음에 중복 글자가 있다면?
# 일단 지금까지의 길이 업데이트
# 중복된 글자가 등장한 인덱스 체크
# 현재 모아둔 문자열의 길이에서 해당 인덱스까지의 "머리"를 덜어내고 지금 보는 문자를 더해서, 서브스트링을 이어나감

current = {}
tuning = 0
result = 0

for (index, letter) in enumerate(s):
if current.get(letter, index) < index:
result = max(result, len(current))

tail_of_head = current[letter]

new_current = {}
for key in current:
if current[key] > tail_of_head:
new_current[key] = current[key]

current = new_current

current[letter] = index

result = max(result, len(current))

return result
40 changes: 40 additions & 0 deletions number-of-islands/radiantchoi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
class Solution {
func numIslands(_ grid: [[Character]]) -> Int {
var grid = grid
var result = 0

for i in 0..<grid.count {
for j in 0..<grid[0].count {
// 임의의 인덱스 i, j에 대해 탐색 수행
// 서로 떨어져 있는 섬도 모두 찾기 위해
var isIsland = false
traverse(i, j, &grid, &isIsland)

if isIsland {
result += 1
}
}
}

return result
}

// DFS 함수
func traverse(_ row: Int, _ col: Int, _ grid: inout [[Character]], _ isIsland: inout Bool) {
// 인덱스가 유효한지 검사하고 유효하지 않으면 함수 종료
guard (0..<grid.count) ~= row && (0..<grid[0].count) ~= col else { return }

// 이미 방문한 곳, 원래 바다인 곳 등의 이유로 유효하지 않은 면적이면 함수 종료
guard grid[row][col] != "0" else { return }

// 방문 표시 + 유효한 면적을 발견했으므로 "섬이다" 라고 인정
grid[row][col] = "0"
isIsland = true

// 상하좌우 탐색 - 한 번의 콜 스택에서 유효한 모든 연결된 면적을 찾아서 방문 표시
traverse(row+1, col, &grid, &isIsland)
traverse(row-1, col, &grid, &isIsland)
traverse(row, col+1, &grid, &isIsland)
traverse(row, col-1, &grid, &isIsland)
}
}
24 changes: 24 additions & 0 deletions reverse-linked-list/radiantchoi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// 문제에서 주어진 ListNode
class ListNode {
val: number
next: ListNode | null

constructor(val?: number, next?: ListNode | null) {
this.val = (val===undefined ? 0 : val)
this.next = (next===undefined ? null : next)
}
}

function reverseList(head: ListNode | null): ListNode | null {
let current = null;

// 매번 새로운 노드를 생성하고, 지금까지 순회한 모든 결과를 이 새로운 노드의 next로 연결
while (head !== null) {
const newNode = new ListNode(head.val);
Copy link
Member

Choose a reason for hiding this comment

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

새로운 노드를 생성하는 것도 좋지만 기존 노드의 next를 변경하는 방식도 있습니다!
그런데 이게 어떻게 보면 직관적이긴 하네요 ㅎㅎ

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네 저도 리뷰를 하다 보니까, 참조를 바꾸는 방식으로 푸신 분들이 제법 있었습니다! 아무래도 그쪽 방식이 정석인 것 같은데, 이건 제가 참조가 오락가락하다 보니 헷갈려서 직관적으로 풀겠다 하는 의향이 강하게 반영되지 않았나 생각합니다ㅋㅋ

newNode.next = current;
current = newNode;
head = head.next;
}

return current;
};
75 changes: 75 additions & 0 deletions set-matrix-zeroes/radiantchoi.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
class Solution {
func setZeroes(_ matrix: inout [[Int]]) {
// 원래 0이었던 것의 주변을 모두 0으로 만들되, 기존에 0이었던 것들은 독립적으로 영향력을 행사해야 함
// 주변으로 먼저 0으로 만들어 버리면, flood fill 형태로 모든 원소가 0이 되어버림
// 따라서 변경해야 할 값을 미리 "마크해 두고", 이후 이 마크해 둔 값을 0으로 바꾸는 전략 선택

// 원소 값의 범위: -2^31보다 크거나 같고, 2^31 - 1보다 작거나 같음
// 따라서 범위에 포함되지 않는 2^32를 사용하여 계산 - 일부 언어에서는 overflow 발생 가능
let threshold = Int(pow(2.0, 32))

for i in 0..<matrix.count {
for j in 0..<matrix[i].count {
if matrix[i][j] == 0 {
// 상, 하, 좌, 우를 각각 전담해 마크하는 함수들
// 해당하는 자리의 중복 조회를 줄이기 위해 각각의 인덱스에 미리 튜닝을 가해서 투입
traverseRowNegative(i-1, j, &matrix, threshold)
traverseRowPositive(i+1, j, &matrix, threshold)
traverseColumnNegative(i, j-1, &matrix, threshold)
traverseColumnPositive(i, j+1, &matrix, threshold)
}
}
}

// 전체 매트릭스를 순회하면서 마크해뒀던 값을 0으로 치환
for i in 0..<matrix.count {
for j in 0..<matrix[i].count {
if matrix[i][j] == threshold {
matrix[i][j] = 0
}
}
}
}

func traverseRowNegative(_ row: Int, _ col: Int, _ matrix: inout [[Int]], _ threshold: Int) {
guard (0..<matrix.count) ~= row else { return }

// 이미 0이었던 원소라면 건드리지 말고, 그렇지 않다면 threshold로 마크
// 아래 모든 함수에서도 동일한 원리로 동작
if matrix[row][col] != 0 {
matrix[row][col] = threshold
}

traverseRowNegative(row - 1, col, &matrix, threshold)
}

func traverseRowPositive(_ row: Int, _ col: Int, _ matrix: inout [[Int]], _ threshold: Int) {
guard (0..<matrix.count) ~= row else { return }

if matrix[row][col] != 0 {
matrix[row][col] = threshold
}

traverseRowPositive(row + 1, col, &matrix, threshold)
}

func traverseColumnNegative(_ row: Int, _ col: Int, _ matrix: inout [[Int]], _ threshold: Int) {
guard (0..<matrix[row].count) ~= col else { return }

if matrix[row][col] != 0 {
matrix[row][col] = threshold
}

traverseColumnNegative(row, col - 1, &matrix, threshold)
}

func traverseColumnPositive(_ row: Int, _ col: Int, _ matrix: inout [[Int]], _ threshold: Int) {
guard (0..<matrix[row].count) ~= col else { return }

if matrix[row][col] != 0 {
matrix[row][col] = threshold
}

traverseColumnPositive(row, col + 1, &matrix, threshold)
}
}
10 changes: 10 additions & 0 deletions unique-paths/radiantchoi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import math

class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 도착을 위해 실제로 움직여야 하는 칸은 아래로 (m - 1)칸, 오른쪽으로 (n - 1)칸
# 총 (m + 1) + (n + 1)칸을 움직여야 하는데, 이만큼의 "빈 바구니"가 있다고 가정
# 빈 바구니의 몇 번 박스에 오른쪽으로 가기/아래로 가기를 넣을 것인가? 의 문제
# 조합을 통해 둘 중 아무거나를 바구니에 넣는 경우의 수를 구하면, 나머지 칸에 나머지 하나를 다 넣을 수 있다.
# 따라서 math.comb(m + n - 2, n - 1)도 동일한 결과 반환
return math.comb(m + n - 2, m - 1)