func getFirstScore(scores: [Int]) -> Int? {
return scores.first
}
O(1)
func sumAllScores(scores: [Int]) -> Int {
var total = 0
for score in scores {
total += score
}
return total
}
O(n)
func findPairs(numbers: [Int], target: Int) -> [(Int, Int)] {
var pairs: [(Int, Int)] = []
for i in 0..<numbers.count {
for j in (i+1)..<numbers.count {
if numbers[i] + numbers[j] == target {
pairs.append((numbers[i], numbers[j]))
}
}
}
return pairs
}
O(n^2)
func binarySearch(_ numbers: [Int], _ target: Int) -> Int? {
var left = 0
var right = numbers.count - 1
while left <= right {
let mid = (left + right) / 2
if numbers[mid] == target {
return mid
} else if numbers[mid] < target {
left = mid + 1
} else {
right = mid - 1
}
}
return nil
}
O(logn)
func mergeSort(_ array: [Int]) -> [Int] {
guard array.count > 1 else { return array }
let mid = array.count / 2
let left = mergeSort(Array(array[..<mid]))
let right = mergeSort(Array(array[mid...]))
return merge(left, right)
}
func merge(_ left: [Int], _ right: [Int]) -> [Int] {
var result: [Int] = []
var leftIndex = 0
var rightIndex = 0
while leftIndex < left.count && rightIndex < right.count {
if left[leftIndex] <= right[rightIndex] {
result.append(left[leftIndex])
leftIndex += 1
} else {
result.append(right[rightIndex])
rightIndex += 1
}
}
result.append(contentsOf: left[leftIndex...])
result.append(contentsOf: right[rightIndex...])
return result
}
O(n logn)
func mergeSort(_ array: [Int]) -> [Int] {
guard array.count > 1 else { return array } // Base case: 배열 크기가 1 이하일 때 정렬 완료
let mid = array.count / 2
let left = mergeSort(Array(array[..<mid])) // 왼쪽 절반 분할
let right = mergeSort(Array(array[mid...])) // 오른쪽 절반 분할
return merge(left, right) // 병합 과정
}
func merge(_ left: [Int], _ right: [Int]) -> [Int] {
var result: [Int] = []
var leftIndex = 0
var rightIndex = 0
// 두 배열을 병합
while leftIndex < left.count && rightIndex < right.count {
if left[leftIndex] <= right[rightIndex] {
result.append(left[leftIndex])
leftIndex += 1
} else {
result.append(right[rightIndex])
rightIndex += 1
}
}
// 나머지 요소 추가
result.append(contentsOf: left[leftIndex...])
result.append(contentsOf: right[rightIndex...])
return result
}
O(1)
의 작업으로 이루어진다.n
이라면, 이를 n/2
, n/4
, n/8
로 계속 나누며 총 log n
단계가 걸린다.n
인 경우 병합에 걸리는 시간은 O(n)
이다.n
에 비례한다.O(log n)
(재귀 깊이)O(n)
, 총 log n
단계만큼 수행된다.T(n)
= O(n log n)
O(n)
이 필요하다.log n
깊이의 재귀 호출이 발생하므로, 재귀 스택 공간이 O(\log n)
만큼 추가로 필요하다.최종적으로, 병합 정렬의 공간 복잡도는: O(n)
.
O(n log n)
의 성능을 보장합한다.n
만큼 추가 메모리를 필요로 하므로, 공간 효율성이 낮다.func findCommonElements(in arrays: [[Int]]) -> Set<Int> {
guard let first = arrays.first else { return [] }
var result = Set(first)
for array in arrays {
result = result.intersection(Set(array))
}
return result
}
O(k · m)
func findCommonElements(in arrays: [[Int]]) -> Set<Int> {
guard let first = arrays.first else { return [] } // 첫 번째 배열을 가져옴
var result = Set(first) // 첫 번째 배열을 기준으로 시작
for array in arrays {
result = result.intersection(Set(array)) // 다른 배열과 교집합 계산
}
return result
}
k
: 입력 배열의 개수 (arrays.count
).arrays
는 이차원 배열이므로, 각 배열을 독립적으로 처리해야 하는 횟수를 나타낸다.n
: 모든 배열에 포함된 총 요소 수.[[1, 2], [3, 4, 5], [6]]
라면 n = 6
.m
: 각 배열의 평균 크기.m = n / k
로 계산할 수 있다. 예를 들어, n = 6
, k = 3
이면 m = 2
.Set(first)
로 첫 번째 배열을 집합으로 변환하는 데 걸리는 시간:O(m)
, 여기서 m
은 첫 번째 배열의 크기이다.intersection(Set(array))
의 시간 복잡도는 두 집합 중 작은 집합의 크기에 비례합니다.O(m)
시간 동안 수행된다.k
에 대해 교집합 연산을 반복한다.k - 1
번 교집합 연산을 수행하며, 각 연산은 평균적으로 O(m)
시간이 걸린다.O(m)
(k - 1) * O(m)
O(m) + O((k - 1) · m)
= O(k · m)
모든 배열의 크기가 동일한 경우:
m
, 배열의 개수가 k
라면, 총 요소 수 n
= k · m
.O(k · m)
= O(n)
으로 간단히 표현된다.배열의 크기가 불균형한 경우:
n
일 때 복잡도는 여전히 O(k · m)
= O(n)
이다.빈 배열 포함:
O(1)
시간에 종료된다.O(k · m)
O(n)
, 여기서 n
은 모든 요소의 총합.func fibonacci(_ n: Int) -> Int {
if n <= 1 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
O(2^n)
fibonacci(n)
함수는 다음과 같은 호출 트리를 만든다:
fibonacci(5)
호출 트리fibonacci(5)
├── fibonacci(4)
│ ├── fibonacci(3)
│ │ ├── fibonacci(2)
│ │ │ ├── fibonacci(1)
│ │ │ └── fibonacci(0)
│ │ └── fibonacci(1)
│ └── fibonacci(2)
│ ├── fibonacci(1)
│ └── fibonacci(0)
└── fibonacci(3)
├── fibonacci(2)
│ ├── fibonacci(1)
│ └── fibonacci(0)
└── fibonacci(1)
중복 계산 발생:
fibonacci(3)
은 두 번 호출되고, fibonacci(2)
는 세 번 호출된다.노드 수:
n
번째 호출에서 재귀적으로 2^n
에 가까운 노드가 생성된다.재귀 호출의 횟수:
n
번째 피보나치 수를 계산하기 위해, 트리의 각 레벨에는 2^k
개의 노드가 생성된다. k
은 트리의 깊이이다.n
이므로, 전체 노드 수는 대략 2^n
에 비례한다.각 호출의 작업량:
O(1)
의 상수 시간 작업(덧셈 및 비교)만 수행한다.최종 시간 복잡도:
O(2^n)
이다.재귀 호출의 중복 계산을 제거하면 시간 복잡도를 크게 줄일 수 있다.
var memo = [Int: Int]()
func fibonacci(_ n: Int) -> Int {
if n <= 1 {
return n
}
if let result = memo[n] {
return result
}
let result = fibonacci(n - 1) + fibonacci(n - 2)
memo[n] = result
return result
}
O(n)
memo
에 저장되므로, 각 피보나치 수는 한 번만 계산된다.기존 재귀 구현:
O(2^n)
메모이제이션 사용:
O(n)