https://www.acmicpc.net/problem/2167

 

2167번: 2차원 배열의 합

첫째 줄에 배열의 크기 N, M(1 ≤ N, M ≤ 300)이 주어진다. 다음 N개의 줄에는 M개의 정수로 배열이 주어진다. 배열에 포함되어 있는 수는 절댓값이 10,000보다 작거나 같은 정수이다. 그 다음 줄에는 합을 구할 부분의 개수 K(1 ≤ K ≤ 10,000)가 주어진다. 다음 K개의 줄에는 네 개의 정수로 i, j, x, y가 주어진다(i ≤ x, j ≤ y).

www.acmicpc.net

 

dp[a][b] = (0,0)를 왼쪽 위 시작점으로 (a,b)을 오른쪽 아래 끝점으로 하는 사각형 모양 안에 있는 배열의 합

으로 생각하고 풀면되는 dp문제이다.

 

 

식을 세우면 다음과 같이 된다.

dp[i][j] = dp[i-1][j] + dp[i][j-1] - dp[i-1][j-1] + arr[i][j]

 

 

위의 그림과 같이 dp[i][j] 는 분홍색 네모와 초록색 네모를 합한 값에서 두 네모가 겹쳐진 dp[i-1][j-1] 을 빼주고 (i, j)의 위치에 있는 값을 더해주면 된다.

 

 

모든 위치에서 dp값을 구해놨다면 이제 (i, j)부터 (x, y)까지의 합도 쉽게 구할 수 있다.

dp값을 구할 때와 비슷하게 dp[x][y] (x,y까지의 합)에서 (i,j) 바깥 부분인 분홍색 네모와 초록색 네모 부분을 빼주고 겹치는 부분을 한번 더해준다.

 

그럼 값은 dp[x][y] - dp[x-i][y] - dp[x][y-j] + dp[i-1][j-1] 으로 구할 수 있다.

 

 

 

문제에서 범위는 1부터 시작하므로 인덱스도 1부터 시작하도록 했다.

그러면 i 나 j 가 1 일 때 i-1 이나 j-1 이 되어도 인덱스가 0이 되므로 그냥 0을 더해주게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
using namespace std;
 
