문제

 

풀이 코드

import Foundation

let N = Int(readLine()!)!
let formula = readLine()!
var num = [Int]()
var answer = [Double]()

for _ in 0..<N {
    num.append(Int(readLine()!)!)
}

for op in formula {
    switch op {
    case "*":
        answer.append(answer.removeLast() * answer.removeLast())
    case "/":
        let stackLast = answer.removeLast()
        answer.append(answer.removeLast() / stackLast)
    case "+":
        answer.append(answer.removeLast() + answer.removeLast())
    case "-":
        let stackLast = answer.removeLast()
        answer.append(answer.removeLast() - stackLast)
    default:
        let idx = op.asciiValue! - 65
        answer.append(Double(num[Int(idx)]))
    }
}

print(String(format: "%.2f", answer.removeLast()))

 

풀이 과정

알파벳을 포함한 별도의 배열을 선언해 주고 계산을 해야하나 고민했는데,

Ascii 코드를 이용해서 인덱스를 할당하여 구현하면 된다고 생각했다.

 

A 의 아스키 코드는 65 이고, 입력받은 숫자들을 별도의 배열로 지정하여

A 일때는 0인덱스의 수를, B일때는 1인덱스의 수를 ... 이렇게 할당하면 될것같았다.

 

그렇게 그냥 스택을 이용해 풀이를 해주었고, 고려해야 할 점은 두가지였다.

- 와 / 인데,

 

덧셈과 곱셈의 경우 순서가 상관 없지만, 뺄셈과 나눗셈은 순서가 중요하기 때문에, 먼저 removeLast 를 수행하여 순서를 지정해 주었다.

 

이렇게 풀고 소숫점 2번째 자리까지만 출력하기 위해

String의 format 을 이용해 C언어의 printf 처럼 할당해 주었다

문제

 

풀이 코드

let N = Int(readLine()!)!
var nums = readLine()!.split(separator: " ").map{Int(String($0))!}
var numCount = Array(repeating: 0, count: nums.max()!)
var answer = [Int]()

// 등장횟수 계산
for idx in 0..<N {
    numCount[nums[idx] - 1] += 1
}

// 오등큰수 인덱스 검색
for idx in 0..<N {
    while !answer.isEmpty && numCount[nums[answer.last!] - 1] < numCount[nums[idx] - 1] {
        nums[answer.removeLast()] = nums[idx]
    }
    answer.append(idx)
}

for idx in answer {
    nums[idx] = -1
}

print(nums.map{String($0)}.joined(separator: " "))

 

풀이 과정

이전에 풀었던 오큰수와 크게 다르지 않은 문제라서 거의 코드를 가져온 수준이였다.

대신 다른점이 있다면, 입력된 값 내에서 최대값만큼 배열을 생성해 주었고, count 를 계산하여

count 를 비교하며 오큰수와 같은 형식으로 풀었다.

State

: 값이 변하면 View를 새로 그려주는 역할을 수행

State 란 무엇인가?

1. State Property store values that the view depends on

⇒ 뷰가 의존하는 상태 속성 저장값

2. State Property represent values that can change

⇒ State Property는 변경할 수 있는 값을 나타냅니다.

3. State Property typically declared in the view that nedds them

⇒ State Property는 일반적으로 이를 추가하는 뷰에서 선언됩니다.

예제 코드

  • State 속성을 사용한 toggleValue 의 변화에 따라 Text가 변하는걸 볼수 있다

Binding

: State의 값을 받아오거나 변경할 때 사용 ( View간 양방향 소통 )

$ 기호를 사용하여 속성을 정의한다

Binding이란 무엇인가?

1. Put a ‘$’ infront of a State Property reference in your view code (Not in the declaration) to turn it into a two way, Read/Write relationship

⇒ view 코드(선언 아님)에서 State Property 참조 앞에 '$'를 넣어 양방향 읽기/쓰기 관계로 전환합니다.

2. @Binding is a property wrapper to indicate that it expects a binding to be passed to the view when an instance of the view is created

⇒ @Binding은 뷰의 인스턴스가 생성될 때 뷰에 바인딩이 전달될 것으로 예상함을 나타내는 속성 래퍼입니다.

예제 코드

  • State를 선언한 View
