-
-
Notifications
You must be signed in to change notification settings - Fork 195
[JisooPyo] Week 1 #643
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
[JisooPyo] Week 1 #643
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
/** | ||
* Leetcode | ||
* 217. Contains Duplicate | ||
* Easy | ||
*/ | ||
class ContainsDuplicate { | ||
/** | ||
* Runtime: 17 ms(Beats: 80.99 %) | ||
* Time Complexity: O(n) | ||
* - 배열 순회 | ||
* | ||
* Memory: 50.63 MB(Beats: 70.32 %) | ||
* Space Complexity: O(n) | ||
* - HashSet에 최악의 경우 배열 원소 모두 저장 | ||
*/ | ||
fun containsDuplicate(nums: IntArray): Boolean { | ||
val set = hashSetOf<Int>() | ||
for (i in nums) { | ||
if (set.contains(i)) { | ||
return true | ||
} | ||
set.add(i) | ||
} | ||
return false | ||
} | ||
|
||
@Test | ||
fun test() { | ||
containsDuplicate(intArrayOf(1, 2, 3, 1)) shouldBe true | ||
containsDuplicate(intArrayOf(1, 2, 3, 4)) shouldBe false | ||
containsDuplicate(intArrayOf(1, 1, 1, 3, 3, 4, 3, 2, 4, 2)) shouldBe true | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
import kotlin.math.max | ||
|
||
/** | ||
* Leetcode | ||
* 198. House Robber | ||
* Medium | ||
* | ||
* 사용된 알고리즘: Dynamic Programming | ||
* | ||
* i번째 집에서 얻을 수 있는 최대 금액은 다음 두 가지 중 큰 값입니다. | ||
* - (i-2)번째 집까지의 최대 금액 + 현재 집의 금액 | ||
* - (i-1)번째 집까지의 최대 금액 | ||
*/ | ||
class HouseRobber { | ||
/** | ||
* Runtime: 0 ms(Beats: 100.00 %) | ||
* Time Complexity: O(n) | ||
* | ||
* Memory: 34.65 MB(Beats: 40.50 %) | ||
* Space Complexity: O(n) | ||
*/ | ||
fun rob(nums: IntArray): Int { | ||
if (nums.size == 1) { | ||
return nums[0] | ||
} | ||
if (nums.size == 2) { | ||
return max(nums[0], nums[1]) | ||
} | ||
val dp = IntArray(nums.size) | ||
dp[0] = nums[0] | ||
dp[1] = max(nums[0], nums[1]) | ||
for (i in 2 until nums.size) { | ||
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]) | ||
} | ||
return dp[nums.size - 1] | ||
} | ||
|
||
/** | ||
* 공간 복잡도를 개선 | ||
* Runtime: 0 ms(Beats: 100.00 %) | ||
* Time Complexity: O(n) | ||
* | ||
* Memory: 34.95 MB(Beats: 36.98 %) | ||
* Space Complexity: O(1) | ||
*/ | ||
fun rob2(nums: IntArray): Int { | ||
if (nums.size == 1) return nums[0] | ||
if (nums.size == 2) return max(nums[0], nums[1]) | ||
|
||
var twoBack = nums[0] | ||
var oneBack = max(nums[0], nums[1]) | ||
var current = oneBack | ||
|
||
for (i in 2 until nums.size) { | ||
current = max(twoBack + nums[i], oneBack) | ||
twoBack = oneBack | ||
oneBack = current | ||
} | ||
|
||
return current | ||
} | ||
|
||
@Test | ||
fun test() { | ||
rob(intArrayOf(1, 2, 3, 1)) shouldBe 4 | ||
rob(intArrayOf(2, 7, 9, 3, 1)) shouldBe 12 | ||
rob2(intArrayOf(1, 2, 3, 1)) shouldBe 4 | ||
rob2(intArrayOf(2, 7, 9, 3, 1)) shouldBe 12 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
import kotlin.math.max | ||
|
||
/** | ||
* Leetcode | ||
* 128. Longest Consecutive Sequence | ||
* Medium | ||
*/ | ||
class LongestConsecutiveSequence { | ||
/** | ||
* Runtime: 58 ms(Beats: 79.06 %) | ||
* Time Complexity: O(n) | ||
* - while 루프의 총 반복 횟수는 n을 넘을 수 없다. | ||
* | ||
* Memory: 62.65 MB(Beats: 10.48 %) | ||
* Space Complexity: O(n) | ||
*/ | ||
fun longestConsecutive(nums: IntArray): Int { | ||
val numsSet: MutableSet<Int> = nums.toHashSet() | ||
val startSet: MutableSet<Int> = hashSetOf() | ||
|
||
// 수열의 시작점이 될 수 있는 수를 찾는다. | ||
for (num in numsSet) { | ||
if (!numsSet.contains(num - 1)) { | ||
startSet.add(num) | ||
} | ||
} | ||
var answer = 0 | ||
for (start in startSet) { | ||
// 수열의 시작점부터 몇 개 까지 numsSet에 있는지 확인한다. | ||
var count = 0 | ||
var first = start | ||
while (numsSet.contains(first)) { | ||
first++ | ||
count++ | ||
} | ||
// 최대 수열의 개수를 업데이트한다. | ||
answer = max(answer, count) | ||
} | ||
return answer | ||
} | ||
|
||
/** | ||
* 위 풀이에서 startSet을 제거하여 공간적으로 효율적인 풀이 | ||
* Runtime: 63 ms(Beats: 65.70 %) | ||
* Time Complexity: O(n) | ||
* | ||
* Memory: 58.47 MB(Beats: 70.81 %) | ||
* Space Complexity: O(n) | ||
*/ | ||
fun longestConsecutive2(nums: IntArray): Int { | ||
val numsSet = nums.toHashSet() | ||
var maxLength = 0 | ||
|
||
for (num in numsSet) { | ||
if (!numsSet.contains(num - 1)) { | ||
var currentNum = num | ||
var currentLength = 0 | ||
|
||
while (numsSet.contains(currentNum)) { | ||
currentLength++ | ||
currentNum++ | ||
} | ||
maxLength = max(maxLength, currentLength) | ||
} | ||
} | ||
return maxLength | ||
} | ||
|
||
@Test | ||
fun test() { | ||
longestConsecutive(intArrayOf(100, 4, 200, 1, 3, 2)) shouldBe 4 | ||
longestConsecutive(intArrayOf(0, 3, 7, 2, 5, 8, 4, 6, 0, 1)) shouldBe 9 | ||
|
||
longestConsecutive2(intArrayOf(100, 4, 200, 1, 3, 2)) shouldBe 4 | ||
longestConsecutive2(intArrayOf(0, 3, 7, 2, 5, 8, 4, 6, 0, 1)) shouldBe 9 | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
import java.util.* | ||
|
||
/** | ||
* Leetcode | ||
* 347. Top K Frequent Elements | ||
* Medium | ||
*/ | ||
class TopKFrequentElements { | ||
/** | ||
* Runtime: 30 ms(Beats: 68.62 %) | ||
* Time Complexity: O(n log n) | ||
* - list 정렬 | ||
* | ||
* Memory: 42.20 MB(Beats: 58.82 %) | ||
* Space Complexity: O(n) | ||
*/ | ||
fun topKFrequent(nums: IntArray, k: Int): IntArray { | ||
val countMap: MutableMap<Int, Int> = HashMap() | ||
|
||
for (num in nums) { | ||
countMap[num] = countMap.getOrDefault(num, 0) + 1 | ||
} | ||
|
||
val list = mutableListOf<Node>() | ||
for (key in countMap.keys) { | ||
list.add(Node(key, countMap[key]!!)) | ||
} | ||
list.sortDescending() | ||
|
||
val answer = IntArray(k) | ||
for (i in 0 until k) { | ||
answer[i] = list[i].value | ||
} | ||
return answer | ||
} | ||
|
||
/** | ||
* 개선된 버전: 우선순위 큐를 사용 | ||
* | ||
* Runtime: 19 ms(Beats: 96.30 %) | ||
* Time Complexity: O(n log n) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PriorityQueue에 n개를 삽입하고 k개를 꺼냈으니 O(n log k)가 맞지 않을까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @EgonD3V 리뷰 감사합니다!
따라서 전체 시간 복잡도는
여기서 m은 최대 n이 될 수 있으므로 O(n log n)이 됩니다! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 아! PriorityQueue의 크기를 k로 제한하면 O(n log k)로 더 최적화 할 수 있겠네요..! |
||
* | ||
* Memory: 44.83 MB(Beats: 18.35 %) | ||
* Space Complexity: O(n) | ||
*/ | ||
fun topKFrequent2(nums: IntArray, k: Int): IntArray { | ||
val countMap = nums.groupBy { it } | ||
.mapValues { it.value.size } | ||
|
||
val pq = PriorityQueue<Node>(compareByDescending { it.count }) | ||
countMap.forEach { (num, count) -> | ||
pq.offer(Node(num, count)) | ||
} | ||
|
||
return IntArray(k) { pq.poll().value } | ||
} | ||
|
||
data class Node(var value: Int, var count: Int) : Comparable<Node> { | ||
override fun compareTo(other: Node): Int { | ||
return this.count.compareTo(other.count) | ||
} | ||
} | ||
|
||
@Test | ||
fun test() { | ||
topKFrequent(intArrayOf(1, 1, 1, 2, 2, 3), 2) shouldBe intArrayOf(1, 2) | ||
topKFrequent(intArrayOf(1), 1) shouldBe intArrayOf(1) | ||
|
||
topKFrequent2(intArrayOf(1, 1, 1, 2, 2, 3), 2) shouldBe intArrayOf(1, 2) | ||
topKFrequent2(intArrayOf(1), 1) shouldBe intArrayOf(1) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package leetcode_study | ||
|
||
import io.kotest.matchers.shouldBe | ||
import org.junit.jupiter.api.Test | ||
|
||
/** | ||
* Leetcode | ||
* 125. Valid Palindrome | ||
* Easy | ||
*/ | ||
class ValidPalindrome { | ||
/** | ||
* Runtime: 4 ms(Beats: 98.27 %) | ||
* Time Complexity: O(n) | ||
* | ||
* Memory: 38.22 MB(Beats: 46.74 %) | ||
* Space Complexity: O(1) | ||
*/ | ||
fun isPalindrome(s: String): Boolean { | ||
var left = 0 | ||
var right = s.length - 1 | ||
while (left <= right) { | ||
when (s[left]) { | ||
// 왼쪽의 문자가 alphanumeric일 때 | ||
in 'a'..'z', in 'A'..'Z', in '0'..'9' -> { | ||
|
||
when (s[right]) { | ||
// 오른쪽의 문자가 alphanumeric일 때 | ||
in 'a'..'z', in 'A'..'Z', in '0'..'9' -> { | ||
// 문자 비교 | ||
if (s[left].equals(s[right], true)) { | ||
left++ | ||
right-- | ||
continue | ||
} else { | ||
return false | ||
} | ||
} | ||
// 오른쪽의 문자가 alphanumeric이 아닐 때 | ||
else -> { | ||
right-- | ||
continue | ||
} | ||
} | ||
} | ||
|
||
// 왼쪽의 문자가 alphanumeric이 아닐 때 | ||
else -> { | ||
left++ | ||
continue | ||
} | ||
} | ||
} | ||
return true | ||
} | ||
|
||
/** | ||
* 개선한 버전 | ||
* Runtime: 5 ms(Beats: 87.14 %) | ||
* Time Complexity: O(n) | ||
* | ||
* Memory: 37.76 MB(Beats: 61.52 %) | ||
* Space Complexity: O(1) | ||
*/ | ||
fun isPalindrome2(s: String): Boolean { | ||
var left = 0 | ||
var right = s.length - 1 | ||
|
||
while (left < right) { | ||
// 왼쪽에서 유효한 문자를 찾음 | ||
while (left < right && !s[left].isLetterOrDigit()) { | ||
left++ | ||
} | ||
|
||
// 오른쪽에서 유효한 문자를 찾음 | ||
while (left < right && !s[right].isLetterOrDigit()) { | ||
right-- | ||
} | ||
|
||
// 문자 비교 | ||
if (!s[left].equals(s[right], ignoreCase = true)) { | ||
return false | ||
} | ||
|
||
left++ | ||
right-- | ||
} | ||
return true | ||
} | ||
|
||
@Test | ||
fun test() { | ||
isPalindrome("A man, a plan, a canal: Panama") shouldBe true | ||
isPalindrome("race a car") shouldBe false | ||
isPalindrome(" ") shouldBe true | ||
|
||
isPalindrome2("A man, a plan, a canal: Panama") shouldBe true | ||
isPalindrome2("race a car") shouldBe false | ||
isPalindrome2(" ") shouldBe true | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.
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.
요렇게 하면
currentNum
변수를 사용할 필요가 없어져서 코드가 더 간단해지지 않을까 생각해보았습니다. (안 중요)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.
@DaleSeo 오 그렇네요! 리뷰 감사합니다!!
(ps. 안 중요 -> 중요)