From 0ccec697f250a1d79c5dad042a6791ad40c23398 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Sat, 28 Dec 2024 17:15:22 +0900 Subject: [PATCH 01/11] test --- "JooKangSan/\353\260\260\354\227\264/.gitkeep" | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 "JooKangSan/\353\260\260\354\227\264/.gitkeep" diff --git "a/JooKangSan/\353\260\260\354\227\264/.gitkeep" "b/JooKangSan/\353\260\260\354\227\264/.gitkeep" new file mode 100644 index 0000000..e69de29 From bc4b64a858deb3febd063eccf56904fcf78891ca Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 17:54:28 +0900 Subject: [PATCH 02/11] =?UTF-8?q?feat:=20=EC=95=8C=EA=B3=A0=EB=A6=AC?= =?UTF-8?q?=EC=A6=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "JooKangSan/\353\260\260\354\227\264/test.md" | 532 ++++++++++++++ .../\353\260\260\354\227\264.md" | 669 ++++++++++++++++++ 2 files changed, 1201 insertions(+) create mode 100644 "JooKangSan/\353\260\260\354\227\264/test.md" create mode 100644 "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" diff --git "a/JooKangSan/\353\260\260\354\227\264/test.md" "b/JooKangSan/\353\260\260\354\227\264/test.md" new file mode 100644 index 0000000..6794ef1 --- /dev/null +++ "b/JooKangSan/\353\260\260\354\227\264/test.md" @@ -0,0 +1,532 @@ +# 배열 알고리즘 상세 가이드 + +## 1. 검색 알고리즘 + +### 1.1 선형 검색 (Linear Search) +선형 검색은 가장 단순하고 직관적인 검색 방법입니다. 배열의 처음부터 끝까지 순차적으로 검색하여 원하는 값을 찾습니다. + +**작동 원리**: +1. 배열의 첫 번째 요소부터 시작 +2. 각 요소를 순차적으로 확인 +3. 찾고자 하는 값과 일치하면 해당 인덱스 반환 +4. 끝까지 찾지 못하면 -1 반환 + +**장점**: +- 구현이 매우 간단 +- 정렬되지 않은 배열에서도 사용 가능 +- 작은 배열에서 효율적 +- 추가 메모리가 필요 없음 + +**단점**: +- 배열 크기가 커질수록 검색 시간이 선형적으로 증가 +- 대용량 데이터에서는 비효율적 + +```javascript +function linearSearch(arr, target) { + for (let i = 0; i < arr.length; i++) { + if (arr[i] === target) return i; + } + return -1; +} +``` + +### 1.2 이진 검색 (Binary Search) +이진 검색은 정렬된 배열에서 사용하는 매우 효율적인 검색 알고리즘입니다. 검색 범위를 절반씩 줄여가며 찾는 방식입니다. + +**작동 원리**: +1. 배열의 중간 요소를 선택 +2. 중간 요소와 찾는 값을 비교 +3. 찾는 값이 더 작으면 왼쪽 절반을 검색 +4. 찾는 값이 더 크면 오른쪽 절반을 검색 +5. 찾을 때까지 1-4 반복 + +**장점**: +- 매우 효율적인 검색 속도 (로그 시간 복잡도) +- 대규모 데이터셋에서 특히 효과적 +- 메모리 사용이 적음 + +**단점**: +- 정렬된 배열에서만 사용 가능 +- 동적으로 변하는 데이터에는 부적합 +- 정렬 비용이 추가될 수 있음 + +```javascript +function binarySearch(arr, target) { + let left = 0; + let right = arr.length - 1; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + + if (arr[mid] === target) { + return mid; + } else if (arr[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return -1; +} +``` + +## 2. 정렬 알고리즘 + +### 2.1 버블 정렬 (Bubble Sort) +버블 정렬은 인접한 두 요소를 반복적으로 비교하고 교환하는 간단한 정렬 알고리즘입니다. + +**작동 원리**: +1. 인접한 두 요소를 비교 +2. 순서가 잘못되어 있으면 교환 +3. 배열 끝까지 반복 +4. 정렬이 완료될 때까지 1-3 반복 + +**최적화 기법**: +- 이미 정렬된 경우 조기 종료 +- 각 패스마다 마지막 요소는 확정되므로 비교 범위 감소 + +**장점**: +- 구현이 매우 단순 +- 안정 정렬 +- 추가 메모리가 필요 없음 +- 이미 정렬된 데이터에 대해 최적화 가능 + +**단점**: +- 매우 느린 시간 복잡도 +- 큰 데이터셋에서 비효율적 +- 많은 교환 연산 필요 + +```javascript +function bubbleSort(arr) { + const n = arr.length; + let swapped; + + for (let i = 0; i < n - 1; i++) { + swapped = false; + + // 최적화: 이미 정렬된 마지막 부분 제외 + for (let j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; + swapped = true; + } + } + + // 최적화: 교환이 없으면 이미 정렬된 상태 + if (!swapped) break; + } + + return arr; +} +``` + +### 2.2 선택 정렬 (Selection Sort) +선택 정렬은 각 패스마다 최소값을 찾아 적절한 위치로 이동시키는 정렬 알고리즘입니다. + +**작동 원리**: +1. 정렬되지 않은 부분에서 최소값 찾기 +2. 최소값을 현재 위치로 이동 +3. 정렬된 부분을 한 칸 늘리기 +4. 배열이 정렬될 때까지 1-3 반복 + +**특징**: +- 데이터 교환 횟수가 버블 정렬보다 적음 +- 각 패스마다 최소값이 확정됨 +- 정렬 상태와 무관하게 일정한 시간 소요 + +**장점**: +- 구현이 간단 +- 교환 횟수가 적음 +- 메모리 사용이 적음 + +**단점**: +- 느린 시간 복잡도 +- 불안정 정렬 +- 큰 데이터셋에서 비효율적 + +```javascript +function selectionSort(arr) { + const n = arr.length; + + for (let i = 0; i < n - 1; i++) { + let minIdx = i; + + // 최소값 찾기 + for (let j = i + 1; j < n; j++) { + if (arr[j] < arr[minIdx]) { + minIdx = j; + } + } + + // 최소값이 현재 위치가 아니면 교환 + if (minIdx !== i) { + [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]]; + } + } + + return arr; +} +``` + +### 2.3 삽입 정렬 (Insertion Sort) +삽입 정렬은 각 요소를 이미 정렬된 부분의 적절한 위치에 삽입하는 정렬 알고리즘입니다. + +**작동 원리**: +1. 두 번째 요소부터 시작 +2. 현재 요소를 정렬된 부분의 적절한 위치에 삽입 +3. 배열 끝까지 1-2 반복 +4. 삽입 시 정렬된 부분의 큰 요소들을 오른쪽으로 이동 + +**최적화 기법**: +- 이진 검색을 사용하여 삽입 위치 찾기 +- 필요한 경우에만 이동 수행 + +**장점**: +- 안정 정렬 +- 작은 데이터셋에서 효율적 +- 거의 정렬된 데이터에서 매우 효율적 +- 온라인 알고리즘 (실시간 정렬 가능) + +**단점**: +- 큰 데이터셋에서 비효율적 +- 많은 이동 연산 필요 +- 최악의 경우 느린 성능 + +```javascript +function insertionSort(arr) { + for (let i = 1; i < arr.length; i++) { + const key = arr[i]; + let j = i - 1; + + // 적절한 삽입 위치를 찾아 요소들을 이동 + while (j >= 0 && arr[j] > key) { + arr[j + 1] = arr[j]; + j--; + } + + // 찾은 위치에 삽입 + arr[j + 1] = key; + } + + return arr; +} +``` + +### 2.4 퀵 정렬 (Quick Sort) +퀵 정렬은 분할 정복 방식을 사용하는 매우 효율적인 정렬 알고리즘입니다. + +**작동 원리**: +1. 피벗 선택 (일반적으로 중간 요소) +2. 피벗보다 작은 요소는 왼쪽으로, 큰 요소는 오른쪽으로 분할 +3. 분할된 부분 배열에 대해 재귀적으로 1-2 반복 +4. 부분 배열의 크기가 1 이하가 될 때까지 반복 + +**최적화 기법**: +- 좋은 피벗 선택 (중간값 또는 랜덤) +- 작은 부분 배열에 대해 삽입 정렬 사용 +- 3-way 파티셔닝으로 중복 요소 처리 + +**장점**: +- 평균적으로 매우 빠른 속도 +- 추가 메모리 사용이 적음 +- 캐시 효율성이 좋음 + +**단점**: +- 최악의 경우 성능 저하 +- 불안정 정렬 +- 이미 정렬된 데이터에서 비효율적 + +```javascript +function quickSort(arr) { + if (arr.length <= 1) return arr; + + const pivot = arr[Math.floor(arr.length / 2)]; + const left = []; + const middle = []; + const right = []; + + // 분할 + for (const element of arr) { + if (element < pivot) left.push(element); + else if (element > pivot) right.push(element); + else middle.push(element); + } + + // 정복 및 결합 + return [...quickSort(left), ...middle, ...quickSort(right)]; +} +``` + +## 3. 기타 주요 알고리즘 + +### 3.1 배열 회전 (Array Rotation) +배열 회전은 배열의 요소들을 특정 위치만큼 이동시키는 알고리즘입니다. + +**구현 방법**: +1. 임시 배열 사용 +2. 요소 하나씩 이동 +3. 역전(Reversal) 알고리즘 + +**최적화 기법**: +- GCD를 이용한 저글링 알고리즘 +- 블록 스왑 알고리즘 +- 효율적인 메모리 사용을 위한 제자리 회전 + +**장점**: +- 다양한 구현 방법 존재 +- 특정 상황에 맞는 최적화 가능 +- 실제 응용 사례가 많음 + +```javascript +// 기본적인 회전 구현 +function rotateArray(arr, k) { + k = k % arr.length; // k가 배열 길이보다 큰 경우 처리 + return [...arr.slice(-k), ...arr.slice(0, -k)]; +} + +// 효율적인 제자리 회전 +function rotateArrayInPlace(arr, k) { + k = k % arr.length; + + // 전체 배열 뒤집기 + reverse(arr, 0, arr.length - 1); + // 처음 k개 요소 뒤집기 + reverse(arr, 0, k - 1); + // 나머지 요소 뒤집기 + reverse(arr, k, arr.length - 1); + + return arr; +} + +function reverse(arr, start, end) { + while (start < end) { + [arr[start], arr[end]] = [arr[end], arr[start]]; + start++; + end--; + } +} +``` + +### 3.2 최대 부분합 (Kadane's Algorithm) +연속된 부분 배열의 최대 합을 찾는 효율적인 알고리즘입니다. + +**작동 원리**: +1. 현재까지의 최대 합과 전체 최대 합을 추적 +2. 각 위치에서 새로운 요소를 포함할지 새로 시작할지 결정 +3. 전체 최대 합 갱신 + +**응용 분야**: +- 주식 거래 최적 기간 찾기 +- 신호 처리 +- 패턴 인식 + +**장점**: +- 선형 시간 복잡도 +- 추가 메모리가 필요 없음 +- 실시간 처리 가능 + +```javascript +function maxSubArray(arr) { + let maxSum = arr[0]; + let currentSum = arr[0]; + let start = 0; + let end = 0; + let tempStart = 0; + + for (let i = 1; i < arr.length; i++) { + // 현재 요소부터 새로 시작할지 기존 합에 더할지 결정 + if (arr[i] > currentSum + arr[i]) { + currentSum = arr[i]; + tempStart = i; + } else { + currentSum = currentSum + arr[i]; + } + + // 최대 합 갱신 + if (currentSum > maxSum) { + maxSum = currentSum; + start = tempStart; + end = i; + } + } + + return { + maxSum, + subArray: arr.slice(start, end + 1), + start, + end + }; +} +``` + +### 3.3 두 수의 합 찾기 (Two Sum) +배열에서 특정 합이 되는 두 수를 찾는 알고리즘입니다. + +**구현 방법**: +1. 브루트 포스 방식 (이중 루프) +2. 해시맵을 이용한 방식 +3. 정렬 후 투 포인터 방식 + +**최적화 기법**: +- 정렬된 배열에서는 투 포인터 사용 +- 해시맵으로 조회 시간 최적화 +- 조기 종료 조건 추가 + +**응용 분야**: +- 금융 거래 매칭 +- 데이터 분석 +- 알고리즘 문제 해결 + +```javascript +// 해시맵을 이용한 방식 +function twoSum(arr, target) { + const map = new Map(); + + for (let i = 0; i < arr.length; i++) { + const complement = target - arr[i]; + + if (map.has(complement)) { + return [map.get(complement), i]; + } + + map.set(arr[i], i); + } + + return null; +} + +// 정렬된 배열에서의 투 포인터 방식 +function twoSumSorted(arr, target) { + let left = 0; + let right = arr.length - 1; + + while (left < right) { + const sum = arr[left] + arr[right]; + + if (sum === target) { + return [left, right]; + } else if (sum < target) { + left++; + } else { + right--; + } + } + + return null; +} +``` + +### 3.4 배열 병합 (Array Merge) +두 개의 정렬된 배열을 하나의 정렬된 배열로 병합하는 알고리즘입니다. + +**작동 원리**: +1. 두 배열의 첫 번째 요소부터 비교 +2. 더 작은 요소를 결과 배열에 추가 +3. 사용된 배열의 포인터 이동 +4. 남은 요소들 처리 + +**최적화 기법**: +- 미리 결과 배열 크기 할당 +- 포인터 이동 최소화 +- 병합 시점 최적화 + +**응용 분야**: +- 병합 정렬의 핵심 연산 +- 데이터 통합 +- 실시간 데이터 동기화 + +```javascript +function mergeArrays(arr1, arr2) { + const merged = []; + let i = 0; + let j = 0; + + while (i < arr1.length && j < arr2.length) { + if (arr1[i] <= arr2[j]) { + merged.push(arr1[i]); + i++; + } else { + merged.push(arr2[j]); + j++; + } + } + + // 남은 요소 처리 + while (i < arr1.length) { + merged.push(arr1[i]); + i++; + } + + while (j < arr2.length) { + merged.push(arr2[j]); + j++; + } + + return merged; +} + +// 효율적인 구현 (미리 크기 할당) +function mergeArraysOptimized(arr1, arr2) { + const result = new Array(arr1.length + arr2.length); + let i = 0; + let j = 0; + let k = 0; + + while (i < arr1.length && j < arr2.length) { + result[k++] = arr1[i] <= arr2[j] ? arr1[i++] : arr2[j++]; + } + + while (i < arr1.length) result[k++] = arr1[i++]; + while (j < arr2.length) result[k++] = arr2[j++]; + + return result; +} +``` + +### 3.5 배열 중복 제거 (Array Deduplication) +배열에서 중복된 요소를 제거하는 알고리즘입니다. + +**구현 방법**: +1. Set 객체 사용 +2. 필터 사용 +3. 객체/맵 사용 +4. 정렬 후 순차 처리 + +**최적화 기법**: +- 해시셋 사용으로 조회 시간 최적화 +- 메모리와 성능 간의 트레이드오프 고려 +- 순서 보존 여부에 따른 최적화 + +```javascript +// Set을 이용한 방법 +function removeDuplicatesSet(arr) { + return [...new Set(arr)]; +} + +// 필터를 이용한 방법 (순서 보존) +function removeDuplicatesFilter(arr) { + return arr.filter((item, index) => arr.indexOf(item) === index); +} + +// 객체를 이용한 방법 (순서 보존) +function removeDuplicatesObject(arr) { + const seen = {}; + return arr.filter(item => { + if (seen.hasOwnProperty(item)) { + return false; + } + seen[item] = true; + return true; + }); +} +``` + +각 알고리즘은 특정 상황에서 장단점이 있으며, 실제 사용 시에는 다음 요소들을 고려해야 합니다: + +1. 데이터 크기 +2. 메모리 제약 +3. 성능 요구사항 +4. 데이터 특성 (정렬 여부, 중복 정도 등) +5. 안정성 요구사항 +6. 구현 복잡도 \ No newline at end of file diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" new file mode 100644 index 0000000..253a05f --- /dev/null +++ "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" @@ -0,0 +1,669 @@ +# 배열 알고리즘 가이드 + +## 목차 + +1. [검색 알고리즘](#1-검색-알고리즘) +2. [정렬 알고리즘](#2-정렬-알고리즘) +3. [기타 주요 알고리즘](#3-기타-주요-알고리즘) +4. [알고리즘 비교](#4-알고리즘-비교) + +## 1. 검색 알고리즘 + +### 1.1 선형 검색 + +- 가장 단순하고 직관적인 검색 방법 +- 배열의 처음부터 끝까지 순차적으로 검색하여 원하는 값을 찾음 + +#### 작동 원리 + +1. 배열의 첫 번째 요소부터 시작 +2. 각 요소를 순차적으로 확인 +3. 찾고자 하는 값과 일치하면 해당 인덱스 반환 +4. 끝까지 찾지 못하면 -1 반환 + +#### 장점 + +- 구현이 매우 간단 +- 정렬되지 않은 배열에서도 사용 가능 +- 작은 배열에서 효율적 +- 추가 메모리가 필요 없음 + +#### 단점 + +- 배열 크기가 커질수록 검색 시간이 선형적으로 증가 +- 대용량 데이터에서는 비효율적 + +#### 복잡도 + +- 시간 복잡도: O(n) +- 공간 복잡도: O(1) +- 특징: 정렬되지 않은 배열에서도 사용 가능 + +```javascript +function linearSearch(arr, target) { + for (let i = 0; i < arr.length; i++) { + if (arr[i] === target) return i; + } + return -1; +} +``` + +### 1.2 이진 검색 + +- 정렬된 배열에서 사용하는 매우 효율적인 검색 알고리즘 +- 검색 범위를 절반씩 줄여가며 찾는 방식 + +#### 작동 원리 + +1. 배열의 중간 요소를 선택 +2. 중간 요소와 찾는 값을 비교 +3. 찾는 값이 더 작으면 왼쪽 절반을 검색 +4. 찾는 값이 더 크면 오른쪽 절반을 검색 +5. 찾을 때까지 1-4 반복 + +#### 장점 + +- 매우 효율적인 검색 속도 (로그 시간 복잡도) +- 대규모 데이터셋에서 특히 효과적 +- 메모리 사용이 적음 + +#### 단점 + +- 정렬된 배열에서만 사용 가능 +- 동적으로 변하는 데이터에는 부적합 +- 정렬 비용이 추가될 수 있음 + +#### 복잡도 + +시간 복잡도: O(log n) +공간 복잡도: O(1) +특징: 정렬된 배열에서만 사용 가능 + +```javascript +function binarySearch(arr, target) { + let left = 0; + let right = arr.length - 1; + + while (left <= right) { + const mid = Math.floor((left + right) / 2); + + if (arr[mid] === target) return mid; + if (arr[mid] < target) left = mid + 1; + else right = mid - 1; + } + + return -1; +} +``` + +## 2. 정렬 알고리즘 + +### 2.1 버블 정렬 + +- 인접한 두 요소를 반복적으로 비교하고 교환하는 간단한 정렬 알고리즘 + +#### 작동 원리 + +1. 인접한 두 요소를 비교 +2. 순서가 잘못되어 있으면 교환 +3. 배열 끝까지 반복 +4. 정렬이 완료될 때까지 1-3 반복 + +#### 최적화 방법 + +- 이미 정렬된 경우 조기 종료 +- 각 패스마다 마지막 요소는 확정되므로 비교 범위 감소 + +#### 장점 + +- 구현이 매우 단순 +- 안정 정렬 +- 추가 메모리가 필요 없음 +- 이미 정렬된 데이터에 대해 최적화 가능 + +#### 단점 + +- 매우 느린 시간 복잡도 +- 큰 데이터셋에서 비효율적 +- 많은 교환 연산 필요 + +#### 복잡도 + +- 시간 복잡도: + 평균: O(n²) + 최선: O(n) - 이미 정렬된 경우 + 최악: O(n²) +- 공간 복잡도: O(1) + +```javascript +function bubbleSort(arr) { + const n = arr.length; + + for (let i = 0; i < n - 1; i++) { + for (let j = 0; j < n - i - 1; j++) { + if (arr[j] > arr[j + 1]) { + [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; + } + } + } + + return arr; +} +``` + +### 2.2 선택 정렬 + +- 각 패스마다 최소값을 찾아 적절한 위치로 이동시키는 정렬 알고리즘 + +#### 작동 원리 + +1. 정렬되지 않은 부분에서 최소값 찾기 +2. 최소값을 현재 위치로 이동 +3. 정렬된 부분을 한 칸 늘리기 +4. 배열이 정렬될 때까지 1-3 반복 + +#### 특징 + +- 데이터 교환 횟수가 버블 정렬보다 적음 +- 각 패스마다 최소값이 확정됨 +- 정렬 상태와 무관하게 일정한 시간 소요 + +#### 장점 + +- 구현이 간단 +- 교환 횟수가 적음 +- 메모리 사용이 적음 + +#### 단점 + +- 느린 시간 복잡도 +- 불안정 정렬 +- 큰 데이터셋에서 비효율적 + +#### 복잡도 + +- 시간 복잡도: + 평균: O(n²) + 최선: O(n²) + 최악: O(n²) + +- 공간 복잡도: O(1) + +```javascript +function selectionSort(arr) { + const n = arr.length; + + for (let i = 0; i < n - 1; i++) { + let minIdx = i; + + for (let j = i + 1; j < n; j++) { + if (arr[j] < arr[minIdx]) { + minIdx = j; + } + } + + if (minIdx !== i) { + [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]]; + } + } + + return arr; +} +``` + +### 2.3 삽입 정렬 + +- 각 요소를 이미 정렬된 부분의 적절한 위치에 삽입하는 정렬 알고리즘 + +#### 작동 원리 + +1. 두 번째 요소부터 시작 +2. 현재 요소를 정렬된 부분의 적절한 위치에 삽입 +3. 배열 끝까지 1-2 반복 +4. 삽입 시 정렬된 부분의 큰 요소들을 오른쪽으로 이동 + +#### 최적화 방법 + +- 이진 검색을 사용하여 삽입 위치 찾기 +- 필요한 경우에만 이동 수행 + +#### 장점 + +- 안정 정렬 +- 작은 데이터셋에서 효율적 +- 거의 정렬된 데이터에서 매우 효율적 +- 온라인 알고리즘 (실시간 정렬 가능) + +#### 단점 + +- 큰 데이터셋에서 비효율적 +- 많은 이동 연산 필요 +- 최악의 경우 느린 성능 + +#### 복잡도 + +- 시간 복잡도: + 평균: O(n²) + 최선: O(n) - 거의 정렬된 경우 + 최악: O(n²) + +- 공간 복잡도: O(1) + +```javascript +function insertionSort(arr) { + for (let i = 1; i < arr.length; i++) { + const key = arr[i]; + let j = i - 1; + + while (j >= 0 && arr[j] > key) { + arr[j + 1] = arr[j]; + j--; + } + + arr[j + 1] = key; + } + + return arr; +} +``` + +### 2.4 퀵 정렬 + +- 분할 정복 방식을 사용하는 효율적인 정렬 알고리즘 + +#### 작동 원리 + +1. 피벗 선택 (일반적으로 중간 요소) +2. 피벗보다 작은 요소는 왼쪽으로, 큰 요소는 오른쪽으로 분할 +3. 분할된 부분 배열에 대해 재귀적으로 1-2 반복 +4. 부분 배열의 크기가 1 이하가 될 때까지 반복 + +#### 최적화 방법 + +- 좋은 피벗 선택 (중간값 또는 랜덤) +- 작은 부분 배열에 대해 삽입 정렬 사용 +- 3-way 파티셔닝으로 중복 요소 처리 + +#### 장점 + +- 평균적으로 매우 빠른 속도 +- 추가 메모리 사용이 적음 +- 캐시 효율성이 좋음 + +#### 단점 + +- 최악의 경우 성능 저하 +- 불안정 정렬 +- 이미 정렬된 데이터에서 비효율적 + +#### 복잡도 + +- 시간 복잡도: + +평균: O(n log n) +최선: O(n log n) +최악: O(n²) - 이미 정렬된 경우 + +- 공간 복잡도: O(log n) + +```javascript +function quickSort(arr) { + if (arr.length <= 1) return arr; + + const pivot = arr[Math.floor(arr.length / 2)]; + const left = []; + const middle = []; + const right = []; + + for (const element of arr) { + if (element < pivot) left.push(element); + else if (element > pivot) right.push(element); + else middle.push(element); + } + + return [...quickSort(left), ...middle, ...quickSort(right)]; +} +``` +### 2.5 병합 정렬 + +- 분할 정복 방식을 사용하는 안정적인 정렬 알고리즘 + +#### 작동 원리 +1. 배열을 두 개의 부분 배열로 분할 +2. 각 부분 배열을 재귀적으로 정렬 +3. 정렬된 부분 배열들을 병합 +4. 하나의 정렬된 배열이 될 때까지 반복 + +#### 최적화 방법 +- 작은 부분 배열에 대해 삽입 정렬 사용 +- 병합 시 추가 배열 할당 최소화 +- 캐시 지역성을 고려한 구현 + +#### 장점 +- 안정 정렬 보장 +- 일관된 성능 (최악의 경우에도 O(n log n)) +- 연결 리스트 정렬에 적합 +- 외부 정렬에 활용 가능 + +#### 단점 +- 추가 메모리 공간 필요 +- 작은 데이터셋에서는 삽입 정렬보다 느림 +- 메모리 지역성이 낮음 + +#### 복잡도 +- 시간 복잡도: + - 평균: O(n log n) + - 최선: O(n log n) + - 최악: O(n log n) +- 공간 복잡도: O(n) +- 안정성: 안정 정렬 + +```javascript +function mergeSort(arr) { + if (arr.length <= 1) return arr; + + const mid = Math.floor(arr.length / 2); + const left = mergeSort(arr.slice(0, mid)); + const right = mergeSort(arr.slice(mid)); + + return merge(left, right); +} + +function merge(left, right) { + const result = []; + let leftIndex = 0; + let rightIndex = 0; + + while (leftIndex < left.length && rightIndex < right.length) { + if (left[leftIndex] <= right[rightIndex]) { + result.push(left[leftIndex]); + leftIndex++; + } else { + result.push(right[rightIndex]); + rightIndex++; + } + } + + return result.concat(left.slice(leftIndex), right.slice(rightIndex)); +} +``` + + +## 3. 기타 알고리즘 + +### 3.1 배열 회전 + +- 배열을 특정 위치만큼 회전시키는 알고리즘 + +#### 구현 방법 + +1. 임시 배열 사용 +2. 요소 하나씩 이동 +3. 역전(Reversal) 알고리즘 + +#### 최적화 방법 + +- GCD를 이용한 저글링 알고리즘 +- 블록 스왑 알고리즘 +- 효율적인 메모리 사용을 위한 제자리 회전 + +#### 장점 + +- 다양한 구현 방법 존재 +- 특정 상황에 맞는 최적화 가능 +- 실제 응용 사례가 많음 + +#### 복잡도 + +시간 복잡도: O(n) +공간 복잡도: O(1) - 제자리 회전의 경우 + +```javascript +function rotateArray(arr, k) { + k = k % arr.length; + return [...arr.slice(-k), ...arr.slice(0, -k)]; +} +``` + +### 3.2 최대 부분합 (Kadane's Algorithm) + +- 연속된 부분 배열의 최대 합을 찾는 알고리즘입니다. + +#### 작동 원리 + +1. 현재까지의 최대 합과 전체 최대 합을 추적 +2. 각 위치에서 새로운 요소를 포함할지 새로 시작할지 결정 +3. 전체 최대 합 갱신 + +#### 장점 + +- 선형 시간 복잡도 +- 추가 메모리가 필요 없음 +- 실시간 처리 가능 + +#### 복잡도 + +시간 복잡도: O(n) +공간 복잡도: O(1) + +```javascript +function maxSubArray(arr) { + let maxSum = arr[0]; + let currentSum = arr[0]; + + for (let i = 1; i < arr.length; i++) { + currentSum = Math.max(arr[i], currentSum + arr[i]); + maxSum = Math.max(maxSum, currentSum); + } + + return maxSum; +} +``` + +### 3.3 두 수의 합 찾기 + +- 정렬된 배열에서 특정 합이 되는 두 수를 찾는 알고리즘입니다. + +#### 구현 방법 + +1. 브루트 포스 방식 (이중 루프) +2. 해시맵을 이용한 방식 +3. 정렬 후 투 포인터 방식 + +#### 최적화 방법 + +- 정렬된 배열에서는 투 포인터 사용 +- 해시맵으로 조회 시간 최적화 +- 조기 종료 조건 추가 + +#### 복잡도 + +- 시간 복잡도 + 정렬된 배열: O(n) + 정렬되지 않은 배열: O(n log n) - 정렬 포함 +- 공간 복잡도: O(1) + +```javascript +function findTwoSum(arr, target) { + let left = 0; + let right = arr.length - 1; + + while (left < right) { + const sum = arr[left] + arr[right]; + + if (sum === target) return [left, right]; + if (sum < target) left++; + else right--; + } + + return null; +} +``` + +### 3.4 배열 병합 (Array Merge) + +- 두 개의 정렬된 배열을 하나의 정렬된 배열로 병합하는 알고리즘입니다. + +#### 작동 원리 + +1. 두 배열의 첫 번째 요소부터 비교 +2. 더 작은 요소를 결과 배열에 추가 +3. 사용된 배열의 포인터 이동 +4. 남은 요소들 처리 + +#### 최적화 기법 + +- 미리 결과 배열 크기 할당 +- 포인터 이동 최소화 +- 병합 시점 최적화 + +```javascript +function mergeArrays(arr1, arr2) { + const merged = []; + let i = 0; + let j = 0; + + while (i < arr1.length && j < arr2.length) { + if (arr1[i] <= arr2[j]) { + merged.push(arr1[i]); + i++; + } else { + merged.push(arr2[j]); + j++; + } + } + + // 남은 요소 처리 + while (i < arr1.length) { + merged.push(arr1[i]); + i++; + } + + while (j < arr2.length) { + merged.push(arr2[j]); + j++; + } + + return merged; +} + +// 효율적인 구현 (미리 크기 할당) +function mergeArraysOptimized(arr1, arr2) { + const result = new Array(arr1.length + arr2.length); + let i = 0; + let j = 0; + let k = 0; + + while (i < arr1.length && j < arr2.length) { + result[k++] = arr1[i] <= arr2[j] ? arr1[i++] : arr2[j++]; + } + + while (i < arr1.length) result[k++] = arr1[i++]; + while (j < arr2.length) result[k++] = arr2[j++]; + + return result; +} +``` + +### 3.5 배열 중복 제거 (Array Deduplication) + +- 배열에서 중복된 요소를 제거하는 알고리즘입니다. + +#### 구현 방법 + +1. Set 객체 사용 +2. 필터 사용 +3. 객체/맵 사용 +4. 정렬 후 순차 처리 + +#### 최적화 방법 + +- 해시셋 사용으로 조회 시간 최적화 +- 메모리와 성능 간의 트레이드오프 고려 +- 순서 보존 여부에 따른 최적화 + +```javascript +// Set을 이용한 방법 +function removeDuplicatesSet(arr) { + return [...new Set(arr)]; +} + +// 필터를 이용한 방법 (순서 보존) +function removeDuplicatesFilter(arr) { + return arr.filter((item, index) => arr.indexOf(item) === index); +} + +// 객체를 이용한 방법 (순서 보존) +function removeDuplicatesObject(arr) { + const seen = {}; + return arr.filter((item) => { + if (seen.hasOwnProperty(item)) { + return false; + } + seen[item] = true; + return true; + }); +} +``` + +## 4. 알고리즘 비교 + +### 시간 복잡도 + +### 시간 복잡도 비교표 + +| 알고리즘 | 평균 | 최선 | 최악 | 공간 복잡도 | 안정성 | +|---------|------|------|------|------------|--------| +| 선형 검색 | O(n) | O(1) | O(n) | O(1) | - | +| 이진 검색 | O(log n) | O(1) | O(log n) | O(1) | - | +| 버블 정렬 | O(n²) | O(n) | O(n²) | O(1) | Yes | +| 선택 정렬 | O(n²) | O(n²) | O(n²) | O(1) | No | +| 삽입 정렬 | O(n²) | O(n) | O(n²) | O(1) | Yes | +| 퀵 정렬 | O(n log n) | O(n log n) | O(n²) | O(log n) | No | +| 병합 정렬 | O(n log n) | O(n log n) | O(n log n) | O(n) | Yes | +| 배열 회전 | O(n) | O(n) | O(n) | O(1) | - | +| 최대 부분합 | O(n) | O(n) | O(n) | O(1) | - | +| 두 수의 합 | O(n) | O(1) | O(n) | O(1) | - | +| 배열 병합 | O(n) | O(n) | O(n) | O(n) | - | +| 중복 제거 | O(n) | O(n) | O(n) | O(n) | - | + +### 알고리즘 선택 기준 + +1. 데이터 크기 + + - 작은 데이터셋: 삽입 정렬 + - 큰 데이터셋: 퀵 정렬 + +2. 데이터 특성 + + - 거의 정렬된 데이터: 삽입 정렬 + - 무작위 데이터: 퀵 정렬 + - 제한된 범위의 정수: 계수 정렬 + +3. 메모리 제약 + + - 메모리 제한적: 선택 정렬, 삽입 정렬 + - 메모리 충분: 병합 정렬 + +4. 안정성 필요 + - 안정성 필요: 삽입 정렬, 병합 정렬 + - 안정성 불필요: 퀵 정렬, 선택 정렬 + +### 알고리즘 선택시 참고 사항 + +1. 검색 알고리즘 + + - 정렬되지 않은 배열: 선형 검색 + - 정렬된 배열: 이진 검색 + - 빈번한 검색: 해시 테이블 고려 + +2. 정렬 알고리즘 + + - 일반적인 상황: 퀵 정렬 + - 안정성 필요: 병합 정렬 + - 작은 데이터: 삽입 정렬 + +3. 최적화 고려사항 + - 공간 복잡도 vs 시간 복잡도 + - 데이터 특성 활용 + - 알고리즘 안정성 요구사항 From a6e73630b1e5704abe6543644de76a44a4f8a523 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 17:55:51 +0900 Subject: [PATCH 03/11] =?UTF-8?q?remove:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "JooKangSan/\353\260\260\354\227\264/test.md" | 532 ------------------ 1 file changed, 532 deletions(-) delete mode 100644 "JooKangSan/\353\260\260\354\227\264/test.md" diff --git "a/JooKangSan/\353\260\260\354\227\264/test.md" "b/JooKangSan/\353\260\260\354\227\264/test.md" deleted file mode 100644 index 6794ef1..0000000 --- "a/JooKangSan/\353\260\260\354\227\264/test.md" +++ /dev/null @@ -1,532 +0,0 @@ -# 배열 알고리즘 상세 가이드 - -## 1. 검색 알고리즘 - -### 1.1 선형 검색 (Linear Search) -선형 검색은 가장 단순하고 직관적인 검색 방법입니다. 배열의 처음부터 끝까지 순차적으로 검색하여 원하는 값을 찾습니다. - -**작동 원리**: -1. 배열의 첫 번째 요소부터 시작 -2. 각 요소를 순차적으로 확인 -3. 찾고자 하는 값과 일치하면 해당 인덱스 반환 -4. 끝까지 찾지 못하면 -1 반환 - -**장점**: -- 구현이 매우 간단 -- 정렬되지 않은 배열에서도 사용 가능 -- 작은 배열에서 효율적 -- 추가 메모리가 필요 없음 - -**단점**: -- 배열 크기가 커질수록 검색 시간이 선형적으로 증가 -- 대용량 데이터에서는 비효율적 - -```javascript -function linearSearch(arr, target) { - for (let i = 0; i < arr.length; i++) { - if (arr[i] === target) return i; - } - return -1; -} -``` - -### 1.2 이진 검색 (Binary Search) -이진 검색은 정렬된 배열에서 사용하는 매우 효율적인 검색 알고리즘입니다. 검색 범위를 절반씩 줄여가며 찾는 방식입니다. - -**작동 원리**: -1. 배열의 중간 요소를 선택 -2. 중간 요소와 찾는 값을 비교 -3. 찾는 값이 더 작으면 왼쪽 절반을 검색 -4. 찾는 값이 더 크면 오른쪽 절반을 검색 -5. 찾을 때까지 1-4 반복 - -**장점**: -- 매우 효율적인 검색 속도 (로그 시간 복잡도) -- 대규모 데이터셋에서 특히 효과적 -- 메모리 사용이 적음 - -**단점**: -- 정렬된 배열에서만 사용 가능 -- 동적으로 변하는 데이터에는 부적합 -- 정렬 비용이 추가될 수 있음 - -```javascript -function binarySearch(arr, target) { - let left = 0; - let right = arr.length - 1; - - while (left <= right) { - const mid = Math.floor((left + right) / 2); - - if (arr[mid] === target) { - return mid; - } else if (arr[mid] < target) { - left = mid + 1; - } else { - right = mid - 1; - } - } - - return -1; -} -``` - -## 2. 정렬 알고리즘 - -### 2.1 버블 정렬 (Bubble Sort) -버블 정렬은 인접한 두 요소를 반복적으로 비교하고 교환하는 간단한 정렬 알고리즘입니다. - -**작동 원리**: -1. 인접한 두 요소를 비교 -2. 순서가 잘못되어 있으면 교환 -3. 배열 끝까지 반복 -4. 정렬이 완료될 때까지 1-3 반복 - -**최적화 기법**: -- 이미 정렬된 경우 조기 종료 -- 각 패스마다 마지막 요소는 확정되므로 비교 범위 감소 - -**장점**: -- 구현이 매우 단순 -- 안정 정렬 -- 추가 메모리가 필요 없음 -- 이미 정렬된 데이터에 대해 최적화 가능 - -**단점**: -- 매우 느린 시간 복잡도 -- 큰 데이터셋에서 비효율적 -- 많은 교환 연산 필요 - -```javascript -function bubbleSort(arr) { - const n = arr.length; - let swapped; - - for (let i = 0; i < n - 1; i++) { - swapped = false; - - // 최적화: 이미 정렬된 마지막 부분 제외 - for (let j = 0; j < n - i - 1; j++) { - if (arr[j] > arr[j + 1]) { - [arr[j], arr[j + 1]] = [arr[j + 1], arr[j]]; - swapped = true; - } - } - - // 최적화: 교환이 없으면 이미 정렬된 상태 - if (!swapped) break; - } - - return arr; -} -``` - -### 2.2 선택 정렬 (Selection Sort) -선택 정렬은 각 패스마다 최소값을 찾아 적절한 위치로 이동시키는 정렬 알고리즘입니다. - -**작동 원리**: -1. 정렬되지 않은 부분에서 최소값 찾기 -2. 최소값을 현재 위치로 이동 -3. 정렬된 부분을 한 칸 늘리기 -4. 배열이 정렬될 때까지 1-3 반복 - -**특징**: -- 데이터 교환 횟수가 버블 정렬보다 적음 -- 각 패스마다 최소값이 확정됨 -- 정렬 상태와 무관하게 일정한 시간 소요 - -**장점**: -- 구현이 간단 -- 교환 횟수가 적음 -- 메모리 사용이 적음 - -**단점**: -- 느린 시간 복잡도 -- 불안정 정렬 -- 큰 데이터셋에서 비효율적 - -```javascript -function selectionSort(arr) { - const n = arr.length; - - for (let i = 0; i < n - 1; i++) { - let minIdx = i; - - // 최소값 찾기 - for (let j = i + 1; j < n; j++) { - if (arr[j] < arr[minIdx]) { - minIdx = j; - } - } - - // 최소값이 현재 위치가 아니면 교환 - if (minIdx !== i) { - [arr[i], arr[minIdx]] = [arr[minIdx], arr[i]]; - } - } - - return arr; -} -``` - -### 2.3 삽입 정렬 (Insertion Sort) -삽입 정렬은 각 요소를 이미 정렬된 부분의 적절한 위치에 삽입하는 정렬 알고리즘입니다. - -**작동 원리**: -1. 두 번째 요소부터 시작 -2. 현재 요소를 정렬된 부분의 적절한 위치에 삽입 -3. 배열 끝까지 1-2 반복 -4. 삽입 시 정렬된 부분의 큰 요소들을 오른쪽으로 이동 - -**최적화 기법**: -- 이진 검색을 사용하여 삽입 위치 찾기 -- 필요한 경우에만 이동 수행 - -**장점**: -- 안정 정렬 -- 작은 데이터셋에서 효율적 -- 거의 정렬된 데이터에서 매우 효율적 -- 온라인 알고리즘 (실시간 정렬 가능) - -**단점**: -- 큰 데이터셋에서 비효율적 -- 많은 이동 연산 필요 -- 최악의 경우 느린 성능 - -```javascript -function insertionSort(arr) { - for (let i = 1; i < arr.length; i++) { - const key = arr[i]; - let j = i - 1; - - // 적절한 삽입 위치를 찾아 요소들을 이동 - while (j >= 0 && arr[j] > key) { - arr[j + 1] = arr[j]; - j--; - } - - // 찾은 위치에 삽입 - arr[j + 1] = key; - } - - return arr; -} -``` - -### 2.4 퀵 정렬 (Quick Sort) -퀵 정렬은 분할 정복 방식을 사용하는 매우 효율적인 정렬 알고리즘입니다. - -**작동 원리**: -1. 피벗 선택 (일반적으로 중간 요소) -2. 피벗보다 작은 요소는 왼쪽으로, 큰 요소는 오른쪽으로 분할 -3. 분할된 부분 배열에 대해 재귀적으로 1-2 반복 -4. 부분 배열의 크기가 1 이하가 될 때까지 반복 - -**최적화 기법**: -- 좋은 피벗 선택 (중간값 또는 랜덤) -- 작은 부분 배열에 대해 삽입 정렬 사용 -- 3-way 파티셔닝으로 중복 요소 처리 - -**장점**: -- 평균적으로 매우 빠른 속도 -- 추가 메모리 사용이 적음 -- 캐시 효율성이 좋음 - -**단점**: -- 최악의 경우 성능 저하 -- 불안정 정렬 -- 이미 정렬된 데이터에서 비효율적 - -```javascript -function quickSort(arr) { - if (arr.length <= 1) return arr; - - const pivot = arr[Math.floor(arr.length / 2)]; - const left = []; - const middle = []; - const right = []; - - // 분할 - for (const element of arr) { - if (element < pivot) left.push(element); - else if (element > pivot) right.push(element); - else middle.push(element); - } - - // 정복 및 결합 - return [...quickSort(left), ...middle, ...quickSort(right)]; -} -``` - -## 3. 기타 주요 알고리즘 - -### 3.1 배열 회전 (Array Rotation) -배열 회전은 배열의 요소들을 특정 위치만큼 이동시키는 알고리즘입니다. - -**구현 방법**: -1. 임시 배열 사용 -2. 요소 하나씩 이동 -3. 역전(Reversal) 알고리즘 - -**최적화 기법**: -- GCD를 이용한 저글링 알고리즘 -- 블록 스왑 알고리즘 -- 효율적인 메모리 사용을 위한 제자리 회전 - -**장점**: -- 다양한 구현 방법 존재 -- 특정 상황에 맞는 최적화 가능 -- 실제 응용 사례가 많음 - -```javascript -// 기본적인 회전 구현 -function rotateArray(arr, k) { - k = k % arr.length; // k가 배열 길이보다 큰 경우 처리 - return [...arr.slice(-k), ...arr.slice(0, -k)]; -} - -// 효율적인 제자리 회전 -function rotateArrayInPlace(arr, k) { - k = k % arr.length; - - // 전체 배열 뒤집기 - reverse(arr, 0, arr.length - 1); - // 처음 k개 요소 뒤집기 - reverse(arr, 0, k - 1); - // 나머지 요소 뒤집기 - reverse(arr, k, arr.length - 1); - - return arr; -} - -function reverse(arr, start, end) { - while (start < end) { - [arr[start], arr[end]] = [arr[end], arr[start]]; - start++; - end--; - } -} -``` - -### 3.2 최대 부분합 (Kadane's Algorithm) -연속된 부분 배열의 최대 합을 찾는 효율적인 알고리즘입니다. - -**작동 원리**: -1. 현재까지의 최대 합과 전체 최대 합을 추적 -2. 각 위치에서 새로운 요소를 포함할지 새로 시작할지 결정 -3. 전체 최대 합 갱신 - -**응용 분야**: -- 주식 거래 최적 기간 찾기 -- 신호 처리 -- 패턴 인식 - -**장점**: -- 선형 시간 복잡도 -- 추가 메모리가 필요 없음 -- 실시간 처리 가능 - -```javascript -function maxSubArray(arr) { - let maxSum = arr[0]; - let currentSum = arr[0]; - let start = 0; - let end = 0; - let tempStart = 0; - - for (let i = 1; i < arr.length; i++) { - // 현재 요소부터 새로 시작할지 기존 합에 더할지 결정 - if (arr[i] > currentSum + arr[i]) { - currentSum = arr[i]; - tempStart = i; - } else { - currentSum = currentSum + arr[i]; - } - - // 최대 합 갱신 - if (currentSum > maxSum) { - maxSum = currentSum; - start = tempStart; - end = i; - } - } - - return { - maxSum, - subArray: arr.slice(start, end + 1), - start, - end - }; -} -``` - -### 3.3 두 수의 합 찾기 (Two Sum) -배열에서 특정 합이 되는 두 수를 찾는 알고리즘입니다. - -**구현 방법**: -1. 브루트 포스 방식 (이중 루프) -2. 해시맵을 이용한 방식 -3. 정렬 후 투 포인터 방식 - -**최적화 기법**: -- 정렬된 배열에서는 투 포인터 사용 -- 해시맵으로 조회 시간 최적화 -- 조기 종료 조건 추가 - -**응용 분야**: -- 금융 거래 매칭 -- 데이터 분석 -- 알고리즘 문제 해결 - -```javascript -// 해시맵을 이용한 방식 -function twoSum(arr, target) { - const map = new Map(); - - for (let i = 0; i < arr.length; i++) { - const complement = target - arr[i]; - - if (map.has(complement)) { - return [map.get(complement), i]; - } - - map.set(arr[i], i); - } - - return null; -} - -// 정렬된 배열에서의 투 포인터 방식 -function twoSumSorted(arr, target) { - let left = 0; - let right = arr.length - 1; - - while (left < right) { - const sum = arr[left] + arr[right]; - - if (sum === target) { - return [left, right]; - } else if (sum < target) { - left++; - } else { - right--; - } - } - - return null; -} -``` - -### 3.4 배열 병합 (Array Merge) -두 개의 정렬된 배열을 하나의 정렬된 배열로 병합하는 알고리즘입니다. - -**작동 원리**: -1. 두 배열의 첫 번째 요소부터 비교 -2. 더 작은 요소를 결과 배열에 추가 -3. 사용된 배열의 포인터 이동 -4. 남은 요소들 처리 - -**최적화 기법**: -- 미리 결과 배열 크기 할당 -- 포인터 이동 최소화 -- 병합 시점 최적화 - -**응용 분야**: -- 병합 정렬의 핵심 연산 -- 데이터 통합 -- 실시간 데이터 동기화 - -```javascript -function mergeArrays(arr1, arr2) { - const merged = []; - let i = 0; - let j = 0; - - while (i < arr1.length && j < arr2.length) { - if (arr1[i] <= arr2[j]) { - merged.push(arr1[i]); - i++; - } else { - merged.push(arr2[j]); - j++; - } - } - - // 남은 요소 처리 - while (i < arr1.length) { - merged.push(arr1[i]); - i++; - } - - while (j < arr2.length) { - merged.push(arr2[j]); - j++; - } - - return merged; -} - -// 효율적인 구현 (미리 크기 할당) -function mergeArraysOptimized(arr1, arr2) { - const result = new Array(arr1.length + arr2.length); - let i = 0; - let j = 0; - let k = 0; - - while (i < arr1.length && j < arr2.length) { - result[k++] = arr1[i] <= arr2[j] ? arr1[i++] : arr2[j++]; - } - - while (i < arr1.length) result[k++] = arr1[i++]; - while (j < arr2.length) result[k++] = arr2[j++]; - - return result; -} -``` - -### 3.5 배열 중복 제거 (Array Deduplication) -배열에서 중복된 요소를 제거하는 알고리즘입니다. - -**구현 방법**: -1. Set 객체 사용 -2. 필터 사용 -3. 객체/맵 사용 -4. 정렬 후 순차 처리 - -**최적화 기법**: -- 해시셋 사용으로 조회 시간 최적화 -- 메모리와 성능 간의 트레이드오프 고려 -- 순서 보존 여부에 따른 최적화 - -```javascript -// Set을 이용한 방법 -function removeDuplicatesSet(arr) { - return [...new Set(arr)]; -} - -// 필터를 이용한 방법 (순서 보존) -function removeDuplicatesFilter(arr) { - return arr.filter((item, index) => arr.indexOf(item) === index); -} - -// 객체를 이용한 방법 (순서 보존) -function removeDuplicatesObject(arr) { - const seen = {}; - return arr.filter(item => { - if (seen.hasOwnProperty(item)) { - return false; - } - seen[item] = true; - return true; - }); -} -``` - -각 알고리즘은 특정 상황에서 장단점이 있으며, 실제 사용 시에는 다음 요소들을 고려해야 합니다: - -1. 데이터 크기 -2. 메모리 제약 -3. 성능 요구사항 -4. 데이터 특성 (정렬 여부, 중복 정도 등) -5. 안정성 요구사항 -6. 구현 복잡도 \ No newline at end of file From 294ba5490897acd4a4475e732469ee784af28b0d Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:12:00 +0900 Subject: [PATCH 04/11] =?UTF-8?q?feat:=20=EA=B8=B0=EC=B4=88=20=EC=95=8C?= =?UTF-8?q?=EA=B3=A0=EB=A6=AC=EC=A6=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\353\260\260\354\227\264.md" | 148 +++++++++++++++--- 1 file changed, 128 insertions(+), 20 deletions(-) diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" index 253a05f..50a8912 100644 --- "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" +++ "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" @@ -1,15 +1,123 @@ # 배열 알고리즘 가이드 ## 목차 +1. [간단한 알고리즘](#1-간단한-알고리즘) +2. [검색 알고리즘](#2-검색-알고리즘) +3. [정렬 알고리즘](#3-정렬-알고리즘) +4. [기타 주요 알고리즘](#4-기타-주요-알고리즘) +5. [알고리즘 비교](#5-알고리즘-비교) -1. [검색 알고리즘](#1-검색-알고리즘) -2. [정렬 알고리즘](#2-정렬-알고리즘) -3. [기타 주요 알고리즘](#3-기타-주요-알고리즘) -4. [알고리즘 비교](#4-알고리즘-비교) +## 1. 간단한 알고리즘 -## 1. 검색 알고리즘 +### 1.1 배열 기본 정보 확인 +```javascript +// 배열 길이 구하기 +const arr = [1, 2, 3, 4, 5]; +console.log(arr.length); + +// 배열 요소 출력 +arr.forEach(item => console.log(item)); // 각 요소를 한 줄씩 출력 +console.log(...arr); +``` + +### 1.2 배열 요소 추가/제거 +```javascript +const arr = ['456', '567']; + +// 배열 끝에 요소 추가 (권장) +arr.push('890'); + +// 배열 시작에 요소 추가 (비권장: 성능상 push 선호) +arr.unshift('123'); + +// 성능을 고려한 배열 초기화 후 요소 추가 +const newArr = []; +newArr.push('first'); // 빈 배열에는 push 사용 +``` + +### 1.3 배열 요소 검색 +```javascript +const pets = [ + { type: 'Dog', name: 'Max'}, + { type: 'Cat', name: 'Karl'}, + { type: 'Dog', name: 'Tommy'}, +]; + +// 조건에 맞는 첫 번째 요소 찾기 +const pet = pets.find(pet => + pet.type === 'Dog' && pet.name === 'Tommy' +); +console.log(pet); +``` + +### 1.4 배열 출력 방식 +```javascript +const answer = [1, 2, 3, 4, 5]; + +// 쉼표로 구분된 문자열로 출력 +console.log(`${answer}`); + +// 배열을 펼쳐서 출력 +console.log([...answer]); + +// 사용자 정의 구분자로 문자열 변환 +console.log(answer.join(", ")); +``` + +### 1.5 배열 정렬 +```javascript +const numbers = [5, 2, 8, 1, 9]; + +// 오름차순 정렬 +numbers.sort((a, b) => a - b); + +// 내림차순 정렬 +numbers.sort((a, b) => b - a); + +// 구조분해할당으로 정렬된 배열 활용 +const command = [2, 5, 3]; +const [sPosition, ePosition, position] = command; +``` + +### 1.6 배열 초기화 +```javascript +// 2차원 배열 초기화 (20x10 크기의 0으로 채워진 배열) +const grid = Array.from( + {length: 20}, // 외부 배열 크기 + () => Array(10).fill(0) // 내부 배열 초기화 +); + +// 1차원 배열 초기화 +const zeros = Array(5).fill(0); +const sequence = Array.from({length: 5}, (_, i) => i + 1); +``` + +### 1.7 배열 변환 +```javascript +const arr = [1, 2, 3, 4, 5]; + +// 배열을 문자열로 변환 +console.log(arr.join(", ")); +console.log(arr.join("")); +console.log(arr.join(" ")); + +// 문자열을 배열로 변환 +const str = "1,2,3,4,5"; +const newArr = str.split(","); +``` + +각 메서드의 시간 복잡도: +- length: O(1) +- push/pop: O(1) +- unshift/shift: O(n) +- find: O(n) +- sort: O(n log n) +- join: O(n) +- Array.from: O(n) +- fill: O(n) +## 2. 검색 알고리즘 -### 1.1 선형 검색 +### 2.1 선형 검색 - 가장 단순하고 직관적인 검색 방법 - 배열의 처음부터 끝까지 순차적으로 검색하여 원하는 값을 찾음 @@ -48,7 +156,7 @@ function linearSearch(arr, target) { } ``` -### 1.2 이진 검색 +### 2.2 이진 검색 - 정렬된 배열에서 사용하는 매우 효율적인 검색 알고리즘 - 검색 범위를 절반씩 줄여가며 찾는 방식 @@ -96,9 +204,9 @@ function binarySearch(arr, target) { } ``` -## 2. 정렬 알고리즘 +## 3. 정렬 알고리즘 -### 2.1 버블 정렬 +### 3.1 버블 정렬 - 인접한 두 요소를 반복적으로 비교하고 교환하는 간단한 정렬 알고리즘 @@ -151,7 +259,7 @@ function bubbleSort(arr) { } ``` -### 2.2 선택 정렬 +### 3.2 선택 정렬 - 각 패스마다 최소값을 찾아 적절한 위치로 이동시키는 정렬 알고리즘 @@ -211,7 +319,7 @@ function selectionSort(arr) { } ``` -### 2.3 삽입 정렬 +### 3.3 삽입 정렬 - 각 요소를 이미 정렬된 부분의 적절한 위치에 삽입하는 정렬 알고리즘 @@ -267,7 +375,7 @@ function insertionSort(arr) { } ``` -### 2.4 퀵 정렬 +### 3..4 퀵 정렬 - 분할 정복 방식을 사용하는 효율적인 정렬 알고리즘 @@ -324,7 +432,7 @@ function quickSort(arr) { return [...quickSort(left), ...middle, ...quickSort(right)]; } ``` -### 2.5 병합 정렬 +### 3.5 병합 정렬 - 분할 정복 방식을 사용하는 안정적인 정렬 알고리즘 @@ -389,9 +497,9 @@ function merge(left, right) { ``` -## 3. 기타 알고리즘 +## 4. 기타 알고리즘 -### 3.1 배열 회전 +### 4.1 배열 회전 - 배열을 특정 위치만큼 회전시키는 알고리즘 @@ -425,7 +533,7 @@ function rotateArray(arr, k) { } ``` -### 3.2 최대 부분합 (Kadane's Algorithm) +### 4.2 최대 부분합 (Kadane's Algorithm) - 연속된 부분 배열의 최대 합을 찾는 알고리즘입니다. @@ -460,7 +568,7 @@ function maxSubArray(arr) { } ``` -### 3.3 두 수의 합 찾기 +### 4.3 두 수의 합 찾기 - 정렬된 배열에서 특정 합이 되는 두 수를 찾는 알고리즘입니다. @@ -500,7 +608,7 @@ function findTwoSum(arr, target) { } ``` -### 3.4 배열 병합 (Array Merge) +### 4.4 배열 병합 (Array Merge) - 두 개의 정렬된 배열을 하나의 정렬된 배열로 병합하는 알고리즘입니다. @@ -565,7 +673,7 @@ function mergeArraysOptimized(arr1, arr2) { } ``` -### 3.5 배열 중복 제거 (Array Deduplication) +### 4.5 배열 중복 제거 (Array Deduplication) - 배열에서 중복된 요소를 제거하는 알고리즘입니다. @@ -606,7 +714,7 @@ function removeDuplicatesObject(arr) { } ``` -## 4. 알고리즘 비교 +## 5. 알고리즘 비교 ### 시간 복잡도 From 3dc19dee3709d05ce4be3fcc90c392b495be4674 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:15:39 +0900 Subject: [PATCH 05/11] =?UTF-8?q?=20=EB=B0=B0=EC=97=B4=EC=9E=90=EB=A5=B4?= =?UTF-8?q?=EA=B8=B0=20/=20=EA=B8=B0=EC=B4=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "JooKangSan/\353\260\260\354\227\264/.gitkeep" | 0 ...0\260\354\227\264\354\236\220\353\245\264\352\270\260.js" | 5 +++++ 2 files changed, 5 insertions(+) delete mode 100644 "JooKangSan/\353\260\260\354\227\264/.gitkeep" create mode 100644 "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" diff --git "a/JooKangSan/\353\260\260\354\227\264/.gitkeep" "b/JooKangSan/\353\260\260\354\227\264/.gitkeep" deleted file mode 100644 index e69de29..0000000 diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" new file mode 100644 index 0000000..5ac784f --- /dev/null +++ "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" @@ -0,0 +1,5 @@ +function solution(numbers, num1, num2) { + var answer = []; + answer = numbers.slice(num1, num2+1) + return answer; +} \ No newline at end of file From b53d0965bd4ac9b1555fdcc1b2bc485db3d0d73c Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:17:52 +0900 Subject: [PATCH 06/11] =?UTF-8?q?=20=EB=B0=B0=EC=97=B4=EC=9D=98=20?= =?UTF-8?q?=EC=9B=90=EC=86=8C=20=EA=B8=B8=EC=9D=B4=20/=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...4\233\220\354\206\214 \352\270\270\354\235\264.js" | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" new file mode 100644 index 0000000..bda619c --- /dev/null +++ "b/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" @@ -0,0 +1,11 @@ +function solution(strlist) { + var answer = []; + for(let i=0; i str.length); +} From af71e59b349e974a3076a23d263b838b3605da81 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:20:52 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=20=EB=B0=B0=EC=97=B4=20=ED=9A=8C?= =?UTF-8?q?=EC=A0=84=EC=8B=9C=ED=82=A4=EA=B8=B0=20/=20=EA=B8=B0=EC=B4=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Length_of_elements_in_array.js" | 2 +- .../\353\260\260\354\227\264/Rotate_array.js" | 19 +++++++++++++++++++ .../\353\260\260\354\227\264/Trim_Array.js" | 0 3 files changed, 20 insertions(+), 1 deletion(-) rename "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" => "JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" (99%) create mode 100644 "JooKangSan/\353\260\260\354\227\264/Rotate_array.js" rename "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" => "JooKangSan/\353\260\260\354\227\264/Trim_Array.js" (100%) diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" "b/JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" similarity index 99% rename from "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" rename to "JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" index bda619c..42649ec 100644 --- "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\235\230 \354\233\220\354\206\214 \352\270\270\354\235\264.js" +++ "b/JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" @@ -8,4 +8,4 @@ function solution(strlist) { function solution(strlist) { return strlist.map(str => str.length); -} +} \ No newline at end of file diff --git "a/JooKangSan/\353\260\260\354\227\264/Rotate_array.js" "b/JooKangSan/\353\260\260\354\227\264/Rotate_array.js" new file mode 100644 index 0000000..07b00dd --- /dev/null +++ "b/JooKangSan/\353\260\260\354\227\264/Rotate_array.js" @@ -0,0 +1,19 @@ +function solution(numbers, direction) { + var answer = []; + if(direction == "right"){ + numbers.unshift(numbers[numbers.length-1]) + numbers.pop(); + }else{ + numbers.push(numbers[0]) + numbers.shift(); + } + answer = numbers + return answer; +} + +function solution(numbers, direction) { + if(direction === "right") { + return [numbers[numbers.length-1], ...numbers.slice(0, -1)]; + } + return [...numbers.slice(1), numbers[0]]; +} diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" "b/JooKangSan/\353\260\260\354\227\264/Trim_Array.js" similarity index 100% rename from "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264\354\236\220\353\245\264\352\270\260.js" rename to "JooKangSan/\353\260\260\354\227\264/Trim_Array.js" From 37deffb04add63910abc6cf969fe62681948b5b2 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:23:58 +0900 Subject: [PATCH 08/11] =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=EC=88=AB=EC=9E=90=20=EA=B0=AF=EC=88=98=20/=20=EA=B8=B0?= =?UTF-8?q?=EC=B4=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[week1]\bArray/ Number_of_duplicate_numbers.js" | 13 +++++++++++++ .../[week1]\bArray/Length_of_elements_in_array.js" | 0 .../[week1]\bArray/Rotate_array.js" | 0 .../[week1]\bArray/Trim_Array.js" | 0 .../[week1]\bArray/\353\260\260\354\227\264.md" | 0 5 files changed, 13 insertions(+) create mode 100644 "JooKangSan/[week1]\bArray/ Number_of_duplicate_numbers.js" rename "JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" => "JooKangSan/[week1]\bArray/Length_of_elements_in_array.js" (100%) rename "JooKangSan/\353\260\260\354\227\264/Rotate_array.js" => "JooKangSan/[week1]\bArray/Rotate_array.js" (100%) rename "JooKangSan/\353\260\260\354\227\264/Trim_Array.js" => "JooKangSan/[week1]\bArray/Trim_Array.js" (100%) rename "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" => "JooKangSan/[week1]\bArray/\353\260\260\354\227\264.md" (100%) diff --git "a/JooKangSan/[week1]\bArray/ Number_of_duplicate_numbers.js" "b/JooKangSan/[week1]\bArray/ Number_of_duplicate_numbers.js" new file mode 100644 index 0000000..383dae9 --- /dev/null +++ "b/JooKangSan/[week1]\bArray/ Number_of_duplicate_numbers.js" @@ -0,0 +1,13 @@ +function solution(array, n) { + var answer = 0; + for(let i=0 ; i element === n).length; +} \ No newline at end of file diff --git "a/JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" "b/JooKangSan/[week1]\bArray/Length_of_elements_in_array.js" similarity index 100% rename from "JooKangSan/\353\260\260\354\227\264/Length_of_elements_in_array.js" rename to "JooKangSan/[week1]\bArray/Length_of_elements_in_array.js" diff --git "a/JooKangSan/\353\260\260\354\227\264/Rotate_array.js" "b/JooKangSan/[week1]\bArray/Rotate_array.js" similarity index 100% rename from "JooKangSan/\353\260\260\354\227\264/Rotate_array.js" rename to "JooKangSan/[week1]\bArray/Rotate_array.js" diff --git "a/JooKangSan/\353\260\260\354\227\264/Trim_Array.js" "b/JooKangSan/[week1]\bArray/Trim_Array.js" similarity index 100% rename from "JooKangSan/\353\260\260\354\227\264/Trim_Array.js" rename to "JooKangSan/[week1]\bArray/Trim_Array.js" diff --git "a/JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" "b/JooKangSan/[week1]\bArray/\353\260\260\354\227\264.md" similarity index 100% rename from "JooKangSan/\353\260\260\354\227\264/\353\260\260\354\227\264.md" rename to "JooKangSan/[week1]\bArray/\353\260\260\354\227\264.md" From 7c2335d702283ea4fb3b65533a2da06ef5be7965 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:30:01 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=20=EA=B0=80=EC=9E=A5=20=EC=9E=91?= =?UTF-8?q?=EC=9D=80=20=EC=88=98=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?/=20=EC=A4=91=EA=B8=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "JooKangSan/[week1]\bArray/ Remove_smallest_number.js" | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 "JooKangSan/[week1]\bArray/ Remove_smallest_number.js" diff --git "a/JooKangSan/[week1]\bArray/ Remove_smallest_number.js" "b/JooKangSan/[week1]\bArray/ Remove_smallest_number.js" new file mode 100644 index 0000000..3a147e7 --- /dev/null +++ "b/JooKangSan/[week1]\bArray/ Remove_smallest_number.js" @@ -0,0 +1,9 @@ +function solution(arr) { + var answer = []; + + if (arr.length === 1) return [-1]; + + const min = Math.min(...arr); + answer = arr.filter((num) => num !== min); + return answer; +} From 58245c225873db5d163a12a57cf01aa869b60301 Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:30:46 +0900 Subject: [PATCH 10/11] =?UTF-8?q?=20=ED=96=89=EB=A0=AC=EC=9D=98=20?= =?UTF-8?q?=EB=8D=A7=EC=85=88=20/=20=EC=A4=91=EA=B8=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[week1]\bArray/Matrix_addition.js" | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 "JooKangSan/[week1]\bArray/Matrix_addition.js" diff --git "a/JooKangSan/[week1]\bArray/Matrix_addition.js" "b/JooKangSan/[week1]\bArray/Matrix_addition.js" new file mode 100644 index 0000000..1afd3e2 --- /dev/null +++ "b/JooKangSan/[week1]\bArray/Matrix_addition.js" @@ -0,0 +1,19 @@ +function solution(arr1, arr2) { + const answer = []; + + for(let i = 0; i < arr1.length; i++) { + const row = []; + for(let j = 0; j < arr1[0].length; j++) { + row.push(arr1[i][j] + arr2[i][j]); + } + answer.push(row); + } + + return answer; +} + +function solution(arr1, arr2) { + return arr1.map((row, i) => + row.map((element, j) => element + arr2[i][j]) + ); +} \ No newline at end of file From d5beb1422c67041a0b1004d6592bded7b658daec Mon Sep 17 00:00:00 2001 From: JooKangSan Date: Thu, 2 Jan 2025 18:36:40 +0900 Subject: [PATCH 11/11] =?UTF-8?q?=20=EB=82=98=EB=88=84=EC=96=B4=20?= =?UTF-8?q?=EB=96=A8=EC=96=B4=EC=A7=80=EB=8A=94=20=EC=88=AB=EC=9E=90=20?= =?UTF-8?q?=EB=B0=B0=EC=97=B4=20/=20=EC=A4=91=EA=B8=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Array_of_numbers_that_fall_apart.js" | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 "JooKangSan/[week1]\bArray/Array_of_numbers_that_fall_apart.js" diff --git "a/JooKangSan/[week1]\bArray/Array_of_numbers_that_fall_apart.js" "b/JooKangSan/[week1]\bArray/Array_of_numbers_that_fall_apart.js" new file mode 100644 index 0000000..b2e7dbf --- /dev/null +++ "b/JooKangSan/[week1]\bArray/Array_of_numbers_that_fall_apart.js" @@ -0,0 +1,16 @@ +function solution(arr, divisor) { + const answer = []; + for(let num of arr) { + if(num % divisor === 0) { + answer.push(num); + } + } + if(answer.length === 0) return [-1]; + + return answer.sort((a, b) => a - b); +} + +function solution(arr, divisor) { + const answer = arr.filter(num => num % divisor === 0).sort((a, b) => a - b); + return answer.length ? answer : [-1]; +} \ No newline at end of file