- 문제 : https://school.programmers.co.kr/learn/courses/30/lessons/42626

 

문제 이해 

- scoville 배열에서 모든 숫자가 주어진 K 이상이 될 때까지의 연산 횟수를 반환하는 문제다. 

- 연산은 (가장 작은 수) + 2 * (두 번째로 작은 수)로 진행하며, 새롭게 업데이트 한 숫자를 다시 scoville에 추가한다. 

- 가장 작은 수를 찾아야하고, len(scoville)이 최대 백 만이기 때문에 배열에서 가장 작은 수가 0 인덱스에 있고, 시간 복잡도가 O(logn)인 heap을 이용해야한다! 

- 위와 같은 방식으로 scoville을 갱신하다가 scoville의 가장 앞 숫자가 K이상이라면 나머지 숫자들도 다 K이상이므로 while문을 break 하면 된다.

- 하지만 만약 scoville에 원소 하나만 남았는데 그 숫자가 K 미만이라면 조건을 만족하지 못하므로 -1을 출력하면 된다.

 

정답 풀이

import heapq

def solution(scoville, K):
    answer = 0 # K를 만들기 위해 섞은 횟수 
    
    heapq.heapify(scoville)
    
    while len(scoville) >= 2:
        first = heapq.heappop(scoville)
        if first >= K: # 가장 작은 수마저 K이상이므로 모든 수가 K 이상임을 알 수 있음
            break

        result = first + 2 * heapq.heappop(scoville)
        answer += 1
        heapq.heappush(scoville, result)
        
    if scoville[0] < K :
        return -1
    else:
        return answer

- 문제 : https://school.programmers.co.kr/learn/courses/30/lessons/133501 

 

- 정답 풀이 : 

 

참고한 블로그

def solution(distance, scope, times):
    ch = []
    for i in range(len(scope)):
        start, end = sorted(scope[i])
        work, rest = times[i]
        time = start
        while time <= end:
            N = time % (work+rest)
            if 0 < N <= work:
                ch.append(time)
                break
            time += 1

    if ch: return sorted(ch)[0]
    else:  return distance

 

- 시도해본 풀이 : 

 

78.6에서 틀렸다

def solution(distance, scope, times):  
    answer = []

    soldiers = []
    for i in range(len(scope)):
        scope[i].sort()
        temp = scope[i] + times[i]
        temp.append(sum(times[i]))
        soldiers.append(temp)
        
    soldiers.sort()
    for i in range(len(soldiers)):
        start, end = soldiers[i][0], soldiers[i][1]
        cycle = end // soldiers[i][4] # 사이클 몇번 도는지 
        for j in range(start, end + 1):
            # 병사 근무 범위에서 근무하는 중일 때 
            if soldiers[i][4] * cycle < j <= soldiers[i][4] * cycle + soldiers[i][2]: 
                answer.append(j)
                break

    if len(answer) == 0:
        return distance
    else:
        return min(answer)

테스트 50%에서 틀렸다. 

def solution(distance, scope, times):  
    sum_times = [sum(times[i]) for i in range(len(times))] # 일 + 휴식 단위 
    answer = []
    location = 1
    for i in range(len(scope)):
        start, end = scope[i][0], scope[i][1]
        cycle = end // sum_times[i] # 사이클 몇번 도는지 
        for j in range(start, end + 1):
            # 병사 근무 범위에서 근무하는 중일 때 
            if sum_times[i] * cycle < j <= sum_times[i] * cycle + times[i][0]: 
                answer.append(j)
                break

    if len(answer) == 0:
        return distance
    else:
        return min(answer)

- 문제 : https://school.programmers.co.kr/learn/courses/30/lessons/135807

 

스스로 푼 문제다!

이해는 어렵지 않았는데, 시간 복잡도 때문에 이에 대해 생각해봐야했던 문제다. 

math.gcd 사용하는 법을 익혀야할 것 같다. 

 

