이번 문제는 21년 카카오 채용연계형 인턴쉽 출제 문제이다.

문제 설명


네오와 프로도가 숫자놀이를 하고 있습니다. 네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다.

다음은 숫자의 일부 자릿수를 영단어로 바꾸는 예시입니다.

  • 1478 → "one4seveneight"
  • 234567 → "23four5six7"
  • 10203 → "1zerotwozero3"

이렇게 숫자의 일부 자릿수가 영단어로 바뀌어졌거나, 혹은 바뀌지 않고 그대로인 문자열 s가 매개변수로 주어집니다. s가 의미하는 원래 숫자를 return 하도록 solution 함수를 완성해주세요.

 

제한사항


  • 1 ≤ s의 길이 ≤ 50
  • s가 "zero" 또는 "0"으로 시작하는 경우는 주어지지 않습니다.
  • return 값이 1 이상 2,000,000,000 이하의 정수가 되는 올바른 입력만 s로 주어집니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
s="one4seveneight"
number_dict={"zero":"0","one":"1","two":"2","three":"3","four":"4","five":"5","six":"6","seven":"7","eight":"8","nine":"9"}
 
def solution(s):
  #딕셔너리 모든 key 값을 탐색
  for i in list(number_dict.keys()):
    #문자열 내 key 값 존재 유무 판별
    if s.find(i) != (-1):
      old=i
      new=number_dict[i]
      #문자열을 숫자(문자열)로 치환
      s=s.replace(old,new)
  return int(s)
 
solution(s)
cs
1478

 

 

 

영단어를 key,숫자(문자열)를 value로 하는 딕셔너리를 생성한 뒤 주어진 문자열 안에 영단어가 존재할 경우 이를 숫자(문자열)로 치환하는 방식이다.

 

 

 

문제 설명


정수 배열 numbers가 주어집니다. numbers에서 서로 다른 인덱스에 있는 두 개의 수를 뽑아 더해서 만들 수 있는 모든 수를 배열에 오름차순으로 담아 return 하도록 solution 함수를 완성해주세요.

 

제한사항


  • numbers의 길이는 2 이상 100 이하입니다.
    • numbers의 모든 수는 0 이상 100 이하입니다.

numbers1=[2,1,3,4,1]
numbers2=[5,0,2,7]
def solution(numbers):
  answer=[]
  #리스트에 있는 숫자 하나씩 기준으로 잡고 탐색
  for index in range(len(numbers)):
    #먼저 숫자 리스트를 복사한다.
    numbers_copy=numbers.copy()
    #기준 숫자를 ref_number로 저장
    ref_number=numbers_copy[index]
    #복사한 숫자 리스트에서 기준 숫자를 제거
    numbers_copy.remove(ref_number)
    #남은 숫자들을 기준 숫자와 더한 뒤 answer 리스트에 저장
    for number in numbers_copy :
      answer.append(ref_number+number)
  #중복 값을 제거하기 위해 set으로 변환한 뒤 list로 다시 변환
  answer=list(set(answer))
  #sort()로 오름차 순 정렬
  answer.sort()
  return answer

print(solution(numbers1))
print(solution(numbers2))
[2, 3, 4, 5, 6, 7]
[2, 5, 7, 9, 12]

숫자 리스트에서 하나를 기준으로 나머지를 하나씩 더하면서 결과에 저장한 뒤 중복 값을 제거하는 방식이다. 예를 들어 [5,0,2,7] 중 먼저 5를 기준으로 5+0, 5+2, 5+7 를 진행한 뒤 더한 값을 모두 저장한다. 이후 set() 함수로 중복 값을 제거한 뒤 다시 리스트로 변환하고 순서를 오름차 순으로 정렬해주면 된다.

문제 설명


게임개발자인 "죠르디"는 크레인 인형뽑기 기계를 모바일 게임으로 만들려고 합니다.
"죠르디"는 게임의 재미를 높이기 위해 화면 구성과 규칙을 다음과 같이 게임 로직에 반영하려고 합니다.

예시 이미지

