Test_str = input()
alphabet_dict = {}
for i in range(97, 123):
alphabet_dict[chr(i)] = -1
for i in range(len(Test_str)):
if alphabet_dict[Test_str[i]] == -1:
alphabet_dict[Test_str[i]] = i
Ans = list(alphabet_dict.values())
for i in range(len(Ans)):
print(Ans[i],end=" ")
◯설명◯
Test_str = input()
alphabet_dict = {}
먼저 입력한 문장을 받는 변수이다.
그 뒤에 따라오는 코드는 딕셔너리 선언을 위한 코드이다. 이름에서 알 수 있듯이, 알파벳과 숫자를 같이 정리하기 위한 딕셔너리이다.
for i in range(97, 123):
alphabet_dict[chr(i)] = -1
먼저 아스키 코드를 사용해서 모든 알파벳을 key로 넣어주면서, value를 -1로 할당해 준다.
for i in range(len(Test_str)):
if alphabet_dict[Test_str[i]] == -1:
alphabet_dict[Test_str[i]] = i
다음은 해당 코드를 활용하기 위한 코드이다.
for문은 문장의 길이만큼 반복을 해준다.
if문과 그 아래 코드는 입력받은 문장에 해당하는 알파벳을 key로 입력했을 때 value가 -1이면 value를 자릿값으로 교체하기 위한 코드이다.
if문을 활용한 이유는, 단어가 여러번 사용되는 경우에는 맨 처음 오는 자릿수만 저장한다고 했기 때문이다. if문의 조건을 충족한다는 것은 그 이전에는 같은 문자가 없었다는 의미이다.
Ans = list(alphabet_dict.values())
for i in range(len(Ans)):
print(Ans[i],end=" ")
다음은 이렇게 정리가 끝난 value값들을 모두 출력해주기 위한 작업이다.
.values()함수를 활용하면 원하는 딕셔너리의 value값들을 list형태로 저장할 수 있다. 다만 이것은 완전한 list는 아니다. 그래서 list로서 사용을 하기 위해서는 list함수로 변환이 이루어져야한다.
for문은 처리가 완료된 value값들을 한줄로 출력해주기 위한 코드이다. print의 end값을 공백 한칸으로 바꾸었다.
◯배운 것◯
⩥딕셔너리의 key와 value는 list형태로 꺼내 올 수 있다. 다만 온전한 list로 사용하려면 list로 변환해주어야 한다.
⩥딕셔너리에 원소를 추가하려면 (딕셔너리 이름)[key] = (value)의 형태로 코드를 짜면 된다.
Test_case = int(input())
for i in range(Test_case):
S, P = input().split( )
S = int(S)
for k in range(len(P)):
for z in range(S):
print(P[k],end="")
print("")
◯설명◯
Test_case = int(input())
for i in range(Test_case):
먼저 문제의 반복을 위해서 반복 시킬 만큼의 test case를 입력받는다. 이렇게 입력받은 값은 for문으로 반복시킨다.
그럼 for문의 안을 살펴보자.
S, P = input().split( )
S = int(S)
일단 문제에서 주어진 변수를 한 줄로 입력받기 위해서 split을 사용했다.
다만 S부분은 숫자이기 때문에 나중에 정수형을 변환해준다.
for k in range(len(P)):
for z in range(S):
print(P[k],end="")
다음은 P의 길이만큼 for문을 돌린다. 이것은 문자열 인덱싱을 사용하기 위해서이다.
for문 안에 for문은 문자를 반복 출력하기 위한 for문이다. 범위는 당연히 S로 지정한다.
마지막줄은 문자를 출력해주는 print문이다. 끝부분에 end의 값을 여백이 없는 것으로 바꾸었는데, 이는 문제에서 원하는 출력을 해주기 위함이다.
print("")
모든 코드가 작동하고 나서 케이스 구분을 해주기 위해서 줄바꿈을 위해 빈 print문을 하나 출력해준다.
def MRange(Range_X_to_Y):
Move_Range = 0
Len_of_Move_Range = 0
for i in range(1,2**23):
Len_of_Move_Range += i
Move_Range += 1
if Len_of_Move_Range >= Range_X_to_Y:
return Move_Range
Len_of_Move_Range += i
Move_Range += 1
if Len_of_Move_Range >= Range_X_to_Y:
return Move_Range
TestCase = int(input())
for i in range(TestCase):
x,y = map(int,input().split( ))
print(MRange(y-x))
◯설명◯
정말 어려웠던 문제다. 어떻게 풀어야 할지 감이 전혀 오지 않았다. 그래서 해본 것이 엑셀에다가 모든 경우의 수를 적기 시작한 것이었다. 그러다보니 패턴이 보였다.
바로 거리가 1+1+2+2+3+3+4+4+... 순서로 증가할 때마다 움직이는 횟수가 1씩 증가한다는 것이다.
그렇게 해서 코드를 짜게 되었다.
def MRange(Range_X_to_Y):
Move_Range = 0
Len_of_Move_Range = 0
for i in range(1,2**31):
Len_of_Move_Range += i
Move_Range += 1
if Len_of_Move_Range >= Range_X_to_Y:
return Move_Range
Len_of_Move_Range += i
Move_Range += 1
if Len_of_Move_Range >= Range_X_to_Y:
return Move_Range
가장 먼저 한것은 내가 이해한 것을 코드로 구현하는 것이었다.
Move_Range는 이동거리, Len_of_Move_Range는 순서를 의미한다. Range_X_to_Y는 x와 y 사이의 거리이다.
거리와 순서 모두 거리가 반복적으로 증가하므로 for문을 사용했다. 범위는 1부터 입력의 최대값인 2의 31까지로 했다. 중간에 조건이 만족하면 식은 알아서 멈추고, 이것보다 큰 값은 나올 수 없기 때문이다.
for문의 처음은 거리와 순서를 위에서 말했던 방식으로 증가시키는 것이다. 이 과정이 끝나면 입력받은 값과 거리를 비교해서 값이 거리보다 작을 때 순서를 반환한다. 아닐 때는 앞선 과정을 한번 더 반복한다.
TestCase = int(input())
for i in range(TestCase):
x,y = map(int,input().split( ))
print(MRange(y-x))
이제 함수를 사용해줄 차례이다.
먼저 테스트케이스를 입력받는다. 그리고 그만큼 for문을 반복시킨다.
for문 안에서는 x와 y를 입력받는다. 이 때 한줄로 입력받기 위해서 map함수를 사용한다.
입력받은 값에서 구해야하는 거리를 계산한다음 아까 만든 MRange함수에 집어넣는다. 그리고 반환되는 값을 출력해준다.
◯배운 것◯
⩥엑셀을 이용해서 예제를 적어보는 것도 패턴 파악에 도움이 될 수 있다. 머리로만 고민하지 말자!
def HanSu(Input_Num):
if Input_Num < 100:
return Input_Num
else :
Count_HanSu = 0
for i in range(100,Input_Num+1):
Base_Num = str(i)
First = int(Base_Num[0])
Second = int(Base_Num[1])
Third = int(Base_Num[2])
if Second - First == Third - Second :
Count_HanSu += 1
Final_Num = Count_HanSu + 99
return Final_Num
Num = int(input())
print(HanSu(Num))
◯설명◯
코드에 들어가기 전에 이번 문제에서 제일 중요한 개념을 설명하겠다. 문제 이름에도 나와있는 한수이다. 문제에서 주어진 설명을 정리하면, 한수는 각 자리 숫자가 등차수열을 이루고 있는 숫자이고, 등차수열은 연속된 두개의 수의 차이가 일정한 수열이라는 것이다.
자릿수가 3자리인 경우에는 비교가 가능하니 그냥 등차수열인지만 알아내면 되지만, 두자리와 한자리일 때는 그렇지 않으니 애매해진다. 이 문제를 해결할 방법을 우리는 예제에서 알 수 있다. 예제 2를 보면 입력된 값이 1이고 출력된 값이 1이다. 이는 한자리 숫자도 한수에 포함됨을 의미한다. 이 결과를 가지고 예제 1로 가보자. 예제 1에서 입력값은 110이고 출력값은 99이다. 100번대의 숫자들은 등차수열이 성립할 수 없다. 1에서 0으로 가는데 숫자가 1 감소했기 때문이다. 남은 숫자들은 1부터 99까지인데, 출력값이랑 일치한다. 즉, 두자리 숫자도 한수에 포함된다는 것이다. 이 두개의 결과를 가지고 우리는 문제에 접근해야한다.
def HanSu(Input_Num):
이번 문제도 함수를 선언해준다.
if Input_Num < 100:
return Input_Num
먼저 주어진 값이 100보다 작은(=두자리거나 한자리 수일 때) 경우에는 입력값을 그대로 반환한다. 위에서도 말했듯이, 한자리 숫자와 두자리 숫자는 모두 한수이기 때문이다.
else :
Count_HanSu = 0
아닌 경우에는 한수들을 구해야한다.
일단 기본적인 변수부터 선언해준다. Count_HanSu는 한수의 갯수를 저장할 변수이다.
for i in range(100,Input_Num+1):
Base_Num = str(i)
First = int(Base_Num[0])
Second = int(Base_Num[1])
Third = int(Base_Num[2])
if Second - First == Third - Second :
Count_HanSu += 1
for문의 범위는, 앞서 두자리와 한자리는 모두 걸렀기 때문에 100부터 시작하고, 마지막 숫자는 포함되지 않기 때문에 마지막 숫자에 1을 더해준다.
Base_Num은 자릿수들을 인덱싱으로 꺼내오기 위해 숫자 i를 문자열로 바꾼것이다. i를 바꾸는 이유는 for문이 반복하면서 계속해서 테스트하는 변수가 바로 i이기 때문이다.
First, Second, Third는 각각 첫째, 둘째, 셋째 자릿수를 의미한다. 주어지는 값의 최대가 999이고 최소가 100이기 때문에 세자리 수만 고려하면 된다.
if문의 조건은 등차수열인지를 검증한다. 조건이 True일 때, i는 한수임으로 Count_HanSu변수의 값을 1 올린다.
Final_Num = Count_HanSu + 99
return Final_Num
이렇게 for문이 종료되고 나면 세자리 숫자의 한수는 전부 세게 된다. 두자리와 한자리 숫자는 세지 않았으므로, 99를 더해준다. 그 값을 Final_Num을 저장하고 반환한다.
def SelfNum(list1):
from contextlib import suppress
for i in range(1,100001):
Base_Num = str(i)
Plus_Num = 0
for z in range(len(Base_Num)):
Plus_Num += int(Base_Num[z])
Plus_Num += int(Base_Num)
with suppress(ValueError): list1.remove(Plus_Num)
return list1
Base_List = list(range(10000))
Base_List.remove(0)
Base_List.append(10000)
Self_Num_List = SelfNum(Base_List)
for i in range(len(Self_Num_List)):
print(Self_Num_List[i])
◯설명◯
def SelfNum(list1):
먼저 SelfNum이라는 함수를 선언해 주었다. 문제의 분류가 함수 쪽에 들어가 있어서 함수를 선언했지만, 안에 있는 코드를 그냥 꺼내서 붙여넣어도 상관없지 않을까 싶다.
from contextlib import suppress
먼저 contextlib이라는 모듈에서 suppress라는 함수를 가져왔다. try-except의 대용으로 오류를 무시하기 위해 가져온 것인데, 자세한 것은 나중에 suppress함수가 나오는 부분에서 설명하겠다.
for i in range(1,100001):
Base_Num = str(i)
Plus_Num = 0
for z in range(len(Base_Num)):
Plus_Num += int(Base_Num[z])
Plus_Num += int(Base_Num)
with suppress(ValueError): list1.remove(Plus_Num)
함수의 가장 큰 뼈대를 이루고 있는 for 문이다. for 문을 사용한 이유는 두 가지 정도인데, 범위를 정하기 편하다는 것과 i가 알아서 증가한다는 점이다. 그러므로 [i += 1]같은 코드를 추가하지 않더라도 범위에 해당하는 모든 숫자를 테스트해볼 수 있다.
Base_Num은 인덱싱을 사용하기 위해 테스트할 i 값을 문자열로 바꾸어준 변수이다. Plus_Num은 값을 더하기 위한 변수로, 매 루프마다 0으로 초기화 해주어야 한다. 이는 이전 값과 섞이지 않게하기 위해서이다.
for 문 안에 들어오는 for 문은 밑에 있는 Plus_Num으로 시작하는 코드까지 세트이다. 이 코드들은 문제에서 말하고 있는 함수 d(n)를 표현하기 위한 코드이다. 이 코드가 완료되면 Plus_Num이 가지고 있는 값은 셀프넘버가 아닌 숫자이다.
그래서 제일 아래의 코드로 입력받은 list에서 Plus_Num에 들어온 값을 제거해주는 것이다.
여기서 주의할 점은, Plus_Num에 들어가는 숫자가 중복으로 생길 수도 있다는 것이다. 문제에서 예시를 들었듯이 숫자 101같이 생성자를 91과 100 2개를 가질 수가 있고, 이런 경우가 얼마나 생길지는 모른다. 게다가, remove함수는 찾고자 하는 원소가 해당 list에 존재하지 않을 때 ValueError가 발생하게 된다. 이 에러를 무시하기 위해 사용한 코드가 바로 suppress함수이다. 이렇게 되면 Plus_Num변수에서 중복이 발생하게 돼서 지워야 하는 숫자가 이미 list에서 지워진 경우에도 문제없이 다음 숫자로 넘어갈 수 있게 된다.
return list1
이렇게 for문이 끝나고 나면, 매개변수 list1 안에는 우리가 원하는 셀프넘버들만 들어가 있게 된다. 이 값을 return을 통해 반환하게 되면 함수 SelfNum의 코드가 끝나게 된다.
Base_List = list(range(10000))
Base_List.remove(0)
Base_List.append(10000)
Self_Num_List = SelfNum(Base_List)
for i in range(len(Self_Num_List)):
print(Self_Num_List[i])
다음은 위에서 선언한 함수를 사용하게 되는 메인 코드이다.
먼저 Base_List를 선언해준다. 1부터 10000까지의 숫자가 전부 들어가야 하므로 range 선언, remove 함수, append 함수 가지 사용해준다.
그다음, SelfNum함수에 인자 Base_List를 넣어준다. 그렇게 해서 나온 반환 값인 셀프넘버들로 이루어진 list를 대입 연산자를 통해 Self_Num_List에 넣어준다.
마지막으로, 문제에서 제시하는 출력값대로 출력하기 위해서 for문을 활용하게 되면 문제가 끝이 난다.
◯배운 것◯
⩥에러를 무시할 때 사용하는 함수로 try-except 말고도 suppress 함수가 존재한다. 이 함수는 from-import를 사용해서 contextlib 에서 꺼내와야 사용할 수 있다. 이 함수의 장점으로는 한 줄로 끝낼 수 있어서 간편하다는 점이다. 단점은 예외처리가 필요한 코드마다 전부 입력해야 한다는 점이다.
⩥문제에서 요구하는 것이 무엇인지 정확히 파악해야 한다. 문제를 적어가면서 이해해보도록 하자.