문제 이해 

arrayA 원소의 공약수 중 arrayB의 모든 원소를 나누지 못하는 수를 구하고

arrayB 원소의 공약수 중 arrayA의 모든 원소를 나누지 못하는 수를 구해서

그 중 최댓값을 반환하고, 없다면 0을 반환하면 된다고 이해했다. 

 

풀이 이해

  • 각 배열에 대해 모든 원소를 나누는 공약수가 있는지 확인하기 위해 get_common() 함수를 이용했다. 
    • 처음에는 여기서 모든 원소의 약수를 모은 다음 진행했는데, 이렇게 하면 시간초과가 발생하므로 시간을 줄일 수 있는 방법을 생각했다.
    • 배열의 모든 원소를 나눌 수 있는 수라면 배열의 한 원소를 선택해 그것의 약수로 진행해도 된다라는 생각했다. 그래서 가장 큰 원소의 약수를 temp에 저장한다음 그 원소 중에 arr의 모든 원소를 나눌 수 있는 것들을 result에 모은 다음 반환했다. 
  • arrayA와 arrayB에 대해 commons_A, commons_B를 구한 다음 길이에 따라 로직을 다르게 했고, 공통된 연산은 operation()함수를 이용했다. 결과는 answer에 저장했다.
  • 이렇게 구한 answer는 조건을 만족하는 수이므로 answer에 원소가 없다면 0을, 있다면 최대값을 반환한다. 
  • 이때 arrayA = [3], arrayB = [17]인 경우 각 배열의 원소는 본인이 속한 배열의 원소를 다 나누고, 반대는 다 나누지 못하기 때문에 두 수 모두 조건을 만족한다. 이런 경우는 둘 중 최댓값을 반환하는 로직을 추가해야 테스트 두 개를 통과할 수 있다. (edge case)

 

- 정답 풀이 :

풀이가 너무 길다.

다른 풀이 참고해서 약수 구하는 것 등 코드 줄일 수 있는 방법을 생각해봐야겠다.

 

import math

