https://programmers.co.kr/learn/courses/30/lessons/42576

 

코딩테스트 연습 - 완주하지 못한 선수

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

programmers.co.kr

try1. in 연산자

썼다가 효율성 0점 맞음 (당연함... 시간복잡도 O(n)... )

 

try2. binary_search

찾아가면서 진행했더니 효율성 테케 2개 fail

 

try3. 계수 정렬에서 착안해서 collections.Counter 사용해서 값 찾음

처음에는 set 연산 써서 참가자와 완주자의 차집합을 구해서 그 차집합의 길이가 0이 아니면 동명이인이 있다고 생각해서 동명이인 숫자를 most_common() 써서 출력했음. 

근데 생각해보면 동명이인이 여러명 있고, 그 여러명이 다 통과할지 안할지 모르는 부분임..

 

try4. Counter 사용해서 등장횟수 체크하고, 완주하지 못한 선수는 딱 1명이니까 Counter 객체의 key, value값 비교해서 다른 요소를 찾아냄

만약 키값이 존재하고 value가 다를때와, 키값이 아예 존재하지 않을때 두가지 경우만 존재해서 풀음.

 

-> 다른 사람 코드 보니까 Counter객체는 빼기 연산이 가능해서 ... 단순히 빼주고 그 요소의 key값만 출력해줘도 됬었다. 그래도 목표 시간 1시간 안에는 품!

 

from collections import Counter

def solution(participant, completion):
    answer = ""

    c_p = Counter(participant)
    c_c = Counter(completion)

    for key_cp, value_cp in c_p.items():
        # 만약 key가 존재하고 value값이 다르면 answer에 추가
        if key_cp in c_c and value_cp != c_c.get(key_cp):
            answer += key_cp
            break
        # key가 없으면 answer에 추가
        elif not key_cp in c_c:
            answer += key_cp
            break

    return answer

 

프로그래머스 고득점 kit 정렬 파트에 있는 문제다.

https://programmers.co.kr/learn/courses/30/lessons/42746

 

코딩테스트 연습 - 가장 큰 수

0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요. 예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰

programmers.co.kr

 

 

내부에서 제공하는 sort() 함수를 써야 시간 복잡도 상 유리한 걸 머리로는 알면서도 어떻게 써야될지 감이 안와서 무식하게 비교했더니 시간 초과가 났다. 당연한 결과지만서도... 

def solution(numbers):
    answer = ''
    
    while len(numbers) > 0:
        max_num = -1
        for i in range(len(numbers)):
            if str(max_num)*3 < str(numbers[i])*3:
                max_num = numbers[i]
        
        numbers.remove(max_num)
        answer += str(max_num)
    
    return str(int(answer))

 

마지막에 str(int(answer)) 해준 이유는 숫자 배열이 [0,0,0,0] 이라고 주어질 때 '0000'이 아니라 '0'으로 나와야해서 정수형으로 바꿔주고 다시 문자열로 바꿔준 것이다. 테케 11번이 이건듯?

 

문자열에 *3을 해주는건 "3" 이랑 "30" 이랑 비교했을 때 후자가 더 커서 그 부분을 해결해주기 위해 작성했다.

 

그나저나 이 코드로는 시간 초과가 잡힐 수가 없어서 파이썬 기본 제공 라이브러리 sort함수 + 람다 함수써서 어떻게 하나 검색해봤더니 기가 막히는 코드가 있더라... 어떻게 이렇게 깔끔하게 쓰는지 ㅠㅠ

 

def solution(numbers):
    numbers = list(map(str, numbers))
    numbers.sort(key=lambda x: x * 3, reverse=True)
    return str(int("".join(numbers)))

위 코드로 하면 깔끔하게 통과한다. join 함수랑 sort 함수에 람다로 넘겨주는 방법에 더 익숙해지자

도현이의 집 N개가 수직선 위에 있다. 각각의 집의 좌표는 x1, ..., xN이고, 집 여러개가 같은 좌표를 가지는 일은 없다.

도현이는 언제 어디서나 와이파이를 즐기기 위해서 집에 공유기 C개를 설치하려고 한다. 최대한 많은 곳에서 와이파이를 사용하려고 하기 때문에, 한 집에는 공유기를 하나만 설치할 수 있고, 가장 인접한 두 공유기 사이의 거리를 가능한 크게 하여 설치하려고 한다.

C개의 공유기를 N개의 집에 적당히 설치해서, 가장 인접한 두 공유기 사이의 거리를 최대로 하는 프로그램을 작성하시오.

입력

첫째 줄에 집의 개수 N (2 ≤ N ≤ 200,000)과 공유기의 개수 C (2 ≤ C ≤ N)이 하나 이상의 빈 칸을 사이에 두고 주어진다. 둘째 줄부터 N개의 줄에는 집의 좌표를 나타내는 xi (0 ≤ xi ≤ 1,000,000,000)가 한 줄에 하나씩 주어진다.

