Swift 알고리즘 및 언어공부
최대공약수와 최소공배수..
어떻게든 구하려고 for문 돌려보다가 뭔가 최대공약수랑 최소공배수를 쉽게 구할 수 있는 공식 같은 게 있을 것 같아서
최대공약수 최소공배수를 구하는 수학 공식?을 찾아봤다.
유클리드 호제법이라고 두 개의 정수(자연수) 사이에서의 최대공약수를 구하는 알고리즘 이 있다.
이 방식을 이용해서 문제를 풀면 간단하다.
2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면 (단, a>b), a와 b의 최대공약수는 b와 r의 최대공약수와 같다. 이 성질에 따라, b를 r로 나눈 나머지 r'를 구하고, 다시 r을 r'로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다.
이 과정을 코드로 풀어 쓰면 밑에 코드를 완성할 수 있다.
정수 a, b값을 받아서 b의 값이 0인지 확인하고, 0이면 a값 리턴. 아닌 경우 다시 재귀함수를 실행하여
a에 b의 값을 , b에는 a를 b로 나눈 값에 나머지가 0이 될 때까지 반복하는 방법
func gcd(_ a: Int, _ b: Int) -> Int {
if b == 0 {
return a
} else {
return gcd(b, a % b)
}
}
그리고 최소공배수는 (정수1 x 정수2 / 두 정수의 최대공약수) 공식으로 구할 수 있다.
//두 정수 20과 16의 최대공배수 구하기
result = 20 * 16 / gcd(20, 16)
// result 는 80
//39. 최대공약수와 최소공배수
// 최대 공약수
func gcd(_ a: Int, _ b: Int) -> Int {
if b == 0 {
return a
} else {
return gcd(b, a % b)
}
}
/// 최소공배수
func lcm(_ a: Int, _ b: Int) -> Int {
return a * b / gcd(a, b)
}
func solution(_ n:Int, _ m:Int) -> [Int] {
return [gcd(n, m), lcm(n, m)]
}
역시 코딩에는 수학적 사고가 많이 필요하다고 느꼈다.
그리고 최대공약수와 최소공배수의 값을 구하는 과정을 함수로 나눠서 사용한 것을 다른 사람의 풀이에서 봤는데
인상적이었다. 이렇게 또 하나 배워감.. 굳굳 👍
//40. 3진법 뒤집기
import Foundation
func solution(_ n:Int) -> Int {
var num:Int = n
var changeNum:String = ""
// 3진수 변환
while num != 0 {
changeNum = String(num % 3) + changeNum
num /= 3
}
// 뒤집기
var reverseNum = Int(String(changeNum.reversed()))!
var result = 0
var count = 0
// 3진수를 10진수로 변환
while reverseNum != 0 {
result += (reverseNum % 10) * Int(pow(Double(3), Double(count)))
reverseNum /= 10
count += 1
}
return result
}
이번엔 진법.. 여기 링크에서 진법에 대해서 자세히 알려준다 !
10진법에서 3진법으로 바꾸려면 나눗셈을 이용하면 된다.
3을 계속 나누고, 나머지들을 모아서 합치면 3진법이 된다.
10진법인 45가 있다고 생각했을 때, 3진법으로 바꾸면 1200이 된다.
그리고 3진법에서 10진법으로 변환하려면 오른쪽부터 3의 0승씩 곱해서 더하면 된다.
1*27(3^3) + 2*9(3^2)+ 0*3(3^1) + 0*1(3^0) = 45
이 방식을 바탕으로 코드를 짰다.
그리고 새로 알게 된 제곱 함수인 pow 함수
pow()
: 두 정수를 입력하면 a의 b제곱을 해준다. 제곱을 구할 수 있는 함수
let value1 = 2
let value2 = 5
pow(Double(value1), Double(value2))
주의할 점은 Double 형식만 입력할 수 있음. Double 타입(소수점형)으로 변환해주지 않으면 에러가 발생한다.
그런데 !
radix를 사용하면 간단하게 진법을 변환할 수 있다... ㅠㅠㅠ
//radix 사용
import Foundation
func solution(_ n:Int) -> Int {
var chgNum = String(n, radix: 3)
var reverseNum = ""
for i in chgNum.reversed() {
reverseNum += String(i)
}
return Int(reverseNum, radix: 3)!
}
String(n, radix: 3) -> 변환하고자 하는 정수와 radix: 어떤 진수로 변환할 것인지 (3진수로 변환하고 싶으면 '3' )
그리고 String 값을 Int로 변환할 때는 옵셔널 제거해 주는 작업이 필요하다 !
iOS 앱 개발 입문
AutoLayout
: AutoLayout을 안 해주면 화면에 객체들이 x, y 좌표에 따라 표시되어서 다른 크기의 화면에서는 생각하는 것과 다르게 보일 수 있음.
제약조건
Alignment : 정렬을 통해 제약조건 설정
- Code를 통한 제약조건 지정 (현업에서는 코드를 통한 제약조건 더 많이 사용)
NSLayoutConstraint.activate([
// 가로 가운데 정렬 (X축)
self.textLabel.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
// 세로 가운데 정렬 (Y축)
self.textLabel.centerYAnchor.constraint(equalTo: self.view.centerYAnchor),
])
Constraints : 상하좌우 영역 지정
- Code를 통한 제약조건 지정 (현업에서는 코드를 통한 제약조건 더 많이 사용)
NSLayoutConstraint.activate([
// 위쪽 Constraints (Top)
textLabel.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0),
// 아래쪽 Constraints (Bottom)
textLabel.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0),
// 왼쪽 Constraints (Leading)
textLabel.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 0),
// 오른쪽 Constraints (Trailing)
textLabel.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: 0),
])
생명주기(LifeCycle)
: 실제 실행되고 종료되는 동안 어떤 순환을 가지고 있는 지를 나타낸다.
앱이 갖는 생명주기
Not running: 실행되지 않거나 종료된 상태
Foreground
- Inactive : 실행은 되었지만, 어떤 이벤트를 받을 수 없는 상태
- Active : 활성화되어서 이벤트를 받을 수 있는 상태
Background : 유예 상태, 진입하기 전 거치는 상태
(음악, 통화가 앱을 닫아도 사용가능한 것은 background 상태에 있는 것)
Suspended : background 상태지만 아무 이벤트도 받지 않는 상태 (Not running과 일반적으로 동일)
UIView 생명주기 : 나타남과 사라짐 두 상태를 가지면서, 상태를 전환 (8가지 메소드)
1. init 메소드 : 객체가 생성될 때 호출. (필요한 의존성이나 구성요소)
2. loadView : 컨트롤러의 view 계층 구조가 생성될 때 호출
3. viewDidLoad : 보통 이 메소드가 호출되는 시점에서 다양한 뷰 컴포넌트들을 올려주고 레이아웃을 잡는 것을 실행.
4. viewWillApear : 뷰가 화면에 나타나기 전 호출 (뷰를 업데이트하거나 애니메이션 시작)
5. viewDidApear : 뷰가 화면에 나타나면 호출 (애니메이션 종료하거나 뷰의 상태를 업데이트)
6. viewWillDisapear : 뷰가 화면에서 사라지기 직전에 호출 (데이터 저장, 애니메이션 시작)
7. viewDidDisapear : 뷰가 화면에서 사라지면 호출 (애니메이션 종료, 뷰의 상태 업데이트)
8. deinit : UIViewController 객체가 메모리에서 해제될 때 호출
로직 다루기
버튼이나 라벨과 같은 것들을 control 키로 잡아서 코드에 드래그하면
IBOutlet을 사용해서 연결하고, IBAction으로 동작을 설정해 줄 수 있음
@IBOutlet weak var textLabel: UILabel!
@IBAction func buttonTapped(_ sender: UIButton) {
self.textLabel.text = "버튼을 클릭했습니다."
let button = sender as? UIButton
button?.isEnabled = false
}
버튼 클릭 시, 텍스트 라벨에 텍스트는 "버튼을 클릭했습니다."로 바뀌고, 버튼은 비활성화되는 코드
Sender
: Sender는 이 메소드의 caller
아래와 같은 코드에서 두 개의 UIButton이 있다면 sender를 통해서
어떤 버튼이 불러왔는지(func의 caller)를 확인하는지 알 수 있다.
@IBAction func buttonPressed(sender: AnyObject) {
let button = sender as UIButton
println("Button \(button.tag) was pressed!")
}
? 근데 위에 강의 예시자료 코드에 as에는 왜 '?'가 붙었을까.. 옵셔널?
직접 실행해 보니 에러가 있어서 ?를 지워줬더니 (button 뒤에 물음표까지) 정상으로 작동했다.
isEnabled
: 활성화할 것인지, 비활성화할 것인지 true와 false(Bool 값)를 통해서 동작
강의에서 디버깅 파트는 필요할 때
한 번 더 보면서 해보면 좋을 것 같음 !
(브레이크 포인트, LLDB ,,,)
Counter 예제
드디어 카운터 예제 !
레이아웃 요구사항
1. UILabel이 가운데 위치
2. UILabel을 기준으로 상단에는 감소버튼, 아래에는 증가버튼 위치
3. UILabel과 UIButton 사이의 간격은 16px로 설정
4. AutoLayout 사용
로직 요구사항
1. count의 시작은 0
2. 감소버튼을 눌렀을 때, -1씩 감소시켜 UILabel에 표시
3. 증가버튼을 눌렀을 때, +1씩 증가시켜 UILabel에 표시
는 내일.. 해야겠다..
내일은 counter 예제 끝내고, 과제 시작해야겠다 !
아자잣