게시물을 작성하면서 복습하는 문제를 선정하는 기준은<solved.ac 티어 브론즈 1 (Bronze1) 이상>입니다.
※ 본 사진과 해당 게시글 내용의 문제 모두 백준 : 온라인 저지[Baekjoon_OnlineJudge]사이트에서 발췌해왔습니다.
<문제>
알파벳 대소문자로 된 단어가 주어지면,
이 단어에서 가장 많이 사용된 알파벳이 무엇인지 알아내는 프로그램을 작성하시오.
단, 대문자와 소문자를 구분하지 않는다.
<입력>
첫째 줄에 알파벳 대소문자로 이루어진 단어가 주어진다.
(주어지는 단어의 길이는 1,000,000을 넘지 않는다.)
<출력>
첫째 줄에 이 단어에서 가장 많이 사용된 알파벳을 대문자로 출력한다.
(단, 가장 많이 사용된 알파벳이 여러 개 존재하는 경우에는 ?를 출력한다.)
[Input] | [Output]
Mississipi | ?
zZa | Z
z | Z
baaa | A
메모리 : 41872 KB
시간 : 180ms
(시간이 좀 길게 걸렸다... 모듈을 사용하면서 무거워진 듯 하다)
from collections import Counter
v = [alp for alp in input().upper()] # 대문자 출력 조건이기때문에 먼저 upper 해주기
c = Counter(v) # 리스트에 각 요소별 빈도값을 튜플형 _ [(value, count),...]으로 생성
mst = c.most_common() # 빈도값 정렬
max = mst[0][1] # 맨앞값이 최빈값 튜플이기때문에 최빈값 index로 최빈값 변수에 대입
# 최빈값이 중복될 때 대비
max_alps = []
for cnt in mst : # 정렬한 순서대로 뒤 count값을 서로 비교하기
if cnt[1] == max:
max_alps.append(cnt[0])
# 만약 Counter 객체의 맨 앞값과 동일한 값이 뒤에 있으면 똑같이 append -> ?출력할때 사용
if len(max_alps) == 1 : # 최빈값을 가진 값이 하나일 땐 해당 알파벳 출력
print(max_alps[0]) # 빈도수 말고 알파벳 출력
else : # 두 개 이상의 알파벳의 출현횟수가 동일할 경우 : len(max_alps) > 1 경우
print('?')
백준에서는
프로그래머스와는 달리 예제가 얼마나 있는지,
코드의 효율성이 얼만큼인지 확인할 수 가 없다...
개인적인 예상으로는 collections.Counter
를 사용해서 복잡도가 증가한 것 같다.
(1)
import sys
word = sys.stdin.readline()
ALPHABET = list(range(0x41, 0x5A+1)) # 아스키코드 숫자 범위 (대문자)
alphabet = list(range(0x61, 0x7A+1)) # 아스키코드 숫자 범위 (소문자)
cnt = [0] * 26
for i in range(0, 26) :
cnt[i] += word.count(chr(ALPHABET[i]))
cnt[i] += word.count(chr(alphabet[i]))
if cnt.count(max(cnt)) > 1:
print("?")
else:
# 복잡한 출력식이라 가독성은 별로라고 느껴짐
print(chr(ALPHABET[cnt.index(max(cnt))]))
이 풀이는 컴퓨터와 직접적인 소통을하는 듯한 방법이다..ㅋㅋㅋㅋ
아스키 코드 16진수 숫자범위를 통해서
.count()
함수의 인수로
chr([아스키코드 i번째 16진수 값])
를 투입해서
" 16진수값에 해당하는 알파벳으로 변환 후, 해당 알파벳을 count "하는 방법을 사용했다.
이 count한 값은
미리 만들어둔 cnt라는 26개의 0으로 이루어진 빈 리스트에 더해주는데
대문자의 경우와 소문자의 경우를 한번에 합해서
" 해당 알파벳의 빈도수 "를 빠짐없이 측정한다.
이후
조건문에서 다시 count()
함수를 사용해서
이번엔 빈도수를 저장한 cnt 리스트에서
최빈값이 몇 개인가를 세보았고
최빈값이 중복된다면 (count(max(cnt))
> 1) ?를 출력하게하고
그 외에는
cnt리스트의 최댓값(최빈값)을 가진 알파벳 위치 (cnt.index(max(cnt))
)를
다시 " 대문자 알파벳 16진수 아스키코드 리스트에서의 인덱스 "로 사용해서
chr()
함수를 통해 대문자로 변환하여 출력하게끔 만들었다.
(2)
S = input().upper() # 입력받고, 처음부터 모두 대문자로 바꿔줌 (출력할 때도 편하고, 셀 때도 편하게)
sarray = list(set(S)) # 앞에서부터 나온 알파벳의 종류만 저장 (중복 X)
array = [] # 빈도수를 저장할 리스트
for s in sarray:
array.append(S.count(s)) # 문자열 S에서 sarray를 구성하는 각각의 알파벳 빈도수를 array에 추가
mc = max(array) # 배열 array에서 max값 : 최빈값
if array.count(mc) != 1: # 최빈값을 가진 값의 개수가 1이 아니면 동일한 빈도수 값이 더 있다는 것
print("?")
else:
mi = array.index(mc) # array배열에서 최빈값이 있는 index찾아서 mi에 저장
# array에 append되는 순서도 그대로 sarray를 따르기 때문에 index를 그대로 사용할 수 있음.
print(sarray[mi]) # array 인덱스와 sarray가 같기 때문에 max값 인덱스번째 값을 찾음
.upper()
를 쓰는 것은 필자의 경우와 같은데
이 풀이에서는
Set 형을 사용해서 중복값을 제거한 것이 인상적이다.
(3)
word = input().upper()
#각 알파벳의 갯수를 세기 위한 배열
count_alph = [0] * 26
for i in range(len(word)):
for k in range(26):
#아스키코드로 65->A 인점을 활용해서
# 정직했던 (1) 풀이를 조금 유동적으로 변형한 것
if word[i] == chr(65+k):
count_alph[k] += 1
if count_alph.count(max(count_alph)) > 1:
print('?')
else:
for i in range(26):
if count_alph[i] == max(count_alph):
print(chr(65+i))
이 풀이도 (1)풀이와 같이 아스키 코드와 chr()
함수를 활용했는데
10진수로 65~90이 A~Z라는 것을 활용해
조금 더 간결하게 바꾼 경우이다.
뭐가 맞다할 수 없지만
16진수 활용법과 아스키코드를 대부분 외운 경우가 아니라면
(3)풀이처럼 10진수를 활용하는 것도 좋은 방법이다.