https://school.programmers.co.kr/learn/courses/30/lessons/12933
프로그래머스
코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.
programmers.co.kr
* 정수 내림차순으로 배치하기 *
함수 solution은 정수 n을 매개변수로 입력받습니다.
n의 각 자릿수를 큰것부터 작은 순으로 정렬한 새로운 정수를 리턴해주세요.
예를들어 n이 118372면 873211을 리턴하면 됩니다.
* 제한조건 *
n은 1이상 8000000000 이하인 자연수입니다.
* 알고리즘 이해하기 *
"주어진 숫자 n의 각 자릿수를 큰 순서대로 정렬하여 새로운 숫자를 만들어라"
이해한 알고리즘의 예시를 분석해봅시다.
예시에서는 "118372"를 주었고,
이를 큰 순서대로 정렬하면 "873211"이 됩니다.
알고리즘을 이해했다면 이제 로직을 구상해봅시다.
* 로직구상 *
첫번째. 입력된 숫자를 자릿수별로 분리해서 배열에 담아야 하겠고
두번째. 다음으로 배열을 내림차순으로 정렬해주고
세번째. 마지막으로, 정렬된 배열을 다시 하나의 숫자로 합치면 되겠죠?!
그렇다면 구상한 로직을 바탕으로 코드를 작성해봅시다.
* 코드작성 *
func solution(_ n: Int64) -> Int64 {
가장먼저 함수를 정의해 줘야겠죠?
func 키워드를 사용해 함수를 정의해 주고 함수이름은 solution이 되고
다음으로 매개변수 (_ n: Int64)를 주는데
int64는 매개변수 자료형을 나타내고
int64 타입의 정수를 받는 n이라는 이름의
매개변수를 선언해줍시다!
그리고
반환하는 값으로 " -> Int64 "를 해줍시다.
이는 함수가 반환하는 값의 자료형을 말하고
여기서는 "Int64" 타입의 값을 반환하는 것을 말하죠.
"Int64" 타입은 함수가 반환하는 값의 자료형을 말하고
64비트 정수를 이야기 하며 64비트 정수는 일반적으로
매우 큰 범위의 정수를 표현할 수 있으며,
부호 있는 정수 이 타입의 변수는 매우 큰 값이나
정밀도가 필요한 연산을 수행할 때 유용하게 사용하는 것이죠
이 문제에서는 큰 범위의 값을 표현해야 하기 때문에
Int64 타입을 명시적으로 사용 하는게 좋습니다.
var digits: [Int] = String(n).compactMap { Int(String($0)) }
함수를 정의해 주었으니 이제 "digits"라는 변수를 만들어 배열 공간을 확보해야겠죠?
배열을 확보하는것도 중요하지만
정수 n을 문자열로 변환"을 해야겠고
문자열로 변환을 하기 위해서는 " String(문자열)" 함수를 사용해야 하겠죠
게다가
문제에서 " n의 각 자릿수를 큰것부터
작은 순으로 정렬한 새로운 정수 " 라고
명시 되어 있으니 고차함수인 "compactMap"을 사용해서
배열을 생성해주는데
이 과정에서 "nil"이 아닌 값을 포함시켜주어야죠
왜냐면 문자열 함수를 사용했기 때문에
다시 숫자 배열로 변환 하는 과정이 있잖아요?
그렇기 때문에 "nil"을 걸러내기 위해서 입니다.
"compactMap" 고차함수를 설명하자면 아래 접은 내용을 확인해보세요.
고차함수 "compactMap"은 Swift의 배열 메서드 중 하나인데
이 메서드는 배열의 각 요소에 대해 클로저를 적용하고,
그 결과가 nil이 아닌 경우에만 새로운 배열을 생성합니다.
이때 nil이 아닌 값만을 포함하며, nil인 요소는 제외됩니다.
즉, compactMap은 옵셔널 값을 다룰 때 유용하게 사용되요.
클로저를 사용하여 각 요소를 변환하고,
그 결과가 nil이 아닌 경우에만 새로운 배열에 추가합니다.
예를 들어, 문자열 배열에서 정수로 변환 가능한 값만을 추출하고자 할 때
compactMap을 사용할 수 있는데 이때 정수로 변환할 수 없는 문자열은
nil이 되므로 이러한 값을 제외하고 정수만을 포함하는 배열을 얻을 수 있죠
간단한 예제로
let strings = ["1", "2", "three", "4", "five"]
// 문자열을 정수로 변환하고, 변환 가능한 경우에만 정수로 매핑합니다.
let integers = strings.compactMap { Int($0) }
return integers
위의 예제에서는 문자열 배열 strings를 정수 배열로 변환하는데,
compactMap을 사용하여 문자열을 정수로 변환 가능한 경우에만 포함시켰습니다.
그리고
그렇게 문자열로 변환된 "각 문자"를
다시 "정수로 변환"해서 "배열에 저장"하는 과정이 필요하니까
Int 생성자를 사용하여 문자열을 숫자로 변환해 줘야겠죠?
그러기 위해선 "클로저함수"를 활용해야 합니다.
클로저함수
클로저함수는 일급 객체로서, 코드 블록을 의미하고
이것은 함수의 기능을 포함하고 있지만 별도의 이름이 없는 함수이죠
주로 함수를 간결하게 표현하거나 다른 함수에 전달할 때 사용하고
주어진 형식의 함수를 작성하거나 사용할 수 있는 능력을 제공하죠
주로 간결한 문법과 함께 주변 환경의 값을 포획하여 사용할 수 있는 능력이 특징이고
클로저는 중괄호 "{}"로 둘러싸여 있어 매개 변수와 반환 형식을 가질 수 있습니다.
클로저 내에서 in 키워드를 사용하여
매개 변수와 반환 값, 그리고 클로저의 본문을 구분합니다.
간단한 예시로
let greeting = { (name: String) -> String in
return "Hello, \(name)!"
}
print(greeting("John")) // 출력: Hello, John!
위의 예시에서 { (name: String) -> String in return "Hello, \(name)!" } 부분이 클로저 함수가 되는거에요!
이 클로저 함수는 문자열을 입력받아
해당 문자열을 포함한 인사말을 반환하죠.
클로저 함수를 활용 해 본다면
주어진 정수를 문자열로 변환해 주어야 하니까 String() 생성자를 사용해서
정수를 문자열로 변환할 수 있는 구조를 만들고 그렇게 변환된 문자열로
변환된 각 문자를 숫자로 변환해야 하는데 이때, 각 문자를 숫자로 변환하는데에는
Int() 생성자를 사용하고 각 문자가 숫자로 변환된 후에는 이를 배열에 저장하고
이때, 숫자로 변환된 각 문자열은 배열에 순서대로 저장되는 것으로 마무리하여
변수를 생성해주고
* 알기 쉽게 정리 *
1. 변수를 만들어 배열 공간을 확보
배열 확보가 중요, 문제에서 주어진 조건에 따라 compactMap을 사용하여 배열을 생성
이때 nil이 아닌 값을 포함시켜야 하는데,
이는 문자열을 숫자로 변환하는 과정에서 발생할 수 있는
nil 값을 걸러내기 위한 조치입니다.
2. 정수를 문자열로 변환
입력으로 받은 정수 n을 문자열로 변환하여 각 자릿수를 분리해야 합니다.
이를 위해 String(n) 함수를 사용합니다.
3. 문자열을 숫자 배열로 변환
각 문자열을 숫자로 변환해야 하는데, 이를 위해 클로저 함수를 사용할 필요가 없습니다.
「그런데 "var digits: [Int] = String(n).compactMap { Int(String($0)) }"
이 구문에서 클로저함수가 들어가죠?
이 코드 라인에서 사용된 클로저는
문자를 숫자로 변환하는데에 있어서는 필요하지 않아요
"$0"는 클로저의 인자로, 각 문자를 나타내주는것입니다.
Int 생성자를 사용하여 숫자로 변환 시켜주는거죠.」
대신에 문자열을 숫자로 변환하는 과정은 기본적으로 Int 또는 Int64 생성자를 사용하여 수행됩니다.
digits.sort(by: >)
그리고 이제 우리가 내림차순으로 정렬을 해야하니까
sort(by:) 메서드를 사용하여 숫자 배열을 내림차순으로 정렬해줍시다.
이 때 " > " 연산자를 사용해서 큰 숫자가 앞으로 오도록 정렬주어 정렬문을 마무리 해줍시다.
sort(by:) 메서드는 배열의 요소를 정렬하는 데 사용됩니다.
이 메서드는 배열의 요소를 비교하여 주어진 순서에 따라 정렬합니다.
sort(by:) 메서드는 배열의 각 요소를 비교하는 클로저를 인자로 받습니다.
이 클로저는 비교 연산자를 사용하여 두 요소를 비교하고, 정렬 기준을 정의합니다.
클로저는 두 요소를 입력으로 받아서 두 요소를 비교한 후에,
정렬이 필요한 경우에는 true를 반환하고,
그렇지 않은 경우에는 false를 반환합니다.
예를 들어,
배열을 숫자의 오름차순으로 정렬하려면 다음과 같이 사용할 수 있습니다:
var numbers = [5, 2, 7, 1, 3]
numbers.sort(by: <) // 숫자를 오름차순으로 정렬
위의 코드에서는 < 연산자를 사용하여 숫자를 오름차순으로 정렬하고 있습니다.
sort(by:) 메서드는 배열의 요소를 해당 연산자에 따라 정렬하게 됩니다.
let sortedNumber = digits.reduce(0) { result, digit in
result * 10 + digit
}
다음으로 문제에서 "정렬된 숫자를 리턴하라" 라고 되어있었죠?
그렇기 때문에 배열에 있는 숫자들을 다시 합치는 과정이 필요하죠
배열의 각 요소를 결합해 단일 값으로 만드는데에는 어떠한 메서드가 필요해요
우리가 이전 알고리즘에서도 사용했던 "reduce" 이죠
"sortedNumber" 이라는 상수를 선언해주고, 그 안에 "digits" 라는 배열변수에
"reduce" 메서드를 ". (접근 연산자)" 호출해주고 그 값을 0으로 초기화 시켜주어서
초기값을 0을 사용하게 해서 각 배열의 요소를 가져와 결과 값에 해당하는
정수에 10을 곱하고 현재 요소를 더해서 새로운 결과 값을 생성 해주어
배열의 각 숫자들이 자릿수를 가진 숫자로 만들어 지게 해주면 되겠죠
간단한 예시를 통해 설명하면,
배열 [1, 2, 3]이 있다고 가정해 본다면
reduce 메서드는 초기값인 0부터 시작하여
각 요소를 가져와서 다음과 같은 계산을 수행해요.
초기값 0에 10을 곱하고 첫 번째 요소 1을 더하여 1
결과 값 1에 10을 곱하고 두 번째 요소 2를 더하여 12
결과 값 12에 10을 곱하고 세 번째 요소 3을 더하여 123
따라서 최종적으로는 정렬된 숫자 123이 되는 형태로
이렇게 합쳐진 정렬된 숫자를 sortedNumber에 저장
이제 sortedNumber에 저장된 값을 반환하기만 하면 되겠죠?
return Int64(sortedNumber)
마지막으로, 정렬된 숫자를 Int64로 변환하여 반환해주면
64비트 정수로 변환된 결과를 얻게 되는것이죠.
여기서 Int64로 변환하는 이유는 아래 접은 글내용에 있어요
sortedNumber 변수는 배열에 있는 숫자를
정렬된 숫자로 합치는 과정을 거쳐서 만들어진 정수 값인데
이 값은 Swift의 기본적인 정수 타입인 Int일 가능성이 있지만
문제에서 명시한 조건은 "정수 n이 64비트 정수 타입인 Int64 범위 내에 있어야 한다"는 것이잖아요?
그래서 "sortedNumber"가 Int 타입이라면, 이 값을 그대로 반환하면
64비트 정수 타입인 Int64의 범위를 초과할 수 있기 때문에 Int64() 생성자를 사용해서
" sortedNumber "를 Int64로 변환하고 반환하는 것이 안전한것이죠
이렇게 하면 sortedNumber의 값이 64비트 정수 타입인 Int64에 맞게 변환되는 거죠
따라서 return Int64(sortedNumber)을 사용하여
안전하게 반환하는 것이 좋아요
선택사항이지만 제한조건을 준수해 주어야 해요.
총 코드는 아래와 같아요.
func solution(_ n: Int64) -> Int64 {
// Step 1: 숫자를 자릿수별로 분리해서 배열에 담기
var digits: [Int] = String(n).compactMap {
Int(String($0))
}
// Step 2: 숫자를 내림차순으로 정렬
digits.sort(by: >)
// Step 3: 정렬된 배열을 하나의 숫자로 합치기
let sortedNumber = digits.reduce(0) {
result, digit in
result * 10 + digit
}
// 정렬된 숫자 리턴
return Int64(sortedNumber)
}
'IOS > Swift-Algorithm (Programmers)' 카테고리의 다른 글
[Swift]Programmers - 두 정수 사이의 합 (2) | 2024.02.27 |
---|---|
[Swift] Programmers - 하샤드 수 (0) | 2024.02.23 |
[Swift] Programmers - 정수 제곱근 판별 (0) | 2024.02.21 |
[Swift]Programmers - 문자열을 정수로 바꾸기 (0) | 2024.02.20 |
[Swift] Programmers - 자연수 뒤집어 배열로 만들기 (0) | 2024.02.19 |