문제

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오.

예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이고, 길이는 4이다.

입력

첫째 줄에 수열 A의 크기 N (1 ≤ N ≤ 1,000)이 주어진다.

둘째 줄에는 수열 A를 이루고 있는 Ai가 주어진다. (1 ≤ Ai ≤ 1,000)

출력

첫째 줄에 수열 A의 가장 긴 증가하는 부분 수열의 길이를 출력한다.

내가 푼 풀이

- 처음에는 문제를 잘 이해못해서 받은 수열을 set으로 바꿔서 count 출력 하면 되는거 아닌가 했는데, 수열 순서대로 부분수열의 갯수를 구하는것이였다.

- arr = [10, 11, 9]  Set(arr).count = 3, 부분 수열의 최대 길이: [10,11] = 2

- dp를 수열의 크기+1 만큼 만들어서 해당 숫자가 이미 나와있는 수열의 몇번째인지 저장한다.

 

arr = [0, 10, 20, 10, 30, 20, 50]

  • dp[1] = 1 
  • dp[2] : arr[2] = 20 , 20보다 작은수 10 ---> dp[2] = 2
  • dp[3] : arr[3] = 10 , 10보다 작은수는 없다. ---> 증가하는 수열의 첫번째다. dp[3] = 1
  • dp[4] : arr[4] = 30 , 40보다 작은수 10, 20, 10 ---> max(dp[1], dp[2], dp[3]) + 1 , dp[4] = 3

 

import Foundation

var count = Int(String(readLine()!))!
var arr = [0] + readLine()!.split(separator: " ").map{ Int(String($0))!}
var dp = Array(repeating: 0, count: count+1)

dp[1] = 1
if count == 1 {
    print(dp[1])
} else {
    for i in 2...count {
        var check = [Int]()
        for j in 1..<i {
            if arr[i] > arr[j] {
                check.append(dp[j])
            }
        }
        if check.isEmpty {
            dp[i] += 1
        } else {
            dp[i] = check.max()! + 1
        }
    }
    print(dp.max()!)
}

 

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

BOJ-1912 연속합 Swift  (0) 2023.04.19
BOJ-1932 정수 삼각형 Swift  (0) 2023.04.19
BOJ-2579 계단 오르기 Swift  (0) 2023.04.18
BOJ-1149 RGB거리 Swift  (0) 2023.04.18
BOJ-11726 2xn 타일링 Swift  (0) 2023.04.17

문제

계단 오르기 게임은 계단 아래 시작점부터 계단 꼭대기에 위치한 도착점까지 가는 게임이다. <그림 1>과 같이 각각의 계단에는 일정한 점수가 쓰여 있는데 계단을 밟으면 그 계단에 쓰여 있는 점수를 얻게 된다.

예를 들어 <그림 2>와 같이 시작점에서부터 첫 번째, 두 번째, 네 번째, 여섯 번째 계단을 밟아 도착점에 도달하면 총 점수는 10 + 20 + 25 + 20 = 75점이 된다.

계단 오르는 데는 다음과 같은 규칙이 있다.

  1. 계단은 한 번에 한 계단씩 또는 두 계단씩 오를 수 있다. 즉, 한 계단을 밟으면서 이어서 다음 계단이나, 다음 다음 계단으로 오를 수 있다.
  2. 연속된 세 개의 계단을 모두 밟아서는 안 된다. 단, 시작점은 계단에 포함되지 않는다.
  3. 마지막 도착 계단은 반드시 밟아야 한다.

따라서 첫 번째 계단을 밟고 이어 두 번째 계단이나, 세 번째 계단으로 오를 수 있다. 하지만, 첫 번째 계단을 밟고 이어 네 번째 계단으로 올라가거나, 첫 번째, 두 번째, 세 번째 계단을 연속해서 모두 밟을 수는 없다.

각 계단에 쓰여 있는 점수가 주어질 때 이 게임에서 얻을 수 있는 총 점수의 최댓값을 구하는 프로그램을 작성하시오.

입력

입력의 첫째 줄에 계단의 개수가 주어진다.

둘째 줄부터 한 줄에 하나씩 제일 아래에 놓인 계단부터 순서대로 각 계단에 쓰여 있는 점수가 주어진다. 계단의 개수는 300이하의 자연수이고, 계단에 쓰여 있는 점수는 10,000이하의 자연수이다.

출력

