🧩 Algorithm/프로그래머스

[programmers] 없는 숫자 더하기, 로또의 최고 순위와 최저 순위

nerowiki 2024. 4. 8. 23:30
728x90
💡 오늘의 학습 키워드
- 없는 숫자 더하기
- 로또의 최고 순위와 최저 순위

 

없는 숫자 더하기

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/86051 

 

문제 설명

더보기
0부터 9까지의 숫자 중 일부가 들어있는 정수 배열 numbers가 매개변수로 주어집니다. 
numbers 에서 찾을 수 없는 0부터 9까지의 숫자를 모두 찾아 더한 수를 return 하도록 solution 함수를 완성해주세요.
제한 사항
1 ≤ numbers의 길이 ≤ 9
0 ≤ numbers의 모든 원소 ≤ 9
numbers의 모든 원소는 서로 다릅니다.

 

문제 회고

💡 어떤 문제가 있었고, 나는 어떤 시도를 했는지 그리고 새롭게 안 사실은 무엇인지

반복문을 통해 간단하게 풀이할 수 있는 문제 였습니다. 처음엔 로직을 그대로 따라가며
0 부터 9까지 수를 입력 받은 numbers 리스트와 비교하며 없는 수를 구해 보았습니다.

그리고 numbers 리스트에 0 ~ 9 까지 수가 존재하지 않을 때를 생각해보니,
0 ~ 9까지의 전체 합에서 numbers 배열의 전체 합을 빼도 동일한 값이 리턴되는 것을 알 수 있었습니다.

 

💡 내가 해결한 방식은?
반복문을 통한 같은 수 제거
def solution(numbers):
    answer = 0
    # 0 ~ 9 순회
    for num in range(10):
        # numbers 배열 수와 같다면 continue
        if num in numbers:
            continue
        answer = answer + num
    return answer

 

리스트 합을 통한 나머지 구하기
def solution(numbers):
    num_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    return sum(num_list) - sum(numbers)

 


로또의 최고 순위와 최저 순위

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/77484

 

문제 설명

더보기
로또 6/45 (이하 '로또'로 표기)는 1부터 45까지의 숫자 중 6개를 찍어서 맞히는 대표적인 복권입니다.
아래는 로또의 순위를 정하는 방식입니다. 

순위    당첨 내용
1         6개 번호가 모두 일치
2         5개 번호가 일치
3         4개 번호가 일치
4         3개 번호가 일치
5         2개 번호가 일치
6         (낙첨)그 외

로또를 구매한 민우는 당첨 번호 발표일을 학수고대하고 있었습니다.
하지만, 민우의 동생이 로또에 낙서를 하여, 일부 번호를 알아볼 수 없게 되었습니다.
당첨 번호 발표 후, 민우는 자신이 구매했던 로또로 당첨이 가능했던
최고 순위와 최저 순위를 알아보고 싶어 졌습니다. 알아볼 수 없는 번호를 0으로 표기하기로 하고,
민우가 구매한 로또 번호 6개가 44, 1, 0, 0, 31 25 라고 가정해보겠습니다.
당첨 번호 6개가 31, 10, 45, 1, 6, 19 라면, 당첨 가능한 최고 순위와 최저 순위의 한 예는 아래와 같습니다.

당첨 번호              31        10         45        16           19                 결과
최고 순위 번호      31      0→10     44      10→62      5            4개 번호 일치, 3등
최저 순위 번호      31      0→11      44      10→72      5            2개 번호 일치, 5등

순서와 상관없이, 구매한 로또에 당첨 번호와 일치하는 번호가 있으면 맞힌 걸로 인정됩니다.
알아볼 수 없는 두 개의 번호를 각각 10, 6이라고 가정하면 3등에 당첨될 수 있습니다.
3등을 만드는 다른 방법들도 존재합니다.
하지만, 2등 이상으로 만드는 것은 불가능합니다.
알아볼 수 없는 두 개의 번호를 각각 11, 7이라고 가정하면 5등에 당첨될 수 있습니다.
5등을 만드는 다른 방법들도 존재합니다. 하지만, 6등(낙첨)으로 만드는 것은 불가능합니다.

민우가 구매한 로또 번호를 담은 배열 lottos, 당첨 번호를 담은 배열 win_nums가 매개변수로 주어집니다.
이때, 당첨 가능한 최고 순위와 최저 순위를 차례대로 배열에 담아서 return 하도록
solution 함수를 완성해주세요.
제한 사항
1. lottos는 길이 6인 정수 배열입니다.
2. lottos의 모든 원소는 0 이상 45 이하인 정수입니다.
       2.1 0은 알아볼 수 없는 숫자를 의미합니다.
       2.2 0을 제외한 다른 숫자들은 lottos에 2개 이상 담겨있지 않습니다.
       2.3 lottos의 원소들은 정렬되어 있지 않을 수도 있습니다.