def get_common(arr): #리스트의 모든 원소 약수를 모두 모아서 반환하는 함수 
    temp = []
    arr.sort()
    num = arr[-1]
    for i in range(2, int(math.sqrt(num) + 1)):
        if num % i == 0:
            temp.append(i)
            temp.append(num // i)
            
    result = []
    for i in range(len(temp)):
        flag = True
        for j in range(len(arr)):
            if arr[j] % temp[i] != 0:
                flag = False
                break
        if flag:
            result.append(temp[i])
            
    return result

def operation(arr, commons):
    answer = []
    for i in range(len(commons)):
            flag = True
            for j in range(len(arr)):
                if arr[j] % commons[i] == 0:
                    flag = False
                    break
            if flag:
                answer.append(commons[i])
    return answer
                         
def solution(arrayA, arrayB):
    if len(arrayA) == 1 and len(arrayB) == 1:
        min_num, max_num = min(arrayA[0], arrayB[0]), max(arrayA[0], arrayB[0])
        if max_num % min_num != 0: # 두 수는 소수 관계
            return max_num
    
    commons_A = get_common(arrayA) # A의 모든 원소를 나누는 공약수 
    commons_B = get_common(arrayB) # B의 모든 원소를 나누는 공약수 
    
    answer = []
    if len(commons_A) == 0 and len(commons_B) == 0:
        return 0
    
    elif len(commons_A) == 0:
        answer = operation(arrayA, commons_B)
        
    elif len(commons_B) == 0:
        answer = operation(arrayB, commons_A)
                
    else: 
        answer = operation(arrayA, commons_B)
        answer += operation(arrayB, commons_A)
                      
    if len(answer) == 0:
        return 0 
    else:
        return max(answer)

 

 

- 시도해본 풀이 :

테스트 2 / 3 통과했다. 

import math

def get_common(arr): #리스트의 모든 원소 약수를 모두 모아서 반환하는 함수 
    temp = set()
    for i in range(len(arr)):
        num = arr[i]
        for j in range(2, int(math.sqrt(arr[i])) + 1):
            if num % j == 0:
                temp.add(j)
                temp.add(num // j)
                
    temp = list(temp)
    result = []
    for i in range(len(temp)):
        flag = True
        for j in range(len(arr)):
            if arr[j] % temp[i] != 0:
                flag = False
                break
        if flag:
            result.append(temp[i])
            
    return result

def operation(arr, commons):
    answer = []
    for i in range(len(commons)):
            flag = True
            for j in range(len(arr)):
                if arr[j] % commons[i] == 0:
                    flag = False
                    break
            if flag:
                answer.append(commons[i])
    return answer
                         
def solution(arrayA, arrayB):
    commons_A = get_common(arrayA) # A의 모든 원소를 나누는 공약수 
    commons_B = get_common(arrayB) # B의 모든 원소를 나누는 공약수 
    
    answer = []
    if len(commons_A) == 0 and len(commons_B) == 0:
        return 0
    
    elif len(commons_A) == 0:
        answer = operation(arrayA, commons_B)
        
    elif len(commons_B) == 0:
        answer = operation(arrayB, commons_A)
                
    else: 
        answer = operation(arrayA, commons_B)
        answer += operation(arrayB, commons_A)
                      
    if len(answer) == 0:
        return 0 
    else:
        return max(answer)

- 문제 : https://school.programmers.co.kr/learn/courses/30/lessons/131130

 

스스로 푼 문제다!

 

문제 이해

처음엔 무슨 문제지 하면서 하나도 이해가지 않았다. 

예제를 기반으로 풀어보니 

- cards의 원소 - 1는 다음 인덱스의 값을 가리키고 있고,

- 0인덱스부터 시작하는데 인덱스 i에서 cards[i]로 이동한 다음,

- cards[i]를 방문하지 않았다면 cards[cards[i]]로 계속 이동하는 문제였다.

 

위와 같은 방식으로 계속 이동하다가 멈추었을 때가 하나의 박스 세트다. 각 갯수를 저장한 다음 가장 큰 값과 두번째로 큰 값의 곱을 반환하면 된다고 이해했다. 

 

풀이 이해

  • cards의 값과 인덱스를 통일하기 위해서 전체 값에 -1을 한다. 
  • 방문하지 않은 인덱스를 구별할 것이므로 visit를 초기화하고, 각 박스 세트의 박스 갯수를 세기위해 box_set도 초기화한다. 
  • 인덱스 0부터 순차적으로 진행한는데, 방문하지 않은 인덱스 i에 대해 while문을 돌린다. 
    • index = cards[i]로 설정한뒤 visit[index] == 1이라면 while문을 break 하고
    • 아니라면 방문처리와 갯수를 증가하고 cards[index]로 이동한다.(index = cards[index])
  • 갯수가 첫 번째로 많은 세트와 두번째로 많은 세트를 구해야하므로 내림차순으로 정렬한다. 
  • 문제에서 세트가 한번에 끝나면 0을 반환하라고 했으므로 box_set가 하나만 있으면 0을 반환하고
  • 아니라면 가장 큰 두 값의 곱을 반환한다. 

 

- 정답 풀이 :

def solution(cards):
    n = len(cards)
    for i in range(n):
        cards[i] -= 1
        
    box_set = []
    visit = [0] * n
    for i in range(n):
        if not visit[i]:
            visit[i], count, index = 1, 1, cards[i]
            while True:
                if visit[index]:
                    box_set.append(count)
                    break
                visit[index] = 1
                count += 1
                index = cards[index]            
    box_set.sort(reverse = True)
    
    if len(box_set) == 1:
        return 0
    else:
        return box_set[0] * box_set[1]

+ Recent posts