9046 복호화 파이썬
문제
암호학에서 치환 암호(substitution cipher)란, 평문에 들어있는 각각의 문자를 주어진 치환 방법으로 암호화하는 방법 중 하나다.
가장 단순한 방법은 평문의 알파벳을 암호문의 알파벳으로 대치시켜 치환시키는 것이다.
예를 들어, 아래와 같은 알파벳 대치표가 주어졌다고 하자.
- 평문 알파벳 대치표 : abcdefghijklmnopqrstuvwxyz
- 암호문 알파벳 대치표 : wghuvijxpqrstacdebfklmnoyz
위에 주어진 치환 방법을 통해 암호화하면 평문 "hello there"은 "xvssc kxvbv"가 된다.
한 가지 흥미로운 점은 영어 문법 특성상, 알파벳 'e'가 다른 영문 알파벳에 비해 자주 쓰인다는 것이다.
즉, 암호문 알파벳 대치표 없이 암호문을 복호화하려 할 때, 암호문 알파벳 빈도수를 체크하면 암호문 알파벳 빈도수 중 가장 빈번하게 나타나는 알파벳이 'e'라는 사실을 유추해볼 수 있다.
위 방법으로 암호문 알파벳의 빈도수를 체크하고, 가장 빈번하게 나타나는 문자를 출력하는 프로그램을 작성하면 된다.
만약 주어진 암호문에서 가장 빈번하게 나타나는 문자가 여러 개일 경우, 그 빈번한 문자 중 어느 것이 평문 알파벳 'e'를 가리키는지 확실하게 알 수 없기 때문에 "모르겠음"을 의미하는 '?'를 출력하면 된다.
입력
입력의 T(1 ≤ T ≤ 20)는 테스트 케이스로, 입력 제일 상단에 주어진다. 각각의 테스트 케이스는 한 줄마다 소문자와 공백으로 이루어진 영어 문장이 주어진다. 이 문장의 길이는 적어도 1이상이며 255이하다.
출력
각각의 테스트 케이스에 대해, 가장 빈번하게 나타나는 문자를 출력하거나 빈번하게 나타나는 문자가 여러 개일 경우 '?'를 출력한다.
문자열에서 가장 많은 빈도의 문자를 찾아서 출력하되, 빈도수가 많은 문자가 2개 이상이면 ?를 출력하는 문제이다.
내가 한 풀이 방법은
딕셔너리에 ' '을 제외한 문자들의 빈도를 저장하고,
가장 큰 value를 가져와서
2개 이상인지 판단하는 식으로 진행했다.
from collections import defaultdict
T=int(input())
for i in range(T):
cnt = 0
word=input()
#처음 인자값이 들어와도 0으로 초기화되서 입력가능하게 defaultdict사용
wordlist=defaultdict(int)
#딕셔너리에 빈도수 계산
for j in range(len(word)):
if word[j]!=' ':
wordlist[word[j]]+=1
#가장 빈도수가 높은 값 가져옴.
Mxnum=max(wordlist.values())
for key,value in wordlist.items():
#빈도수가 가장 높은 키값을 가져온다.
if value==Mxnum:
Mxkey=key
cnt+=1
if cnt>=2:
print('?')
else:
print(Mxkey)
cnt=0
참고한 풀이가 더 뛰어나서 가져와보았다.
아스키코드 방식을 사용해서 a만큼의 숫자를 뺀 인덱스에 빈도를 저장하는 방식이다.
count()함수를 사용해서 선택한 빈도수와 같은 값이 배열 내에 몇개나 있는지를 구한다.
즉 빈도수가 여러개인 문자의 종류가 몇가지인지 이 함수하나로 해결했다.
그다음 li.index( max(li) )+ord('a')는 가장 빈도수가 큰 값이 가리키는 인덱스 번호에 a의 아스키 코드를 더함으로써
ord(x)값을 구할 수 있다. 여기에 chr를 씌워 원래 문자열 값을 구했다.
출처: https://www.acmicpc.net/source/29197590
import sys
input = sys.stdin.readline
T = int(input())
for _ in range(T):
li = [0] * 26
s = input().strip().replace(' ', '')
for i in s:
li[ord(i) - ord('a')] += 1
if li.count(max(li)) > 1:
print('?')
else:
print(chr(li.index(max(li)) + ord('a')))