일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- hash
- array
- Easy
- DailyLeetCoding
- 자료구조
- greedy
- SinglyLinkedList
- Leedcode
- Two Pointers
- ArrayList vs LinkedList
- String
- stack
- hash table
- LinkedList
- heap
- graph
- sorting
- VCS
- BFS
- python3
- Java
- Bellman-Ford
- A* Algorithm
- dfs
- Hashtable
- 광연자동차운전면허학원
- Medium
- 구현
- Union Find
- leetcode
- Today
- Total
Min IT's Devlog
[python3] 1338. Reduce Array Size to The Half 본문
풀이 일자: 22.08.18
난이도: [Medium]
문제 내용
주어진 integer array를 가지고 해당 array의 length를 반 이하로 줄일 때 최소한의 빼야하는 숫자의 개수에 대한 문제였다.
arr = [3,3,3,3,5,5,5,2,2,7]
→ 이런식으로 주어졌을 때 3과 7을 뺀다면 남는 array는 [5,5,5,2,2]가 되게 되면서 기존의 1/2가 되게 된다.
문제 해결 흐름
1. 우선 중복되는 수를 몇 개씩 있는지 check를 해야겠다.
→ Dictionary를 이용하여 각각 몇개씩 있는지 세자.
2. 어떤 원소를 빼야 하는지가 아니라 최소한 빼야하는 원소의 개수에 대한 문제이니까 갯수에 대한 정보만 있으면 되겠네!
→ Dictionary의 value값만을 가져와서 list로 저장해두자
3. 기존 array의 1/2이하가 되도록 빼야하니까 최소한 빼야하는 개수를 알아야겠는데?
→ 기존 array의 length를 2로 나누어 올림을 해준다면 빼야하는 최소 갯수를 알 수 있겠다.
4. 빼야하는 최소 갯수만 넘기면 되는 거고 하나씩 뺄때마다 최대로 빼는 갯수를 check한다면 되지 않을까?
→ 각 원소의 갯수가 담긴 array를 내림차순으로 정렬해주고 앞에서부터 한개씩 더해가면서 빼야하는 최소 개수를 넘기는지만 확인하면 되겠다.
추가설명
문제의 예시를 그대로 사용한다면
arr = [3,3,3,3,5,5,5,2,2,7]
있다고 했을 때
1. counter = {'3':4, '5':3, '2':2, '7':1} # arr에 있는 숫자의 개수를 그대로 센 것
2. cntList = [4, 3, 2, 1] # counter의 value값만을 저장했다.
3. minSize = len(arr) // 2 + 1 if (len(arr) / 2 - len(arr) // 2 > 0) else len(arr) // 2 # 나눈 값을 올림해주었다. math.ceil()도 무방 => 5
4. cntList = [4,3,2,1] # 내림차순해준다.
원소를 하나로 뺏을 때 가장 많이 빼는 경우가 4번 나온 3을 빼는 경우 많이 빼는 것이므로 4를 했을 때 최소한 빼야하는 개수인 5보다 작으니까 다음으로 넘어가야함
원소를 두개를 뺐을 때 가장 많이 빼는 경우가 4번 나온 3과 3번 나온 5를 빼는 것이므로 합치면 7이며 최소한 빼야하는 갯수인 5보다 크니까 2개가 답이다.
=> 원소를 최대한 많이 뺄 수 있는 경우의 수만 계산해서 최소한 빼야하는 원소의 갯수를 넘기는 그 시점이 원소를 최소한으로 빼는 경우의 수에 해당한다고 보면 된다. (Greedy식 해결법)
=> 관건은 Time Complexity가 O(N^2)을 만들지 않는 것으로 보인다.
→ for와 sum을 사용시 즉, O(N^2)을 만들게 되면 29번째의 TC에서 Time Limit Exceeded Error가 발생한다.
class Solution:
def minSetSize(self, arr: List[int]) -> int:
counter = dict()
for i in range(len(arr)):
if arr[i] not in counter:
counter[arr[i]] = 0
counter[arr[i]] += 1
minSize = len(arr) // 2 + 1 if (len(arr) / 2 - len(arr) // 2 > 0) else len(arr) // 2
cntList = list(counter.values())
cntList.sort(reverse=True)
total = 0
for i in range(len(cntList)):
total += cntList[i]
if total >= minSize:
return i + 1
다른 해결 방식
1. 내림차순 정렬을 했는데 그것보다는 priority queue를 이용한 heap을 통해 관리한다면 더 빠르지 않을까?
→ 기존에 각각의 원소의 갯수를 센 결과를 list에 넣어서 reverse 정렬을 하는 것이 아니라 heap으로 넣어서 처리해보자.
→ defualt가 max heap이기 때문에 -를 곱해줌으로써 가장 큰 수가 작게 만들어 순서가 유지되도록 하자.
class Solution:
def minSetSize(self, arr: List[int]) -> int:
counter = dict()
for i in range(len(arr)):
if arr[i] not in counter:
counter[arr[i]] = 0
counter[arr[i]] += 1
pq = [-i for i in counter.values()]
heapq.heapify(pq)
length = len(arr)
for i in range(len(pq)):
result = -heapq.heappop(pq)
length -= result
if length <= len(arr)/2:
return i+1
문제 링크
https://leetcode.com/problems/reduce-array-size-to-the-half/
'코테 > LeetCode(Solve)' 카테고리의 다른 글
[python3] 967. Numbers With Same Consecutive Differences (0) | 2022.09.03 |
---|---|
[python3] 637. Average of Levels in Binary Tree (0) | 2022.09.03 |
[python3] 1448. Count Good Nodes in Binary Tree (0) | 2022.09.01 |
[python3] 804. Unique Morse Code Words (0) | 2022.08.17 |
[python3] 387. First Unique Character in a String (0) | 2022.08.16 |