오늘 공부한 내용 정리(2024년 5월 30일)
1. 코드카타 문제풀이
A. 둘만의 암호
문제 내용
문제 풀이 방법
- s의 각 문자들을 index만큼 뒤로 옮기기(a -> b -> c...)
- 옮기는 문자들 중에 skip에 문자가 포함되어 있으면 그 문자를 제외(건너뜀)
- 문자가 z를 넘어가면 a로 다시 돌아가서 옮기기 시작.
해결 코드(스포 주의)
더보기
// s의 각 문자를 index만큼 뒤로 옮기기
// 옮기는 문자가 skip에 포함되어 있는 경우, 제외하고 넘어가기
// 문자가 z를 넘어가면 a로 돌아가서 다시 시작.
fun solution(s: String, skip: String, index: Int): String {
var answer: String = ""
var move = 0
val rollbackCode = 97
s.forEach { char ->
var charCode = char.code
while (move < index) {
charCode++
if (charCode > 122) charCode = rollbackCode
if (skip.contains(charCode.toChar())) continue
move++
}
move = 0
answer += charCode.toChar()
}
return answer
}
풀이 과정
- s의 각 문자들을 code 화해서 charCode에 저장(a = 97, z = 122)
- charCode를 1씩 더하고, charCode가 122를 넘어가면(z를 넘김) a로 롤백하고, skip에 charCode.toChar()가 포함되어 있으면 건너뛰기.
두 조건을 모두 수행하고 나면 얼마나 글자를 이동시켰는지에 대한 변수인 move를 +1. 이를 move가 index와 같아질 때까지 반복. - while을 빠져나온 후, move를 0으로 초기화하고 answer에 charCode를 Char로 바꿔서 넣어주기.
문제 해결 과정
- z를 넘어갔을 때의 조건과, skip이 charCode를 Char로 바꿨을 때 포함되는지 확인하는 조건의 순서를 올바르게 하지 않았었다.
만약 문자가 z이고 skip이 za 일 때 포함 조건을 z를 넘어갔을 때 조건보다 먼저 쓰게 되면 z -> { 가 되는데 포함 조건을 넘어가게 돼서 z -> {(a)가 된다 정상적인 동작은 z -> a -> b가 되어야 한다.
z를 넘어갔을 때의 조건을 먼저 사용하면 z(122)를 넘어가면 바로 a로 바꾸고 그럼 정상적으로 skip에 문자가 포함되어 있는지 체크할 수 있다.
2. 개인 공부
A. 괄호(백준, 9012번)
문제 내용
문제 풀이 방법
- 괄호 문자열이 주어졌을 때, 괄호 문자열이 올바른 괄호 문자열인지 확인해 return.
"()"는 올바른 괄호 문자열이고, ")("는 올바르지 않은 괄호 문자열이다.
해결 코드(스포 주의)
더보기
import java.util.Scanner
fun main() = with(Scanner(System.`in`)) {
val case = nextInt()
repeat(case) {
val parenthesis = next()
val parenthesisList = parenthesis.toMutableList()
var result = "YES"
while (parenthesisList.contains('(')) {
if (parenthesisList[0] == '(') {
parenthesisList.removeAt(0)
val matchIndex = parenthesisList.indexOf(')')
if (matchIndex != -1) {
parenthesisList.removeAt(matchIndex)
} else {
result = "NO"
break
}
} else {
result = "NO"
break
}
}
if (parenthesisList.isNotEmpty()) result = "NO"
println(result)
}
}
풀이 과정
- 괄호 문자열을 받는 parentgesis를 생성.
parentgesis를 list로 변환한 parentgesisList도 생성. - parentgesisList에서 괄호의 시작인 '(' 데이터가 없을 때까지 반복한다.
- parentgesisList의 첫 번째 데이터가 시작 괄호가 아니면 올바른 괄호 문자열이 될 수 없다.
- 첫 번째 데이터가 시작 괄호면 끝 괄호 ')' 데이터가 어떤 index에 있는지 확인하고 parentgesisList의 데이터를 괄호에 맞게 지워 나간다.
- 위 과정을 반복하면 while문을 빠져나오게 되는데, 이때 parentgesisList에 데이터가 남아 있으면 올바르지 않은 괄호 문자열이다.
B. 2 x n 타일링(백준, 11726번)
문제 내용
문제 풀이 방법
- 세로가 2로 고정되어 있고 가로가 n인 직사각형을 1x2, 2x1 타일로 채우는 방법의 경우의 수를 구하기.
- 경우의 수를 구하는 것이 아닌 경우의 수에 10007을 나눈 값을 출력해야 한다.
해결 코드(스포 주의)
더보기
import java.util.Scanner
fun main() = with(Scanner(System.`in`)) {
val width = nextInt()
var prev: Long = 0
var curr: Long = 1
// 0 1 2 3 5 8 13 21 34 55
for (i in 1..width) {
val temp = curr
curr = (curr + prev) % 10007
prev = temp
}
println(curr)
}
풀이 과정
- 피보나치 수열 알고리즘을 이용한 풀이.
- 재귀를 사용하면 숫자가 커질수록 재귀가 깊어져 시간 초과가 발생하기 때문에 반복문을 사용.
- 피보나치 수열 결과 변수인 curr에 값을 넣고 나서 10007로 나눈 나머지를 넣어준다.
문제 해결 과정
- 피보나치 수열에 대해 알지 못하면 풀기가 어려워 보이는 문제였다.
문제를 피보나치 수열로 풀어야 한다는 것을 깨닫게 되면 공짜 문제가 된다. - n을 1부터 9까지 모든 경우의 수를 일일이 적어놓고 보니 피보나치 수열의 규칙과 흡사해서 피보나치 수열 알고리즘을 공부하고 문제를 해결하였다.
C. AC(백준, 5430번)
문제 내용
문제 풀이 방법
- 테스트 케이스의 개수(T)와 수행할 함수가 주어진다. 함수는 R, D가 있다.
배열의 길이와 배열 형태("[1,2,3....]")의 데이터를 string으로 입력받는다. - 입력받은 배열에서 함수에 맞는 기능을 수행한(R: 배열 뒤집기, D: 버리기) 결과를 출력.
D를 수행할 때, 버릴 데이터가 없으면 error를 출력.
해결 코드(스포 주의)
더보기
import java.io.BufferedReader
import java.io.InputStreamReader
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val case = readLine().toInt()
repeat(case) {
val command = readLine()
val arrLength = readLine().toInt()
val inputArr = readLine()
val arrStr = StringBuilder(inputArr.substring(1, inputArr.length-1))
// string이 뒤집히는지 확인하기 위함.
var isReserved = false
var error = ""
for (cmd in command) {
when (cmd) {
// true 배열이 뒤집힘.
// false 배열이 원래 방향으로 돌아옴.
'R' -> isReserved = !isReserved
'D' -> {
if (arrStr.isEmpty()) {
error = "error"
break
} else {
if (isReserved) {
val comma = arrStr.lastIndexOf(",")
if (comma != -1) arrStr.delete(comma, arrStr.length)
else arrStr.deleteRange(0, arrStr.length)
} else {
val comma = arrStr.indexOf(",")
if (comma != -1) arrStr.delete(0, comma + 1)
else arrStr.deleteRange(0, arrStr.length)
}
}
}
}
}
val resultList = arrStr.split(",")
if (error.isEmpty()) {
if (isReserved) println("[${resultList.reversed().joinToString(",")}]")
else println("[${resultList.joinToString(",")}]")
}
else println(error)
}
}
풀이 과정
- command(함수 명령어), arrLength(입력받을 배열의 길이), inputArr(배열 형태의 문자열)을 입력받는다.
inputArr를 String형태로 변환한(대괄호 제거) arrStr 데이터 생성.
command에서 R 함수의 기능을 수행했는지를 판단할 isReserved 생성.
에러가 발생했을 때, "error" 문자열을 넣을 error 변수를 생성. - command의 문자를 반복문으로 돌려서 어떤 문자인지 확인한다.
R인 경우는 isReserved를 반대로 저장한다. string에 reserved()를 안 쓴 이유는 문제 해결에 언급함. - D인 경우는 isReserved 상태에 따라 로직이 다르다.
arrStr이 비어 있는 경우에 데이터가 없다는 뜻이 되기 때문에 "error"를 대입한다.
arrStr 데이터는 1,2,3,4... 와 같은 콤마(,)가 포함된 문자열 데이터 형식이다.
지워야 할 데이터의 콤마 위치를 알기 위해 comma 변수를 생성한다. isReserved가 true일 때는 뒤집기가 된 상태이므로 마지막 콤마 index를 불러오고, false일 때는 첫 번째의 index를 불러온다.
comma 데이터가 존재할 경우(-1이 아님), arrStr에서 해당되는 숫자와 콤마를 같이 제거해 준다. -1인 경우는 숫자 데이터가 1개밖에 없거나 없는 경우이므로 완전 삭제를 해준다(deleteRange). - 함수 적용을 끝낸 arrStr에 split을 해서 list형태로 바꿔준다(resultList).
- error가 비어 있으면(error가 없음) isReserved 상태에 따라 뒤집힌 상태(true)이면 이때 list에 reserved()를 해주고 string으로 전환해 준다(joinToString). 뒤집히지 않은 상태이면 reserved를 하지 않고 출력한다.
문제 해결 과정
- 시간 초과와의 싸움.
시간 초과를 해결하기 위해 처음에 arrStr을 입력받고 나서 list로 command의 로직을 수행하려 했지만 StringBuilder로 수행함.
when 문에서 R일 때 무지성으로 reserved()를 하면 시간 초과가 나기 때문에 isReserved를 만들어 isReserved 상태에 따른 로직을 추가해 주었음. - command가 R이고, arrStr이 [12]일 경우 마지막 과정에 string을 list로 변환했다가 다시 string으로 변환하는 코드를 넣어주지 않으면 R이 수행되고 isReserved가 true이기 때문에 string에 reserved() 함수가 적용되는데, 출력이 다음과 같이 되게 된다. [21] 숫자 데이터는 1개밖에 없는데 위와 같은 오류가 나는 경우는 배열 데이터가 10 이상인 경우 reserved() 했을 때도 데이터가 정상적으로 들어가는지 확인하자.
D. 수 정렬하기(백준, 2751번)
문제 내용
문제 풀이 방법
- 간단한 오름차순 정렬 문제. 하지만 숫자의 개수가 백만개인.
- 입력이 백만 개까지 들어올 수 있어서 시간 초과의 우려가 큰 문제.
해결 코드(스포 주의)
더보기
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
fun main() = with(BufferedReader(InputStreamReader(System.`in`))) {
val case = readLine().toInt()
val inputStr = StringBuilder()
repeat(case) {
val num = readLine()
if (case-1 == it) inputStr.append(num)
else inputStr.append("$num,")
}
val list = inputStr.split(",").map { it.toInt() }
val bw = BufferedWriter(OutputStreamWriter(System.out))
list.sorted().forEach {
bw.write("$it\n")
}
bw.flush()
bw.close()
}
풀이 과정
- 숫자를 배열이 아닌 문자열로 입력받을 수 있도록 StringBuilder를 사용함.
- case의 개수만큼 반복하면서 inputStr에 데이터를 추가한다. 마지막 반복인 경우 같이 추가했던 콤마(,)를 추가하지 않는다.
- 바로 inputStr를 List<Int>타입으로 바꿔주고, bufferedWriter()를 이용해 println() 보다 더 빠른 출력을 할 수 있도록 했다.
문제 해결 과정
- 시간 초과를 해결하기 위해
배열로 입력 데이터를 저장 -> StringBuilder로 저장.
println()으로 출력 -> bw.write()로 출력으로 변경했다. - 다른 사람들 풀이를 보고 정렬 알고리즘을 사용한 코드가 많았는데 안 써도 돼서 다행이었다.
오늘 공부 내용 정리 및 회고
- 좀 티어가 높은 문제들을 풀어보았음.
- 티어가 오를수록 프로그래밍 실력 말고도 문제를 보고 특정한 규칙을 찾아 해결하는 문제가 많이 나오는 듯하다.
- 백준 silver 4 이상 문제부터 수학적 사고도 많이 필요할 것 같다. 수학 공식을 몰라서 검색을 해보는 경우가 많다.
728x90
'♞ | 공부일지 > ♝ | TIL' 카테고리의 다른 글
[Android, 내일배움캠프] 공부일지(2024-06-03) (0) | 2024.06.03 |
---|---|
[Android, 내일배움캠프] 공부일지(2024-05-31) (0) | 2024.05.31 |
[Android, 내일배움캠프] 공부일지(2024-05-29) (0) | 2024.05.29 |
[Android, 내일배움캠프] 공부일지(2024-05-28) (0) | 2024.05.28 |
[Android, 내일배움캠프] 공부일지(2024-05-27) (0) | 2024.05.27 |