문제

1번부터 N번까지 N개의 풍선이 원형으로 놓여 있고. i번 풍선의 오른쪽에는 i+1번 풍선이 있고, 왼쪽에는 i-1번 풍선이 있다. 단, 1번 풍선의 왼쪽에 N번 풍선이 있고, N번 풍선의 오른쪽에 1번 풍선이 있다. 각 풍선 안에는 종이가 하나 들어있고, 종이에는 -N보다 크거나 같고, N보다 작거나 같은 정수가 하나 적혀있다. 이 풍선들을 다음과 같은 규칙으로 터뜨린다.

우선, 제일 처음에는 1번 풍선을 터뜨린다. 다음에는 풍선 안에 있는 종이를 꺼내어 그 종이에 적혀있는 값만큼 이동하여 다음 풍선을 터뜨린다. 양수가 적혀 있을 경우에는 오른쪽으로, 음수가 적혀 있을 때는 왼쪽으로 이동한다. 이동할 때에는 이미 터진 풍선은 빼고 이동한다.

예를 들어 다섯 개의 풍선 안에 차례로 3, 2, 1, -3, -1이 적혀 있었다고 하자. 이 경우 3이 적혀 있는 1번 풍선, -3이 적혀 있는 4번 풍선, -1이 적혀 있는 5번 풍선, 1이 적혀 있는 3번 풍선, 2가 적혀 있는 2번 풍선의 순서대로 터지게 된다.

입력

첫째 줄에 자연수 N(1 ≤ N ≤ 1,000)이 주어진다. 다음 줄에는 차례로 각 풍선 안의 종이에 적혀 있는 수가 주어진다. 종이에 0은 적혀있지 않다.

출력

첫째 줄에 터진 풍선의 번호를 차례로 나열한다.

내가 푼 풀이

- 처음에 인덱스만으로 풀려고 했다가 너무 복잡해져서 다른 방법을 찾았다.

- 이 문제는 자료구조 중 Deque의 성질인 양방향 Pop,push기능을 사용하여 풀었다.

- 코드와 알고리즘에 대한 설명은 주석처리해두었다.

 

import Foundation

// Deque
struct Deque<T> {
    var enqueue: [T]
    var dequeue: [T] = []

    init(enqueue: [T]) {
        self.enqueue = enqueue
    }
    var count: Int {
        return enqueue.count + dequeue.count
    }
    var isEmpty: Bool {
        return enqueue.isEmpty && dequeue.isEmpty
    }

    mutating func first() -> T? {
        if dequeue.isEmpty {
            dequeue = enqueue.reversed()
            enqueue.removeAll()
        }
        return dequeue.last
    }
    mutating func pushFront(_ element: T) {
        dequeue.append(element)
    }
    mutating func pushRear(_ element: T) {
        enqueue.append(element)
    }
    mutating func popFront() -> T? {
        if dequeue.isEmpty {
            dequeue = enqueue.reversed()
            enqueue.removeAll()
        }
        return dequeue.popLast()
    }
    mutating func popRear() -> T? {
        if enqueue.isEmpty {
            enqueue = dequeue.reversed()
            dequeue.removeAll()
        }
        return enqueue.popLast()
    }
}
// 입력
let N = Int(readLine()!)!
let booms = readLine()!.split(separator: " ").map{Int(String($0))!}
// Deque에 입력받은 정수 크기의 배열 넣는다
var dq = Deque(enqueue: Array(1...N))
// 결과를 저장할 배열
var result = [Int]()

