Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[정현준] 12주차 #566

Merged
merged 5 commits into from
Nov 3, 2024
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
48 changes: 48 additions & 0 deletions maximum-subarray/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test
import kotlin.math.max

class `maximum-subarray` {

fun maxSubArray(nums: IntArray): Int {
return usingDP(nums)
}

/**
* TC: O(n), SC: O(n)
*/
private fun usingDP(nums: IntArray): Int {
val dp = IntArray(nums.size).apply {
this[0] = nums[0]
}

for (index in 1 until nums.size) {
dp[index] = max(nums[index], nums[index] + dp[index - 1])
}

return dp.max()
}

/**
* TC: O(n), SC: O(1)
*/
private fun usingKadane(nums: IntArray): Int {
var (current, max) = nums[0] to nums[0]

for (index in 1 until nums.size) {
current = max(nums[index], current + nums[index])
max = max(max, current)
}

return max
}

@Test
fun `정수 배열의 하위 배열 중 가장 큰 합을 반환한다`() {
maxSubArray(intArrayOf(-2,1,-3,4,-1,2,1,-5,4)) shouldBe 6
maxSubArray(intArrayOf(1)) shouldBe 1
maxSubArray(intArrayOf(5,4,-1,7,8)) shouldBe 23
}
}
63 changes: 63 additions & 0 deletions number-of-connected-components-in-an-undirected-graph/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.HashSet;
import java.util.Set;

public class CountConnectedComponents {

public int countComponents(int n, int[][] edges) {
final int[] relation = new int[n];
for (int i = 0; i < n ; i++) {
relation[i] = i;
}

int result = n;
for (int[] edge : edges) {
if (union(relation, edge) == 1) {
result--;
}
}

return result;
}

private int union(int[] relation, int[] edge) {
Copy link
Contributor

Choose a reason for hiding this comment

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

union find 풀이 잘 보았습니다 :)
helper 함수 깔끔하게 잘 나누어져 있어서 보기에도 편했습니다

int parent1 = find(relation, edge[0]);
int parent2 = find(relation, edge[1]);

if (parent1 == parent2) {
return 0;
}

if (parent1 < parent2) {
relation[parent2] = parent1;
} else {
relation[parent1] = parent2;
}
return 1;
}

private int find(int[] relation, int node) {
int result = node;
while (relation[result] != result) {
relation[result] = relation[relation[result]];
result = relation[result];
}
return result;
}

@Test
@DisplayName("입력받은 노드와 간선을 통해 그래프의 개수를 반환한다")
void graphCount() {
int actual = countComponents(3, new int[][]{ {0,1}, {0,2} });
Assertions.assertThat(actual).isEqualTo(1);

int actual1 = countComponents(6, new int[][]{ {0,1}, {1,2}, {2,3}, {4,5} });
Assertions.assertThat(actual1).isEqualTo(2);

int actual2 = countComponents(6, new int[][]{ {0,1}, {2,3}, {4,5}, {1,2}, {3,4} });
Assertions.assertThat(actual2).isEqualTo(1);
}
}
82 changes: 82 additions & 0 deletions remove-nth-node-from-end-of-list/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class `remove-nth-node-from-end-of-list` {

fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
if (head == null || (head.next == null && n == 1)) {
return null
}
return usingTwoPointers(head, n)
}

/**
* TC: O(n), SC: O(n)
*/
private fun usingExtraList(head: ListNode, n: Int): ListNode {

fun toList(node: ListNode): List<ListNode> {
val list = mutableListOf<ListNode>()
var tmp: ListNode? = node
while (tmp != null) {
list.add(tmp)
tmp = tmp.next
}
return list
}

val list = toList(head)
var root = head
if (list.size == n) {
root = list[1]
} else {
list[list.size - n - 1].next = list[list.size - n].next
}
return root
}

/**
* fast를 n만큼 먼저 이동 시킨 후 fast.next가 null일 때까지 fast와 slow를 다음 노드로 이동시킨다.
* fast를 n만큼 이동시키면 결국 slow는 n의 이전 노드에 도달하게 되기에 해당 slow 노드의 next를 변경하면 된다.
* TC: O(n), SC: O(1)
*/
private fun usingTwoPointers(head: ListNode, n: Int): ListNode? {
var fast: ListNode? = head
var slow: ListNode? = head

repeat(n) {
fast = fast?.next
}
if (fast == null) return head.next

while (fast?.next != null) {
fast = fast?.next
slow = slow?.next
}
slow?.next = slow?.next?.next
return head
}

