문제

 

풀이 코드

function solution(numbers) {
    var answer = -1;
    const MAX_NUM = 9;
    let sum = 0;
    
    for (let i = 0 ; i <= MAX_NUM; i++) {
        sum += i;
    }
    
    let numbers_sum = numbers.reduce((total, current) => total + current, 0);
    answer = sum - numbers_sum; 
    return answer;
}

 

풀이 과정

1. 문제에서 요구사항을 보고 reduce 함수를 사용 하면 될 것 같았다. reduce 함수로 들어온 배열의 모든값을 더하고, 

0 ~ 9 까지의 합에서 해당 값을 빼면 된다고 생각했다!

 

너무 간단한 문제지만
고차 함수인 reduce 를 모르면 코드가 훨씬 길어졌을 것이다.

 

개발할때는 항상 모든 상황에 대한 경우의 수를 생각해야 한다고 했다.
간단하게 0~9 까지의 더한 값을 바로 사용하면 코드가 더 간결해 지겠지만...

숫자의 범위가 9 까지가 아니고, 10 , 100, 4000.. 등등 범위값이 달라지면 해당 코드를 다시 작성해야 하는 것 이 아닌,
MAX_NUM 상수의 값만 변경하면 바로 적용되도록 코드를 작성 하였다!

 

이제부터 습관화 하기로 했다..

무언갈 찾아볼때 순서를..

1. 공식문서

2. 이해 안된 내용 + 추가적인 내용에 대해서 구글링

 

결론.. 공식문서 짱짱..

 

1. 공식문서 훑어보기

1) Frame

The frame rectangle, which describes the view’s location and size in its superview’s coordinate system.

-> 슈퍼뷰 를 기준으로 위치 및 크기를 정의

강조한 부분을 잘 기억해야한다! 기준점이 자신보다 한단계 위의 뷰인 슈퍼뷰 이다!

var frame: CGRect { get set }

2) Bounds

The bounds rectangle describing the item’s location and size in its own coordinate system.

-> 자기 자신을 기준으로 위치 및 크기를 정의

강조한 부분을 잘 보자! 기준점이 자기 자신이다!

var bounds: CGRect { get }

 

💡CGRect는 직사각형의 위치와 치수를 포함하는 구조체 이며, 해당 구조는 

public struct CGRect {

    public var origin: CGPoint
    // 위치 정보

    public var size: CGSize
    // 크기 정보

    public init()

    public init(origin: CGPoint, size: CGSize)
}
/*

	...
	...
	...
	기타 확장 기능들이 구현되어 있음 
*/

로 정의되어 있습니다.. 이부분은 Code로 앱을 구현할때 사용하게 되는데

제가 아직 스토리보드 밖에 다룰줄을 몰라서.. 알게되면 포스팅 하겠슴다ㅎㅎ..

 

다시 본론으로 돌아가서

자! 공식문서만 봐도 차이점을 바로 알아버렸다 ^_-

간단하게 차이점을 이야기 하자면..

 

Frame 은 기준점이 슈퍼뷰에서부터 위치 및 크기를 지정하게 되는 반면,

Bounds 는 기준점이 자기 자신으로부터 위치 및 크기를 지정하게 된다!

 

 

로 끝내기엔 뭔가.. 이해가 되지 않으니 예시로 살펴 봐야겠다..

 

예시로 살펴보기

1. 먼저 frame 이다, 분홍색(빨간색) View가 superview고, 파란색 뷰가 frame을 적용한 뷰이다,

코드 를 살펴보자

class ViewController: UIViewController {
    @IBOutlet var superView: UIView!
    
    var view1 = UIView()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view1.frame = CGRect(origin: CGPoint(x: 50, y: 50), size: CGSize(width: 300, height: 300))
        view1.backgroundColor = .blue
        superView.addSubview(view1)
        superView.backgroundColor = .systemPink
    }
}

위치 정보를 (50.50) 으로 주었고, 크기 정보를 (300 * 300) 으로 설정했다.

우리는 위에서 슈퍼뷰기준 으로 위치와 크기를 나타낸다고 배웠다

각 수치값을 표현다면 위와 같이 될것이다 

분홍배경의 슈퍼뷰 로 부터 50.50 만큼 떨어진 거리에 300 * 300 크기의 뷰를 그려준것이다.

 

2. Bounds 를 살펴보자!

배경에 대한 설명은 같고, 위 코드에서 frame 을 bounds로 변경하여 적용하였다!

@IBOutlet var superView: UIView!
    
    var view1 = UIView()
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        view1.bounds = CGRect(origin: CGPoint(x: 50, y: 50), size: CGSize(width: 300, height: 300))
        view1.backgroundColor = .blue
        superView.addSubview(view1)
        superView.backgroundColor = .systemPink
    }

 