// 처음에 첫번째 풍선을 터트리고 해당 인덱스에 있는 요소만큼 이동하여 다음 풍선을 터트린다.
// 인덱스를 사용하여 풍선을 터트릴 수 있지만, Deque 성질을 활용한다.
// 오른쪽으로(양수) 이동한다는 것은 가장 왼쪽 원소를 떼서 오른쪽으로 붙여넣는것이랑 같다.
// 반대로 왼쪽으로(음수) 이동한다는 것은 가장 오른쪽 원소를 떼서 왼쪽으로 붙여넣는것이랑 같다.
// push(pop)을 움직여야할 수만큼 움직였다면, 가장 왼쪽에는 문제에 나온대로 터트려야할 풍선이 위치하게 된다.
// 주의할점: 터트려야 할 풍선을 뻈다면, 자료형이 배열이라서 이미 오른쪽으로 한번 이동한 것과 같다.
// 따라서 오른쪽(양수)으로 이동은 1 적게 가고, 왼쪽(음수)이동은 이동해야 할 만큼 가야한다.
while true {
    let balloon = dq.popFront()!
    result.append(balloon)
    if result.count == N { break }
    var move = booms[balloon-1]
    if move > 0 {
        for i in 0..<move-1 {
            dq.pushRear(dq.popFront()!)
        }
    } else {
        for i in 0..<abs(move) {
            dq.pushFront(dq.popRear()!)
        }
    }
    
}
print(result.map{String($0)}.joined(separator: " "))

 

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-28279 덱 2 Swift  (0) 2024.04.03
BOJ-24511 queuestack Swift  (1) 2024.04.03
BOJ-2164 카드2 Swift  (0) 2024.04.02
BOJ-18258 큐 2 Swift  (0) 2024.04.02
BOJ-9012 괄호 Swift  (0) 2024.04.02

문제

N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다.

이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, 제일 위에 있는 카드를 바닥에 버린다. 그 다음, 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다.

예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나면, 남는 카드는 4가 된다.

N이 주어졌을 때, 제일 마지막에 남게 되는 카드를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 정수 N(1 ≤ N ≤ 500,000)이 주어진다.

출력

첫째 줄에 남게 되는 카드의 번호를 출력한다.

내가 푼 풀이

- 큐를 간단히 구현한 후 해당 동작들을 메소드로 선언한다.

- 큐는 선입선출이기 때문에 Swift에서 큐를 배열로 선언해서 removeFirst() 식으로 하면 시간초과가 날것으로 예상했다.

- 그래서 index로 접근하여 push / pop 한다.

 

import Foundation
// 큐 구현 (index를 통한 pop)
struct Queue {
    var elements = [Int]()
    var idx = 0
    var count: Int {
        return elements.count
    }
    var top: Int {
        if elements.isEmpty || idx >= elements.count {
            return -1
        } else {
            return elements[idx]
        }
    }
    mutating func pop() -> Int {
        if elements.isEmpty || idx >= elements.count {
            return -1
        } else {
            let num = elements[idx]
            idx += 1
            return num
        }
    }
    
    mutating func moveToBack(element: Int) {
        if idx <= elements.count {
            elements.append(element)
        }
    }
}

let N = Int(readLine()!)!
var queue = Queue()
queue.elements = Array(1...N)
// index로 접근하기 때문에, 모든 동작이 완료될때까지
// 1번동작: pop, 2번동작: pop and move to back
// pop을 한 원소가 마지막인경우 출력, pop을 한 다음 원소 한개가 남은경우 2번동작 후 출력
// 마지막 순서로 옮기면 앞 원소가 pop되는거라 index가 증가해야 하지만 pop에서 이미 증가시키므로 추가로 증가하지않는다
while queue.idx < queue.count {
    let num = queue.pop()
    if queue.top == -1 {
        print(num)
        break
    }
    queue.moveToBack(element: queue.pop())
}

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-24511 queuestack Swift  (1) 2024.04.03
BOJ-2346 풍선 터트리기 Swift  (0) 2024.04.03
BOJ-18258 큐 2 Swift  (0) 2024.04.02
BOJ-9012 괄호 Swift  (0) 2024.04.02
BOJ-10773 제로 Swift  (1) 2024.04.02

문제

정수를 저장하는 큐를 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.

명령은 총 여섯 가지이다.

  • push X: 정수 X를 큐에 넣는 연산이다.
  • pop: 큐에서 가장 앞에 있는 정수를 빼고, 그 수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.
  • size: 큐에 들어있는 정수의 개수를 출력한다.
  • empty: 큐가 비어있으면 1, 아니면 0을 출력한다.
  • front: 큐의 가장 앞에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.
  • back: 큐의 가장 뒤에 있는 정수를 출력한다. 만약 큐에 들어있는 정수가 없는 경우에는 -1을 출력한다.