게임 화면은 "1 x 1" 크기의 칸들로 이루어진 "N x N" 크기의 정사각 격자이며 위쪽에는 크레인이 있고 오른쪽에는 바구니가 있습니다. (위 그림은 "5 x 5" 크기의 예시입니다). 각 격자 칸에는 다양한 인형이 들어 있으며 인형이 없는 칸은 빈칸입니다. 모든 인형은 "1 x 1" 크기의 격자 한 칸을 차지하며 격자의 가장 아래 칸부터 차곡차곡 쌓여 있습니다. 게임 사용자는 크레인을 좌우로 움직여서 멈춘 위치에서 가장 위에 있는 인형을 집어 올릴 수 있습니다. 집어 올린 인형은 바구니에 쌓이게 되는 데, 이때 바구니의 가장 아래 칸부터 인형이 순서대로 쌓이게 됩니다. 다음 그림은 [1번, 5번, 3번] 위치에서 순서대로 인형을 집어 올려 바구니에 담은 모습입니다.

만약 같은 모양의 인형 두 개가 바구니에 연속해서 쌓이게 되면 두 인형은 터뜨려지면서 바구니에서 사라지게 됩니다. 위 상태에서 이어서 [5번] 위치에서 인형을 집어 바구니에 쌓으면 같은 모양 인형 두 개가 없어집니다.

크레인 작동 시 인형이 집어지지 않는 경우는 없으나 만약 인형이 없는 곳에서 크레인을 작동시키는 경우에는 아무런 일도 일어나지 않습니다. 또한 바구니는 모든 인형이 들어갈 수 있을 만큼 충분히 크다고 가정합니다. (그림에서는 화면표시 제약으로 5칸만으로 표현하였음)

 

게임 화면의 격자의 상태가 담긴 2차원 배열 board와 인형을 집기 위해 크레인을 작동시킨 위치가 담긴 배열 moves가 매개변수로 주어질 때, 크레인을 모두 작동시킨 후 터트려져 사라진 인형의 개수를 return 하도록 solution 함수를 완성해주세요.

 

제한사항


  • board 배열은 2차원 배열로 크기는 "5 x 5" 이상 "30 x 30" 이하입니다.
  • board의 각 칸에는 0 이상 100 이하인 정수가 담겨있습니다.
    • 0은 빈 칸을 나타냅니다.
    • 1 ~ 100의 각 숫자는 각기 다른 인형의 모양을 의미하며 같은 숫자는 같은 모양의 인형을 나타냅니다.
  • moves 배열의 크기는 1 이상 1,000 이하입니다.
  • moves 배열 각 원소들의 값은 1 이상이며 board 배열의 가로 크기 이하인 자연수입니다.

board=[[0,0,0,0,0],[0,0,1,0,3],[0,2,5,0,1],[4,2,4,4,2],[3,5,1,3,1]]
moves=[1,5,3,5,1,2,1,4]

def solution(board,moves):
  basket=[]
  answer=0
  #인형은 집게가 움직인 횟수만큼 상자에 담긴다.
  for move in moves :
    #집게가 움직인 위치에서 인형이 몇 번째 칸에 위치하고 있는지 탐색
    for i in range(len(board)):
      #맨 위부터 탐색하다 0이 아닌 숫자가 나오면 상자에 담고, 인형이 있던 칸을 0으로 만든다.
      if board[i][move-1] != 0 :
        basket.append(board[i][move-1])
        board[i][move-1]=0
        #상자에 인형이 2개 이상 채워지고 마지막에 들어온 인형이 그 전 인형과 같을 경우, 인형 두개가 사라지고 숫자는 2가 더해진다.
        if len(basket) >= 2 and basket[-1] == basket[-2] :
          basket=basket[:-2]
          answer+=2
        break
  return answer
solution(board,moves)
4

크레인이 움직이는 위치마다 모든 칸을 탐색하여 인형이 있는 위치를 확인 후 상자에 담는 방식이다. 상자에 담고 나면 인형이 있던 위치는 0으로 치환하여 인형이 없다고 표시한다. 인형을 상자에 담을 때, 그 전에 담긴 인형과 같을 경우 두 인형을 상자에서 없앤 뒤 사라진 인형 숫자 2를 더한다.

문제 설명


수많은 마라톤 선수들이 마라톤에 참여하였습니다. 단 한 명의 선수를 제외하고는 모든 선수가 마라톤을 완주하였습니다.

마라톤에 참여한 선수들의 이름이 담긴 배열 participant와 완주한 선수들의 이름이 담긴 배열 completion이 주어질 때, 완주하지 못한 선수의 이름을 return 하도록 solution 함수를 작성해주세요.

