Skip to content

Commit 93a6ebf

Browse files
committed
4주차 답안 제출
1 parent 8cdb2dc commit 93a6ebf

File tree

5 files changed

+328
-0
lines changed

5 files changed

+328
-0
lines changed
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import kotlin.math.max
6+
7+
class `longest-consecutive-sequence` {
8+
fun longestConsecutive(nums: IntArray): Int {
9+
if (nums.isEmpty()) return 0
10+
return usingUnionFind(nums)
11+
}
12+
13+
/**
14+
* 1. 배열을 정렬하여 순서대로 순회하며 연속 수열 길이를 확인한다.
15+
* TC: O(n * log(n)), SC: O(1)
16+
*/
17+
private fun usingSort(nums: IntArray): Int {
18+
nums.sort()
19+
20+
var (length, maxLength) = 1 to 0
21+
for (index in 0 until nums.size - 1) {
22+
if (nums[index] == nums[index + 1]) {
23+
continue
24+
} else if (nums[index] + 1 == nums[index + 1]) {
25+
length++
26+
} else {
27+
maxLength = max(length, maxLength)
28+
length = 1
29+
}
30+
}
31+
return max(length, maxLength)
32+
}
33+
34+
/**
35+
* 2. Set의 자료구조를 활용하여 가장 작은 값부터 while문을 통한 최대 증가 값을 반환한다.
36+
* TC: O(n), SC: O(n)
37+
*/
38+
private fun usingSet(nums: IntArray): Int {
39+
val numberSet = nums.toSet()
40+
var maxLength = 0
41+
42+
for (number in nums) {
43+
if (numberSet.contains(number - 1)) {
44+
continue
45+
}
46+
var length = 1
47+
while (numberSet.contains(number + length)) {
48+
length++
49+
}
50+
maxLength = max(maxLength, length)
51+
}
52+
53+
return maxLength
54+
}
55+
56+
/**
57+
* 3. Union-Find
58+
* TC: O(n), SC: O(n)
59+
*/
60+
private fun usingUnionFind(nums: IntArray): Int {
61+
val nodes = mutableMapOf<Int, Int>()
62+
val dsu = DSU(nums.size)
63+
64+
for ((i,n) in nums.withIndex()) {
65+
if (n in nodes) continue
66+
67+
nodes[n - 1]?.let { dsu.union(i, it) }
68+
nodes[n + 1]?.let { dsu.union(i, it) }
69+
70+
nodes[n] = i
71+
}
72+
73+
return dsu.maxLength()
74+
}
75+
76+
@Test
77+
fun `입력받은 정수 배열의 최대 연속 수열 길이를 반환한다`() {
78+
longestConsecutive(intArrayOf()) shouldBe 0
79+
longestConsecutive(intArrayOf(100,4,200,1,3,2)) shouldBe 4
80+
longestConsecutive(intArrayOf(11,23,12,13,14,21)) shouldBe 4
81+
longestConsecutive(intArrayOf(0,3,7,2,5,8,4,6,0,1)) shouldBe 9
82+
longestConsecutive(intArrayOf(11,64,43,12,13,10,9,8,7)) shouldBe 7
83+
}
84+
}
85+
86+
class DSU(val n: Int) {
87+
private val parent = IntArray(n) { it }
88+
private val size = IntArray(n) { 1 }
89+
90+
private fun find(x: Int): Int {
91+
if (parent[x] != x)
92+
parent[x] = find(parent[x])
93+
return parent[x]
94+
}
95+
96+
fun union(x: Int, y: Int) {
97+
val root = find(x)
98+
val child = find(y)
99+
if(root != child) {
100+
parent[child] = root
101+
size[root] += size[child]
102+
}
103+
}
104+
105+
fun maxLength(): Int {
106+
var res = 0
107+
for (i in parent.indices) {
108+
if (parent[i] == i)
109+
res = maxOf(res, size[i])
110+
}
111+
return res
112+
}
113+
}