입력

첫째 줄에 주어지는 명령의 수 N (1 ≤ N ≤ 2,000,000)이 주어진다. 둘째 줄부터 N개의 줄에는 명령이 하나씩 주어진다. 주어지는 정수는 1보다 크거나 같고, 100,000보다 작거나 같다. 문제에 나와있지 않은 명령이 주어지는 경우는 없다.

출력

출력해야하는 명령이 주어질 때마다, 한 줄에 하나씩 출력한다.

내가 푼 풀이

- 큐 구현자체는 어렵지않다. 해당 명령어만 메소드와 속성으로 만든 구조체 하나 만들면된다.

- 문제는 엄청 많은 입력값과 그에 준하는 출력이다.

- swift에 내장된 readLine() 과 print는 너무 느려서 시간초과가 난다.

- 이 문제는 Swift 파일 입출력, 큐의 index를 이용한 pop, 입력된 명령어를 byte로 바꿔 풀어야 겨우 시간초과를 면할 수 있었다.

- 추가로 출력은 문자열출력이 print 보다 더 빠르다

 

 

import Foundation

final class FileIO {
    private let buffer:[UInt8]
    private var index: Int = 0

    init(fileHandle: FileHandle = FileHandle.standardInput) {
        
        buffer = Array(try! fileHandle.readToEnd()!)+[UInt8(0)] // 인덱스 범위 넘어가는 것 방지
    }

    @inline(__always) private func read() -> UInt8 {
        defer { index += 1 }

        return buffer[index]
    }

    @inline(__always) func readInt() -> Int {
        var sum = 0
        var now = read()
        var isPositive = true

        while now == 10
                || now == 32 { now = read() } // 공백과 줄바꿈 무시
        if now == 45 { isPositive.toggle(); now = read() } // 음수 처리
        while now >= 48, now <= 57 {
            sum = sum * 10 + Int(now-48)
            now = read()
        }

        return sum * (isPositive ? 1:-1)
    }

    @inline(__always) func readString() -> Int {
        var str = 0
        var now = read()

        while now == 10 || now == 32 { now = read() } // 공백과 줄바꿈 무시

        let beginIndex = index-1

        while now != 10,
              now != 32,
              now != 0 {
            str += Int(now)
            now = read()
        }

        return str
    }

    @inline(__always) func readByteSequenceWithoutSpaceAndLineFeed() -> [UInt8] {
        var now = read()

        while now == 10 || now == 32 { now = read() } // 공백과 줄바꿈 무시

        let beginIndex = index-1

        while now != 10,
              now != 32,
              now != 0 { now = read() }

        return Array(buffer[beginIndex..<(index-1)])
    }
}

struct Queue {
    var elements = [Int]()
    var idx = 0
    var count: Int {
        return elements.count - idx
    }
    var front: Int {
        if elements.isEmpty || idx >= elements.count {
            return -1
        } else {
            return elements[idx]
        }
    }
    var back: Int {
        if elements.isEmpty || idx >= elements.count {
            return -1
        } else {
            return elements[elements.count - 1]
        }
    }
    var isEmpty: Int {
        if elements.isEmpty || idx >= elements.count {
            return 1
        } else {
            return 0
        }
    }
    
    mutating func push(element: Int) {
        elements.append(element)
    }
    
    mutating func pop() -> Int {
        if elements.isEmpty || idx >= elements.count  {
            return -1
        } else {
           let output = elements[idx]
            idx += 1
            
            return output
        }
    }
    
}
let fIO = FileIO()
let N = fIO.readInt()
var queue = Queue()
var answer = ""

