목표: 정렬되지 않은 배열에서 최소값 또는 최대값을 찾는다.
제네릭 객체로 이루어진 배열이 있다. 모든 객체를 순회하면서 현재까지의 최소값 또는 최대값을 추적한다.
정렬되지 않은 리스트 [ 8, 3, 9, 4, 6 ]
에서 최댓값을 찾아보자.
먼저 첫 번째 숫자인 8
을 선택하고, 이를 현재까지의 최댓값으로 저장한다.
리스트에서 다음 숫자 3
을 선택하고, 현재 최댓값과 비교한다. 3
은 8
보다 작으므로 최댓값은 여전히 8
이다.
다음 숫자 9
를 선택하고, 현재 최댓값과 비교한다. 9
는 8
보다 크므로 최댓값을 9
로 업데이트한다.
리스트의 모든 요소를 처리할 때까지 이 과정을 반복한다.
Swift로 간단하게 구현한 예제는 다음과 같다:
func minimum<T: Comparable>(_ array: [T]) -> T? {
guard var minimum = array.first else {
return nil
}
for element in array.dropFirst() {
minimum = element < minimum ? element : minimum
}
return minimum
}
func maximum<T: Comparable>(_ array: [T]) -> T? {
guard var maximum = array.first else {
return nil
}
for element in array.dropFirst() {
maximum = element > maximum ? element : maximum
}
return maximum
}
이 코드를 플레이그라운드에 넣고 다음과 같이 테스트할 수 있다:
let array = [ 8, 3, 9, 4, 6 ]
minimum(array) // 3 반환
maximum(array) // 9 반환
Swift 라이브러리는 이미 SequenceType
에 대한 확장을 포함하고 있다. 이 확장은 시퀀스에서 최소/최대 엘리먼트를 반환한다.
let array = [ 8, 3, 9, 4, 6 ]
array.minElement() // 3을 반환
array.maxElement() // 9를 반환
let array = [ 8, 3, 9, 4, 6 ]
//swift3
array.min() // 3을 반환
array.max() // 9를 반환
배열에 포함된 최대값과 최소값을 찾으면서 비교 횟수를 최소화하려면, 각 요소를 쌍으로 비교하는 방식을 사용할 수 있다.
정렬되지 않은 리스트 [ 8, 3, 9, 6, 4 ]
에서 최솟값과 최댓값을 찾아보자.
첫 번째 숫자 8
을 선택하고, 이를 현재 최솟값과 최댓값으로 저장한다.
리스트의 항목 수가 홀수이므로 8
을 리스트에서 제거하고, 남은 쌍은 [ 3, 9 ]
와 [ 6, 4 ]
가 된다.
다음 숫자 쌍 [ 3, 9 ]
를 선택한다. 이 두 숫자 중 3
이 더 작으므로, 3
을 현재 최솟값 8
과 비교하고, 9
를 현재 최댓값 8
과 비교한다. 3
은 8
보다 작으므로 새로운 최솟값은 3
이 된다. 9
는 8
보다 크므로 새로운 최댓값은 9
가 된다.
다음 숫자 쌍 [ 6, 4 ]
를 선택한다. 여기서 4
가 더 작으므로, 4
를 현재 최솟값 3
과 비교하고, 6
을 현재 최댓값 9
와 비교한다. 4
는 3
보다 크므로 최솟값은 변경되지 않는다. 6
은 9
보다 작으므로 최댓값도 변경되지 않는다.
결과적으로 최솟값은 3
이고 최댓값은 9
가 된다.
다음은 Swift로 구현한 간단한 예제다:
func minimumMaximum<T: Comparable>(_ array: [T]) -> (minimum: T, maximum: T)? {
guard var minimum = array.first else {
return nil
}
var maximum = minimum
// 'array'의 요소 개수가 홀수일 경우, 'minimum' 또는 'maximum'이 남은 요소를 처리하도록 함
let start = array.count % 2 // 홀수일 경우 1, 첫 번째 요소를 건너뜀
for i in stride(from: start, to: array.count, by: 2) {
let pair = (array[i], array[i+1])
if pair.0 > pair.1 {
if pair.0 > maximum {
maximum = pair.0
}
if pair.1 < minimum {
minimum = pair.1
}
} else {
if pair.1 > maximum {
maximum = pair.1
}
if pair.0 < minimum {
minimum = pair.0
}
}
}
return (minimum, maximum)
}
이 코드를 플레이그라운드에 넣고 다음과 같이 테스트한다:
let result = minimumMaximum(array)!
result.minimum // 3을 반환
result.maximum // 9를 반환
요소를 쌍으로 묶어 각 쌍의 최댓값과 최솟값을 현재까지의 최솟값과 최댓값과 비교함으로써, 2개의 요소마다 3번의 비교만 수행하도록 최적화했다.
이 알고리즘은 O(n) 시간 복잡도로 동작한다. 배열의 각 요소를 현재 최소값/최대값과 비교하기 때문에, 알고리즘 실행 시간은 배열 길이에 비례한다.
작성자: Chris Pilcher