첫째 줄에 계단 오르기 게임에서 얻을 수 있는 총 점수의 최댓값을 출력한다.

내가 푼 풀이

- dp문제로 점화식을 찾는데 애먹었다.

- 다음 규칙중 3번이 중요했다. 마지막 계단을 반드시 밟아야한다.

- 마지막 계단 n 을 밟는경우 두가지

  • 바로 직전 계단을 밟는 경우: n, n-1, n-3 번째 계단을 밟는다.
  • 2칸뛰어서 마지막 계단을 밟는경우: n, n-2번째 계단을 밟는다.

위 두가지를 점화식으로 나타낸다. ( points, dp, i는 순번 )

1. dp[n] = dp[n-3] + points[n-1] + points[n]

2. dp[n] = dp[i-2] + points[n]

--> dp[n] = max(points[n-1] + dp[n-3], dp[n-2]) + points[n]

 

import Foundation

var count = Int(String(readLine()!))!
var points = Array(repeating: 0, count: count+1)
var dp = Array(repeating: 0, count: count+1)

for i in 1...count {
    points[i] = Int(String(readLine()!))!
}

dp[1] = points[1]

if count == 1 {
    print(dp[1])
} else if count == 2 {
    dp[2] = max(points[1] + points[2], points[2])
    print(dp[2])
} else {
    dp[2] = max(points[1] + points[2], points[2])
    for i in 3...count {
        dp[i] = max(points[i-1] + dp[i-3], dp[i-2]) + points[i]
    }
    print(dp[count])
}

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

BOJ-1932 정수 삼각형 Swift  (0) 2023.04.19
BOJ-11053 가장 긴 증가하는 부분 수열 Swift  (0) 2023.04.19
BOJ-1149 RGB거리 Swift  (0) 2023.04.18
BOJ-11726 2xn 타일링 Swift  (0) 2023.04.17
BOJ-1003 피보나치 함수 Swift  (1) 2023.04.17

문제

RGB거리에는 집이 N개 있다. 거리는 선분으로 나타낼 수 있고, 1번 집부터 N번 집이 순서대로 있다.

집은 빨강, 초록, 파랑 중 하나의 색으로 칠해야 한다. 각각의 집을 빨강, 초록, 파랑으로 칠하는 비용이 주어졌을 때, 아래 규칙을 만족하면서 모든 집을 칠하는 비용의 최솟값을 구해보자.

  • 1번 집의 색은 2번 집의 색과 같지 않아야 한다.
  • N번 집의 색은 N-1번 집의 색과 같지 않아야 한다.
  • i(2 ≤ i ≤ N-1)번 집의 색은 i-1번, i+1번 집의 색과 같지 않아야 한다.

입력

첫째 줄에 집의 수 N(2 ≤ N ≤ 1,000)이 주어진다. 둘째 줄부터 N개의 줄에는 각 집을 빨강, 초록, 파랑으로 칠하는 비용이 1번 집부터 한 줄에 하나씩 주어진다. 집을 칠하는 비용은 1,000보다 작거나 같은 자연수이다.

출력

첫째 줄에 모든 집을 칠하는 비용의 최솟값을 출력한다.

내가 푼 풀이

- 집의 갯수가 주어지고 각 줄은 빨강, 초록, 파랑의 색칠비용이 주어진다.

- 규칙에 따르면 결국 인접한 집의 색은 서로 다른색이여야 한다는 것이다.

- 각 줄의 최솟값을 찾아 따라가면, 같은 색을 칠할 경우가 생긴다.

- 집의 갯수가 2개 이상이니,  집을 색칠할 색을 정하고, 그 전에 있는 집의 칠할 수 있는 색의 최솟값을 더하는 식으로 접근했다.

- 위 접근을 점화식으로 표현해본다.

  • arr = [R, G, B] , count = 집의 갯수
  • dp = Array(repeating: Array(repeating: 0, count: 3), count: count+1)
  • dp[n][0] = min(dp[n-1][1], dp[n-1][2]) + arr[0]
  • dp[n][1] = min(dp[n-1][0], dp[n-1][2]) + arr[1]
  • dp[n][2] = min(dp[n-1][1], dp[n-1][0]) + arr[2]

-> dp[0][0] = 첫번째 집 빨강색비용,  dp[0][1] = 첫번째 집 파랑색비용, dp[0][2] = 첫번째 집 초록비용, 