for i in 0..<N {
    let operation = fIO.readString()
    switch operation {
    case 448:
        //push
        queue.push(element: fIO.readInt())
    case 335:
        //pop
        answer += "\(queue.pop())\n"
    case 443:
        //size
        answer += "\(queue.count)\n"
    case 559:
        //empty
        answer += "\(queue.isEmpty)\n"
    case 553:
        //front
        answer += "\(queue.front)\n"
    case 401:
        //back
        answer += "\(queue.back)\n"
    default:
        continue
    }
}

print(answer)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-2346 풍선 터트리기 Swift  (0) 2024.04.03
BOJ-2164 카드2 Swift  (0) 2024.04.02
BOJ-9012 괄호 Swift  (0) 2024.04.02
BOJ-10773 제로 Swift  (1) 2024.04.02
BOJ-28278 스택 2 Swift  (0) 2024.04.02

문제

괄호 문자열(Parenthesis String, PS)은 두 개의 괄호 기호인 ‘(’ 와 ‘)’ 만으로 구성되어 있는 문자열이다. 그 중에서 괄호의 모양이 바르게 구성된 문자열을 올바른 괄호 문자열(Valid PS, VPS)이라고 부른다. 한 쌍의 괄호 기호로 된 “( )” 문자열은 기본 VPS 이라고 부른다. 만일 x 가 VPS 라면 이것을 하나의 괄호에 넣은 새로운 문자열 “(x)”도 VPS 가 된다. 그리고 두 VPS x 와 y를 접합(concatenation)시킨 새로운 문자열 xy도 VPS 가 된다. 예를 들어 “(())()”와 “((()))” 는 VPS 이지만 “(()(”, “(())()))” , 그리고 “(()” 는 모두 VPS 가 아닌 문자열이다. 

여러분은 입력으로 주어진 괄호 문자열이 VPS 인지 아닌지를 판단해서 그 결과를 YES 와 NO 로 나타내어야 한다. 

입력

입력 데이터는 표준 입력을 사용한다. 입력은 T개의 테스트 데이터로 주어진다. 입력의 첫 번째 줄에는 입력 데이터의 수를 나타내는 정수 T가 주어진다. 각 테스트 데이터의 첫째 줄에는 괄호 문자열이 한 줄에 주어진다. 하나의 괄호 문자열의 길이는 2 이상 50 이하이다. 

출력

출력은 표준 출력을 사용한다. 만일 입력 괄호 문자열이 올바른 괄호 문자열(VPS)이면 “YES”, 아니면 “NO”를 한 줄에 하나씩 차례대로 출력해야 한다. 

내가 푼 풀이

- 모든 열린 괄호는 닫혀야 VPS 문자열이라 한다.

- 스택으로 입력받은 문자열을 넣고 닫는 기호 ")"가 들어간다면"(" 를 소거하여 풀었다

- 이렇게 받은 스택에 괄호가 남아있다면 NO, 없다면 YES

 

import Foundation
// 값 입력
let T = Int(readLine()!)!
// 스택
var stack = [String]()

for i in 0..<T {
    // 다음 문자열을 받기위해 스택 초기화
    stack.removeAll()
    // 문자열 입력
    let input = readLine()!.map{ String($0)}

    for j in input {
        // 열린 괄호는 스택에 추가
        if j == "(" {
            stack.append(j)
        } else if j == ")" {
            // 닫힌괄호도 추가하지만, 가장 최근에 열린괄호가 있다면, 해당 괄호와 함께 소거
            stack.append(j)
            if stack.count > 1 && stack[stack.count - 2] == "(" {
                stack.popLast()
                stack.popLast()
            }
        }
    }
    if stack.isEmpty {
        print("YES")
    } else {
        print("NO")
    }
}

 

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-2164 카드2 Swift  (0) 2024.04.02
BOJ-18258 큐 2 Swift  (0) 2024.04.02
BOJ-10773 제로 Swift  (1) 2024.04.02
BOJ-28278 스택 2 Swift  (0) 2024.04.02
BOJ-2012 등수 매기기 Swift  (0) 2023.07.10

문제

나코더 기장 재민이는 동아리 회식을 준비하기 위해서 장부를 관리하는 중이다.

재현이는 재민이를 도와서 돈을 관리하는 중인데, 애석하게도 항상 정신없는 재현이는 돈을 실수로 잘못 부르는 사고를 치기 일쑤였다.

재현이는 잘못된 수를 부를 때마다 0을 외쳐서, 가장 최근에 재민이가 쓴 수를 지우게 시킨다.

재민이는 이렇게 모든 수를 받아 적은 후 그 수의 합을 알고 싶어 한다. 재민이를 도와주자!

입력

첫 번째 줄에 정수 K가 주어진다. (1 ≤ K ≤ 100,000)

이후 K개의 줄에 정수가 1개씩 주어진다. 정수는 0에서 1,000,000 사이의 값을 가지며, 정수가 "0" 일 경우에는 가장 최근에 쓴 수를 지우고, 아닐 경우 해당 수를 쓴다.

정수가 "0"일 경우에 지울 수 있는 수가 있음을 보장할 수 있다.

출력

재민이가 최종적으로 적어 낸 수의 합을 출력한다. 최종적으로 적어낸 수의 합은 231-1보다 작거나 같은 정수이다.

내가 푼 풀이

- 정수들을 스택형식으로 저장하다가 0을 만나면 가장 최근의 정수를 지우고, 모든 수를 더한 값을 출력한다.

 

import Foundation

let K = Int(readLine()!)!
var stack = [Int]()

for i in 0..<K {
    let num = Int(readLine()!)!
    if num == 0 {
        stack.popLast()
    } else {
        stack.append(num)
    }
}

print(stack.reduce(0, +))

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-18258 큐 2 Swift  (0) 2024.04.02
BOJ-9012 괄호 Swift  (0) 2024.04.02
BOJ-28278 스택 2 Swift  (0) 2024.04.02
BOJ-2012 등수 매기기 Swift  (0) 2023.07.10
BOJ-9252 LCS 2 Swift  (0) 2023.07.10

문제

정수를 저장하는 스택을 구현한 다음, 입력으로 주어지는 명령을 처리하는 프로그램을 작성하시오.

명령은 총 다섯 가지이다.

  1. 1 X: 정수 X를 스택에 넣는다. (1 ≤ X ≤ 100,000)
  2. 2: 스택에 정수가 있다면 맨 위의 정수를 빼고 출력한다. 없다면 -1을 대신 출력한다.
  3. 3: 스택에 들어있는 정수의 개수를 출력한다.
  4. 4: 스택이 비어있으면 1, 아니면 0을 출력한다.
  5. 5: 스택에 정수가 있다면 맨 위의 정수를 출력한다. 없다면 -1을 대신 출력한다.

입력

첫째 줄에 명령의 수 N이 주어진다. (1 ≤ N ≤ 1,000,000)

둘째 줄부터 N개 줄에 명령이 하나씩 주어진다.

출력을 요구하는 명령은 하나 이상 주어진다.

출력

출력을 요구하는 명령이 주어질 때마다 명령의 결과를 한 줄에 하나씩 출력한다.

내가 푼 풀이

- 스택을 간단히 구현하여 5가지 명령어를 열거형으로 처리하여 풀었다.

 

import Foundation

enum Operation: Int {
    case op1 = 1, op2, op3, op4, op5
}

struct Stack {
    var elements = [Int]()
    
    var count : Int {
        return elements.count
    }
    
    var top: Int {
        if elements.isEmpty {
            return -1
        } else {
            return elements[elements.count - 1]
        }
    }
    
    mutating func addElement(element: Int) {
        elements.append(element)
    }
    
    mutating func popTop() -> Int {
        if elements.count == 0 {
            return -1
        } else {
            return elements.popLast()!
        }
    }
    
    func checkEmpty() -> Int {
        if elements.count == 0 {
            return 1
        } else {
            return 0
        }
    }
}

var stack = Stack()
let N = Int(readLine()!)!

for i in 0..<N {
    let operationNumArray = readLine()!.split(separator: " ").map{ Int($0)! }
    
    switch operationNumArray[0] {
    case 1:
        stack.addElement(element: operationNumArray[1])
    case 2:
        print(stack.popTop())
    case 3:
        print(stack.count)
    case 4:
        print(stack.checkEmpty())
    case 5:
        print(stack.top)
    default:
        print("Error")
    }
}

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-9012 괄호 Swift  (0) 2024.04.02
BOJ-10773 제로 Swift  (1) 2024.04.02
BOJ-2012 등수 매기기 Swift  (0) 2023.07.10
BOJ-9252 LCS 2 Swift  (0) 2023.07.10
BOJ-11403 경로 찾기 Swift  (0) 2023.07.01

문제

2007년 KOI에 N명의 학생들이 참가하였다. 경시일 전날인 예비소집일에, 모든 학생들은 자신이 N명 중에서 몇 등을 할 것인지 예상 등수를 적어서 제출하도록 하였다.

KOI 담당조교로 참가한 김진영 조교는 실수로 모든 학생의 프로그램을 날려 버렸다. 1등부터 N등까지 동석차 없이 등수를 매겨야 하는 김 조교는, 어쩔 수 없이 각 사람이 제출한 예상 등수를 바탕으로 임의로 등수를 매기기로 했다.

자신의 등수를 A등으로 예상하였는데 실제 등수가 B등이 될 경우, 이 사람의 불만도는 A와 B의 차이 (|A - B|)로 수치화할 수 있다. 당신은 N명의 사람들의 불만도의 총 합을 최소로 하면서, 학생들의 등수를 매기려고 한다.

각 사람의 예상 등수가 주어졌을 때, 김 조교를 도와 이러한 불만도의 합을 최소로 하는 프로그램을 작성하시오.

입력

첫째 줄에 자연수 N이 주어진다. (1 ≤ N ≤ 500,000) 둘째 줄부터 N개의 줄에 걸쳐 각 사람의 예상 등수가 순서대로 주어진다. 예상 등수는 500,000 이하의 자연수이다.

출력

첫째 줄에 불만도의 합을 최소로 할 때, 그 불만도를 출력한다.

내가 푼 풀이

- 예상등수들은 최대한 자기 예상등수와 차이값이 적은 등수와 합쳐서 불만도를 최소로 만들어야한다.

- 예상등수들을 배열에 저장하여 내림차순으로 정렬한 후, 마지막부터 불러와 가장 최소가 되는 값과 결합하여 불만도를 최소로 만든다.

- 최소로 만든 불만도를 합하여 출력

 

 

import Foundation

// 입력
let N = Int(readLine()!)!
var arr = [Int]()
var sum = 0

// 예상등수 입력
for i in 0..<N {
    arr.append(Int(readLine()!)!)
}

// 내림차순 정렬
arr.sort{ $0 > $1}

// 예상등수와 차이가 가장 적은 값과 결합하여 불만도를 최소로 한다.
for i in 1...N {
    var num = abs(arr.removeLast() - i)
    sum += num
}
print(sum)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-10773 제로 Swift  (1) 2024.04.02
BOJ-28278 스택 2 Swift  (0) 2024.04.02
BOJ-9252 LCS 2 Swift  (0) 2023.07.10
BOJ-11403 경로 찾기 Swift  (0) 2023.07.01
BOJ-1417 국회의원 선거 Swift  (0) 2023.07.01

문제

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다.

예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

입력

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

출력

첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를, 둘째 줄에 LCS를 출력한다.

LCS가 여러 가지인 경우에는 아무거나 출력하고, LCS의 길이가 0인 경우에는 둘째 줄을 출력하지 않는다.

내가 푼 풀이

- 이전에 LCS를 dp를 이용하여 풀었던 기억을 떠올리며, 코드를 구현했다.

- LCS는 순서에따라 존재하는 같은 알파벳의 중 가장 긴 수열을 출력하면 된다.

- 위에 주어진 ACAYKP와 CAPCAK 에서는 순서만 고려하였을 때  ACAYKP와 CAPCAK 로 ACAK가 되는 것이다.

- 이는 이차원배열을 이용하여 순서대로 탐색했을 때, 같은 알파벳을 만난 경우, 이전 알파벳들 중 같은 알파벳을 만난 수열의 길이를 가져와 + 1을 해주면 된다.

- 다른 알파벳을 만났다면, 이전 알파벳 중 LCS가 가장 긴 수열의 길이를 넣어준다.

    A C A Y K P
  0 0 0 0 0 0 0
C 0 0 1 1 1 1 1
A 0 1 1 2 2 2 2

위 표대로 ACAYKP 수열에서 CAPCAK의 수열 중 알파벳 하나씩 가져와 순서대로 탐색한다.

- 첫 번째 알파벳 C를 검사했을 때, 두 번째에 있는 C와 일치하므로, ACAYKP와 C의 LCS는 C이고, 길이는 1이다.

- 이후의 알파벳은 같은 수를 만나지 않았으므로 이전의 가장 긴 수열의 길이를 가져온다.

- 두 번째 알파벳 A를 검사했을 때, 첫 번째 A와 같은 알파벳이고, 세 번째에도 A가 나온다.

- 첫번째 A는 A수열과 CA수열의 LCS이고, 세번째 A는 ACA와 CA의 LCS이다. 

- LCS: 첫 번째는 A, 세 번째는 CA가 된다.

- 동일한 알파벳을 만난다면 x-1 y-1에 위치한 lcs의 길이 +1을 해준다.

- 동일하지 않은 알파벳을 만난다면 x-1, y와 x, y-1 중 LCS길이가 더 긴 수를 가져온다.

- x-1, y-1에서 길이를 가져오는 이유는 위 표에서 x-1, y-1이 의미하는 것은 현재 검사하는 알파벳이전까지 검사했던 LCS의 최대길이 이다.

- LCS는 순서만 따졌을 때 존재하는 같은 알파벳의 수열의 최대길이가 되므로, x-1, y-1에서 가져온다.

 

길이는 다음과 같이 구하고, LCS의 수열은 역순으로 오른쪽 아래부터 x, y의 값이 x-1, y와 x, y-1의 값과 다른 경우 문자를 추가하는 방법을 사용했다.

위의 표가 만들어지는 과정의 역순으로 이용하였다.

 

코드로 구현하면 다음과 같다.

 

 

import Foundation

// 입력
var s1 = Array(readLine()!).map{ String($0) }
var s2 = Array(readLine()!).map{ String($0) }
var dp = Array(repeating: Array(repeating: 0, count: s1.count+1), count: s2.count+1)
s1.insert("0", at: 0)
s2.insert("0", at: 0)


// DP
// 같은 알파벳을 마주한경우, 이전까지 탐색했던 LCS의 최대길이 + 1을 해준다.
// 다른알파벳을 만났다면 이전에 검사했던 LCS중 가장 긴 길이를 가져온다.
for i in 1..<s2.count {
    for j in 1..<s1.count {
        if s2[i] == s1[j] {
            dp[i][j] = dp[i-1][j-1] + 1
        } else {
            dp[i][j] = max(dp[i-1][j], dp[i][j-1])
        }
    }
}

// LCS의 수열 구하기.
// 위의 DP표를 구했던 방법의 역순으로 구하였다.
var idx = dp[s2.count-1][s1.count-1]
var x = s1.count - 1
var y = s2.count - 1
var result = ""
while idx != 0 {
    if dp[y][x] == dp[y-1][x] {
        y -= 1
        continue
    }
    if dp[y][x] == dp[y][x-1] {
        x -= 1
        continue
    }
    result = s1[x] + result
    x -= 1
    y -= 1
    idx -= 1
}
print(result.count)
print(result)

'코딩테스트 > 백준' 카테고리의 다른 글

BOJ-28278 스택 2 Swift  (0) 2024.04.02
BOJ-2012 등수 매기기 Swift  (0) 2023.07.10
BOJ-11403 경로 찾기 Swift  (0) 2023.07.01
BOJ-1417 국회의원 선거 Swift  (0) 2023.07.01
BOJ-10942 팰린드롬? Swift  (0) 2023.07.01

+ Recent posts