뭔가 이상하다..

frame 같은 경우는 어쩌면 자연스럽게 저렇게 되는구나 를 알수있는데

bounds 는 당최 어떻게 동작하는지를 모르겠다..

300 * 300 크기의 뷰를 (50.50) 위치에 놓았는데 어쩐지 왼쪽상단으로 쭈욱.. 올라갔다

기준점이 자기 자신 이란건 알겠는데 왜 저렇게 되는걸까?

 

이해하기가 좀 어려워서 zeddios 님의 블로그를 열심히 읽어 보았다!

그림하나로 저렇게 되는 이유가 종결된다!

정리하자면 bounds를 변경하는 것은, 변경된(설정된) 위치에서 내 자신의 View 를 다시 그려줘! 라고 하는것이다!

아래 그림을 보면 더 잘 이해가 갈것이다!

 

bounds의 origin(위치정보) 가 변경될때마다, 이미지 자체가 움직이를것이 아닌 

아이폰에 표시되는 view 자체의 위치가 이동된다!

 

이렇게..!!

 

이것이 만약 frame 이였다면. 상위뷰 기준으로 이동하기 때문에

 

이렇게 표시된다!!!

 

해당 개념은 직접 코드로 구현해보고 익숙해져야 더 깊이 이해가 갈것같다!

(특히 bounds..)

 

 

 

참고 사이트 : https://zeddios.tistory.com/203

iOS 공부하면서 스토리보드에서 컴포넌트를 끌어다 놓을때

strong / weak 의 연결을 하는것을 알게되었고 이게 무슨의미인가.. 싶었지만

그냥 weak으로 해라! 라고만해서 그 의미에 대해 깊게 파악해보진 않았던거 같다..

그래서 이 강한참조 / 약한참조 의 근본(?)인 ARC 를 공부해보쟈!

 

What is ARC?

ARC 는 Automatic Reference Counting의 약자다!

ARC는 메모리를 스스로 관리하는 기능을 수행한다 일반적으로 Swift가 자동으로 ARC를 이용해 메모리를 관리하기 때문에 사용자는 메모리는 어떻게 처리해야하는지 깊게 생각할 필요는 없다고.. (공식문서에 써있다..)

💡 Objective-C 에서는 MRC 라고 하는 수동 메모리 관리 기법을 사용하였다, Objective-C 에서는 수동으로 관리해야 하기 때문에
retain / release 를 사용해 사용수의 증가/감소 를 확인하여 메모리를 관리하였는데 ARC 로 넘어오면서 이걸 자동으로 해준다! 그래서 프로그래머는 더이상 메모리관리에 관한 코드를 따로 작성하지 않아도 된다! 

그래서 ARC 어떻게 동작하는데?

Class 의 인스턴스가 생성될때마다, ARC는 해당 인스턴스에 대한 정보를 저장하는 Memory 할당하게 된다!

이 메모리는 당연히 인스턴스의 method, property 의 값 등의 정보를 가지고있다!

 

그리고 해당 인스턴스가 더이상 필요가 없어지면 해당 메모리를 확보하여 다른 목적으로 사용가능케한다!!

그러니까.. 한마디로 요약하면 “ Class가 필요 없어지면 해당 메모리를 해제함

 

그럼.. Class가 필요한지 필요없는지 어떻게 판단하게될까..? 이름에서 유추할수 있다!

해당 Class의 인스턴스가 참조되고 있는 수를 세어 가지고 있다!

이 수를 세기위해 클래스 인스턴스를 할당할 때마다 강력한(Strong) 참조를 하게되며, 이 강력한 참조가 유지되는 동안은 할당 해제를 허용하지 않게된다!

백문이 불여일견 직접 예시로 살펴보자

class OS {
    let kind: String
    
    // 초기화
    init(kind: String) {
        self.kind = kind
        print("[인스턴스 생성] 현재 운영체제는 \\(kind)")
    }
    
    // 소멸자
    deinit {
        print("[인스턴스 할당 해제] \\(kind) 운영체제 종료")
    }
}

일단.. Class를 맹글어 주고..

var os1: OS?
var os2: OS?
var os3: OS?

이렇게 하면 인스턴스가 생성이!!!!

안됩니다.

예 안돼요..

 

Optional 로 선언되어 있어서 기본적으로 nil 값이 할당되기 때문에 class 인스턴스를 할당하지 않아요!

os1 = OS(kind: "MacOS")
// [인스턴스 생성] 현재 운영체제는 MacOS

이제야 비로소 인스턴스가 할당되었습니다! 그러면 ARC에 의해 강한 참조로 os1 변수가 counting 될거에요!

os2 = os1
os3 = os1

이렇게 선언하면 강한참조로 counting이 2개더 더해지겠죠?!

 