-> n번째를 빨강으로 칠한다면, n-1번째 집의 파랑,초록 의 최솟값 + n번째 빨강비용

-> 규칙에 따른 모든 집 색칠 비용의 최솟값은 dp[n]의 최솟값이다.

 

 

import Foundation

var count = Int(String(readLine()!))!
var dp = Array(repeating: Array(repeating: 0, count: 3), count: count+1)

for i in 1...count {
    var arr = readLine()!.split(separator: " ").map{ Int(String($0))!}

    if i == 1 {
        dp[1] = [arr[0], arr[1], arr[2]]
        continue
    }
    dp[i][0] = min(dp[i-1][1], dp[i-1][2]) + arr[0]
    dp[i][1] = min(dp[i-1][0], dp[i-1][2]) + arr[1]
    dp[i][2] = min(dp[i-1][1], dp[i-1][0]) + arr[2]
}

print(dp[count].min()!)

문제

2×n 크기의 직사각형을 1×2, 2×1 타일로 채우는 방법의 수를 구하는 프로그램을 작성하시오.

아래 그림은 2×5 크기의 직사각형을 채운 한 가지 방법의 예이다.

입력

첫째 줄에 n이 주어진다. (1 ≤ n ≤ 1,000)

출력

첫째 줄에 2×n 크기의 직사각형을 채우는 방법의 수를 10,007로 나눈 나머지를 출력한다.

내가 푼 풀이

- n이 5일때까지 경우의 수를 구해봤는데 결국 피보나치 수열을 구하는 식이 나온다.

- f(n) = f(n-1) + f(n-2) 

- n이 일정숫자를 넘으면 담을수없이 커진다. 그래서 계산할때마다 10007로 나눈 나머지를 넣는다.

- f(n) % 10007 = ( f(n-1) + f(n-2) ) % 10007

 

import Foundation

var num = Int(String(readLine()!))!
var dp = Array(repeating: 0, count: 1001)
dp[1] = 1
dp[2] = 2
if num < 3 {
    print(dp[num])
} else {
    for i in 3...num {
        dp[i] = (dp[i-1] + dp[i-2]) % 10007
    }
    print(dp[num])
}

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

BOJ-2579 계단 오르기 Swift  (0) 2023.04.18
BOJ-1149 RGB거리 Swift  (0) 2023.04.18
BOJ-1003 피보나치 함수 Swift  (1) 2023.04.17
BOJ-9095 1,2,3 더하기 Swift  (0) 2023.04.17
BOJ-1463 1로 만들기 Swift  (0) 2023.04.17

문제

다음 소스는 N번째 피보나치 수를 구하는 C++ 함수이다.

int fibonacci(int n) {
    if (n == 0) {
        printf("0");
        return 0;
    } else if (n == 1) {
        printf("1");
        return 1;
    } else {
        return fibonacci(n‐1) + fibonacci(n‐2);
    }
}

fibonacci(3)을 호출하면 다음과 같은 일이 일어난다.

  • fibonacci(3)은 fibonacci(2)와 fibonacci(1) (첫 번째 호출)을 호출한다.
  • fibonacci(2)는 fibonacci(1) (두 번째 호출)과 fibonacci(0)을 호출한다.
  • 두 번째 호출한 fibonacci(1)은 1을 출력하고 1을 리턴한다.
  • fibonacci(0)은 0을 출력하고, 0을 리턴한다.
  • fibonacci(2)는 fibonacci(1)과 fibonacci(0)의 결과를 얻고, 1을 리턴한다.
  • 첫 번째 호출한 fibonacci(1)은 1을 출력하고, 1을 리턴한다.
  • fibonacci(3)은 fibonacci(2)와 fibonacci(1)의 결과를 얻고, 2를 리턴한다.

1은 2번 출력되고, 0은 1번 출력된다. N이 주어졌을 때, fibonacci(N)을 호출했을 때, 0과 1이 각각 몇 번 출력되는지 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다.

각 테스트 케이스는 한 줄로 이루어져 있고, N이 주어진다. N은 40보다 작거나 같은 자연수 또는 0이다.

출력

각 테스트 케이스마다 0이 출력되는 횟수와 1이 출력되는 횟수를 공백으로 구분해서 출력한다.

내가 푼 풀이

- 정수 n이 주어지면 fibonacci(n) 의 f(0)과 f(1)의 호출횟수를 구하는 문제다.

