본문 바로가기
알고리즘 문제 풀이/Programmers

[17회차] 괄호 회전하기, H-index, 예상 대진표, 순위 검색, 올바른 괄호

by 중앙백 2021. 12. 27.

Programmers Level.2 괄호 회전하기

def correctstring(st):
    cnt = [0, 0, 0] # 소괄호, 중괄호, 대괄호
    for i in st:
        if i == '(':
            cnt[0] += 1
        if i == ')':
            cnt[0] -= 1
        if i == '{':
            cnt[1] += 1
        if i == '}':
            cnt[1] -= 1
        if i == '[':
            cnt[2] += 1
        if i == ']':
            cnt[2] -= 1
        if any(j < 0 for j in cnt):
            return False # 올바르지 않은 문자열이면 False
    if all(j == 0 for j in cnt):
        return True # 올바른 문자열이면 True
    return False

def solution(s):
    n = 0
    answer = 0
    while n < len(s):
        if correctstring(s):
            answer += 1
        s = s[1:] + s[0]
        n += 1
    return answer

 - 처음에 내가 푼 풀이.

 - '( { [' 기호는 +1, ') } ]' 기호는 -1씩 cnt에 더하면서 값이 음수가 되는 경우가 있다면 올바르지 않은 문자열이고, 혹은 연산 마지막에서 cnt 값이 0이 아니라면 올바르지 않은 문자열일 것이다.

 - 괄호를 하나씩 회전하면서 올바른 문자열인지 일일이 확인하면 될 것이다.

 - 그러나 테스트 케이스 중 하나가 실패했고 '( { ) }'와 같은 반례가 있음을 알게 되었다.

 - 이 아이디어로는 '( { } )'와 '( { ) }'를 구분하는 게 쉽지 않다고 생각한다.

 

def correctstring(st):
    stack = []
    for i in st:
        if i == '(':
            stack.append(')')
        elif i == '{':
            stack.append('}')
        elif i == '[':
            stack.append(']')
        else: # ')}]'일 경우
            if stack == []: # stack이 비어있으면 False 반환
                return False 
            else:
                a = stack.pop() # stack에서 마지막 원소를 추출하고 i와 다르다면 False
                if a != i:
                    return False
    if stack == []: # 모든 과정을 마치고 stack이 비어있다면 True
        return True
    return False # 모든 과정을 마치고 stack이 비어있지 않다면 False
            

def solution(s):
    n = 0
    answer = 0
    while n < len(s):
        if correctstring(s):
            answer += 1
        s = s[1:] + s[0]
        n += 1
    return answer

 - 앞선 문제를 해결하기 위해 stack을 활용했다.

 - 매번 stack에서 꺼낸 원소(a)가 현재의 원소(i)와 짝을 이루는지 확인하는 과정을 통해 앞에서 문제가 된 케이스를 걸러낼 수 있었다.

 

 

Programmers Level.2 H-index

def solution(citations):
    answer = 0
    citations = sorted(citations, reverse=True)
    for i, j in enumerate(citations, start=1):
        if i <= j:
            answer += 1
        else:
            break
    return answer

 - 내 풀이

def solution(citations):
    citations.sort(reverse=True)
    answer = max(map(min, enumerate(citations, start=1)))
    return answer

 - 다른 사람의 풀이. 이 문제를 이런 식으로 풀이할 수 있다는 게 놀라웠다. 오늘도 감탄하고 간다.

 

 

Programmers Level.2 예상 대진표

def solution(n,a,b):
    answer = 0
    while a != b:
        a = (a + 1) // 2
        b = (b + 1) // 2
        answer += 1
    return answer

 

 

Programmers Level.2 순위 검색

def cnt(information, a,b,c,d,e):
    count = 0
    if a == '-':
        return cnt(information,'cpp',b,c,d,e) + cnt(information,'java',b,c,d,e) + cnt(information,'python',b,c,d,e)
    if b == '-':
        return cnt(information,a,'backend',c,d,e) + cnt(information,a,'frontend',c,d,e)
    if c == '-':
        return cnt(information,a,b,'junior',d,e) +cnt(information,a,b,'senior',d,e)
    if d == '-':
        return cnt(information,a,b,c,'chicken',e) + cnt(information,a,b,c,'pizza',e)
    for i in information[a,b,c,d]:
        if i >= e:
            count += 1
    return count


