Skip to content

Commit 7fc6066

Browse files
committed
3Sum
1 parent 49715e8 commit 7fc6066

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

3sum/JisooPyo.kt

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
package leetcode_study
2+
3+
import io.kotest.matchers.shouldBe
4+
import org.junit.jupiter.api.Test
5+
6+
/**
7+
* Leetcode
8+
* 15. 3Sum
9+
* Medium
10+
*/
11+
class `3Sum` {
12+
/**
13+
* 3중 for문으로 풀어봤는데 시간 초과가 되더라고요(당연)
14+
* 사실 잘 모르겠어서 Topic과 힌트를 살짝 봤는데 투 포인터가 있길래 이걸 이용해서 풀어보기로 했습니다!
15+
*
16+
* Runtime: 72 ms(Beats: 60.54 %)
17+
* Time Complexity: O(n^2)
18+
*
19+
* Memory: 56.28 MB(Beats: 49.51 %)
20+
* Space Complexity: O(n^2)
21+
*/
22+
fun threeSum(nums: IntArray): List<List<Int>> {
23+
val answer = mutableListOf<List<Int>>()
24+
// 배열 정렬 - 중복된 경우를 제거하고 효율적으로 탐색하기 위하여
25+
nums.sort()
26+
27+
// nums[i]의 이전 값을 의미합니다.
28+
var prev = Integer.MIN_VALUE
29+
for (i in nums.indices) {
30+
// 이전 값과 동일한 값이라면 스킵하여 중복된 경우를 제거합니다.
31+
if (nums[i] == prev) {
32+
continue
33+
}
34+
35+
// 투 포인터 알고리즘을 이용하여 다 더하여 0이 되는 경우의 수를 찾습니다.
36+
var left = i + 1
37+
var right = nums.size - 1
38+
while (left < right) {
39+
40+
if (nums[i] + nums[left] + nums[right] > 0) { // 합이 0보다 크다면 right를 줄입니다.
41+
// if 내에 있는 while문들은 중복 경우의 수를 피하기 위함입니다.
42+
while (0 <= right - 1 && nums[right - 1] == nums[right]) {
43+
right--
44+
}
45+
right--
46+
} else if (nums[i] + nums[left] + nums[right] < 0) { // 합이 0보다 적다면 left를 높입니다.
47+
while (left + 1 <= nums.size - 1 && nums[left] == nums[left + 1]) {
48+
left++
49+
}
50+
left++
51+
} else { // 합이 0이라면 경우의 수를 추가합니다.
52+
answer.add(listOf(nums[i], nums[left], nums[right]))
53+
while (left + 1 <= nums.size - 1 && nums[left] == nums[left + 1]) {
54+
left++
55+
}
56+
left++
57+
while (0 <= right - 1 && nums[right - 1] == nums[right]) {
58+
right--
59+
}
60+
right--
61+
}
62+
}
63+
prev = nums[i]
64+
}
65+
return answer
66+
}
67+
68+
/**
69+
* 시간 복잡도나 공간 복잡도가 개선되진 않았지만 가독성 측면에서 개선해본 버전입니다.
70+
* Runtime: 66 ms(Beats: 65.59 %)
71+
* Time Complexity: O(n^2)
72+
*
73+
* Memory: 56.64 MB(Beats: 43.12 %)
74+
* Space Complexity: O(n^2)
75+
*/
76+
fun threeSum2(nums: IntArray): List<List<Int>> {
77+
val answer = mutableListOf<List<Int>>()
78+
nums.sort()
79+
80+
// 첫 세 수의 합이 0보다 크거나, 마지막 세 수의 합이 0보다 작으면 불가능
81+
val lastIndex = nums.size - 1
82+
if (nums[0] + nums[1] + nums[2] > 0 ||
83+
nums[lastIndex] + nums[lastIndex - 1] + nums[lastIndex - 2] < 0
84+
) {
85+
return emptyList()
86+
}
87+
88+
var prev = nums[0] - 1
89+
for (i in nums.indices) {
90+
// 조기 종료 조건 추가
91+
if (nums[i] > 0) {
92+
break
93+
}
94+
if (nums[i] == prev) {
95+
continue
96+
}
97+
var left = i + 1
98+
var right = nums.size - 1
99+
while (left < right) {
100+
// 중복 로직 제거 및 sum 변수화
101+
val sum = nums[i] + nums[left] + nums[right]
102+
when {
103+
sum > 0 -> right = skipDuplicates(nums, right, false)
104+
sum < 0 -> left = skipDuplicates(nums, left, true)
105+
else -> {
106+
answer.add(listOf(nums[i], nums[left], nums[right]))
107+
left = skipDuplicates(nums, left, true)
108+
right = skipDuplicates(nums, right, false)
109+
}
110+
}
111+
}
112+
prev = nums[i]
113+
}
114+
return answer
115+
}
116+
117+
private fun skipDuplicates(nums: IntArray, index: Int, isLeft: Boolean): Int {
118+
var current = index
119+
return if (isLeft) {
120+
while (current + 1 < nums.size && nums[current] == nums[current + 1]) current++
121+
current + 1
122+
} else {
123+
while (0 <= current - 1 && nums[current - 1] == nums[current]) current--
124+
current - 1
125+
}
126+
}
127+
128+
@Test
129+
fun test() {
130+
threeSum(intArrayOf(-1, 0, 1, 2, -1, -4)) shouldBe listOf(
131+
listOf(-1, -1, 2),
132+
listOf(-1, 0, 1)
133+
)
134+
threeSum(intArrayOf(0, 1, 1)) shouldBe emptyList<Int>()
135+
threeSum(intArrayOf(0, 0, 0)) shouldBe listOf(
136+
listOf(0, 0, 0)
137+
)
138+
threeSum(intArrayOf(-2, 0, 0, 2, 2)) shouldBe listOf(
139+
listOf(-2, 0, 2)
140+
)
141+
threeSum2(intArrayOf(-1, 0, 1, 2, -1, -4)) shouldBe listOf(
142+
listOf(-1, -1, 2),
143+
listOf(-1, 0, 1)
144+
)
145+
threeSum2(intArrayOf(0, 1, 1)) shouldBe emptyList<Int>()
146+
threeSum2(intArrayOf(0, 0, 0)) shouldBe listOf(
147+
listOf(0, 0, 0)
148+
)
149+
threeSum2(intArrayOf(-2, 0, 0, 2, 2)) shouldBe listOf(
150+
listOf(-2, 0, 2)
151+
)
152+
}
153+
154+
}

0 commit comments

Comments
 (0)