- f(n) = f(n-1) + f(n-2) 이므로 정수 N부터 1까지 내려오면서 횟수를 더해주면 된다.

- 결과는 dp[0] dp[1] 의 원소값

 

import Foundation

var count = Int(String(readLine()!))!

for i in 0..<count {
    var num = Int(String(readLine()!))!
    var arr = Array(repeating: 0, count: num+1)
    
    if num == 0 {
        arr[0] = 1
        print("1 0")
        continue
    } else if num == 1 {
        arr[1] = 1
        print("\(arr[0]) \(arr[1])")
        continue
    }
    arr[num] = 1
    for i in stride(from: num, to: 1, by: -1) {
        arr[i-1] += arr[i] * 1
        arr[i-2] += arr[i] * 1
    }
    print("\(arr[0]) \(arr[1])")
}

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

BOJ-1149 RGB거리 Swift  (0) 2023.04.18
BOJ-11726 2xn 타일링 Swift  (0) 2023.04.17
BOJ-9095 1,2,3 더하기 Swift  (0) 2023.04.17
BOJ-1463 1로 만들기 Swift  (0) 2023.04.17
BOJ-2903 중앙 이동 알고리즘 Swift  (0) 2023.04.08

문제

정수 4를 1, 2, 3의 합으로 나타내는 방법은 총 7가지가 있다. 합을 나타낼 때는 수를 1개 이상 사용해야 한다.

  • 1+1+1+1
  • 1+1+2
  • 1+2+1
  • 2+1+1
  • 2+2
  • 1+3
  • 3+1

정수 n이 주어졌을 때, n을 1, 2, 3의 합으로 나타내는 방법의 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에 테스트 케이스의 개수 T가 주어진다. 각 테스트 케이스는 한 줄로 이루어져 있고, 정수 n이 주어진다. n은 양수이며 11보다 작다.

출력

각 테스트 케이스마다, n을 1, 2, 3의 합으로 나타내는 방법의 수를 출력한다.

내가 푼 풀이

- n이 5일때 까지 직접 구해봤다.

- n이 5일때 경우의수는 13으로 n=4, n=3, n=2 일때 경우의수를 모두 합한 수로 알 수 있었다.

- 이를 점화식으로 표현하면 dp[n] = dp[n-1] + dp[n-2] + dp[n-3] 로 그만큼의 배열의 크기를 선언해 풀었다.

 

 

import Foundation

var count = Int(String(readLine()!))!
var arr = Array(repeating: 0, count: 12)
arr[1] = 1
arr[2] = 2
arr[3] = 4
for i in 4...11 {
    arr[i] = arr[i-1] + arr[i-2] + arr[i-3]
}

for i in 0..<count {
    var num = Int(String(readLine()!))!
    print(arr[num])
}

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

BOJ-11726 2xn 타일링 Swift  (0) 2023.04.17
BOJ-1003 피보나치 함수 Swift  (1) 2023.04.17
BOJ-1463 1로 만들기 Swift  (0) 2023.04.17
BOJ-2903 중앙 이동 알고리즘 Swift  (0) 2023.04.08
BOJ-2720 세탁소 사장 동혁 Swift  (0) 2023.04.08

문제

정수 X에 사용할 수 있는 연산은 다음과 같이 세 가지 이다.

  1. X가 3으로 나누어 떨어지면, 3으로 나눈다.
  2. X가 2로 나누어 떨어지면, 2로 나눈다.
  3. 1을 뺀다.

정수 N이 주어졌을 때, 위와 같은 연산 세 개를 적절히 사용해서 1을 만들려고 한다. 연산을 사용하는 횟수의 최솟값을 출력하시오.

입력

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

출력

첫째 줄에 연산을 하는 횟수의 최솟값을 출력한다.

내가 푼 풀이

- 연산의 종류는 세가지, 연산을 반복하여 1로 만드는 최소 횟수 를 구한다.

- DP를 이용해 주어진 수 N을 세가지 연산을 통해 최솟값을 저장해내려간다.

- 배열 인덱스 1의 값은 최솟값

 

import Foundation

var num = Int(String(readLine()!))!	
var arr = Array(repeating: Int.max, count: num+1)
arr[num] = 0

