-
-
Notifications
You must be signed in to change notification settings - Fork 195
[정현준] 1주차 답안 제출 #298
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
Merged
Merged
[정현준] 1주차 답안 제출 #298
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.equals.shouldBeEqual | ||
import org.junit.jupiter.api.Test | ||
|
||
class `contains-duplicate`{ | ||
|
||
fun containsDuplicate(nums: IntArray): Boolean { | ||
return usingSet(nums) | ||
} | ||
|
||
// 1. 중첩 반복문 - 시간초과 | ||
// 시간복잡도: O(n^2), 공간복잡도: O(1) | ||
private fun usingNestedLoop(nums: IntArray): Boolean { | ||
nums.forEachIndexed { i, e1 -> | ||
nums.forEachIndexed { j, e2 -> | ||
if (i != j && e1 == e2) { | ||
return true | ||
} | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// 2. 정렬 후 순회 | ||
// 시간복잡도: O(n * log(n)), 공간복잡도: O(1) | ||
private fun usingSort(nums: IntArray): Boolean { | ||
nums.sort() // DualPivotQuicksort -> O(n log(n)) | ||
for (index in 1 until nums.size) { | ||
val prev = nums[index - 1] | ||
val curr = nums[index] | ||
if (prev == curr) { | ||
return true | ||
} | ||
} | ||
return false | ||
} | ||
|
||
// 3. 자료구조 Set 사용 | ||
// 시간복잡도: O(n), 공간복잡도: O(n) | ||
private fun usingSet(nums: IntArray): Boolean { | ||
val set = nums.toSet() | ||
return nums.size != set.size | ||
} | ||
|
||
@Test | ||
fun 동일한_원소가_존재하면_true를_반환한다() { | ||
val nums1 = intArrayOf(1, 2, 3, 1) | ||
val nums2 = intArrayOf(1, 2, 3, 2) | ||
val nums3 = intArrayOf(1, 1, 1, 1, 3, 3, 4, 3, 2, 4, 2) | ||
|
||
containsDuplicate(nums1) shouldBeEqual true | ||
containsDuplicate(nums2) shouldBeEqual true | ||
containsDuplicate(nums3) shouldBeEqual true | ||
} | ||
|
||
@Test | ||
fun 동일한_원소가_존재하지_않으면_false를_반환한다() { | ||
val nums1 = intArrayOf(1, 2, 3, 4) | ||
val nums2 = intArrayOf(1, 5, 7) | ||
|
||
containsDuplicate(nums1) shouldBeEqual false | ||
containsDuplicate(nums2) shouldBeEqual false | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.equals.shouldBeEqual | ||
import org.junit.jupiter.api.Test | ||
import java.util.PriorityQueue | ||
|
||
class `kth-smallest-element-in-a-bst` { | ||
|
||
fun kthSmallest(root: TreeNode?, k: Int): Int { | ||
return inorderTraversal(root, k) | ||
} | ||
|
||
// 1. 재귀 호출로 모든 트리를 조회 후 정렬 | ||
// 시간복잡도: O(n * log(n)), 공간복잡도: O(n) | ||
private fun recursionAndSort(root: TreeNode?, k: Int) = mutableSetOf<Int>().apply { | ||
dfs(root, this) | ||
}.sorted()[k - 1] | ||
|
||
private fun dfs(node: TreeNode?, set: MutableSet<Int>) { | ||
if (node == null) return | ||
|
||
set.add(node.`val`) | ||
dfs(node.left, set) | ||
dfs(node.right, set) | ||
} | ||
|
||
// 2. 재귀 호출로 모든 트리의 값을 우선순위 큐에 삽입하고 작은 값으로 계속 큐를 갱신 | ||
// 시간복잡도: O(n * log(k)), 공간복잡도: O(n + k) | ||
// 트리 순회 : O(n), 우선순위 큐 삽입: O(log k) | ||
private fun usingPriorityQueue(node: TreeNode?, k: Int): Int { | ||
fun dfs(node: TreeNode, k: Int, pq: PriorityQueue<Int>) { | ||
pq.offer(node.`val`) | ||
|
||
if (pq.size > k) { | ||
pq.poll() | ||
} | ||
if (node.left != null) { | ||
dfs(node.left!!, k, pq) | ||
} | ||
if (node.right != null) { | ||
dfs(node.right!!, k, pq) | ||
} | ||
} | ||
|
||
val pq = PriorityQueue { v1: Int, v2: Int -> v2 - v1 } | ||
dfs(node!!, k, pq) | ||
return pq.first() | ||
} | ||
|
||
// 3. 문제의 전제가 이진탐색트리이기에, 중위순회로 탐색하여 값을 누적하면 오름차순의 값이 된다. | ||
// 시간복잡도: O(n), 공간복잡도: O(n) | ||
private fun inorderTraversal(node: TreeNode?, k: Int): Int { | ||
fun dfs(node: TreeNode, k: Int, list: MutableList<Int>) { | ||
if (node.left != null) { | ||
dfs(node.left!!, k, list) | ||
} | ||
list.add(node.`val`) | ||
if (node.right != null) { | ||
dfs(node.right!!, k, list) | ||
} | ||
} | ||
|
||
return mutableListOf<Int>().apply { | ||
dfs(node!!, k, this) | ||
}[k - 1] | ||
} | ||
|
||
@Test | ||
fun `루트와 정수 k가 주어지면 트리에 있는 모든 노드의 값 중 가장 작은 값을 반환한다`() { | ||
kthSmallest(TreeNode.of(listOf(0, 3,1,4,null,2)), 1) shouldBeEqual 1 | ||
kthSmallest(TreeNode.of(listOf(0, 5,3,6,2,4,null,null,1)), 3) shouldBeEqual 3 | ||
} | ||
} | ||
|
||
class TreeNode(var `val`: Int) { | ||
var left: TreeNode? = null | ||
var right: TreeNode? = null | ||
|
||
companion object { | ||
fun of(numbers: List<Int?>): TreeNode? { | ||
fun setChild(node: TreeNode?, nums: List<Int?>, index: Int): TreeNode? { | ||
if (node == null) return null | ||
val (leftIndex, rightIndex) = index * 2 to index * 2 + 1 | ||
|
||
if (leftIndex < nums.size && nums[leftIndex] != null) { | ||
node.left = TreeNode(nums[leftIndex]!!) | ||
setChild(node.left, nums, leftIndex) | ||
} | ||
if (rightIndex < nums.size && nums[rightIndex] != null) { | ||
node.right = TreeNode(nums[rightIndex]!!) | ||
setChild(node.right, nums, rightIndex) | ||
} | ||
return node | ||
} | ||
return setChild(TreeNode(numbers[1]!!), numbers, 1) | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.equals.shouldBeEqual | ||
import org.junit.jupiter.api.Test | ||
|
||
class `number-of-1-bits` { | ||
|
||
fun hammingWeight(n: Int): Int { | ||
return bitOperation(n) | ||
} | ||
|
||
// 1. 직접 2진수를 구함 | ||
// 시간복잡도: O(log n), 공간복잡도: O(1) | ||
private fun binary(n: Int): Int { | ||
var calc = n | ||
var count = 0 | ||
while(calc > 0) { | ||
if (calc % 2 != 0) { | ||
count++ | ||
} | ||
calc /= 2 | ||
} | ||
return count | ||
} | ||
|
||
// 2. 비트 논리 연산자 사용 | ||
// 시간복잡도: O(log n), 공간복잡도: O(1) | ||
private fun bitOperation(n: Int): Int { | ||
var calc = n | ||
var count = 0 | ||
while (calc > 0) { | ||
if (calc and 1 == 1) { | ||
count ++ | ||
} | ||
calc = calc shr 1 | ||
} | ||
return count | ||
} | ||
|
||
@Test | ||
fun `이진수에서_0이_아닌_성분의_개수를 반환한다`() { | ||
hammingWeight(11) shouldBeEqual 3 | ||
hammingWeight(128) shouldBeEqual 1 | ||
hammingWeight(2147483645) shouldBeEqual 30 | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.equals.shouldBeEqual | ||
import org.junit.jupiter.api.Test | ||
|
||
class `palindromic-substrings` { | ||
|
||
fun countSubstrings(s: String): Int { | ||
return dp(s) | ||
} | ||
|
||
// 1. 브루트포스 3중 반복문 | ||
// 시간복잡도: O(n^3), 공간복잡도: O(1) | ||
private fun bruteForce(s: String): Int { | ||
|
||
fun isPalindrome(text: String, left: Int, right: Int): Boolean { | ||
var (start, end) = left to right | ||
while (start < end) { | ||
if (text[start] != text[end]) { | ||
return false | ||
} | ||
start++ | ||
end-- | ||
} | ||
return true | ||
} | ||
|
||
var count = 0 | ||
s.indices.forEachIndexed { left, _ -> | ||
(left until s.length).forEach { right -> | ||
if (isPalindrome(s, left, right)) { | ||
count++ | ||
} | ||
} | ||
} | ||
return count | ||
} | ||
|
||
// 2. 문자열의 길이가 홀수,짝수를 감안하여 특정 지점부터 두 개의 포인터 left , right를 비교한다. | ||
// 시간복잡도: O(n^2), 공간복잡도: O(1) | ||
private fun twoPointer(s: String): Int { | ||
|
||
fun palindromeCount(text: String, left: Int, right: Int): Int { | ||
var count = 0 | ||
var (l , r) = left to right | ||
while (l >= 0 && r < text.length && text[l--] == text[r++]) { | ||
count++ | ||
} | ||
return count | ||
} | ||
|
||
var result = 0 | ||
s.indices.forEachIndexed { index, e -> | ||
val even = palindromeCount(s, index, index + 1) | ||
val odd = palindromeCount(s, index - 1, index + 1) | ||
result += even + odd + 1 | ||
} | ||
|
||
return result | ||
} | ||
|
||
// 3. DP : 이전에 비교했던 결과를 기억하여 (현재 주어진 start, end 비교) && (이전 start, end 비교) | ||
// 시간복잡도: O(n^2), 공간복잡도: O(n^2) | ||
private fun dp(s: String): Int { | ||
val len = s.length | ||
val dp = Array(len) { BooleanArray(len) { false } } | ||
|
||
for (end in 0 until len) { | ||
for (start in end downTo 0) { | ||
if (start == end) { | ||
dp[start][end] = true | ||
} else if (start + 1 == end) { | ||
dp[start][end] = s[start] == s[end] | ||
} else { | ||
dp[start][end] = s[start] == s[end] && dp[start + 1][end - 1] | ||
} | ||
} | ||
} | ||
|
||
return dp.sumOf { row -> row.count { it } } | ||
} | ||
|
||
@Test | ||
fun `주어진 문자열의 회문인 부분 문자열의 개수를 반환한다`() { | ||
countSubstrings("abc") shouldBeEqual 3 | ||
countSubstrings("aaa") shouldBeEqual 6 | ||
countSubstrings("ababa") shouldBeEqual 9 | ||
countSubstrings("abcda") shouldBeEqual 5 | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
import java.util.PriorityQueue | ||
|
||
class `top-k-frequent-elements` { | ||
|
||
fun topKFrequent(nums: IntArray, k: Int): IntArray { | ||
return third(nums, k) | ||
} | ||
|
||
// 1. Map 정렬 | ||
// 시간복잡도: O(n * log(n)), 공간복잡도: O(n) | ||
private fun first(nums: IntArray, k: Int): IntArray { | ||
val map = mutableMapOf<Int, Int>() | ||
|
||
nums.forEach { | ||
map.compute(it) { _, oldValue -> | ||
if (oldValue == null) 1 | ||
else oldValue + 1 | ||
} | ||
} | ||
|
||
return map.entries.sortedByDescending { it.value } | ||
.map { it.key } | ||
.slice(0 until k) | ||
.toIntArray() | ||
} | ||
|
||
// 2. 우선순위 큐 | ||
// 시간복잡도: O(n * log(k)), 공간복잡도: O(n + k) | ||
private fun second(nums: IntArray, k: Int): IntArray { | ||
val map = mutableMapOf<Int, Int>() | ||
|
||
nums.forEach { map.put(it, map.getOrDefault(it, 0) + 1) } | ||
|
||
val heap: PriorityQueue<Map.Entry<Int, Int>> = PriorityQueue<Map.Entry<Int, Int>> { | ||
v1, v2 -> v2.value.compareTo(v1.value) | ||
}.apply { | ||
this.addAll(map.entries) | ||
} | ||
|
||
return (0 until k).map { heap.poll().key }.toIntArray() | ||
} | ||
|
||
// 3. 이차원배열로 빈번도 저장 | ||
// 시간복잡도: O(n), 공간복잡도: O(n) | ||
private fun third(nums: IntArray, k: Int): IntArray { | ||
val map = mutableMapOf<Int, Int>() | ||
|
||
nums.forEach { map.put(it, map.getOrDefault(it, 0) + 1) } | ||
|
||
val freq = Array<MutableList<Int>>(nums.size + 1) { mutableListOf() } | ||
map.entries.forEach { | ||
val frequency = it.value | ||
freq[frequency].add(it.key) | ||
} | ||
|
||
val result = IntArray(k) | ||
var index = 0 | ||
(freq.size - 1 downTo 0).forEach { i -> | ||
freq[i].forEach { | ||
result[index++] = it | ||
if (index == k) { | ||
return result | ||
} | ||
} | ||
} | ||
|
||
return IntArray(0) | ||
} | ||
|
||
@Test | ||
fun `배열에서_가장_빈도가_높은_K개의_원소를_출력한다`() { | ||
topKFrequent(intArrayOf(1,1,1,2,2,3), 2) shouldBe intArrayOf(1,2) | ||
topKFrequent(intArrayOf(1,1,1,2,2,3,3,4), 3) shouldBe intArrayOf(1,2,3) | ||
topKFrequent(intArrayOf(2,2,3,3,1,1,4), 3) shouldBe intArrayOf(2,3,1) | ||
topKFrequent(intArrayOf(4,1,-1,2,-1,2,3), 2) shouldBe intArrayOf(-1,2) | ||
|
||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
코틀린은
>>
를shr
으로 표현하는군요자바 유저라 처음보는데 재밌네요 ㅎㅎ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 비트 연산자는 처음 써봐서 ㅎㅎ 이번에 처음 배웠습니당