struct ParentView: View {
    @State private var toggleValue = true
    var body: some View {
        SubView(toggleValue: $toggleValue)
    }
}
  • Binding으로 State변수를 받는 SubView
struct SubView: View {
    @Binding var toggleValue: Bool
    
    var body: some View {
        if toggleValue == false {
            Text("Toggle is False")
        } else {
            Text("Toggle is True")
        }
        
        Button(action: {
            self.toggleValue.toggle()
        }) {
            Text("토글 버튼")
        }
    }
}
  • @Binding 을 명시함 으로써, State변수를 받아옴을 명시
  • 부모 View 에서 Binding으로 값을 넘겨 줄때는 $ 기호를 사용

Observable Object

: 여러 View에서 의존하기를 원할때 사용하는 Object

Observable Object를 사용하기 위한 절차

  1. Class가 Observable Object 프로토콜을 채택해야함
  2. 프로토콜을 채택함으로써 변경하상에 대해 Class의 객체를 관찰하거나 수신
  3. @Published를 선엄하여 변경사항을 저장할 속성을 명확하게 명시 ( Class 내의 개체에 명시 )
  4. @Observed Object 속성을 사용하여 관찰가능한 개체에 대한 참조를 저장

예제 코드

  • 여러 View에서 의존 할 Class 생성
class Profile: ObservableObject {
    @Published var isLogined = false
}

⇒ Class에 Observable Object를 채택

⇒ @Published 를 사용함 으로써 변하는 값을 감시할 변수 명시

struct LoginView: View {
    @ObservedObject var profile = Profile()
    
    var body: some View {
        if profile.isLogined {
        Text("로그인 완료")
        } else {
            Text("버튼을 눌러 로그인 해주세요")
        }
        
        Button(action: {
            profile.isLogined.toggle()
        }){
            Text("버튼")
        }
    }
}

⇒ @ObservedObject 를 사용함 으로써, 변경 사항을 감시할 개체 인스턴스 생성

하지만 이러한 방식을 사용하면 하위 View 모두에게 동일 인스턴스를 전달 할 수 없다 다음 예를 보자

버튼을 클릭하여 로그인을 하면, 로그인 사용자의 닉네임을 보여줄 것이다.

  • LoginView
struct LoginView: View {
    @ObservedObject var profile = Profile()
    
    var body: some View {
        if profile.isLogined {
        Text("로그인 완료")
        } else {
            Text("버튼을 눌러 로그인 해주세요")
        }
        LoginCheckView()
        Button(action: {
            profile.isLogined.toggle()
        }){
            Text("버튼")
        }
    }
}
  • LoginCheckView
struct LoginCheckView: View {
    @ObservedObject var profile = Profile()
    
    var body: some View {
        if profile.isLogined {
            Text("로그인한 사용자 : Chikong.")
        } else {
            Text("로그인 정보가 없습니다.")
        }
    }
}

코드를 작성하고 앱을 실행하면

  • 하위 View의 값이 변하지 않는것을 확인 할 수 있다

이러한 현상이 나타나는 이유는 다음 그림을 살펴보자

  • 다음과 같이 각 View에 새로운 Class 인스턴스를 생성 했기 때문에 각각 다른 인스턴스를 참조 하고 있다.
  • 그렇기 때문에 두개의 인스턴스는 다른 것으로 인식하게 되고, 연관된 값을 변경 하거나 감시할 수 없다

EnvironmentObject

: 하위 View 모두에게 동일한 객체 인스턴스를 사용

위의 예시를 해결할 수 있는 방법이 EnvironmentObject 이다. EnvironmentObject를 사용하면 동일 인스턴스를 하위 View 모두에게 전달 할 수 있다.

위의 문제를 해결할 예제 코드를 보자

  • MainView
import SwiftUI

@main
struct DataFlowApp: App {
    var body: some Scene {
        WindowGroup {
            LoginView()
                .environmentObject(Profile())
        }
    }
}

⇒ 제일 상위 Main View에서 .environmentObject(Profile()) 를 이용해 객체 인스턴스를 넘겨주었다. 이제 MainView의 하위 View에서 동일한 인스턴스를 참조할 수 있다.

  • LoginView
struct LoginView: View {
    @EnvironmentObject var profile: Profile
    
