관리 메뉴

커리까지

[프로그래머스] 연속 부분 수열 합의 개수 파이썬 본문

알고리즘/풀이

[프로그래머스] 연속 부분 수열 합의 개수 파이썬

목표는 커리 2022. 12. 2. 17:09
728x90
SMALL

문제 설명

철호는 수열을 가지고 놀기 좋아합니다. 어느 날 철호는 어떤 자연수로 이루어진 원형 수열의 연속하는 부분 수열의 합으로 만들 수 있는 수가 모두 몇 가지인지 알아보고 싶어졌습니다. 원형 수열이란 일반적인 수열에서 처음과 끝이 연결된 형태의 수열을 말합니다. 예를 들어 수열 [7, 9, 1, 1, 4] 로 원형 수열을 만들면 다음과 같습니다.
그림.png
원형 수열은 처음과 끝이 연결되어 끊기는 부분이 없기 때문에 연속하는 부분 수열도 일반적인 수열보다 많아집니다.
원형 수열의 모든 원소 elements가 순서대로 주어질 때, 원형 수열의 연속 부분 수열 합으로 만들 수 있는 수의 개수를 return 하도록 solution 함수를 완성해주세요.


제한사항
  • 3 ≤ elements의 길이 ≤ 1,000
  • 1 ≤ elements의 원소 ≤ 1,000

입출력 예
elements result
[7,9,1,1,4] 18

입출력 예 설명

입출력 예 #1
길이가 1인 연속 부분 수열로부터 [1, 4, 7, 9] 네 가지의 합이 나올 수 있습니다.
길이가 2인 연속 부분 수열로부터 [2, 5, 10, 11, 16] 다섯 가지의 합이 나올 수 있습니다.
길이가 3인 연속 부분 수열로부터 [6, 11, 12, 17, 20] 다섯 가지의 합이 나올 수 있습니다.
길이가 4인 연속 부분 수열로부터 [13, 15, 18, 21] 네 가지의 합이 나올 수 있습니다.
길이가 5인 연속 부분 수열로부터 [22] 한 가지의 합이 나올 수 있습니다.
이들 중 중복되는 값을 제외하면 다음과 같은 18가지의 수들을 얻습니다.
[1, 2, 4, 5, 6, 7, 9, 10, 11, 12, 13, 15, 16, 17, 18, 20, 21, 22]

제출 답안

  1. deque를 사용해서 rotate를 하려고 하였다.
  2. elements길이만큼 for loop를 돈다.
    1. 그러면서 각각의 0:(0,1,2,3,4) 각각의 합을 answer에 add한다.
    2. 한 번 끝났으면 돌려서 다시 시작한다.
from collections import deque
def solution(elements):
    elements = deque(elements)
    cnt = len(elements)
    answer = set()
    for _ in range(cnt):
        for j in range(1, cnt + 1):
            ele = list(elements)
            answer.add(sum(ele[0:j]))
        elements.rotate(-1) 
    return len(answer)
테스트 1 〉 통과 (0.01ms, 10.2MB)
테스트 2 〉 통과 (117.34ms, 13MB)
테스트 3 〉 통과 (254.29ms, 14.1MB)
테스트 4 〉 통과 (650.64ms, 18.2MB)
테스트 5 〉 통과 (1043.48ms, 26.9MB)
테스트 6 〉 통과 (1874.25ms, 26.9MB)
테스트 7 〉 통과 (3021.52ms, 26.9MB)
테스트 8 〉 통과 (4496.67ms, 27.6MB)
테스트 9 〉 통과 (6268.21ms, 43.7MB)
테스트 10 〉 통과 (9274.26ms, 43.6MB)
테스트 11 〉 통과 (1445.66ms, 27MB)
테스트 12 〉 통과 (2021.85ms, 27MB)
테스트 13 〉 통과 (2348.33ms, 26.7MB)
테스트 14 〉 통과 (3605.40ms, 26.9MB)
테스트 15 〉 통과 (3871.52ms, 26.9MB)
테스트 16 〉 통과 (4510.33ms, 43.7MB)
테스트 17 〉 통과 (4963.75ms, 43.7MB)
테스트 18 〉 통과 (5478.18ms, 43.5MB)
테스트 19 〉 통과 (6449.70ms, 43.6MB)
테스트 20 〉 통과 (7617.97ms, 43.6MB)
  • 통과는 했지만 시간이 오래 걸리고 메모리를 많이 사용한다.