자 그럼 할당을 해재해 볼거에요 우리는 할당을 해제하면서

print("[인스턴스 할당 해제] \\(kind) 운영체제 종료") 구문이 수행되기를 원합니다!

os1 = nil
os2 = nil

2개의 변수를 할당 해제했음에도 deinit 구문이 수행되지 않습니다.. 왜일까요?!

ARC에 의해 os3 에대한 reference count 를 가지고 있기 때문입니다!!

os3 = nil
// 인스턴스 할당 해제] MacOS 운영체제 종료

비로소 참조 수가 0이 되면서 deinit 이 수행된다!!

 

하지만 ARC를 사용하면서 메모리 누수 가 발생하는 상황이 반드시 나온다!

이를 방지하기 위해서 우리는 weak  unowned 의 개념을 알아야한다!

/*
 문제
 양수 A가 N의 진짜 약수가 되려면, N이 A의 배수이고, A가 1과 N이 아니어야 한다. 어떤 수 N의 진짜 약수가 모두 주어질 때, N을 구하는 프로그램을 작성하시오.
 
 입력
 첫째 줄에 N의 진짜 약수의 개수가 주어진다. 이 개수는 50보다 작거나 같은 자연수이다. 둘째 줄에는 N의 진짜 약수가 주어진다. 1,000,000보다 작거나 같고, 2보다 크거나 같은 자연수이고, 중복되지 않는다.
 
 출력
 첫째 줄에 N을 출력한다. N은 항상 32비트 부호있는 정수로 표현할 수 있다.
 
 */
import Foundation
let inputCount = readLine().map{Int($0)!}!
var inputNum = readLine()!.components(separatedBy: " ").map{Int($0)!}

if inputCount == 1 {
    print(inputNum[0]*inputNum[0])
} else {
    let even = (inputNum.count / 2)
    inputNum = inputNum.sorted()
    if inputNum.count % 2 == 0 {
        print(inputNum[even] * inputNum[even - 1])
    } else {
        print(inputNum[even - 1] * inputNum[even + 1])
    }
}

알고리즘 문제를 많이 풀어봐야 겠다고 느낀 문제..

 

문제를 보고 무슨뜻인지 잘 이해가 안되서 한참을 쳐다봤다 ㅋㅋㅋ

해당 풀이 방법은 이렇게 수행된다

 

1. 약수의 갯수가 1개이면 고민할 필요도 없이 해당 값을 제곱하여 출력하면 된다

2. 약수의 갯수가 2개 이상이라면 입력받은 배열을 정렬하고,[ 갯수 / 2 ] 를 하여 배열의 중간값위치를 구한다!

3. 약수의 갯수가 짝수 라면 중간값의 계산한 [ 인덱스의 값 * 이전 인덱스의 값 ] 을 하여 구한다!

4. 약수의 갯수가 홀수 라면 중간인덱스의 [ 이전 값 * 이후 값 ] 을 수행하여 구한다!

/*
 문제
 2와 5로 나누어 떨어지지 않는 정수 n(1 ≤ n ≤ 10000)가 주어졌을 때, 1로만 이루어진 n의 배수를 찾는 프로그램을 작성하시오.
 
 입력
 입력은 여러 개의 테스트 케이스로 이루어져 있다. 각 테스트 케이스는 한 줄로 이루어져 있고, n이 주어진다.

 출력
1로 이루어진 n의 배수 중 가장 작은 수의 자리수를 출력한다.
 
 */
import Foundation
//while let input = readLine() {
//    var one = "1"
//    while Int(one)! % Int(input)! != 0 {
//        print(one)
//        one.append("1")
//    }
//    print(one.count)
//}

while let input = readLine() {
    var one = 1
    var count = 1
    while one % Int(input)! != 0 {
        one = one * 10 + 1
        one %= Int(input)!
        count += 1
    }
    print(count)
}

 

단순히 문자열에 "1" 을 추가하고, 해당 문자열의 길이를 출력하는 방법으로 풀었으나 Runtime 오류가 발생했다.

실행 할때마다 결과값이 잘 나와서 왜 안되는지 한잘 머리를 굴렸다.. ( 주석처리한 부분! )

 

그리고 11113 같은 큰 수를 넣었더니.. 에러가 발생했다!!

 

이유는 Int 형의 범위를 넘어가서 오류가 발생하는 거였다..

 

그래서 어떻게 하지 고민하다가..

 

input으로 들어온 값으로 나눈 나머지로 계산하는 방식을 고안해 냈다..

 

왜 저렇게 고안했는지는 디버깅 몇번 해보면 알게 될것이당...

저렇게 계산하면 최대 범위를 넘어갈 일도 없을 뿐더러 계산도 차이없이 잘 된다!

+ Recent posts