제한사항


  • 마라톤 경기에 참여한 선수의 수는 1명 이상 100,000명 이하입니다.
  • completion의 길이는 participant의 길이보다 1 작습니다.
  • 참가자의 이름은 1개 이상 20개 이하의 알파벳 소문자로 이루어져 있습니다.
  • 참가자 중에는 동명이인이 있을 수 있습니다.

participants=["mislav", "stanko", "mislav", "ana"]
completion=["stanko", "ana", "mislav"]

def solution(participants,completion):
  participants.sort()
  completion.sort()
  for i in completion:
    participants.pop(participants.index(i))
  answer=participants[0]
  return answer
solution(participants,completion)

위 코드는 답을 구하는 것은 문제가 없지만 풀이 시간이 오래 걸려 탈락 판정을 받았다. 

풀이 시간이 오래 걸린 이유를 생각해보면 완주자 이름을 참가자 명단에서 탐색(index) 후 제외(pop)하면서 마지막에 남는 참가자가 탈락자일꺼라 판단해 코드를 작성했지만 완주자 명단 전체를 가지고 탐색하다 시간이 오래 걸린 것 같다.

 

participants=["mislav", "stanko", "mislav", "ana"]
completion=["stanko", "ana", "mislav"]

def solution(participants,completion):
  participants.sort()
  completion.sort()
  answer=""
  for i in range(len(completion)):
    if participants[i] != completion[i]:
      answer+=participants[i]
      break
  return answer

위 코드는 답을 구하는 것과 풀이 시간 모두 통과 판정을 받았다.

제한 사항에서 완주자 수가 참가자 수보다 1 작다는 것은 탈락자가 한명 뿐이라는 것이다. 그렇기 때문에 참가자 명단과 완주자 명단을 정렬한 뒤 처음부터 하나씩 비교하다 보면 탈락한 참가자 이름이 완주자 명단과 맞지 않는 순간이 나올 것이다. 이때 비교된 참가자 이름이 곧 탈락자 명이므로 전체 리스트를 탐색하지 않아도 답을 구할 수 있기 때문에 불필요한 계산 시간을 줄여 풀이 시간도 통과한 것 같다.

 

+탐색 전 정렬 과정은 계산 시간을 줄여주는 방법이라는 것을 알게 되었다.

 

+바로 위 코드에서 문제가 있다. 리스트를 정렬했을 때 탈락자 이름이 참가자 명단 맨 뒤에 있는 경우 코드에서 판별이 되지 않는다는 점이다. 그래서 추가 코드를 기입하여 해결하고자 했다.

 

def solution(participants,completion):
  participants.sort()
  completion.sort()
  answer=""
  for i in range(len(completion)):
    if participants[i] != completion[i]:
      answer+=participants[i]
      break
    ####추가한 코드####
    elif i==(len(completion)-1) :
      answer=participants[i+1]
    ###############
  return answer

완주자 명단 마지막까지 참가자 명단과 같을 경우 참가자 명단에서 맨 뒤 마지막 한명이 탈락자라고 판단하는 코드를 추가하였다. 테스트 한 결과 마찬가지로 통과하였다.

문제 설명


카카오에 입사한 신입 개발자 네오는 "카카오계정개발팀"에 배치되어, 카카오 서비스에 가입하는 유저들의 아이디를 생성하는 업무를 담당하게 되었습니다. "네오"에게 주어진 첫 업무는 새로 가입하는 유저들이 카카오 아이디 규칙에 맞지 않는 아이디를 입력했을 때, 입력된 아이디와 유사하면서 규칙에 맞는 아이디를 추천해주는 프로그램을 개발하는 것입니다.
다음은 카카오 아이디의 규칙입니다.

  • 아이디의 길이는 3자 이상 15자 이하여야 합니다.
  • 아이디는 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.) 문자만 사용할 수 있습니다.
  • 단, 마침표(.)는 처음과 끝에 사용할 수 없으며 또한 연속으로 사용할 수 없습니다.

"네오"는 다음과 같이 7단계의 순차적인 처리 과정을 통해 신규 유저가 입력한 아이디가 카카오 아이디 규칙에 맞는 지 검사하고 규칙에 맞지 않은 경우 규칙에 맞는 새로운 아이디를 추천해 주려고 합니다.
신규 유저가 입력한 아이디가 new_id 라고 한다면,

 