def solution(info, query):
    answer = []
    information = dict()
    for i in ('cpp','java','python'):
        for j in ('backend','frontend'):
            for k in ('junior','senior'):
                for l in ('chicken','pizza'):
                    information[i,j,k,l] = []
    for inf in info:
        a, b, c, d, e = inf.split(' ')
        information[a,b,c,d].append(int(e))
    for que in query:
        a,b,c,d = que.split(' and ')
        d, e = d.split(' ')
        e = int(e)
        answer.append(cnt(information, a, b, c, d, e))
    return answer

 - 첫 번째 아이디어(실패)

 - "개발언어, 직군, 경력, 소울푸드"-"점수" 쌍으로 사전 자료형을 만든 뒤에 query에 적힌 정보대로 count하는 함수를 설계하면 되겠다고 생각. 사전 자료형에는 3 * 2^3 (=48)개의 키 값이 존재.

 - 그 다음에 문제였던 것은 query에서 요구하는 value를 어떻게 셀 것인가. 특히 key 값에 '-'를 어떻게 구현할지 고민했다.

 - 재귀함수를 이용해 '-' 일 때는 거기에 해당하는 모든 key값들에 해당하는 cnt 함수를 불러와 더했다

 - 효율성 테스트에서 실패

def cnt(information, a,b,c,d,e):
    count = 0
    for i in information[a,b,c,d]:
        if i >= e:
            count += 1
    return count


def solution(info, query):
    answer = []
    information = dict()
    for i in ('cpp','java','python','-'):
        for j in ('backend','frontend','-'):
            for k in ('junior','senior','-'):
                for l in ('chicken','pizza','-'):
                    information[i,j,k,l] = []
    for inf in info:
        a, b, c, d, e = inf.split(' ')
        information[a,b,c,d].append(int(e))
        information['-',b,c,d].append(int(e))
        information[a,'-',c,d].append(int(e))
        information[a,b,'-',d].append(int(e))
        information[a,b,c,'-'].append(int(e))
        information['-','-',c,d].append(int(e))
        information['-',b,'-',d].append(int(e))
        information['-',b,c,'-'].append(int(e))
        information[a,'-','-',d].append(int(e))
        information[a,'-',c,'-'].append(int(e))
        information[a,b,'-','-'].append(int(e))
        information['-','-','-',d].append(int(e))
        information['-','-',c,'-'].append(int(e))
        information['-',b,'-','-'].append(int(e))
        information[a,'-','-','-'].append(int(e))
        information['-','-','-','-'].append(int(e))
    for que in query:
        a,b,c,d = que.split(' and ')
        d, e = d.split(' ')
        e = int(e)
        answer.append(cnt(information, a, b, c, d, e))
    return answer

 - 두 번째 시도(실패)

 - 재귀함수를 호출했기 때문에 생기는 비효율이 아닐까 생각해서 재귀함수를 사용하지 않기 위해, 사전자료형을 만들 때 key값에 '-' 항목도 추가해서 만들었다.

 - count하기 위해 모든 value들을 하나씩 확인하면서 세는 방식을 채택.

def cnt(information, a,b,c,d,e):
    count = 0
    i = 0
    while i < len(information[a,b,c,d]):
        if information[a,b,c,d][i] >= e:
            count += 1
        else:
            break
        i += 1
    return count