    var body: some View {
        if profile.isLogined {
        Text("로그인 완료")
        } else {
            Text("버튼을 눌러 로그인 해주세요")
        }
        LoginCheckView()
        Button(action: {
            profile.isLogined.toggle()
        }){
            Text("버튼")
        }
    }
}
  • LoginCheckView
struct LoginCheckView: View {
    @EnvironmentObject var profile: Profile

    var body: some View {
        if profile.isLogined {
            Text("로그인한 사용자 : Chikong.")
        } else {
            Text("로그인 정보가 없습니다.")
        }
    }
}

⇒ LoginView 와 LoginCheckView에 @EnvironmentObject var profile: Profile 부분을 보자.

@EnvironmentObject 속성을 명시 했고 같은 인스턴스를 참조함을 구체적으로 적어 주었다

 

⇒ 같은 인스턴스를 참조하기 때문에 로그인상태에 따라 값이 변함을 확인 할 수 있다.

이처럼 하위 View에 동일 인스턴스를 참조해야 할때, 필요한 View에 명시해주면 사용할 수 있다.

 

 

참고 유튜브 : https://www.youtube.com/watch?v=jD6c9y8CFGQ

문제

 

풀이 코드

let n = Int(readLine()!)!
var nums = readLine()!.split(separator: " ").map{Int(String($0))!}
var answer = [Int]()

for index in 0..<n {
    while !answer.isEmpty && nums[answer.last!] < nums[index] {
        nums[answer.removeLast()] = nums[index]
    }
    answer.append(index)
}

for index in answer {
    nums[index] = -1
}

print(nums.map{String($0)}.joined(separator: " "))

 

풀이 과정

혼자 해결하지 못한 문제였다.

 

처음 생각은 filter를 이용해 현재 인덱스의 값보다 작은것들만 모아놓고,

그렇게 생성된 배열이 비어있으면 -1을, 

비어있지 않으면 해당 배열의 첫번째 인덱스를 저장하면 될것 같았는데

애초에 그렇게 구현하지 못하는 문제였기도 했고, 가능하다 했어도 매번 filter를 사용해야 하기 때문에 시간초과에서 걸렸을것 같았다.

 

그래서 인터넷의 코드를 참고하여 이해하는 수준에 그쳤다..

너무 어려운 문제였다.

 

우선,

answer 배열에 -1이 들어갈 인덱스를 저장한다.

그리고 for 루프 내에서 while 루프를 돌려, 오큰수를 찾고, 오큰수를 찾지 못하면 해당 인덱스를 저장하여

 

마지막에 해당인덱스 요소를 -1 로 바꿔 주었다.

 

디버깅 

문제

 

풀이 코드

let inputs = readLine()!.map{String($0)}
var answer = 0
var stick = 0

for index in 0..<inputs.count {
    if inputs[index] == "(" {
        stick += 1
    } else {
        stick -= 1
        if inputs[index - 1] == "(" {
            answer += stick
        } else {
            answer += 1
        }
    }
}

print(answer)

 

풀이 과정

그림을 그려가며 규칙을 찾았다.

 

레이저를 만나면 막대의 수는 레이저 + 1개가 된다.

그렇게 생각하고 문제를 해결 하려 했는데 도저히 감이 안왔다.

 

그렇게 고민을 하다가 결국 검색을 통해 답을 보게 되었다.. ㅠㅠ

 

코드의 흐름대로 보면 다음과 같은 단계로 갯수를 셀 수 있다

1. '(' 를 만나면 막대의 수를 +1 한다.

2. ')'를 만나면 막대의 수를 -1 한다.

2 - 1. ')'를 만났을때 바로 전의 요소가 '('면 레이저를 만났다는 소리가 되고, 레이저를 만나면 현재까지 쌓인 막대의 수 만큼 저장된다

2 - 2 ')'를 만나고, 해당 요소가 레이저가 아니라면, 막대의 마지막 부분이기 때문에 잘린상태의 막대가 +1 된다 ( 레이저 + 1의 규칙이 여기서 적용 )

 

글로 설명이 어려울거 같아 그림도 같이 첨부하지만..

그림을 봐도 이해를 못할거 같다 이문제는 나중에 코드를 까먹었을때 다시 한번 스스로 풀어보는걸로..

+ Recent posts