개선 답안

  1. 2배를 하면 연결된 형태로 사용가능하다.
    1. 그렇게 계속 index를 증가시키며 계산한다.
def solution(elements):
    elements_twice = elements * 2
    answer = set()
    cnt = len(elements)
    for i in range(1, cnt + 1):
        for j in range(cnt):
            answer.add(sum(elements_twice[j:i + j]))
    return len(answer)
테스트 1 〉 통과 (0.01ms, 9.99MB)
테스트 2 〉 통과 (38.15ms, 12.9MB)
테스트 3 〉 통과 (115.69ms, 14.1MB)
테스트 4 〉 통과 (255.23ms, 18.2MB)
테스트 5 〉 통과 (488.80ms, 26.9MB)
테스트 6 〉 통과 (825.88ms, 26.9MB)
테스트 7 〉 통과 (1288.88ms, 26.9MB)
테스트 8 〉 통과 (1902.36ms, 27.6MB)
테스트 9 〉 통과 (2770.23ms, 43.7MB)
테스트 10 〉 통과 (4251.45ms, 43.5MB)
테스트 11 〉 통과 (622.07ms, 26.8MB)
테스트 12 〉 통과 (790.82ms, 26.9MB)
테스트 13 〉 통과 (1172.44ms, 27MB)
테스트 14 〉 통과 (1314.36ms, 26.9MB)
테스트 15 〉 통과 (1690.66ms, 27MB)
테스트 16 〉 통과 (2063.34ms, 43.7MB)
테스트 17 〉 통과 (2590.54ms, 43.8MB)
테스트 18 〉 통과 (2827.80ms, 43.8MB)
테스트 19 〉 통과 (3431.00ms, 43.6MB)
테스트 20 〉 통과 (3992.95ms, 43.8MB)

더 호율적인 답안

  1. 각 자리의 값을 계속 더하면서 업데이트 한다.
  2. 그 리스트를 answer에 다시 저장하면 된다.
  3. 다른 사람의 풀이였는데 내가 원했던 답이 바로 이거였다.
    1. 현재 인덱스랑 나머지 인덱스를 더하는 것 까지만 생각했었는데 이렇게 구현된걸 보고 다시 한 번 배웠다.
def solution(elements):
    answer = set()
    n = len(elements)
    add = [0 for i in range(n)]
    for i in range(n):
        add = [add[j] + elements[(i+j)%n] for j in range(n)]
        answer.update(add)
    return len(answer)
테스트 1 〉 통과 (0.02ms, 10.2MB)
테스트 2 〉 통과 (11.31ms, 13MB)
테스트 3 〉 통과 (15.11ms, 14.3MB)
테스트 4 〉 통과 (28.92ms, 18.2MB)
테스트 5 〉 통과 (67.73ms, 26.9MB)
테스트 6 〉 통과 (79.60ms, 26.9MB)
테스트 7 〉 통과 (110.59ms, 27MB)
테스트 8 〉 통과 (118.52ms, 27.7MB)
테스트 9 〉 통과 (162.42ms, 43.7MB)
테스트 10 〉 통과 (216.05ms, 43.7MB)
테스트 11 〉 통과 (86.93ms, 27MB)
테스트 12 〉 통과 (91.16ms, 27MB)
테스트 13 〉 통과 (77.31ms, 27MB)
테스트 14 〉 통과 (83.61ms, 27MB)
테스트 15 〉 통과 (98.95ms, 27MB)
테스트 16 〉 통과 (120.11ms, 43.6MB)
테스트 17 〉 통과 (137.31ms, 43.7MB)
테스트 18 〉 통과 (166.34ms, 43.7MB)
테스트 19 〉 통과 (162.78ms, 43.7MB)
테스트 20 〉 통과 (196.07ms, 43.7MB)
728x90
LIST
Comments