6월 - syh39/ProblemSolving GitHub Wiki
괄호변환
-
난이도 : Level 2
-
풀이 여부 : Y
-
소요 시간 : 1시간
-
유형 : Recursion (재귀)
-
주의 사항: 파이썬에서 제공하는 Recursion Depth는 설정값에 따라 다르긴 하지만, default 값은 1000이기 때문에 제한사항을 잘 보고 Recursion, Iterator 중 잘 선택해야 한다. 여기서는 문자열 길이가 1000이하 이기 때문에 Recursion으로 해도 상관없음.(Recursion Depth를 500으로 잘못알고 있어서 Iterator한 방법으로 풀려다 시간이 더 걸림.)
-
풀이 방법: 기본적인 Logic 자체가 문제에 나와있기 때문에 이를 이해하고 해석하여 코딩을 한다.
#올바른 괄호 문자열
def validation(p):
stack = []
for s in p:
if s == "(":
stack.append(s)
else:
if stack == [] and s == ")":
return False
else:
stack.pop()
return stack == []
def reversed_para(p):
return "".join(["(" if s ==")" else ")" for s in p ])
def recursion(p):
if p == "":
return ""
u, v = "", ""
#균형잡힌 괄호 문자열
zero_sum = 0
#2. 문자열 w를 두 "균형잡힌 괄호 문자열" u, v로 분리합니다. 단, u는 "균형잡힌 괄호 문자열"로 더 이상 분리할 수 없어야 하며, v는 빈 문자열이 될 수 있습니다.
for s in p:
if zero_sum == 0 and u != "":
break
if s == "(":
zero_sum += 1
elif s == ")":
zero_sum -= 1
u += s
v = p.replace(u, "", 1)
#3. 문자열 u가 "올바른 괄호 문자열" 이라면 문자열 v에 대해 1단계부터 다시 수행합니다.
if validation(u):
return u + recursion(v)
#4. 문자열 u가 "올바른 괄호 문자열"이 아니라면 아래 과정을 수행합니다.
else:
return "(" + recursion(v) + ")" + reversed_para(u)[1:-1]
def solution(p):
#1. 입력이 빈 문자열인 경우, 빈 문자열을 반환합니다. & 만약 p가 이미 "올바른 괄호 문자열"이라면 그대로 return 하면 됩니다.
if p == "" or validation(p):
return p
return recursion(p)
N-Queen
-
출처: 연습문제
-
난이도 : Level 2
-
풀이 여부 : N
-
소요 시간 : 2시간
-
유형 : 완전탐색
-
풀이 방법: 위에서부터 모든 부분을 확인하면서, Queen 범위에 들어오는지 체크
-
Queen 범위 : 모든 가로, 세로, 대각선 --> 가로는 생각할 필요 없으므로, 세로, 대각선만 생각 (x1, y1), (x2, y2)가 있을 때,
- 세로 범위 : y1 == y2
- 대각선 범위 : abs(y1 - y2) == abs(x1 - x2)
이 범위 안에 들 경우 Queen 범위 안에 들기 때문에 체크 안함.
-
global answer
def check(result, cur_y, x):
for (row, col) in result:
# 세로 범위 & 대각선 범위에 드는지 확인
if col == x or abs(cur_y-row) == abs(x-col):
return False
return True
def queen(n, cur_y, result):
global answer
if cur_y == n:
answer += 1
return
for x in range(n):
if check(result, cur_y, x): #important 1
result.append((cur_y, x))
queen(n, cur_y+1, result[:])
result.pop() #important 2
def solution(n):
global answer
answer = 0
queen(n, 0, [])
return answer
- 틀린 이유:
- important 1 : 이 부분은 함수로 만들지 않고 구현했었는데, 함수로 구현 하지 않으면 이중 포문이 되고, Queen 범위를 체크하는 논리 구현이 힘들었음.
- important 2 : Queen을 놓으면서 체크하고 release를 해주어야 했는데, 하지 않으니 result 리스트에 Queen들이 쌓이게 되고 원하는 결과를 못 얻음.
멀리뛰기
-
출처: 연습문제
-
난이도 : Level 2
-
풀이 여부 : Y
-
소요 시간 : 30분
-
유형 : DP
-
풀이 방법: 규칙만 찾으면 되는 문제
칸의 개수 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
1개 | 2개 | 3개 | 5개 | 8개 |
- dp[1] = 1
- dp[2] = 2
- dp[n] = dp[n-2] + dp[n-1]
줄 서는 방법
-
출처: 연습문제
-
난이도 : Level 2
-
풀이 여부 : N
-
소요 시간 : 2시간
-
유형 : 구현
-
못 푼 이유: 효율성 때문에
- 첫번째 시도: itertools 에 있는 permutations 사용 --> 시간초과
- 두번째 시도: permutations을 사용하되, 해당 k번째에 해당하면 바로 return --> 효율성 x
-
풀이 방법: 모든 경우를 보는 것이 아니라 해당하는 k번째 순서를 바로 아는 방법. 숫자들로 분류하고, 작은 문제로 쪼개는 방식.
n=3, k=4 일때, arr = [1, 2, 3]
1 [1, 2, 3]
2 [1, 3, 2]
3 [2, 1, 3]
4 [2, 3, 1] <-- 정답
5 [3, 1, 2]
6 [3, 2, 1]
첫번째 index에 있는 숫자들은 뒤에 있는 숫자들의 경우의 수로 개수가 정해짐. [1, 2, 3] [1, 3, 2]
--> (2, 3), (3, 2) 로 1의 개수가 정해짐.
--> 3! / 3 == 2! == 2 --> 즉, 첫번째 index의 숫자들은 2개로 쪼개짐.
--> 이렇게 하는 이유는, k번째 첫번째 index를 찾기 위해
import math
'''
offset: 맨 앞으로 있는 숫자를 기준으로 나누어주는 변수
k: 찾고자 하는 index
'''
def solution(n, k):
answer = []
#초기화
arr = list(range(1, n+1))
while n != 0:
offset = math.factorial(n-1)
index = (k-1)//offset
answer.append(arr.pop(index))
k = offset if k%offset==0 else k%offset
n -= 1
return answer
파일명 정렬
-
난이도 : Level 2
-
풀이 여부 : Y
-
소요 시간 : 30분
-
유형 : 정렬
-
풀이 방법:
- 문자열 --> HEADER와 NUMBER 분리
- HEADER정렬 --> NUMBER 정렬순
def split(s):
list_str = list(s.upper())
header, number = "", "0"
# HEADER 분리
while True:
if list_str[0].isdigit():
break
header += list_str.pop(0)
# NUMBER 분리
while True:
if list_str == [] or not list_str[0].isdigit():
break
number += list_str.pop(0)
return (header, int(number), s)
def solution(files):
result = [split(f) for f in files]
# HEADER정렬 --> NUMBER 정렬순
result.sort(key=lambda x: (x[0], x[1])) # sorted(result, kay=lambda x: (x[0], x[1]))
return [r[2] for r in result] # [s for header, number, s in result]
H-Index
-
출처: 정렬
-
난이도 : Level 2
-
풀이 여부 : Y
-
소요 시간 : 40분
-
유형 : 정렬
-
풀이 방법: 그냥 읽고 풀면 되는데, 말장난 같은 문제. 어휘력 테스트 같은 문제임. 별로 안 좋은 문제 같음. 안 푸는 것을 추천
파일명 정렬
-
난이도 : Level 2
-
풀이 여부 : Y
-
소요 시간 : 40분
-
유형 : 구현
-
풀이 방법:
- 주어진 n을 k진수로 바꾼다 (conversion 함수). 단, 바뀌어진 n값에 "0"의 포함 여부를 확인해야 하므로 output 값은 String type으로 함.
- 바꿔진 n값을 windowing하면서(offset 변수) 소수가 있는지 판별 (isPrime 함수) 한다.
- 만일, 소수라면 문제에서 주어진 조건들을 확인한다. !! isPrime 함수에서 기본적인 O(n) 시간복잡도가 되도록 짜면, 시간초과가 뜬다. n을 k진수로 바꾸었을 때, 바뀌어진 n값이 10진수로 봤을 때 억단위가 될 수도 있음.
#시간복잡도: O(n)
def isPrime(target):
target = int(target)
if target < 2:
return False
for n in range(2, target):
if target % n == 0:
return False
return True
--> 이에 대한 해결 방법으로 제곱근(sqrt)나 더 효율적인 것으로 유명한 에라토스테네스의 체를 사용하면 된다. (경험상, 제곱근까지만 써도 왠만해서 다 통과됨. 백준 문제 제외)
#시간복잡도: O(n^(1/2))
import math
def isPrime(target):
target = int(target)
if target < 2:
return False
for n in range(2, int(math.sqrt(target))+1):
if target % n == 0:
return False
return True
결과
def conversion(n, k):
result = ""
while n:
result = str(n%k) + result
n = n//k
return result
def isPrime(target):
target = int(target)
if target < 2:
return False
for n in range(2, target):
if target % n == 0:
return False
return True
def solution(n, k):
answer = 0
if n < 2:
return 0
# 1. 주어진 n을 k진수로 바꾼다.
target = conversion(n, k)
for offset in range(1, len(target)+1):
idx = 0
while idx+offset <= len(target):
# 2. 바꿔진 n값을 windowing하면서(offset 변수) 소수가 있는지 판별(isPrime 함수)한다.
if "0" not in target[idx:idx+offset] and isPrime(target[idx:idx+offset]):
# 3. 만일, 소수라면 문제에서 주어진 조건들을 확인한다.
if idx == 0 and idx+offset < len(target) and target[idx+offset] == "0":
answer += 1
elif idx-1>=0 and target[idx-1] == "0" and idx+offset < len(target) and target[idx+offset] == "0":
answer += 1
elif idx-1>=0 and target[idx-1] == '0' and idx+offset == len(target):
answer += 1
elif idx == 0 and idx+offset == len(target):
answer += 1
idx += 1
return answer