@Test
fun `링크된 목록의 헤드가 주어지면 목록의 끝에서 n번째 노드를 제거하고 그 헤드를 반환합니다`() {
removeNthFromEnd(ListNode.of(1), 1).also {
it shouldBe null
}

removeNthFromEnd(ListNode.of(1, 2), 2).also {
it shouldBe ListNode(2)
}

removeNthFromEnd(ListNode.of(1, 2), 1)!!.also {
it shouldBe ListNode(1)
it.next shouldBe null
}

removeNthFromEnd(ListNode.of(1, 2, 3, 4, 5), 2)!!.also {
it.next!!.next!!.`val` shouldBe 3
it.next!!.next!!.next!!.`val` shouldBe 5
}
}
}
35 changes: 35 additions & 0 deletions same-tree/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test

class `same-tree` {

fun isSameTree(p: TreeNode?, q: TreeNode?): Boolean {
return if (p == null && q == null) {
true
} else if (p == null || q == null || p.`val` != q.`val`) {
false
} else {
isSameTree(p.left, q.left) && isSameTree(p.right, q.right)
Copy link
Contributor

Choose a reason for hiding this comment

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

Kotlin은 Implicit return이 가능하군요 ㅎㅎ

Copy link
Member Author

Choose a reason for hiding this comment

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

코틀린에서는 if문과 try문을 식으로 작성할 수 있더라구요 ㅎㅎ

Copy link
Contributor

Choose a reason for hiding this comment

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

아 return 문이었네요 이거 ㅋㅋㅋ 제가 잘못 봤습니다
이것도 또한 특이하네요

}
}

@Test
fun `두 개의 트리의 동등성을 반환한다`() {
isSameTree(
TreeNode.of(1,1,2),
TreeNode.of(1,1,2)
) shouldBe true

isSameTree(
TreeNode.of(1,1,2),
TreeNode.of(1,1,2,3)
) shouldBe false

isSameTree(
TreeNode.of(1,1,2),
TreeNode.of(1,1,3)
) shouldBe false
}
}
69 changes: 69 additions & 0 deletions serialize-and-deserialize-binary-tree/jdalma.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package leetcode_study

import io.kotest.matchers.shouldBe
import org.junit.jupiter.api.Test
import java.util.StringJoiner

/**
* 문제의 핵심은 트리를 탐색하는 순서 기준으로 직렬화된 문자열을 반대로 풀어내는 것
* 직렬화를 DFS로 해결하면 역직렬화시 선입선출 방식으로 해결하여야 하고,
* 직렬화를 BFS로 해결하면 역직렬화시 힙의 인덱스 규칙을 이용하여 해결할 수 있을 듯
*/
class `serialize-and-deserialize-binary-tree` {

private val empty = "X"
private val delimiter = "|"

/**
* DFS로 탐색하면서 노드의 값을 누적한다.
* TC: O(n), SC: O(n)
*/
fun serialize(root: TreeNode?): String {
if (root == null) return ""

val joiner = StringJoiner("|")
nodeToString(root, joiner)
return joiner.toString()
}

private fun nodeToString(node: TreeNode?, joiner: StringJoiner) {
if (node == null) {
joiner.add(empty)
} else {
joiner.add(node.`val`.toString())
nodeToString(node.left, joiner)
nodeToString(node.right, joiner)
}
}

/**
* 깊이 탐색으로 누적된 문자열을 선입선출로 꺼내어 노드를 생성한다.
* TC: O(n), SC: O(n)
*/
fun deserialize(data: String): TreeNode? {
if (data.isEmpty()) return null
return stringToNode(ArrayDeque(data.split(delimiter)))
}

private fun stringToNode(queue: ArrayDeque<String>): TreeNode? {
val value = queue.removeFirst()
return if (value == empty) {
null
} else {
val node = TreeNode(value.toInt())
node.left = stringToNode(queue)
node.right = stringToNode(queue)
node
}
}

@Test
fun `트리 노드를 직렬화한다`() {
serialize(TreeNode.of(1,2,3,null,null,4,5)) shouldBe "1|2|X|X|3|4|X|X|5|X|X"
}

@Test
fun `문자열을 트리 노드로 역직렬화한다`() {
deserialize("1|2|X|X|3|4|X|X|5|X|X") shouldBe TreeNode.of(1,2,3,null,null,4,5)
}
}