maximum-product-subarray/jdalma.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
import kotlin.math.max
6+
import kotlin.math.min
7+
8+
class `maximum-product-subarray` {
9+
10+
/**
11+
* 현재의 값, 이전 위치의 최대 누적곱, 이전 위치의 최소 누적곱 이 세 개를 비교하여 한 번의 순회로 최대 값을 반환한다.
12+
* 음수와 음수가 곱해져 최대 값이 도출될 수 있기에 DP 배열을 두 개 생성한다.
13+
* TC: O(n), SC: O(n)
14+
*/
15+
fun maxProduct(nums: IntArray): Int {
16+
val (min, max) = IntArray(nums.size) { 11 }.apply { this[0] = nums[0] } to IntArray(nums.size) { -11 }.apply { this[0] = nums[0] }
17+
var result = max(-11, nums[0])
18+
for (index in 1 until nums.size) {
19+
max[index] = max(max(nums[index], nums[index] * max[index - 1]), nums[index] * min[index - 1])
20+
min[index] = min(min(nums[index], nums[index] * max[index - 1]), nums[index] * min[index - 1])
21+
result = max(max(min[index], max[index]), result)
22+
}
23+
24+
return result
25+
}
26+
27+
@Test
28+
fun `입력받은 정수 배열의 가장 큰 곱을 반환한다`() {
29+
maxProduct(intArrayOf(2,3,-2,4)) shouldBe 6
30+
maxProduct(intArrayOf(-2,0,-1)) shouldBe 0
31+
maxProduct(intArrayOf(-10)) shouldBe -10
32+
maxProduct(intArrayOf(-2,3,-4)) shouldBe 24
33+
}
34+
}

missing-number/jdalma.kt

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `missing-number` {
7+
8+
fun missingNumber(nums: IntArray): Int {
9+
return usingSum(nums)
10+
}
11+
12+
/**
13+
* 1. 배열을 추가로 생성하여 존재하는 정수의 인덱스에 true를 저장하여, false인 인덱스를 반환한다.
14+
* TC: O(n), SC: O(n)
15+
*/
16+
private fun usingIndex(nums: IntArray): Int {
17+
val existed = BooleanArray(nums.size + 1)
18+
nums.forEach { existed[it] = true }
19+
20+
existed.forEachIndexed { i, e ->
21+
if (!e) return i
22+
}
23+
return -1
24+
}
25+
26+
/**
27+
* 2. 0부터 정수 배열의 사이즈만큼 정수를 합산하여 기대하는 합산과 뺀 결과를 반환한다.
28+
* TC: O(n), SC: O(1)
29+
*/
30+
private fun usingSum(nums: IntArray): Int {
31+
val size = nums.size
32+
return nums.fold((size + 1) * size / 2) { acc , i -> acc - i }
33+
}
34+
35+
@Test
36+
fun `입력받은 정수 배열에서 비어있는 정수를 반환한다`() {
37+
missingNumber(intArrayOf(3,2,1)) shouldBe 0
38+
missingNumber(intArrayOf(3,0,1)) shouldBe 2
39+
missingNumber(intArrayOf(9,6,4,2,3,5,7,0,1)) shouldBe 8
40+
}
41+
}

valid-palindrome/jdalma.kt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
class `valid-palindrome` {
7+
8+
/**
9+
* 입력받은 문자열의 양 끝부터 투 포인터를 이용하여 비교한다.
10+
* TC: O(n), SC: O(1)
11+
*/
12+
fun isPalindrome(s: String): Boolean {
13+
var (left, right) = 0 to s.length - 1
14+
while (left < right) {
15+
while (left < right && !isAlphabetOrDigit(s[left])) {
16+
left++
17+
}
18+
while (left < right && !isAlphabetOrDigit(s[right])) {
19+
right--
20+
}
21+
if (s[left].lowercaseChar() != s[right].lowercaseChar()) {
22+
return false
23+
}
24+
left++
25+
right--
26+
}
27+
return true
28+
}
29+
30+
private fun isAlphabetOrDigit(c: Char): Boolean = c.isDigit() || (c in 'a' .. 'z') || (c in 'A' .. 'Z')
31+
32+
@Test
33+
fun `입력받은 문자열의 영숫자가 팰린드롬 여부를 반환한다`() {
34+
isPalindrome("A man, a plan, a canal: Panama") shouldBe true
35+
isPalindrome("race a car") shouldBe false
36+
isPalindrome("ㅁaㄹㅁb듐노+_c$#&$%#b*&@!!@a$") shouldBe true
37+
}
38+
39+
@Test
40+
fun `입력받은 문자열이 공백만 존재한다면 참을 반환한다`() {
41+
isPalindrome(" ") shouldBe true
42+
isPalindrome(" ") shouldBe true
43+
}
44+
}