출력

첫째 줄에 가장 인접한 두 공유기 사이의 최대 거리를 출력한다.

 

예제 입력 1

5 3
1
2
8
4
9

예제 출력 1

3

 


1차 접근 (2022.1.18 못품)

가능한 집의 좌표가 10억이기 때문에 탐색 범위가 매우 크다. 따라서 이진탐색으로 접근해야한다는 점까지는 캐치를 했는데, 이진 탐색은 특정 값을 찾는 알고리즘인데 공유기 설치를 하는 범위에 어떻게 적용이 되어야 하는지 감이 잘 안 왔다. 얼마 전에 풀었던 떡볶이 떡 자르기 문제와 유사하다는 것까지는 눈치를 챘는데, 그 뒤로 2시간동안 헤매다가 결국 해설을 참고해서 이해를 한다.

 

해설 1

이진 탐색으로 가장 인접한 두 공유기 사이의 거리를 조절해가며, 매번 실제로 공유기를 설치하여 C보다 많은 개수로 공유기를 설치할 수 있는지 체크하여 문제를 해결한다. 다만 가장 인접한 두 공유기 사이의 거리의 최댓값을 찾아야 하므로, C보다 많은 개수로 공유기를 설치할 수 있다면 가장 인접한 두 공유기 사이의 거리의 값을 증가시켜서 더 큰 값에 대해서도 성립하는지 체크하기 위해 다시 탐색을 수행한다. 

 

따라서 매번 가장 인접한 두 공유기 사이의 거리 (gap)의 최소값, 최대값을 계산해주면 될 것이다. 

 

{1,2,4,8,9} 인 수열에 설치해야 하는 공유기의 수 C = 3이라고 해보자.

현재 gap은 1~8 사이의 값이다.  gap = [1,8] 사이

 

1) gap의 값을 중간에 해당하는 4로 설정하면, 공유기를 2개밖에 설치할 수 없다. 따라서 범위를 더 줄일 필요가 있다. 따라서 범위를 [1,3]으로 수정한다. 

2) 범위가 1~3이므로 gap의 값을 중간에 해당하는 2로 설정한다. 이 경우 공유기를 3개 설치할 수 있다. 다만 더 큰 값에 에 대해서도 확인해볼 필요가 있으므로 현재의 gap 값을 저장하고 gap의 값을 증가시켜서 gap이 더 커졌을 때도 가능한지 확인할 필요가 있다. 따라서 범위가 [1,3]인 상태에서 범위를 [3,3]으로 수정한다. 

3) 범위가 3~3이므로 gap의 값을 중간에 해당하는 3으로 설정한다. 이 경우 공유기를 3개 설치할 수 있다. gap이 더 커졌을 떄도 확인해봐야 하나, 현재 gap 범위는 더이상 변경이 불가능하다. 따라서 gap=3이 최적의 경우이다.

--> 솔직히 이코테 책에 있는 풀이 잘 모르겠다. 다른 블로그를 참고했다...

 

해설2

공유기 설치 길이를 움직여(이분 탐색을 통해) 적절한 집에 설치 가능한지 살펴보는 문제.

 

거리가 주어지면 공유기(router)를 몇 개 설치할 수 있는지 계산하는 router_setting 함수

첫번째 집을 start로, 첫집과 끝집의 차이을 end로 둔다

 1) 중간값mid로 충분한 설치 장소를 찾지 못했다면 거리를 줄여주고

 2) 설치된 집이 더 많다면 거리를 늘려준다.

 

Python

# 2022-01-18
# 이코테 ch15 이진 탐색 문제 Q29 공유기 설치
# https://www.acmicpc.net/problem/2110

import sys

input = sys.stdin.readline

n, c = map(int, input().split())
house = [int(input()) for _ in range(n)]
house.sort()

# 해당 거리를 유지하며 공유기를 몇대까지 설치 가능한지
def router_setting(dist):
    count = 1
    cur_house = house[0]  # 시작점 (공유기 설치)
    for i in range(1, n):  # 집 모두를 순회
        # 이전 집에서 해당 거리보다 멀리 떨어진 집이라면
        if cur_house + dist <= house[i]:
            count += 1  # 공유기 설치
            cur_house = house[i]  # 공유기 설치된 집 갱신

    return count


start = 1
end = house[-1] - house[0]  #
answer = 0

while start <= end:
    mid = (start + end) // 2
    if router_setting(mid) >= c:
        answer = mid
        start = mid + 1
    else:
        end = mid - 1

print(answer)

 

회고

이진탐색 진짜 어렵다.... 토폴로지 풀 때랑 비슷한 갑갑함이다. 익숙해질 때까지 부딪혀보자 ㅠㅠ 해설을 한시간동안이나 찾아보고 읽어봤다

+ Recent posts