1단계 new_id의 모든 대문자를 대응되는 소문자로 치환합니다.

2단계 new_id에서 알파벳 소문자, 숫자, 빼기(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 제거합니다.

3단계 new_id에서 마침표(.)가 2번 이상 연속된 부분을 하나의 마침표(.)로 치환합니다.

4단계 new_id에서 마침표(.)가 처음이나 끝에 위치한다면 제거합니다.

5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입합니다.

6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개의 문자를 제외한 나머지 문자들을 모두 제거합니다. 만약 제거 후 마침표(.)가 new_id의 끝에 위치한다면 끝에 위치한 마침표(.) 문자를 제거합니다.

7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 new_id의 길이가 3이 될 때까지 반복해서 끝에 붙입니다.

 

제한사항


new_id는 길이 1 이상 1,000 이하인 문자열입니다.
new_id는 알파벳 대문자, 알파벳 소문자, 숫자, 특수문자로 구성되어 있습니다.
new_id에 나타날 수 있는 특수문자는 -_.~!@#$%^&*()=+[{]}:?,<>/ 로 한정됩니다.


import re

def solution(new_id):
  #1단계 모든 대문자를 소문자로 치환
  new_id=new_id.lower()
  
  #2단계 영문자, 숫자, .,-,_를 제외한 문자를 제거
  tmp=""
  for i in list(new_id) :
    if i.isalpha() or i.isdigit() or i in ["-",".","_"]:
      tmp+=i
  new_id=tmp
  #new_id=re.sub("[^a-z1-9-.\_]","",new_id)

  #3단계 마침표가 두번 이상 반복되면 마침표 한개로 변경
  new_id=re.sub(r"[.]+",".",new_id)
  
  #4단계
  #문자열 시작이나 끝이 마침표인 경우 제거
  new_id=new_id.strip(".")
  
  #5단계 new_id가 빈 문자열이라면, new_id에 "a"를 대입
  if new_id =="":
    new_id+="a"

  #6단계 new_id의 길이가 16자 이상이면, new_id의 첫 15개 문자를 제외한 나머지 문자 제거
  if len(new_id) >= 16 :
    new_id=new_id[:15]
    #만약 제거 후 마침표가 new_id의 끝에 위치한다면 끝에 위치한 마침표 문자를 제거
    if new_id[-1]==".": 
      new_id=new_id[0:-1]

  #7단계 new_id의 길이가 2자 이하라면, new_id의 마지막 문자를 길이가 3이 될 때 까지 반복해서 추가
  while len(new_id) < 3 :
    new_id+=new_id[-1]
  return new_id

각 단계 별 조건을 유의하며 코드를 작성해서 해결

어려움을 겪었던 것은 2단계 였는데, re.sub() 함수로 정규표현식을 사용해서 영문자, 숫자, 마침표, -, _ 이 아닌 문자열을 제거하는 코드를 짰는데(주석 처리), 26개 테스트 문제 중 3개가 계속 풀리지 않았다. 결국 문자열을 리스트로 변환해서 반복문으로 하나씩 검사해서 해결하였다.

문제 설명


배열 array의 i번째 숫자부터 j번째 숫자까지 자르고 정렬했을 때, k번째에 있는 수를 구하려 합니다.

예를 들어 array가 [1, 5, 2, 6, 3, 7, 4], i = 2, j = 5, k = 3이라면

  1. array의 2번째부터 5번째까지 자르면 [5, 2, 6, 3]입니다.
  2. 1에서 나온 배열을 정렬하면 [2, 3, 5, 6]입니다.
  3. 2에서 나온 배열의 3번째 숫자는 5입니다.

배열 array, [i, j, k]를 원소로 가진 2차원 배열 commands가 매개변수로 주어질 때, commands의 모든 원소에 대해 앞서 설명한 연산을 적용했을 때 나온 결과를 배열에 담아 return 하도록 solution 함수를 작성해주세요.

 

제한사항


  • array의 길이는 1 이상 100 이하입니다.
  • array의 각 원소는 1 이상 100 이하입니다.
  • commands의 길이는 1 이상 50 이하입니다.
  • commands의 각 원소는 길이가 3입니다.

array=[1, 5, 2, 6, 3, 7, 4]
commands=[[2, 5, 3], [4, 4, 1], [1, 7, 3]]

def solution(array,commands) :
  result=[]
  for command in commands:
    start=command[0]-1
    end=command[1]
    position=command[2]-1
    sampled_list=array[start:end]
    sampled_list.sort()
    result.append(sampled_list[position])
  return result

result=solution(array,commands)
print(result)
[5, 6, 3]

commands 리스트 안에 있는 각 리스트는 앞에서부터 슬라이스 시작 위치, 끝 위치, 정렬 후 추출 위치를 의미한다.

문제 설명


오픈채팅방

 

카카오톡 오픈채팅방에서는 친구가 아닌 사람들과 대화를 할 수 있는데, 본래 닉네임이 아닌 가상의 닉네임을 사용하여 채팅방에 들어갈 수 있다.

신입사원인 김크루는 카카오톡 오픈 채팅방을 개설한 사람을 위해, 다양한 사람들이 들어오고, 나가는 것을 지켜볼 수 있는 관리자창을 만들기로 했다. 채팅방에 누군가 들어오면 다음 메시지가 출력된다.

"[닉네임]님이 들어왔습니다."

채팅방에서 누군가 나가면 다음 메시지가 출력된다.

"[닉네임]님이 나갔습니다."

채팅방에서 닉네임을 변경하는 방법은 다음과 같이 두 가지이다.

  • 채팅방을 나간 후, 새로운 닉네임으로 다시 들어간다.
  • 채팅방에서 닉네임을 변경한다.

닉네임을 변경할 때는 기존에 채팅방에 출력되어 있던 메시지의 닉네임도 전부 변경된다.

예를 들어, 채팅방에 "Muzi"와 "Prodo"라는 닉네임을 사용하는 사람이 순서대로 들어오면 채팅방에는 다음과 같이 메시지가 출력된다.

"Muzi님이 들어왔습니다."
"Prodo님이 들어왔습니다."

채팅방에 있던 사람이 나가면 채팅방에는 다음과 같이 메시지가 남는다.

"Muzi님이 들어왔습니다."
"Prodo님이 들어왔습니다."
"Muzi님이 나갔습니다."

Muzi가 나간후 다시 들어올 때, Prodo 라는 닉네임으로 들어올 경우 기존에 채팅방에 남아있던 Muzi도 Prodo로 다음과 같이 변경된다.

"Prodo님이 들어왔습니다."
"Prodo님이 들어왔습니다."
"Prodo님이 나갔습니다."
"Prodo님이 들어왔습니다."

채팅방은 중복 닉네임을 허용하기 때문에, 현재 채팅방에는 Prodo라는 닉네임을 사용하는 사람이 두 명이 있다. 이제, 채팅방에 두 번째로 들어왔던 Prodo가 Ryan으로 닉네임을 변경하면 채팅방 메시지는 다음과 같이 변경된다.

"Prodo님이 들어왔습니다."
"Ryan님이 들어왔습니다."
"Prodo님이 나갔습니다."
"Prodo님이 들어왔습니다."

채팅방에 들어오고 나가거나, 닉네임을 변경한 기록이 담긴 문자열 배열 record가 매개변수로 주어질 때, 모든 기록이 처리된 후, 최종적으로 방을 개설한 사람이 보게 되는 메시지를 문자열 배열 형태로 return 하도록 solution 함수를 완성하라.

 

제한사항


  • record는 다음과 같은 문자열이 담긴 배열이며, 길이는 1 이상 100,000 이하이다.
  • 다음은 record에 담긴 문자열에 대한 설명이다.
    • 모든 유저는 [유저 아이디]로 구분한다.
    • [유저 아이디] 사용자가 [닉네임]으로 채팅방에 입장 - "Enter [유저 아이디] [닉네임]" (ex. "Enter uid1234 Muzi")
    • [유저 아이디] 사용자가 채팅방에서 퇴장 - "Leave [유저 아이디]" (ex. "Leave uid1234")
    • [유저 아이디] 사용자가 닉네임을 [닉네임]으로 변경 - "Change [유저 아이디] [닉네임]" (ex. "Change uid1234 Muzi")
    • 첫 단어는 Enter, Leave, Change 중 하나이다.
    • 각 단어는 공백으로 구분되어 있으며, 알파벳 대문자, 소문자, 숫자로만 이루어져있다.
    • 유저 아이디와 닉네임은 알파벳 대문자, 소문자를 구별한다.
    • 유저 아이디와 닉네임의 길이는 1 이상 10 이하이다.
    • 채팅방에서 나간 유저가 닉네임을 변경하는 등 잘못 된 입력은 주어지지 않는다.

logs=["Enter uid1234 Muzi", "Enter uid4567 Prodo","Leave uid1234","Enter uid1234 Prodo","Change uid4567 Ryan"]

def check_changes_in_name(logs):
  id_name={}
  for log in logs :
    move_message=log.split(" ")[0]
    if move_message=="Enter" or move_message=="Change"  :
      user_id=log.split(" ")[1]
      user_name=log.split(" ")[2]
      id_name[user_id]=user_name
  return id_name

def solution(logs):
  id_name=check_changes_in_name(logs)
  result=[]
  for log in logs:
    move_message=log.split(" ")[0]
    user_id=log.split(" ")[1]
    user_name=id_name[user_id]
    if move_message=="Enter":
      result.append("{0}님이 들어왔습니다.".format(user_name))
    elif move_message=="Leave":
      result.append("{0}님이 나갔습니다.".format(user_name))
  return result

result=solution(logs)
print(result)
['Prodo님이 들어왔습니다.', 'Ryan님이 들어왔습니다.', 'Prodo님이 나갔습니다.', 'Prodo님이 들어왔습니다.']

문제는 전체 출입 로그를 확인하고 닉네임 변경 사항을 확인하여 최종적으로 어떤 사람이 들어오고 나갔는지를 메세지로 저장하는 것이다.

 

채팅방에 유저가 들어올 때, 닉네임을 변경할 때마다 유저의 아이디에 맞춰 닉네임 정보를 저장한 뒤 최종적으로 저장된 유저 아이디와 닉네임 정보에 맞춰 메세지를 리스트에 저장하면 된다.

문제 설명


주어진 숫자 중 3개의 수를 더했을 때 소수가 되는 경우의 개수를 구하려고 합니다. 숫자들이 들어있는 배열 nums가 매개변수로 주어질 때, nums에 있는 숫자들 중 서로 다른 3개를 골라 더했을 때 소수가 되는 경우의 개수를 return 하도록 solution 함수를 완성해주세요.

 

제한사항


  • nums에 들어있는 숫자의 개수는 3개 이상 50개 이하입니다.
  • nums의 각 원소는 1 이상 1,000 이하의 자연수이며, 중복된 숫자가 들어있지 않습니다.
import itertools

def solution(nums):  
  #3개를 골라 더하는 경우의 수 구하기
  result=[]
  for i in itertools.combinations(nums,3):
    result.append(i)
  #소수인지 확인
  n=0
  for number in result :
    count=0
    for k in range(2,sum(number)):
      if sum(number) % k == 0:
        count+=1
    if count != 0 :
      continue
    else : 
      n+=1
  return n

nums=[1,2,7,6,4]

solution(nums)
4

문제는 주어진 숫자들에서 무작위로 3개를 골라 더한 값들 중 소수인 경우가 몇 개인지 구하는 것이다.

해결하기 위해 주어진 숫자들로부터 3개씩 골라 조합을 만들고 이것이 소수인지 판단하는 과정이 필요하다.

itertools.combinations() 함수를 사용해서 모든 조합을 구하였다.

소수는 약수가 1과 자신 뿐인 수를 의미한다. 그렇기 때문에 2~(소수-1)인 모든 값으로 나누었을 때 나머지가 0이 나올 수 없다. 이러한 특징을 활용하면 문제를 해결할 수 있다.

파이썬 리스트에서 중복되는 값이 있을 경우 이를 제거하는 방법에 대한 정리

 

test=[1,1,1,0,3,3,3,1,1]

위와 같이 숫자가 담긴 리스트가 있을 때, 몇 가지 경우를 나누어 중복되는 값을 제거하는 방법을 알아보자.

 

순서 유지 O, 중복되는 값 모두 제거

test=[1,1,1,0,3,3,3,1,1]
result=[]
for i in test :
  if i not in result :
    result.append(i)
print(result)
[1, 0, 3]

빈 result 리스트를 생성한 뒤 for문으로 test 리스트 값이 result 리스트에 포함되는지 확인하면서 추가

 

순서 유지 O, 연속으로 중복되는 값만 제거

test=[1,1,1,0,3,3,3,1,1]
result=[]
for i in test :
  if i not in result :
    result.append(i)
  elif i in result and i != result[-1] :
    result.append(i)
print(result)
[1, 0, 3, 1]

연속되는 값만 제거하고 싶은 경우 if 문에 한 가지 조건을 추가하면 된다. for문으로 연속적인 값들을 확인하다 비연속적인 값이 result 리스트에 담기게 될 경우 result 리스트의 마지막 값과 다를 것이기 때문에 이를 확인하는 조건을 넣어서 연속으로 중복되는 값만 제거할 수 있다.

 

순서 유지 X, 중복되는 값 모두 제거

test=[1,1,1,0,3,3,3,1,1]
result=list(set(test))
print(result)
[0, 1, 3]

튜플은 중복 값을 포함하지 않는다. 이 특징을 사용해서 test 리스트를 set() 함수를 사용해서 튜플로 바꾼 뒤 다시 리스트로 변환하면 중복된 값이 제거된다. 단, 원래 리스트에 있던 순서는 유지되지 않을 수 있다.

 

'Python' 카테고리의 다른 글

오픈API 사용해보기  (3) 2021.07.01

전체 토끼 커플 수 구하기


6 3

위와 같이 개월 수(6)와 살 수 있는 개월 수(3)가 주어졌을 때

4

6개월 뒤 존재하는 전체 토끼 쌍 구하기


문제출처 http://rosalind.info/problems/fibd/

 

#문제 불러오기
with open("rosalind_fibd.txt","r") as f:
  line=f.readline()

#번식 개월 수와 생존 가능 개월 수 변수에 할당
month=int(line.split(" ")[0])
live=int(line.split(" ")[1])

#첫 달 자손 세대 토끼쌍 수 1 저장
start=[1]

#첫 달 부모 세대 토끼쌍 수 0 저장
for i in range(live-1):
  start.append(0)

#매달 발생하는 토끼쌍 수를 저장할 리스트 생성
all_number_of_rabbit=[start]

#for문으로 매달 발생하는 토끼쌍 수 계산
for i in range(month-1):
  tmp=[]
  new_born=0
  for k in range(1,live):
    new_born=new_born+all_number_of_rabbit[-1][k]
  tmp.append(new_born)
  for k in range(live-1):
    tmp.append(all_number_of_rabbit[-1][k])
  all_number_of_rabbit.append(tmp)

#마지막 달 토끼쌍 수 합 구하기
result=0
for i in all_number_of_rabbit[-1]:
  result+=i
print(result)

Point는 1. 매달 발생하는 토끼 쌍의 개수를 세대를 구분 지어 계산하는 것이다.

3달 안에 죽을 경우 피보나치 토끼 번식 양상

위와 같이 토끼들이 세 달 안에 죽는 상황에서 6개월 동안 번식했을 때의 토끼 쌍을 구하면 네 쌍이 발생한다.

 

중요한 것은 첫 달에 토끼가 태어나면 둘 째, 셋 째 달에 자손을 낳고 죽는다는 것이다.

 

이해를 위해 위 그림을 표로 나타내면 다음과 같다. 

번식이 가능한 세대더라도 아직 수명이 남은 토끼 쌍은 다음 달에 번식이 가능하고 수명이 남지 않은 토끼 쌍은 다음 달에 자식을 낳고 죽는다. 그렇기 때문에 수명이 세 달인 토끼들은 네 번째 세대가 없다.

 

이러한 특징을 가지고 예측을 하면 7번째 달에 존재하는 토끼 쌍은 6번째 달에 존재하는 번식이 가능한 토끼 쌍의 수(2번째, 3번째 세대)와 살아있을 토끼 쌍의 수의 합(1번째, 2번째 세대)과 같다.

 

이를 유의하여 각 개월에 따른 세대 별 토끼 쌍 수를 구하고 마지막 개월에 존재하는 토끼 쌍 수를 전부 합하면 답을 구할 수 있다.

+ Recent posts