알고리즘

Greed 탐욕 법 (프로그래머스)

쿠와와 2021. 1. 29. 13:22

그리디 알고리즘

- 동적 프로그래밍 사용시 지나치게 많은 일을 한다, 그래서 보완하는 개념으로 나옴 

미래를 생각하지 않고 최선의 선택을 하는 방법, 즉 문제를 해결하는 과정에서 그 순간순간마다 최적이라고 생각되는 결정을 하는 방식으로 최종 해답에 도달하는 문제 해결 방식

 

 

1번. 체육복

 

코딩테스트 연습 - 체육복

점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번

programmers.co.kr

# greedy_1.py
n = 5               # 전체 학생
lost = [2, 4]       # 잃어버림
reserve = [1, 3, 5]     # 여벌


def solution(n, lost, reserve):
    l = [l for l in lost if l not in reserve]
    r = [r for r in reserve if r not in lost]

    for res in r:
        if res-1 in l:
            l.remove(res-1)
        elif res+1 in l:
            l.remove(res+1)

    return n - len(l)


print(solution(n, lost, reserve))

 

 

2번. 조이스틱

 

코딩테스트 연습 - 조이스틱

조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다. ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA 조이스틱을 각 방향으로 움직이면 아래와 같습니다. ▲ - 다

programmers.co.kr

테스트 케이스가 강화되고 꽤나 신경써야 하는 문제로 바꿘거 같다.

# greedy_2.py
# name = "JEROEN"
name = "ABABAAAAAAABA"
# name = "JAZ"
# 아스키 값 이용하면 될듯? ord
# 1  2  3  4  5  6  7  8  9 10 11 12 13
# A, B, C, D, E, F, G, H, I, J, K, L, M,
# N, O, P, Q, R, S, T, U, V, W, X, Y, Z


def solution(name):
    def check_char(ch):
        if ch == "N":
            return 13
        elif ord(ch) < 78:
            return ord(ch) - 65
        else:
            return 91 - ord(ch)

    def check_move(name):
        right_list = [i for i, ch in enumerate(name) if ch != 'A']
        left_list = [-(i-len(name)) for i in right_list]
        # print(right_list, left_list)
        max_val = 0
        max_loc = 0
        max_index = 0
        for i in range(len(right_list)-1):
            if max_val < right_list[i+1] - right_list[i]:
                max_loc = right_list[i]
                max_index = i
                max_val = right_list[i+1] - right_list[i]

        # print(max_index, max_val, max_loc)
        return min(right_list[-1], left_list[0],
                   (max_loc*2)+left_list[max_index + 1],
                   (left_list[max_index + 1]*2) + max_loc)

    answer = 0
    check_move(name)

    for i in range(len(name)):
        answer += check_char(name[i])
    return answer + check_move(name)


print(solution(name))

 

3번. 큰 수 만들기

 

코딩테스트 연습 - 큰 수 만들기

 

programmers.co.kr

# greedy_3.py
number = "1924"     # 1231234 4177252841
k = 2       # 3 4


def solution(number, k):
    max_num = [number[0]]
    for num in number[1:]:
        # 핵심 코드 [ 4 2 ] < - 7 들어오면 [] + 7
        while len(max_num) > 0 and max_num[-1] < num and k > 0:
            k -= 1
            max_num.pop()

        max_num.append(num)

    if k != 0:
        max_num = max_num[:-k]
    return ''.join(max_num)


print(solution(number, k))

 

4번. 구명보트

 

코딩테스트 연습 - 구명보트

무인도에 갇힌 사람들을 구명보트를 이용하여 구출하려고 합니다. 구명보트는 작아서 한 번에 최대 2명씩 밖에 탈 수 없고, 무게 제한도 있습니다. 예를 들어, 사람들의 몸무게가 [70kg, 50kg, 80kg, 5

programmers.co.kr

# greedy_4.py
people = [70, 50, 80, 50]
limit = 100


def solution(people, limit):
    people.sort()
    answer = 0
    i, j = 0, len(people) - 1
    while i <= j:
        answer += 1
        if people[j] + people[i] <= limit:
            i += 1
        j -= 1
    return answer


print(solution(people, limit))

 

5번. 섬 연결하기

 

코딩테스트 연습 - 섬 연결하기

4 [[0,1,1],[0,2,2],[1,2,5],[1,3,1],[2,3,8]] 4

programmers.co.kr

크루스칼 써도 됨 

# greedy_5.py
n = 5       # 1 이상 100 이하
# cost 의 길이는 ((n-1) * n) / 2
# costs = [[0, 1, 1],     # 0 <-> 1  비용 1
#          [0, 2, 2],     # 0 <-> 2  비용 2
#          [1, 2, 5],     # 1 <-> 2  비용 5
#          [1, 3, 1],     # 1 <-> 3  비용 1
#          [2, 3, 8]]     # 2 <-> 3  비용 8
costs = [[0, 1, 1],
         [0, 2, 2],
         [1, 2, 5],
         [1, 3, 3],
         [2, 3, 8],
         [3, 4, 1]]


def solution(n, costs):
    answer = 0      # 최소 비용의 합 return
    max_cost = int((((n-1) * n) / 2)+1)
    visit = [max_cost] * n
    costs = sorted(costs, key=lambda x: x[2])

    for cost in costs:
        if visit[cost[0]] == max_cost or visit[cost[1]] == max_cost:
            temp_min = min(visit[cost[0]], visit[cost[1]])
            if temp_min == max_cost:        # 둘다 초기상태일때
                _min = min(cost[0], cost[1])
                visit[cost[0]] = _min
                visit[cost[1]] = _min
            else:           # 둘 중 하나면 초기상태일때
                visit[cost[0]] = temp_min
                visit[cost[1]] = temp_min
            answer += cost[2]
        else:       # 둘다 초기 상태가 아닐 때
            if visit[cost[0]] != visit[cost[1]]:
                _max = max(visit[cost[0]], visit[cost[1]])
                _min = min(visit[cost[0]], visit[cost[1]])
                answer += cost[2]
                for i in range(len(visit)):
                    if visit[i] == _max:
                        visit[i] = _min
            else:
                print("이어져 있음")

    return answer


print(solution(n, costs))


# 크루스칼 <- 보기 
# def ancestor(node, parents):
#     if parents[node] == node:
#         return node
#     else:
#         return ancestor(parents[node], parents)
#
# def solution(n, costs):
#     answer = 0
#     edges = sorted([(x[2], x[0], x[1]) for x in costs])
#     parents = [i for i in range(n)]
#     bridges = 0
#     for w, f, t in edges:
#         if ancestor(f, parents) != ancestor(t, parents):
#             answer += w
#             parents[ancestor(f, parents)] = t
#             bridges += 1
#         if bridges == n - 1:
#             break
#     return answer

 

 

6번. 단속카메라

 

코딩테스트 연습 - 단속카메라

[[-20,15], [-14,-5], [-18,-13], [-5,-3]] 2

programmers.co.kr

# greedy_6.py
# 차량의 경로 -30,000 ~ 30,000
routes = [[-20, 15],    # 이동 경로 -20 진입 지점, 15 빠져나간 지점
          [-14, -5],
          [-18, -13],
          [-5, -3]]


# 차량의 수 - 1 ~ 10000
def solution(routes):
    answer = 0
    overlap = -30001
    routes = sorted(routes, key=lambda x: x[1])
    for r in routes:
        if r[0] > overlap:
            answer += 1
            overlap = r[1]

    return answer


print(solution(routes))