for i in stride(from: num, to: 1, by: -1) {
    if i % 3 == 0 {
        arr[i / 3] = min(arr[i / 3], arr[i] + 1)
    }
    if i % 2 == 0 {
        arr[i / 2] = min(arr[i / 2], arr[i] + 1)
    }
    arr[i-1] = min(arr[i-1], arr[i] + 1)
}

print(arr[1])

문제 설명

영재는 택배상자를 트럭에 싣는 일을 합니다. 영재가 실어야 하는 택배상자는 크기가 모두 같으며 1번 상자부터 n번 상자까지 번호가 증가하는 순서대로 컨테이너 벨트에 일렬로 놓여 영재에게 전달됩니다. 컨테이너 벨트는 한 방향으로만 진행이 가능해서 벨트에 놓인 순서대로(1번 상자부터) 상자를 내릴 수 있습니다. 하지만 컨테이너 벨트에 놓인 순서대로 택배상자를 내려 바로 트럭에 싣게 되면 택배 기사님이 배달하는 순서와 택배상자가 실려 있는 순서가 맞지 않아 배달에 차질이 생깁니다. 따라서 택배 기사님이 미리 알려준 순서에 맞게 영재가 택배상자를 실어야 합니다.

만약 컨테이너 벨트의 맨 앞에 놓인 상자가 현재 트럭에 실어야 하는 순서가 아니라면 그 상자를 트럭에 실을 순서가 될 때까지 잠시 다른 곳에 보관해야 합니다. 하지만 고객의 물건을 함부로 땅에 둘 수 없어 보조 컨테이너 벨트를 추가로 설치하였습니다. 보조 컨테이너 벨트는 앞 뒤로 이동이 가능하지만 입구 외에 다른 면이 막혀 있어서 맨 앞의 상자만 뺄 수 있습니다(즉, 가장 마지막에 보조 컨테이너 벨트에 보관한 상자부터 꺼내게 됩니다). 보조 컨테이너 벨트를 이용해도 기사님이 원하는 순서대로 상자를 싣지 못 한다면, 더 이상 상자를 싣지 않습니다.

예를 들어, 영재가 5개의 상자를 실어야 하며, 택배 기사님이 알려준 순서가 기존의 컨테이너 벨트에 네 번째, 세 번째, 첫 번째, 두 번째, 다섯 번째 놓인 택배상자 순서인 경우, 영재는 우선 첫 번째, 두 번째, 세 번째 상자를 보조 컨테이너 벨트에 보관합니다. 그 후 네 번째 상자를 트럭에 싣고 보조 컨테이너 벨트에서 세 번째 상자 빼서 트럭에싣습니다. 다음으로 첫 번째 상자를 실어야 하지만 보조 컨테이너 벨트에서는 두 번째 상자를, 기존의 컨테이너 벨트에는 다섯 번째 상자를 꺼낼 수 있기 때문에 더이상의 상자는 실을 수 없습니다. 따라서 트럭에는 2개의 상자만 실리게 됩니다.

택배 기사님이 원하는 상자 순서를 나타내는 정수 배열 order가 주어졌을 때, 영재가 몇 개의 상자를 실을 수 있는지 return 하는 solution 함수를 완성하세요.


제한사항
  • 1 ≤ order의 길이 ≤ 1,000,000
  • order는 1이상 order의 길이 이하의 모든 정수가 한번씩 등장합니다.
  • order[i]는 기존의 컨테이너 벨트에 order[i]번째 상자를 i+1번째로 트럭에 실어야 함을 의미합니다.

내가 푼 풀이

- while문 안에 여러 조건을 넣기에 너무 힘들어서 단계를 나눴다.

- 1단계 order를 모두 수행 ( 수행중 보조컨테이너의 마지막원소와 같다면 지우기 )

- 2단계 보조컨테이너에 남아있다면 털어내기

 

 

import Foundation

func solution(_ order:[Int]) -> Int {
    var result = 0
    var stack = [Int]()
    var idx = 0
    var i = 1
    
    while i < order.count + 1 {
        var check = order[idx]
        if i == check {
            result += 1
            idx += 1
            i += 1
        } else if !stack.isEmpty && stack.last! == check {
            idx += 1
            stack.popLast()!
            result += 1
        } else {
            stack.append(i)
            i += 1
        }
    }
    
    while !stack.isEmpty {
        if stack.popLast()! == order[idx] {
            result += 1
            idx += 1
        } else {
            break
        }
        
    }
    
    return result
}

+ Recent posts