반응형
문제
문제 해결 방법
- 정렬을 하는데 함수(메서드)를 쓰지 말라는 조건이 붙었으므로, 정렬알고리즘을 구현할수 있는지 물어보는 문제입니다.
- input이 0,1,2뿐이므로, 이를 이용한 로직 알고리즘으로 푸는 것이 가능합니다.
- 알고리즘
- 모든 엘레멘트를 순회하며, 0,1,2의 개수를 확인합니다
- 각 개수만큼 0,1,2순서대로 어레이에 넣습니다.
- Follow up에서 원하는 one-pass algorithm은 네덜란드 국기 알고리즘을 알고 있느냐고 묻는것이며, 이 알고리즘은 0,1를 정렬하는데 특화된 알고리즘 입니다.
- 또는 퀵정렬을 구현할수도 있습니다.
참고
네덜란드 국기(Dutch National Flag) 알고리즘이란
Github Link
https://github.com/eunhanlee/LeetCode_75_SortColors_Solution.git
로직 알고리즘 시간복잡도: O(n), 공간복잡도: O(1)
/**
* Solution 클래스는 0, 1, 2만 포함된 배열을 정렬하는 메서드를 제공합니다.
*/
public class Solution {
/**
* 주어진 배열을 계수 기법을 사용하여 정렬합니다. 배열은 0, 1, 2만 포함되어야 합니다.
*
* @param nums 정렬할 배열
*/
public void sortColors(int[] nums) {
int Zero = 0, One = 0, Two = 0; // 0의 개수, 1의 개수, 2의 개수를 세는 변수들
int idx = 0; // 배열 내 위치를 추적하는 인덱스
// 0의 개수, 1의 개수, 2의 개수를 세기
for (int num : nums) {
if (num == 0) Zero++;
if (num == 1) One++;
if (num == 2) Two++;
}
// 0의 개수, 1의 개수, 2의 개수만큼 배열을 채우기
for (int i = 0; i < Zero; i++) {
nums[idx] = 0;
idx++;
}
for (int i = 0; i < One; i++) {
nums[idx] = 1;
idx++;
}
for (int i = 0; i < Two; i++) {
nums[idx] = 2;
idx++;
}
}
}
네덜란드 국기 알고리즘 시간복잡도: O(n), 공간복잡도: O(1)
public class Solution {
/**
* 주어진 배열을 0, 1, 2만 포함하도록 Dutch National Flag 알고리즘을 사용하여 정렬합니다.
*
* @param nums 정렬할 배열.
*/
public void sortColors(int[] nums) {
int low = 0; // 0을 가리키는 포인터
int mid = 0; // 1을 가리키는 포인터
int high = nums.length - 1; // 2를 가리키는 포인터
while (mid <= high) {
if (nums[mid] == 0) {
// 현재 요소가 0인 경우, low 포인터가 가리키는 요소와 교환합니다.
swap(nums, low, mid);
low++; // low 포인터를 증가시킵니다.
mid++; // 교환된 요소는 1임이 확실하므로 mid 포인터도 증가시킵니다.
} else if (nums[mid] == 1) {
// 현재 요소가 1인 경우, mid 포인터를 앞으로 이동시킵니다.
mid++;
} else if (nums[mid] == 2) {
// 현재 요소가 2인 경우, mid 포인터가 가리키는 요소와 high 포인터가 가리키는 요소를 교환합니다.
swap(nums, mid, high);
high--; // high 포인터를 감소시킵니다.
// 주의: 여기서 mid 포인터는 아직 교환된 요소가 무엇인지 확실하지 않으므로 증가시키지 않습니다.
}
}
}
/**
* 주어진 배열에서 두 요소를 교환합니다.
*
* @param nums 배열에서 요소를 교환할 배열.
* @param i 첫 번째 교환할 요소의 인덱스.
* @param j 두 번째 교환할 요소의 인덱스.
*/
private void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
퀵정렬 시간복잡도: O(n log n), 공간복잡도: O()
public class Solution3 {
/**
* 주어진 배열을 Quick Sort 알고리즘을 사용하여 정렬합니다.
*
* @param nums 정렬할 배열.
*/
public void sortColors(int[] nums) {
quickSort(nums);
}
private static void quickSort(int[] input) {
quickSortRecur(input, 0, input.length - 1);
}
/**
* Lomuto 분할법을 이용하여 Quick Sort를 재귀적으로 구현합니다.
* pivot : 가장 오른쪽 값
* 선택값(left) 시작점 : 0
* 비교값(right) 시작점 : 0
* @param input 정렬할 배열.
* @param left 분할할 배열의 시작 인덱스.
* @param right 분할할 배열의 끝 인덱스.
*/
private static void quickSortRecur(int[] input, int left, int right) {
// Quick Sort 종료 조건: 분할할 배열의 길이가 1 이하일 때
if (left >= right) {
return;
}
// 분할 위치를 찾아서 pivot을 중심으로 작은 값들은 왼쪽으로, 큰 값들은 오른쪽으로 정렬합니다.
int pivotPos = partition(input, left, right);
// 분할된 왼쪽 부분 배열을 재귀적으로 정렬합니다.
quickSortRecur(input, left, pivotPos - 1);
// 분할된 오른쪽 부분 배열을 재귀적으로 정렬합니다.
quickSortRecur(input, pivotPos + 1, right);
}
/**
* 배열에서 두 요소의 위치를 교환합니다.
*
* @param input 배열.
* @param a 첫 번째 요소의 인덱스.
* @param b 두 번째 요소의 인덱스.
*/
private static void swap(int[] input, int a, int b) {
int temp = input[a];
input[a] = input[b];
input[b] = temp;
}
/**
* Lomuto 분할법을 사용하여 배열을 분할하고, pivot의 위치를 반환합니다.
*
* @param input 배열.
* @param left 분할할 배열의 시작 인덱스.
* @param right 분할할 배열의 끝 인덱스.
* @return pivot의 위치.
*/
private static int partition(int[] input, int left, int right) {
int pivot = input[right];
int i = (left - 1);
for (int j = left; j < right; ++j) {
if (input[j] < pivot) {
++i;
swap(input, i, j);
}
}
swap(input, (i + 1), right);
return i + 1;
}
}
반응형
'old > Algorithm Solving' 카테고리의 다른 글
LeetCode 112. Path Sum 자바 문제 풀이 (0) | 2023.10.24 |
---|---|
LeetCode 2413. Smallest Even Multiple 자바 문제 풀이 (0) | 2023.09.03 |
LeetCode 1672. Richest Customer Wealth 자바 문제 풀이 (0) | 2023.08.11 |
GFG Count the Substrings 자바 문제 풀이 (0) | 2023.08.09 |
LeetCode 236. Lowest Common Ancestor of a Binary Tree 자바 문제 풀이 (0) | 2023.08.07 |