3. win_nums은 길이 6인 정수 배열입니다.
4 win_nums의 모든 원소는 1 이상 45 이하인 정수입니다.
       4.1 win_nums에는 같은 숫자가 2개 이상 담겨있지 않습니다.
       4.2 win_nums의 원소들은 정렬되어 있지 않을 수도 있습니다.

 

문제 회고

💡 어떤 문제가 있었고, 나는 어떤 시도를 했는지 그리고 새롭게 안 사실은 무엇인지

문제 길이는 길지만 결국 lottos와 win_nums 리스트 간 공통 요소를 어떻게 추출하는 지가 주요 포인트였습니다.
제가 생각한 문제 해결 방법은 다음과 같습니다.

  1. 반복문으로 순회하며 조건에 맞는 번호를 저장합니다. 각 조건은 다음과 같습니다.
    1. lottos 리스트에서 0인 번호의 개수를 구합니다.
    2. lottos, win_nums 리스트 간 공통 요소를 구합니다.
  2. 등수를 구하기 위해 저장된 번호를 등수에 맞게 변환해줍니다.

로직 자체는 간단해 가장 먼저 반복문을 사용해 풀이를 진행 해보았습니다.
두 조건의 번호 값을 조건문을 통해 구한 후 최고, 최저 순위를 등수에 맞게 변환 해 주었습니다.

 

일부 TC를 통과하지 않아 제한 사항을 통해 범위 설정이 필요한 것을 확인했습니다.
1 초과일 경우에만 허용하도록 설정하고 그 외에는 6등으로 6이 출력되도록 조건을 걸어주었습니다.

 

그리고 습관처럼 반복문을 생략할 방법을 고민해보니,
lottos의 0의 개수는 count로 구할 수 있어 보이고,
lottos와 win_nums 배열 간의 공통 값을 어떻게 구할지가(?) 관건이었습니다.

 

저번 문제에서 학습한 lambda를 사용 해 filter 함수에서 lottos 리스트를 순회한 값을 
win_nums 원소와 비교해 추출하도록 구현해보았습니다.
막상 구현해보니 반복문이 가독성이 더 좋을 것 같다는 생각이 들었습니다. 

 

💡 내가 해결한 방식은?
반복문을 통한 번호 추가   
def solution(lottos, win_nums):
    answer = []
    a = b = 0
    for num in lottos:
        if num == 0:            # 알아볼 수 없는 번호
            a += 1
        elif num in win_nums:   # 당첨 번호일 경우
            b += 1
    # 최고 순위일 경우,  
    answer.append(7 - (a + b) if a+b > 1 else 6)
    # 최저 순위일 경우 
    answer.append(7 - b if b > 1 else 6)
     
    return answer

 

filter, lambda, count 함수를 통한 번호 추가
def solution(lottos, win_nums):
    answer = []
    # 민우가 구매한 로또 번호와 당첨 번호의 각각의 배열의 중복을 제거한 후
    # list 간 공통 요소 찾기 어떻게?
    w_num = len(list(filter(lambda x: x in win_nums, lottos)))
    z_num = lottos.count(0)
    answer.append(7 - (w_num + z_num) if w_num+z_num > 1 else 6)
    answer.append(7 - w_num if w_num > 1 else 6)
    return answer

 

TIL

첫 번째 문제, 두 번째 문제 모두 리스트를 사용한 간단한 구현문제였다.
특히 두 번째 문제에서 list 간 공통 요소를 찾는 방법을 고민하면서 filter 와 lambda 로 구현하는 것 말고
set 와 & 연산자를 사용한 방식도 있었다.
win_nums 제한 사항에 중복 요소가 없어 구현 의의가 없기에 넘어가긴 했는데,
리스트 간에 & 연산으로 구하면 되지 않을까? 했지만 응 안돼~ 돌아가 바~로 에러가 발생했다.
그래도 덕분에 & 연산자를 깊게 이해할 수 있었고 리스트 간 연산이 왜 안되는지 유의미한 지식(?)을 얻을 수 있었다.

& 연산이 set만 가능한 이유는 set 연산으로 반환되는 set 객체가 집합 연산을 지원하기 때문입니다.
그 이유로 두 set 객체 안 공통으로 존재하는 요소들로 이루어진 새로운 set 객체를 반환하는 것입니다.
반면 리스트는 순서가 있는 데이터 구조이고, 중복이 허용되므로 집합 연산의 의미가 명확하지 않아
& 연산을 직접 사용할 수 없고 오직 set을 통해서만 가능합니다.