오늘 공부한 내용 정리(2024년 6월 6일)
1. 알고리즘 문제풀이
A. 듣보잡(백준, S4, 1764번)
문제 내용
문제 풀이 방법
- 첫째 줄에 듣도 못한 사람의 수가 주어지고, 보도 못한 사람의 수가 주어질 때, 둘째 줄부터 듣도 못함 사람 이름부터 보도 못한 사람 이름 순서대로 입력된다.(듣도 못한 사람이 3이고, 보도 못한 사람이 4일 때 2번째 줄부터 7줄에 걸쳐서 입력이 주어짐)
- 입력받은 사람들 중 듣보잡의 수를 출력(듣도 못한 사람과 보도 못한 사람에 모두 포함되는 사람)
해결 코드(스포 주의)
더보기
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.util.*
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val people = readLine().split(" ").map { it.toInt() }
val noListen = mutableSetOf<String>()
for (i in 0 until people.first()) {
noListen.add(readLine())
}
val noSeen = mutableSetOf<String>()
for (i in 0 until people.last()) {
noSeen.add(readLine())
}
val bw = BufferedWriter(OutputStreamWriter(System.out))
val noListenSeen = noListen.intersect(noSeen).toTypedArray()
Arrays.sort(noListenSeen)
bw.write("${noListenSeen.size}\n")
for (i in noListenSeen.indices) {
bw.write("${noListenSeen[i]}\n")
}
bw.flush()
bw.close()
}
풀이 과정
- people로 첫째 줄의 입력을 처리하고, for문 2개를 이용해 연속된 입력을 처리(noListen, noSeen) 해 주었다.
- noListen, noSeen은 MutableSet 타입이고, noListen과 noSeen의 교집합(중복되는 데이터만) 연산을 수행한다.
- 그러면 중복되는 데이터들만 남게 되는데, 이 데이터들의 size와 데이터를 반복을 돌려서 출력.
문제 해결 과정
- 문제 해결에 어려움은 없었다. 이전에 한 번 접했던 교집합 함수를 사용하면 매우 쉽게 해결할 수 있는 문제.
B. 조합(백준, S3, 2407번)
문제 내용
문제 풀이 방법
- n과 m이 주어질 때, nCm(집합)을 수행해 출력.
집합 공식은 n! / (n-m)! * r!이다(! 는 팩토리얼을 뜻함)
해결 코드(스포 주의)
더보기
import java.util.*
fun main() = with(Scanner(System.`in`)) {
val n = nextInt()
val m = nextInt()
var factorialN = 1L.toBigInteger()
for (i in n-m+1 .. n) {
factorialN *= i.toBigInteger()
}
var factorialM = 1L.toBigInteger()
for (i in 1 .. m) {
factorialM *= i.toBigInteger()
}
println(factorialN / factorialM)
}
풀이 과정
- n과 m을 입력받고, m+1부터 n까지의 팩토리얼을 수행한다.
n이 6이고 m이 2일 때, 집합 공식을 이용하면 6! / 4! * 2! 이 되게 되는데, 약분으로 4! 을 지울 수 있다. 4! 을 지우고 나면
6 * 5 / 2 * 1이 남게 된다. 지금 현재 우리는 분자에 해당하는 데이터를 구하고 있기 때문에 6-2+1=5부터 6까지의 팩토리얼을 구하면 되기 때문에 분자 데이터는 30이다. - 분모 부분은 factorialM으로 처리한다. 이제 분모에는 m! 밖에 남지 않았기 때문에 평범하게 1부터 m까지 for를 돌려서 분모를 구하면 된다. 분모 데이터는 2
- 집합 공식에 따라 factorialN과 factorialM을 나눠준다. 결과: 15
문제 해결 과정
- 최대 숫자 제한이 100이지만, 팩토리얼을 해야 하기 때문에 숫자가 커질 경우에는 Long보다 커지는 경우도 있다.
- 이럴 때는 BigInteger 자료형을 사용한다. BigInteger는 Long과 달리 제한이 없이 무한이기 때문에 Long보다 큰 수를 다뤄야 할 때 적합하다.
- BigInteger 사용법을 익히고 적용해 쉽게 해결했다.
2. 과제 수행
A. 과제 내용
입력받은 연산식이 올바르지 않았을 때의 처리.
- 연산식을 입력받을 때 "3+4/"와 같은 연산 기호로 끝나는 경우에는 올바른 계산을 할 수 없으므로 예외처리 print를 출력하고 다시 입력받도록 코드를 변경했다.
연산 기호로 끝나는 경우 splitFormula가 [3, 4, ]로 받아지므로 splitFormula 중 데이터가 하나라도 비어 있는 경우 예외 처리 print를 출력하도록 했다.
. . .
// 정규 표현식을 이용한 수식 분할(여러 개의 문자를 기준으로 분할 가능함).
val splitFormula = formula.split("+", "-", "*", "/")
val splitFormulaSymbol = formula.filter { it in setOf('+', '-', '*', '/') }.map { it }
// splitFormula에서 숫자만 포함되도록 하기(정규 표현식 사용).
if (!splitFormula.all { it.matches(Regex("\\d*")) })
println("연산식이 문자를 포함하고 있습니다. 다시 시도해 주세요.")
else if (splitFormula.any { it.isEmpty() })
// splitFormula의 데이터 중 빈값이 존재함(연산식이 올바르게 끝나지 않음.)
println("연산식이 올바르게 끝나지 않았습니다. 다시 시도해 주세요.")
else {
calculation(
splitFormula = splitFormula,
splitFormulaSymbol = splitFormulaSymbol
)
}
. . .
사칙연산 우선순위 부여
- 사칙 연산을 할 때는 곱하기와 나누기가 우선적으로 실행되어야 하기 때문에 이를 고려한 로직을 짜야한다.
- 곱하기, 나누기 기호가 있는 경우 반복문을 돌려서 곱하기, 나누기 연산을 따로 해주고 연산에 사용한 연산 기호와 숫자를 제거하고, 연산 결과를 그대로 넣어주는 작업을 해주었다.
3+4*2를 splitFormula로 나타내면 [3, 4, 2]이고, splitFormulaSymbol로 나타내면 [+, *]가 된다.
위의 리스트에서 곱하기를 먼저 수행해야 하므로 *기호의 위치를 불러온 다음(index: 1) 해당 위치에 해당하는 splitFormula의 값과 위치의 +1 한 값을 연산해 준다. 그리고 리스트에서 사용한 데이터들을 지워준다.
[3, 4, 2] => [3], [+, *] => [+]
여기서 연산 결과를 splitFormula의 *기호 위치의 index에 넣어주면 된다.
[3] => [3, 8], [+]
위의 리스트를 바탕으로 더하기, 빼기를 하면 사칙 연산이 완료된다.
private fun calculation(splitFormula: List<String>, splitFormulaSymbol: List<Char>) {
// 수식을 입력받아 계산하기.
val calculator = Calculator()
val mutableSplitFormula = splitFormula.map { it.toInt() }.toMutableList()
val mutableSplitFormulaSymbol = splitFormulaSymbol.map { it.toString() }.toMutableList()
println(mutableSplitFormula)
println(mutableSplitFormulaSymbol)
// todo :: 계산 우선순위 부여해서 계산하도록 구현(*, /)
// 곱하기, 나누기를 우선으로 계산하기
// 먼저 곱하기, 나누기가 존재하는지 indexOf로 확인해야 함(초기값 -2).
var multiplyIndex = -2
var divideIndex = -2
// 곱하기, 나누기 기호가 없어질 때까지 반복.
while (multiplyIndex != -1 || divideIndex != -1) {
// 반복마다 곱하기, 나누기의 위치를 구함.
multiplyIndex = mutableSplitFormulaSymbol.indexOf("*")
divideIndex = mutableSplitFormulaSymbol.indexOf("/")
if (multiplyIndex < divideIndex) {
// 나누기가 더 먼저 있음
val divideResult = calculator.divide(mutableSplitFormula[divideIndex], mutableSplitFormula[divideIndex+1])
// 계산에 사용한 숫자 2개를 지운다.
mutableSplitFormula.removeAt(divideIndex)
mutableSplitFormula.removeAt(divideIndex)
// 계산에 사용한 나누기 기호를 지운다.
mutableSplitFormulaSymbol.removeAt(divideIndex)
// 나누기 계산 결과를 추가한다.
mutableSplitFormula.add(divideIndex, divideResult)
} else if (multiplyIndex > divideIndex) {
// 곱하기가 더 먼저 있음
val multiplyResult = calculator.multiply(mutableSplitFormula[multiplyIndex], mutableSplitFormula[multiplyIndex+1])
mutableSplitFormula.removeAt(multiplyIndex)
mutableSplitFormula.removeAt(multiplyIndex)
mutableSplitFormulaSymbol.removeAt(multiplyIndex)
mutableSplitFormula.add(multiplyIndex, multiplyResult)
}
}
var calculateResult = mutableSplitFormula[0]
mutableSplitFormula.removeAt(0)
while (mutableSplitFormula.size > 0) {
when (mutableSplitFormulaSymbol[0]) {
"+" -> calculateResult = calculator.add(calculateResult, mutableSplitFormula[0])
"-" -> calculateResult = calculator.minus(calculateResult, mutableSplitFormula[0])
}
mutableSplitFormula.removeAt(0)
mutableSplitFormulaSymbol.removeAt(0)
}
println("계산 결과: $calculateResult")
}
오늘 공부 내용 정리 및 회고
- 콘솔 계산기 과제는 lv.4까지 완료하고 추가 기능을 구현할까 생각 중이다.
아직 괄호에 따른 우선순위 부여를 하지 않았다. - Long보다 더 큰 수를 다룰 때 사용할 수 있는 BigInteger를 사용해 보았다. 내일은 백준에서 BigInteger를 사용할 수 있는 문제를 풀어볼 것이다.
- 코틀린 강의는 어제 4주 차까지 들었다. 5주 차를 수강할지 아니면 복습을 하면서 알고리즘 공부를 할지 고민해 봐야겠다.
728x90
'♞ | 공부일지 > ♝ | TIL' 카테고리의 다른 글
[Android, 내일배움캠프] 공부일지(2024-06-10) (0) | 2024.06.10 |
---|---|
[Android, 내일배움캠프] 공부일지(2024-06-07) (0) | 2024.06.07 |
[Android, 내일배움캠프] 공부일지(2024-06-05) (0) | 2024.06.06 |
[Android, 내일배움캠프] 공부일지(2024-06-04) (0) | 2024.06.04 |
[Android, 내일배움캠프] 공부일지(2024-06-03) (0) | 2024.06.03 |