int arr[301][301];
int dp[301][301];
 
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    int n, m;
    cin >> n >> m;
 
    for(int i=1; i<=n; i++) {
        for(int j=1; j<=m; j++) {
            cin >> arr[i][j];
            dp[i][j] = dp[i-1][j] + dp[i][j-1- dp[i-1][j-1+ arr[i][j];
        }
    }
 
    int k;
    cin >>k;
 
    int i, j, x, y;
    int ans;
    while(k--) {
        cin >> i >> j >> x >> y;
        ans = dp[x][y] - dp[i-1][y] - dp[x][j-1+ dp[i-1][j-1];
        cout << ans << '\n';
    }
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 1965. 상자넣기  (0) 2020.01.29
[BOJ] 11053. 가장 긴 증가하는 부분 수열  (0) 2020.01.29
[BOJ] 2805. 나무 자르기  (0) 2020.01.21
[BOJ] 1654. 랜선 자르기  (0) 2020.01.20
[BOJ] 10816. 숫자 카드 2  (0) 2020.01.20

https://www.acmicpc.net/problem/2805

 

2805번: 나무 자르기

문제 상근이는 나무 M미터가 필요하다. 근처에 나무를 구입할 곳이 모두 망해버렸기 때문에, 정부에 벌목 허가를 요청했다. 정부는 상근이네 집 근처의 나무 한 줄에 대한 벌목 허가를 내주었고, 상근이는 새로 구입한 목재절단기을 이용해서 나무를 구할것이다. 목재절단기는 다음과 같이 동작한다. 먼저, 상근이는 절단기에 높이 H를 지정해야 한다. 높이를 지정하면 톱날이 땅으로부터 H미터 위로 올라간다. 그 다음, 한 줄에 연속해있는 나무를 모두 절단해버린다. 따

www.acmicpc.net

랜선 자르기 문제와 비슷하게 parametric search문제이다.

0부터 절단기의 최대길이가 될 수 있는 값(나무길이 중 가장 큰 값)까지를 이분 탐색을 진행하면서 필요한 나무만 가져갈 수 있는 절단기의 최대길이를 구한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <algorithm>
using namespace std;
 
int n, m;
long long ans;
long long namu[1000000];
 
void solve(int left, int right) {
 
    long long h = (left + right) / 2;
    long long len = 0;
 
 
    //절단기 높이를 h(mid값)로 했을때 가져갈 수 있는 나무길이(len)을 구한다.
//(각 나무에서 h만큼 자르고 남은 값을 더한다)
    for (int i = 0; i < n; i++) {
        if (namu[i] >= h) {
            len += (namu[i] - h);
        }
    }
 
    
    if (len > m) {
        if (left >= right) {
            //left가 right보다 같거나 커진 경우 이분탐색 중지하고 ans 값과 현재 h를 비교
            if (ans < h) ans = h;
            return;
        }
 
        //len이 가져가려는 길이m보다 크면 절단기 크기를 더 크게 해도 된다.
        solve(h + 1, right);
    }
    else if (len < m) {
        //len이 가져가려는 길이 m보다 작으면 절단기 크기h를 더 작게해야 한다.
        solve(left, h - 1);
    }
    else {
        //같은 경우에는 현재 절단기 크기와 비슷해서 최댓값을 저장
        if (ans < h) ans = h;
        return;
    }
 
 
}
 
 
int main()
{
 
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
 
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        cin >> namu[i];
    }
 
    //정렬
    sort(namu, namu + n);
 
    //left값은 0 right값은 나무 길이의 최대 값
    solve(0, namu[n - 1]);
 
 
    cout << ans << '\n';
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 11053. 가장 긴 증가하는 부분 수열  (0) 2020.01.29
[BOJ] 2167. 2차원 배열의 합  (0) 2020.01.24
[BOJ] 1654. 랜선 자르기  (0) 2020.01.20
[BOJ] 10816. 숫자 카드 2  (0) 2020.01.20
[BOJ] 5567. 결혼식  (0) 2019.11.13

https://www.acmicpc.net/problem/1654

 

1654번: 랜선 자르기

첫째 줄에는 오영식이 이미 가지고 있는 랜선의 개수 K, 그리고 필요한 랜선의 개수 N이 입력된다. K는 1이상 10,000이하의 정수이고, N은 1이상 1,000,000이하의 정수이다. 그리고 항상 K ≦ N 이다. 그 후 K줄에 걸쳐 이미 가지고 있는 각 랜선의 길이가 센티미터 단위의 정수로 입력된다. 랜선의 길이는 231-1보다 작거나 같은 자연수이다.

www.acmicpc.net

parametric search를 이용해서 푸는 문제이다. parametric search는 답이 나올 수 있는 범위 안에서 이분 탐색을 통해 답을 구하는 방법이다.

 

 

이 문제에서 가장 작게 자르는 크기는 1이고, 가장 크게 자르는 경우는 랜선의 길이중 최대값이기 때문에 각각 left값과 right값이 된다.

 

 

mid값으로 자르는 경우마다 잘라지는 랜선의 개수를 구하고

개수가 n값 이상인 경우에는 size를 더 늘릴 수 있으므로 left를 mid +1로 옮겨준다.

반대로 n값 보다 작은 경우에는 현재 mid값으로 n개를 만들 수 없으므로 right를 mid -1 로 옮긴다.

 

 

이 문제에서 주의할 점은 랜선의 길이가 2의31승 -1보다 작은 값이므로 left와 right를 더했을때 int범위를 넘어갈 수 있기때문에 타입을 long long으로 해줘야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <algorithm>
using namespace std;
 
int k, n;
int arr[10000];
 
long long getCount(long long size) {
    long long cnt = 0;
 
    //k개의 랜선을 size(mid)로 잘라서 나오는 개수를 더해준다. 
    for (int i = 0; i < k; i++) {
        cnt += (arr[i] / size);
    }
 
    return cnt;
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> k >> n;
    for (int i = 0; i < k; i++cin >> arr[i];
 
    //입력 받은 랜선길이를 정렬한다.
    sort(arr, arr + k);
 
    int ans;
 
    //자를 수 있는 가장 작은 단위인 1이 left값
    long long left = 1;
    //자를 수 있는 가장 큰 단위(최댓값)인 arr의 마지막 값이 right 
    long long right = arr[k - 1];
 
 
 
    //이분 탐색
    while (left <= right) {
 
        long long mid = (left + right) / 2;
 
        //mid값으로 잘랐을때 나오는 랜선의 개수를 구한다
        long long cnt = getCount(mid);
 
        //mid값으로 잘라서 나온 랜선의 개수가 n이상이면 더 큰 값으로 잘라도 되므로 left값이 앞으로 간다.
        //현재 최대 길이는 mid값 만큼 자른 경우
        if (cnt >= n) {
            left = mid + 1;
            ans = mid;
        }
        else {
            //현재 mid값으로 랜선을 자르면 n개를 못만드는 경우
            //크기르 줄이기 위해 right를 mid앞쪽으로 당긴다.
            right = mid - 1;
        }
    }
 
    cout << ans << '\n';
 
 
 
    return 0;
}
Colored by Color Scripter
 

 

 

 

'BOJ' 카테고리의 다른 글

[BOJ] 2167. 2차원 배열의 합  (0) 2020.01.24
[BOJ] 2805. 나무 자르기  (0) 2020.01.21
[BOJ] 10816. 숫자 카드 2  (0) 2020.01.20
[BOJ] 5567. 결혼식  (0) 2019.11.13
[BOJ] 7662. 이중 우선순위 큐  (0) 2019.11.13

https://www.acmicpc.net/problem/10816

 

10816번: 숫자 카드 2

첫째 줄에 상근이가 가지고 있는 숫자 카드의 개수 N(1 ≤ N ≤ 500,000)이가 주어진다. 둘째 줄에는 숫자 카드에 적혀있는 정수가 주어진다. 숫자 카드에 적혀있는 수는 -10,000,000보다 크거나 같고, 10,000,000보다 작거나 같다. 셋째 줄에는 M(1 ≤ M ≤ 500,000)이 주어진다. 넷째 줄에는 상근이가 몇 개 가지고 있는 숫자 카드인지 구해야 할 M개의 정수가 주어지며, 이 수는 공백으로 구분되어져 있다. 이수도 -10,00

www.acmicpc.net

숫자 카드의 개수가 최대 500,000개이기 때문에 이분 탐색으로 해결해야 한다.

이분 탐색을 직접 구현해줘도 되지만 lower_boundupper_bound함수를 이용하여 쉽게 답을 구할 수 있다.

 

 

lower_bound : 찾으려는 값 이상이 처음 나타나는 위치를 반환한다.

upper_bound : 찾으려는 값을 처음으로 초과하는 위치를 반환한다.

 

 

upper_bound 값에서 lower_bound 값을 빼면 찾으려는 값의 개수를 구할 수 있다.

 

 

문제에 나와있는 예시를 이용하면 다음과 같은 숫자카드들을 먼저 정렬시킨다.

6 3 2 10 10 10 -10 -10 7 3

 

그럼 다음과 같이 정렬된다.

-10 -10 2 3 3 6 7 10 10 10

 

 

여기서 3의 개수를 찾기 위해 3의 lower_bound 값은 처음으로 3 이상이 나타나는 3번째 위치이고

upper_bound값은 처음으로 3을 초과하는 값(6)이 나타나는 5번째 위치이다.

 

upper_bound - lower_bound = 5 - 3 = 2로 개수를 구할 수 있다.

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>
#include <algorithm>
using namespace std;
 
int n, m;
int arr[500000];
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    cin >> n;
    for (int i = 0; i<n; i++cin >> arr[i];
 
 
    sort(arr, arr + n);
 
 
    cin >> m;
    
    int x;
    while (m--) {
        cin >> x;
        int cnt = upper_bound(arr, arr + n, x) - lower_bound(arr, arr + n, x);
        cout << cnt << ' ';
    }
 
 
    return 0;
}
Colored by Color Scripter
 

 

 

'BOJ' 카테고리의 다른 글

[BOJ] 2805. 나무 자르기  (0) 2020.01.21
[BOJ] 1654. 랜선 자르기  (0) 2020.01.20
[BOJ] 5567. 결혼식  (0) 2019.11.13
[BOJ] 7662. 이중 우선순위 큐  (0) 2019.11.13
[BOJ] 17472. 다리 만들기 2  (0) 2019.10.16

https://www.acmicpc.net/problem/5567

 

5567번: 결혼식

문제 상근이는 자신의 결혼식에 학교 동기 중 자신의 친구와 친구의 친구를 초대하기로 했다. 상근이의 동기는 모두 N명이고, 이 학생들의 학번은 모두 1부터 N까지이다. 상근이의 학번은 1이다. 상근이는 동기들의 친구 관계를 모두 조사한 리스트를 가지고 있다. 이 리스트를 바탕으로 결혼식에 초대할 사람의 수를 구하는 프로그램을 작성하시오. 입력 첫째 줄에 상근이의 동기의 수 n (2 ≤ n ≤ 500)이 주어진다. 둘째 줄에는 리스트의 길이 m (1 ≤ m

www.acmicpc.net

먼저 친구관계를 인접 리스트로 구현해주고 입력받은 값이 상근이의 친구(1번과 친구)인 경우 바로 큐에 넣어주고 체크한다. 그럼 처음 큐의 사이즈는 상근이의 친구들 수만큼이 되므로 ans 변수(초대할 친구 수)에 큐 사이즈를 저장한다

 

 

그리고 상근이의 친구들에 대해서 친구를 조사해준다. 아직 check가 되지 않았다면 ans값\을 증가시킨다. 친구의 친구만 더해주면 되므로 친구의 친구는 큐에 새로 넣지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include<iostream>
#include <vector>
#include <queue>
using namespace std;
 
int n, m;
vector<int> list[501];
bool check[501];
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    queue<int> q;
    
    cin >> n >> m;
 
    int x, y;
    for (int i = 0; i<m; i++) {
        cin >> x >> y;
        list[x].push_back(y);
        list[y].push_back(x);
 
        //상근이의 친구를 큐에 넣는다.
        if (x == 1) {
            q.push(y);
            check[y] = true;
        }
        else if (y == 1) {
            q.push(x);
            check[x] = true;
        }
    }
 
    //현재 큐 사이즈가 상근이의 친구 수
    int ans = q.size();
    check[1= true;
    
 
    int size;
    while (!q.empty()) {
        x = q.front();
        q.pop();
 
        size = list[x].size();
        for (int k = 0; k < size; k++) {
            y = list[x][k];
            if (check[y]) continue;
 
            ans++;
            check[y] = true;
        }
    }
 
    cout << ans << '\n';
 
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 1654. 랜선 자르기  (0) 2020.01.20
[BOJ] 10816. 숫자 카드 2  (0) 2020.01.20
[BOJ] 7662. 이중 우선순위 큐  (0) 2019.11.13
[BOJ] 17472. 다리 만들기 2  (0) 2019.10.16
[BOJ] 2146. 다리 만들기  (0) 2019.10.16

https://www.acmicpc.net/problem/7662

 

7662번: 이중 우선순위 큐

문제 이중 우선순위 큐(dual priority queue)는 전형적인 우선순위 큐처럼 데이터를 삽입, 삭제할 수 있는 자료 구조이다. 전형적인 큐와의 차이점은 데이터를 삭제할 때 연산(operation) 명령에 따라 우선순위가 가장 높은 데이터 또는 가장 낮은 데이터 중 하나를 삭제하는 점이다. 이중 우선순위 큐를 위해선 두 가지 연산이 사용되는데, 하나는 데이터를 삽입하는 연산이고 다른 하나는 데이터를 삭제하는 연산이다. 데이터를 삭제하는 연산은 또

www.acmicpc.net

stl에 있는 multiset을 사용하면 자동으로 정렬되기 때문에 쉽게 풀 수 있는 문제다.

set은 중복이 허용되지 않기때문에 multiset을 사용하여야한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <set>
using namespace std;
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
 
    int T;
    cin >> T;
 
    int k;
    while (T--) {
        multiset<int> ms;
        cin >> k;
        
        while (k--) {
            char i;
            int num;
            cin >> i >> num;
            
            if (i == 'I') {
                ms.insert(num);
            }
            else if (i == 'D') {
                if (ms.empty()) continue;
 
 
                if (num == 1) {
                    //최댓값 삭제
                    ms.erase(--ms.end());
                }
                else {
                    //최솟값 삭제
                    ms.erase(ms.begin());
                }
            }
 
        }
 
        if (ms.empty()) cout << "EMPTY" << '\n';
        else cout << *(--ms.end()) << ' ' << *ms.begin() << "\n";
    }
    
 
    return 0;
}
Colored by Color Scripter
 

'BOJ' 카테고리의 다른 글

[BOJ] 10816. 숫자 카드 2  (0) 2020.01.20
[BOJ] 5567. 결혼식  (0) 2019.11.13
[BOJ] 17472. 다리 만들기 2  (0) 2019.10.16
[BOJ] 2146. 다리 만들기  (0) 2019.10.16
[BOJ] 17471. 게리맨더링  (0) 2019.10.16

https://programmers.co.kr/learn/courses/30/lessons/60058

 

코딩테스트 연습 - 괄호 변환 | 프로그래머스

카카오에 신입 개발자로 입사한 콘은 선배 개발자로부터 개발역량 강화를 위해 다른 개발자가 작성한 소스 코드를 분석하여 문제점을 발견하고 수정하라는 업무 과제를 받았습니다. 소스를 컴파일하여 로그를 보니 대부분 소스 코드 내 작성된 괄호가 개수는 맞지만 짝이 맞지 않은 형태로 작성되어 오류가 나는 것을 알게 되었습니다. 수정해야 할 소스 파일이 너무 많아서 고민하던 콘은 소스 코드에 작성된 모든 괄호를 뽑아서 올바른 순서대로 배치된 괄호 문자열을 알려주는

programmers.co.kr

문제가 복잡해 보이지만 정말 시키는 대로만 재귀로 잘 구현하면 된다. 재귀로 구현해야하는 부분도 문제에 잘 나와있다.

 

올바른 괄호 문자열인지 검사하는 부분만 스택을 이용해서 따로 구현했다.

문자열의 모든 문자들에 대해서 여는 괄호면 스택에 넣어주고 닫는 괄호면 스택에서 빼준다. 이때, 스택이 비어있다면 올바른 괄호 문자열이 아니므로 false를 바로 리턴한다.

 

문자열 검사가 끝났는데 스택에 아직 괄호가 남아있다면 그것도 올바른 괄호 문자열이 아니므로 false를 리턴한다.

위에서 false를 리턴하지 않았다면 올바른 괄호 문자열이므로 true를 리턴한다.

 

 

각 조건을 구현한 부분에 주석을 달아놨다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <string>
#include <vector>
#include <stack>
using namespace std;
 
//올바른 괄호 문자열인지 검사
bool isok(string s) {
    stack<char> st;
 
    for (char c : s) {
        if (c == '(') {
            st.push(c);
        }
        else if (c == ')') {
            if (st.empty()) {
                return false;
            }
            else {
                st.pop();
            }
        }
    }
 
    if (st.empty()) return true;
    else return false;
 
}
 
 
string seperate(string p) {
    if (p == ""return "";
 
    string u = "";
    string v = "";
    string result = "";
 
    int cnt1 = 0;
    int cnt2 = 0;
    int index = 0;
 
    //2번 조건
    for (char c : p) {
        if (c == '(') {
            cnt1++;
        }
        else {
            cnt2++;
        }
        index++;
 
        //균형잡힌 상태가 되면 바로 break(더 분리할 수 없도록);
        if (cnt1 == cnt2) break;
    }
 
    //u와 v로 나누다. 
    u += p.substr(0, index);
    v += p.substr(index);
 
 
    //3번 조건
    if (isok(u)) {
        result += u;
        result += seperate(v);
    }
    else {
        //4번 조건
 
        //4-1
        result = "(";
        //4-2
        result += seperate(v);
        //4-3
        result += ")";
 
        //4-4
        u = u.substr(1, u.size() - 2);
        int len = u.size();
        for (int i = 0; i<len; i++) {
            if (u[i] == '(') {
                result += ")";
            }
            else {
                result += "(";
            }
        }
    }
 
 
    //4-5
    return result;
 
}
 
 
string solution(string p) {
    string answer = "";
    
    //1번 조건
    if (isok(p)) return p;
 
 
    answer = seperate(p);
 
 
    return answer;
}
Colored by Color Scripter
 

https://programmers.co.kr/learn/courses/30/lessons/60057

 

코딩테스트 연습 - 문자열 압축 | 프로그래머스

데이터 처리 전문가가 되고 싶은 어피치는 문자열을 압축하는 방법에 대해 공부를 하고 있습니다. 최근에 대량의 데이터 처리를 위한 간단한 비손실 압축 방법에 대해 공부를 하고 있는데, 문자열에서 같은 값이 연속해서 나타나는 것을 그 문자의 개수와 반복되는 값으로 표현하여 더 짧은 문자열로 줄여서 표현하는 알고리즘을 공부하고 있습니다. 간단한 예로 aabbaccc의 경우 2a2ba3c(문자가 반복되지 않아 한번만 나타난 경우 1은 생략함)와 같이 표현할 수

programmers.co.kr

문자열을 자르는 단위를 1부터 시작해서 모두 해보면 된다.

단위가 문자열의 길이의 반보다 커지면 절대 더 압축되지 않으므로 1부터 문자열의 길이/2 까지만 해보면 된다.

 

 

i개로 자른다고 했을 때, 문자열의 처음부터 i개만큼씩을 문자열 끝까지 계속 검사해주면 된다.

(i개로 나누어 떨어지지 않고 남은 부분은 마지막에 추가적으로 붙여준다.)

 

 

i개로 자른 문자열이 바로 이어서 나타난다면 cnt값을 증가시킨다.

그렇지 않다면, 압축된 결과를 저장할 문자열(result)에 문자열 단위를 붙여주고 문자열 단위를 새로 j번부터 i개로 업데이트한다. 이때, 문제 조건에 따라서 이 문자열 단위가 여러 개였다면(cnt가 1 이상이라면) cnt를 문자열 앞에 붙여서 result에 추가하고 cnt는 1로 다시 초기화한다.

 

 

i개로 잘라서 압축한 경우의 문자열을 모두 완성했다면 그때의 길이를 최솟값과 비교한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <string>
#include <vector>
using namespace std;
 
int solution(string s) {
    int len = s.size();
    int answer = len;
 
    int n = len / 2;
 
 
    //i개 단위로 잘라서 압축
    for (int i = 1; i <= n; i++) {
 
        //i개 단위로 잘라서 압축한뒤 만들어지는 문자열
        string result = "";
 
        //자를 문자열 단위
        string ss = s.substr(0, i);
 
        int cnt = 1;
 
        //앞에서 자른 문자열 단위를 제외한 뒷부분(j번 문자부터) 문자열을 검사한다.
        for (int j = i; j <= len; j += i) {
            //j번 부터 i개 만큼이 문자열 단위와 똑같은 경우 cnt 증가
            if (ss == s.substr(j, i)) {
                cnt += 1;
            }
            else {
                //다른 경우 중 cnt가 1이면 result에 그대로 ss를 붙인다.
                if (cnt == 1) {
                    result += ss;
                }
                else {
                    //cnt가 1보다 크다면 cnt를 문자열 단위 앞에 붙여서 result에 이어준다.
                    result += (to_string(cnt) + ss);
                }
 
                //문자열 단위를 j번부터 i개로 변경 
                ss = s.substr(j, i);
                //cnt값 다시 1로 초기화
                cnt = 1;
            }
 
        }
 
        //문자열이 i로 나누어 떨어지지 않는다면 result에 나머지 부분을 붙여줘야한다.
        if ((len%i) != 0) {
            result += s.substr((len / i)*i);
        }
 
        //최솟값을 answer에 저장
        if (answer > result.size()) answer = result.size();
    }
 
 
    return answer;
}
Colored by Color Scripter
 

+ Recent posts