관리 메뉴

TEAM EDA

[엘리스] 엘리스와 비밀번호 본문

EDA Study/알고리즘

[엘리스] 엘리스와 비밀번호

김현우 2020. 3. 26. 21:17

엘리스와 비밀번호

엘리스 아카데미의 프로그램 개발자로 취직한 엘리스는 회원들의 현재 비밀번호가 새롭게 개편된 보안 정책에 얼마나 위반하는지 알아보는 업무를 할당받았습니다. 엘리스를 도와 아래에 주어진 보안 정책을 따라 몇 번이나 비밀 번호를 수정 해야 하는지 출력하는 프로그램을 만들어 주세요.

 

보안 정책

  1. 비밀 번호는 8자 이상 30자 이하 의 길이를 가져야 한다.
  2. 비밀 번호에는 하나 이상의 소문자, 숫자, 특수문자가 포함 되어야 한다.
  3. 하나의 문자가 3번 이상 연속 되면 안된다. 예를 들어 aaabb11!는 사용 불가능한 비밀 번호지만 aabab11!는 사용 가능하다.

입력 예시 1

aBcD2fg!

출력 예시 1

0

입력 예시 2

AA

출력 예시 2

6

입력

비밀 번호가 문자열 형태로 제공됩니다. 이 문자열의 길이는 1이상 100이하 입니다.

출력

주어진 비밀 번호가 새로운 보안 정책에 따라 변경되려면 몇 번의 수정이 필요한 지 출력해주세요. 수정에 있어, 한 문자의 삽입, 변경, 삭제는 모두 하나의 수정으로 간주됩니다.

풀이

  • 5가지의 경우에 대해 Flag를 설정해놓고, 소문자와 특수문자를 저장한 리스트를 생성

  • 위의 상황중에서 어떤 상황에 위배되었는 지 확인

  • 길이가 넘는 경우, 넘지 않는 경우, 적당한 경우 3가지에 대해 조사

    • 참고 : 3번 이상 반복되는 경우에 대해 AAA AAA 처럼 중복되는 경우 INDEX를 2개 기록해야 함
def sol(A):
    flag_a = True # 길이 
    flag_b = False # 소문자 
    flag_c = False # 숫자 
    flag_d = False # 특수문자 
    flag_e = True # 연속 

    alphabet = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
    others = list("-=+,#/\?:^$.@*\"※~&%ㆍ!』\\‘|\(\)\[\]\<\>`\'…")

    for i in range(len(A)): 
        # 1. 하나 이상의 소문자, 숫자, 특수문자가 전부 포함되었는 지 확인 
        if A[i] in alphabet:
            flag_b = True
        elif A[i].isdigit():
            flag_c = True 
        elif A[i] in others:
            flag_d = True

    e_point = []
    # 3번 이상 반복되는 지 확인 
    for i in range(0, len(A)-2):
        if len(set(list(A[i:i+3]))) == 1:
            flag_e = False

            # 3번이상 반복되는데 AAA AAA 처럼 하나의 수정으로 불가능한 경우 
            # 0 1 2 3 4 5 -> 0 3으로 수정해야 함            
            if len(e_point) != 0: 
                if (e_point[-1][1] == A[i]) & (i - e_point[-1][0] <= 2):
                    pass
                else:
                    e_point.append((i, A[i]))
            else:
                e_point.append((i, A[i]))
    # 길이가 넘는 지 확인 
    # 1. 길이가 넘지 않는 경우 
    if (len(A) <= 7) | (len(A) > 30):
        flag_a = False

    if (len(A) <= 7):
        if flag_e == True: 
            return 8 - len(A) + len(e_point)
        else:
            return 8 - len(A)

    # 2. 길이가 넘는 경우 
    elif (len(A) > 30):
        if flag_e == True: 
            total = sum([flag_b, flag_c, flag_d])
            return len(A) - 30 + (3-total)
        else:
            total = sum([flag_b, flag_c, flag_d])
            return len(A) - 30 + max(len(e_point), 3-total)

    #  3. 길이는 만족하는 경우 
    else:
        if flag_e == True: 
            total = sum([flag_b, flag_c, flag_d])
            return (3-total)
        else:
            total = sum([flag_b, flag_c, flag_d])
            return max(len(e_point), 3-total)    

def main():
    A = str(input())
    print(sol(A))

if __name__ == '__main__':
    main()

모범 답안

  • isalnum과 islower라는 함수를 사용해서 특수문자와 소문자를 체크
  • repeat의 경우 숫자를 집어넣지 못하기에 [j]을 이용
  • 길이에 따라 3가지 경우로 나누고, 전체의 계산은 한번에 진행
    • 거리가 30을 초과하면 replace의 경우, 반복되는 값들은 삭제와 대체를 통해서 해결할 수 있음
      • delete가 allbydel보다 크다면, 지우면서 연속도 다 없애버리면 되므로 replace는 0
      • 그렇지 않으면, 연속되는 문자에서 지워야하는 숫자를 계산 : allbydel (예: AAAAA이면 3개를 지워야 함)
      • replace에서는 두가지 경우 중 큰 값을 선택 (대체를 안하고 delete로 제거되는 경우를 고려해야 함)
        • 연속되는 각 부분에 대해 대체해야하는 수(//3) - delete로 해결되는 수
        • 대체해야하는 문자열의 수 (allbydel-delete) + 2) // 3
    • 그렇지 않은 경우는 단순하게 대체만 하면 됨
def classifier(c):

    if c.islower(): return 0
    elif c.isalnum() == False: return 1
    elif c.isdigit(): return 2
    else: return 3

s = input()

length = len(s)
repeat = []
types = [False]*4
i, j  = 0, 1

while i < length:
    while (i+j < length and s[i+j] == s[i]): 
        j += 1
    if j >= 3: 
        repeat += [j] 
    # 모든 입력값에 대해서 해당하는게 맞는 지 확인하고, 하나라도 만족하면 True로 변환 
    types[classifier(s[i])] = True         
    i, j = i+j, 1


insert, delete, replace = 0, 0, 0

if length < 8: 
    insert = 8-length

elif length > 30:   
    delete = length-30
    allbydel = sum([(r-2) for r in repeat])
    if delete < allbydel:     
        replace = max(sum([r//3 for r in repeat]) - delete, ((allbydel-delete) + 2) // 3)

else:               
    for rp in repeat: 
        replace += rp // 3


print(insert+delete+max(replace, types[:-1].count(False)-insert))

 

출처 : 엘리스 아카데미, https://academy.elice.io/learn