diff --git a/longest-consecutive-sequence/jaejeong1.java b/longest-consecutive-sequence/jaejeong1.java index 25a0ba9550..a2b7931c95 100644 --- a/longest-consecutive-sequence/jaejeong1.java +++ b/longest-consecutive-sequence/jaejeong1.java @@ -4,43 +4,33 @@ class SolutionLongestConsecutiveSequence { public int longestConsecutive(int[] nums) { - // 정렬되지 않은 정수 nums 배열이 주어지면 가장 긴 연속 요소 시퀀스 길이를 반환 - // O(N) 시간 내 실행되야함 - // 전부 해시맵에 때려넣고, 키를 꺼내 연속 요소가 있는지 확인한다 - // 연속 요소가 있으면 answer를 1 증가시키고, 연속 요소는 제거한다 - // 시간복잡도: O(N), 공간복잡도: O(N) - - Set set = new HashSet<>(); - for (var num : nums) { - set.add(num); - } - var answer = 0; - for (var num : nums) { - var length = 1; - - if (set.contains(num-1)) { - set.remove(num); - var minusKey = num; - while (set.contains(--minusKey)) { - length++; - set.remove(minusKey); - } + // 시퀀스 조회를 O(1)에 수행 가능하고, 중복은 무시할 수 있는 조건이므로 Set이 적합한 자료구조 + // 시간복잡도: O(N), 공간복잡도: O(N) + Set num_set = new HashSet(); + for (int num : nums) { + num_set.add(num); } - if (set.contains(num+1)) { - set.remove(num); - var plusKey = num; - while (set.contains(++plusKey)) { - length++; - set.remove(plusKey); - } - } + int longestSequence = 0; + + // 시간복잡도: O(N) + for (int num : num_set) { + // 시퀀스 중간에 있는 숫자가 아닌 시작하는 숫자를 찾음 + // 시작하는 숫자는 - 1 값이 Set에 없을 것 + if (!num_set.contains(num - 1)) { + int currentNum = num; + int currentLength = 1; + // + 1 값이 Set에 있는 지 확인하면서 증가 + while (num_set.contains(currentNum + 1)) { + currentNum += 1; + currentLength += 1; + } - if (length > answer) { - answer = length; + // 순회가 끝나면 최대 시퀀스 길이인지 확인하고 적용 + longestSequence = Math.max(longestSequence, currentLength); + } } - } - return answer; + return longestSequence; } } diff --git a/top-k-frequent-elements/jaejeong1.java b/top-k-frequent-elements/jaejeong1.java index 2d8abe76a6..6b2e4c2109 100644 --- a/top-k-frequent-elements/jaejeong1.java +++ b/top-k-frequent-elements/jaejeong1.java @@ -1,24 +1,35 @@ import java.util.HashMap; import java.util.Map; +import java.util.PriorityQueue; +import java.util.Queue; class SolutionTopKFrequentElements { public int[] topKFrequent(int[] nums, int k) { - // 빈도순으로 k개 반환 - // 빈도 체크: 해시맵으로 카운트. 시간복잡도 O(N), 공간복잡도 O(N) - // 빈도순 정렬: sorting, 시간복잡도 O(N log N), 공간복잡도 O(N) - // 합산: 시간복잡도 O(N log N), 공간복잡도 O(N) + // 풀이 + // 시간복잡도: O(N log K), 공간복잡도: O(N) - // 빈도 체크 - Map freq = new HashMap<>(); - for (int num : nums) { - freq.put(num, freq.getOrDefault(num, 0) + 1); - } + // 숫자 별 빈도 누적을 Map 이용 + // 시간복잡도: O(N), 공간복잡도: O(N) + Map count = new HashMap<>(); + for (int n: nums) { + count.put(n, count.getOrDefault(n, 0) + 1); + } - // 빈도순 정렬 - return freq.keySet().stream() - .sorted((a, b) -> freq.get(b) - freq.get(a)) - .mapToInt(i -> i) - .limit(k) // 배열에서 상위 k개만 반환 - .toArray(); + Queue heap = new PriorityQueue<>((x, y) -> count.get(x) - count.get(y)); + // 가장 빈번한 k개의 수를 만들기 위해 우선순위 큐를 사용 + // 시간복잡도: O(N log k), 공간복잡도: O(N) + for (int n: count.keySet()) { + heap.add(n); + if (heap.size() > k) heap.poll(); // 가장 빈번한 K개가 만족됐으니 더이상 추가하지 않고 제외 + } + + // k ~ 0 순서대로 힙에서 역순으로 뽑음 + // 시간복잡도: O(k log k), 공간복잡도: O(N) + int[] result = new int[k]; + for(int i = k - 1; i >= 0; --i){ + result[i] = heap.poll(); + } + + return result; } }