word-search/jdalma.kt

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import leetcode_study.`word-search`.Position.Companion.MOVES
5+
import org.junit.jupiter.api.Test
6+
7+
class `word-search` {
8+
9+
/**
10+
* 격자에 존재하는 문자를 사용하여 word 를 만들 수 있는지 확인하기 위해 DFS를 통한 visited 배열 백트래킹을 사용하여 해결
11+
* TC: O(너비 * 높이 * 4^word), SC: O(너비 * 높이 * 4^word)
12+
*/
13+
fun exist(board: Array<CharArray>, word: String): Boolean {
14+
return usingBacktracking(board, word)
15+
}
16+
17+
private fun usingBacktracking(board: Array<CharArray>, word: String): Boolean {
18+
fun dfs(board: Array<CharArray>, visited: Array<BooleanArray>, word: String, position: Position, index: Int): Boolean {
19+
if (index == word.length) return true
20+
visited[position.x][position.y] = true
21+
22+
for (move in MOVES) {
23+
val next = position + move
24+
if (next.isNotOutOfIndexed(board) && !visited[next.x][next.y] && board[next.x][next.y] == word[index]) {
25+
visited[next.x][next.y] = true
26+
if (dfs(board, visited, word, next, index + 1)) return true
27+
visited[next.x][next.y] = false
28+
}
29+
}
30+
return false
31+
}
32+
33+
val visited = Array(board.size) {
34+
BooleanArray(board[0].size)
35+
}
36+
37+
for (x in board.indices) {
38+
for (y in board[x].indices) {
39+
if (board[x][y] == word[0] && dfs(board, visited, word, Position(x,y), 1)) {
40+
return true
41+
}
42+
visited[x][y] = false
43+
}
44+
}
45+
return false
46+
}
47+
48+
@Test
49+
fun `문자로 구성된 2차원 배열에서 word 문자열 존재 유무를 반환한다`() {
50+
exist(arrayOf(
51+
charArrayOf('A','B','C','E'),
52+
charArrayOf('S','F','C','S'),
53+
charArrayOf('A','D','E','E')
54+
), "ABCCED") shouldBe true
55+
exist(arrayOf(
56+
charArrayOf('A','B','C','E'),
57+
charArrayOf('S','F','C','S'),
58+
charArrayOf('A','D','E','E')
59+
), "SEE") shouldBe true
60+
exist(arrayOf(
61+
charArrayOf('A','B','C','E'),
62+
charArrayOf('S','F','C','S'),
63+
charArrayOf('A','D','E','E')
64+
), "SES") shouldBe false
65+
exist(arrayOf(
66+
charArrayOf('A','B','C','E'),
67+
charArrayOf('S','F','E','S'),
68+
charArrayOf('A','D','E','E')
69+
), "ABCESEEEFS") shouldBe true
70+
exist(arrayOf(
71+
charArrayOf('C','A','A'),
72+
charArrayOf('A','A','A'),
73+
charArrayOf('B','C','D')
74+
), "AAB") shouldBe true
75+
}
76+
77+
data class Position(
78+
val x: Int,
79+
val y: Int
80+
) {
81+
82+
operator fun plus(other: Position) = Position(this.x + other.x, this.y + other.y)
83+
84+
fun isNotOutOfIndexed(board: Array<CharArray>) =
85+
this.x < board.size && this.x >= 0 && this.y < board[0].size && this.y >= 0
86+
87+
companion object {
88+
val MOVES: List<Position> = listOf(
89+
Position(-1, 0),
90+
Position(0, 1),
91+
Position(1, 0),
92+
Position(0, -1),
93+
)
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)