def solution(info, query):
    answer = []
    information = dict()
    for i in ('cpp','java','python','-'):
        for j in ('backend','frontend','-'):
            for k in ('junior','senior','-'):
                for l in ('chicken','pizza','-'):
                    information[i,j,k,l] = []
    for inf in info:
        a, b, c, d, e = inf.split(' ')
        information[a,b,c,d].append(int(e))
        information['-',b,c,d].append(int(e))
        information[a,'-',c,d].append(int(e))
        information[a,b,'-',d].append(int(e))
        information[a,b,c,'-'].append(int(e))
        information['-','-',c,d].append(int(e))
        information['-',b,'-',d].append(int(e))
        information['-',b,c,'-'].append(int(e))
        information[a,'-','-',d].append(int(e))
        information[a,'-',c,'-'].append(int(e))
        information[a,b,'-','-'].append(int(e))
        information['-','-','-',d].append(int(e))
        information['-','-',c,'-'].append(int(e))
        information['-',b,'-','-'].append(int(e))
        information[a,'-','-','-'].append(int(e))
        information['-','-','-','-'].append(int(e))
    for i in information:
        information[i] = sorted(information[i], reverse=True)
    for que in query:
        a,b,c,d = que.split(' and ')
        d, e = d.split(' ')
        e = int(e)
        answer.append(cnt(information, a, b, c, d, e))
    return answer

 - 세 번째 시도(실패)

 - 사전자료형 안에 자료들을 내림차순으로 정렬시키고 count를 하면 좀 더 빠르지 않을까 생각했다.

 - 내림차순으로 정렬되어 있으므로 요구하는 값보다 작은 value값이 나올 때 break하면 된다고 생각. 하지만 실패.

def cnt(information, a,b,c,d,e):
    if not information[a,b,c,d]:
        return 0
    count = 0
    start = 0
    end = len(information[a,b,c,d]) - 1
    while start <= end:
        mid = (start + end) // 2
        if information[a,b,c,d][mid] >= e:
            count = mid + 1
            start = mid + 1
        else:
            end = mid - 1
    return count


def solution(info, query):
    answer = []
    information = dict()
    for i in ('cpp','java','python','-'):
        for j in ('backend','frontend','-'):
            for k in ('junior','senior','-'):
                for l in ('chicken','pizza','-'):
                    information[i,j,k,l] = []
    for inf in info:
        a, b, c, d, e = inf.split(' ')
        information[a,b,c,d].append(int(e))
        information['-',b,c,d].append(int(e))
        information[a,'-',c,d].append(int(e))
        information[a,b,'-',d].append(int(e))
        information[a,b,c,'-'].append(int(e))
        information['-','-',c,d].append(int(e))
        information['-',b,'-',d].append(int(e))
        information['-',b,c,'-'].append(int(e))
        information[a,'-','-',d].append(int(e))
        information[a,'-',c,'-'].append(int(e))
        information[a,b,'-','-'].append(int(e))
        information['-','-','-',d].append(int(e))
        information['-','-',c,'-'].append(int(e))
        information['-',b,'-','-'].append(int(e))
        information[a,'-','-','-'].append(int(e))
        information['-','-','-','-'].append(int(e))
    for i in information:
        information[i] = sorted(information[i], reverse=True)
    for que in query:
        a,b,c,d = que.split(' and ')
        d, e = d.split(' ')
        e = int(e)
        answer.append(cnt(information, a, b, c, d, e))
    return answer

 - 성공 케이스

 - 좀 더 효율적으로 세기 위해 정렬된 자료를 이진탐색을 이용해 count하는 방식으로 변경.

 

 

Programmers Level.2 올바른 괄호

def solution(s):
    cnt = 0
    for i in s:
        if i == '(':
            cnt += 1
        elif i == ')':
            cnt -= 1
        if cnt < 0:
            return False
    return cnt == 0

 - 가장 먼저 떠오른 방식

def solution(s):
    stack = []
    for i in s:
        if i == '(':
            stack.append(i)
        elif i == ')':
            try:
                stack.pop()
            except IndexError:
                return False
    return stack == []

 - 괄호 회전하기 처럼 stack을 활용해서 문제를 풀이해봤다.

'알고리즘 문제 풀이 > Programmers' 카테고리의 다른 글

[19회차] 후보키, 2개 이하로 다른 비트  (0) 2021.12.29
[18회차] 캐시  (0) 2021.12.28
[16회차] 조이스틱  (0) 2021.12.26
[15회차] 빛의 경로 사이클, 가장 큰 수  (0) 2021.12.25
[14회차]  (0) 2021.12.21

댓글