백준 알고리즘2020. 11. 16. 19:13

www.acmicpc.net/problem/5639

 

5639번: 이진 검색 트리

트리를 전위 순회한 결과가 주어진다. 노드에 들어있는 키의 값은 106보다 작은 양의 정수이다. 모든 값은 한 줄에 하나씩 주어지며, 노드의 수는 10,000개 이하이다. 같은 키를 가지는 노드는 없다

www.acmicpc.net

처음 풀이

/*
    재귀를 이용해서 leftNode에는 subtree의 왼쪽 node들을 저장
    rightNode에는 subtree의 오른쪽 노드들을 저장
    인자로 vector를 전달하기 때문에 메모리 초과 발생
*/
void recursive(vector<int> vec) {
  if(vec.size() == 0) return ;
  int root = vec[0];
  vector<int> leftNode, rightNode;
  for(int idx = 1; idx < vec.size(); idx++) {
    if(vec[idx] < root) leftNode.push_back(vec[idx]);
    else rightNode.push_back(vec[idx]);
  }
  recursive(leftNode);
  recursive(rightNode);
  cout << root << endl;
}

 

정답 코드

vector를 넘기는 대신 왼쪽과 오른쪽 인덱스를 넘겨 구한다.

#include <iostream>
#include <vector>
using namespace std;
vector<int> vec;
void input() {
  int N;
  while(cin >> N) vec.push_back(N);
}

void recursive(int left, int right) {
  int root = vec[left];
  int idx = left + 1;
  for( ; idx <= right; idx++) 
    if(vec[idx] >= root) break;
  if(left < idx - 1) recursive(left + 1, idx - 1);
  if(idx <= right) recursive(idx, right);
  cout << root << endl;
}

int main(void) {
  input();
  recursive(0, vec.size() - 1);
  return 0;
}

 

배열의 양 끝을 left와 right로 잡은 후 root보다 값이 큰 인덱스를 idx변수로 잡아준다.

left + 1에서부터 idx - 1까지가 root의 왼쪽 subtree가 된다.

idx에서부터 right는 root의 오른쪽 subtree가 된다.

위와 같이 진행이 된다.

'백준 알고리즘' 카테고리의 다른 글

가장 긴 증가하는 부분 수열4, 5  (0) 2020.11.11
가장 긴 증가하는 부분 수열  (0) 2020.11.11
백준 11000 (강의실 배정)  (0) 2020.06.29
백준 1327(소트 게임)  (0) 2020.06.04
백준 1484 (다이어트)  (0) 2020.05.29
Posted by rycbar2592
백준 알고리즘2020. 11. 11. 13:20

jaimemin.tistory.com/1095 를 참고하여 해결하였습니다.

 

백준 14003번 가장 긴 증가하는 부분 수열 5

문제 링크입니다: https://www.acmicpc.net/problem/14003 Crocus님(https://www.crocus.co.kr/681) 덕분에 풀 수 있었던 문제였습니다. O(NlogN)에 LIS의 최대 길이를 구하는 알고리즘을 통해서는 정확한 LIS 배..

jaimemin.tistory.com

처음에는 가장 긴 증가하는 부분 수열 1, 2, 3에서 해결한 방법과 똑같이 접근을 했고 lower_bound로 만든 배열의 값을 출력해서 제출했었습니다.

그 결과 '틀렸습니다'를 받았고 반례가 생각나지 않아 위 블로그를 참고해서 해결하였습니다.

vector<int> lis 는 어떤 값을 저장하는가?

가장 긴 증가하는 부분 수열 1, 2, 3과 마찬가지로 가장 길게 증가하는 크기를 구하기 위해 사용하는 배열

 

vector<pair<int, int>> answer는 어떤 값을 저장하는가?

answer[i]은 {0 ~ i번째 중 몇 번째로 증가하는 수열인가, 입력받은 값인 input[i]}를 저장

 

answer배열을 왜 써야 하는가?

단순히 크기를 구하는 문제를 해결할 때에는 answer배열을 사용하지 않고 lis배열의 크기만 출력해주면 된다.

그렇지만 이 문제는 가장 길게 증가하는 배열의 크기와 그때의 원소들을 모두 출력해줘야 하는데 그냥 lis값을 출력했을 때의 반례는 다음과 같다.

8

1 5 3 4 2 6 7 8
올바른 정답은 1 3 4 6 7 8이지만 lis값은 1 2 4 6 7 8값이 나오게 된다.

따라서 몇 번째로 증가하는지에 대한 정보를 이용해서 input배열의 끝(i 가 N - 1일 때)에서부터 수열을 찾아준다. 

 

#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#define MAX 1000001
using namespace std;
vector<int> input(MAX), lis;
vector<pair<int, int>> answer(MAX);

int main(void) {
    int N;
    cin >> N;
    for(int i = 0; i < N; i++) cin >> input[i];

    lis.push_back(input[0]);
    answer[0] = {1, input[0]};

    for(int i = 1; i < N; i++) {
        vector<int>::iterator idx2 = lower_bound(lis.begin(), lis.end(), input[i]);
        if(idx2 == lis.end()) { //lis에 있는 값 중에 가장 큰 값이라면
            lis.push_back(input[i]);
            answer[i] = {lis.size(), input[i]};
        } else {
            lis[idx2 - lis.begin()] = input[i];
            answer[i] = {idx2 - lis.begin() + 1, input[i]};
        }
    }

    stack<int> s;
    int idx = lis.size();
    cout << lis.size() << endl;
    for(int i = N - 1; i >= 0; i--) {
        if(answer[i].first == idx) {
            s.push(answer[i].second);
            idx--;
        }
    }

    while(!s.empty()) {
        cout << s.top() << " ";
        s.pop();
    }

    return 0;
}

 

www.acmicpc.net/problem/14002

 

14002번: 가장 긴 증가하는 부분 수열 4

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이

www.acmicpc.net

www.acmicpc.net/problem/14003

 

14003번: 가장 긴 증가하는 부분 수열 5

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

www.acmicpc.net

 

'백준 알고리즘' 카테고리의 다른 글

백준 5639(이진 검색 트리)  (0) 2020.11.16
가장 긴 증가하는 부분 수열  (0) 2020.11.11
백준 11000 (강의실 배정)  (0) 2020.06.29
백준 1327(소트 게임)  (0) 2020.06.04
백준 1484 (다이어트)  (0) 2020.05.29
Posted by rycbar2592
백준 알고리즘2020. 11. 11. 12:21

가장 길게 증가하는 수열의 길이만 구하면 되는 문제였기 때문에 lower_bound를 이용해서 문제를 해결하였습니다.

가장 긴 증가하는 부분 수열(1, 2, 3) 모두 범위만 다를 뿐 같은 결과를 구하는 문제였기 때문에 아래 코드로 모두 통과하였습니다.

lower_bound의 시간 복잡도가 log이기 때문에 전체 시간 복잡도는 O(NlogN)만에 해결할 수 있었습니다.

 

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

int main(void)
{
    int N, answer = 987654321, num;
    cin >> N;
    vector<int> vec;
    for (int i = 0; i < N; i++)
    {
        cin >> num;
        vector<int>::iterator iter;
        iter = lower_bound(vec.begin(), vec.end(), num);
        if (vec.size() == 0) vec.push_back(num);
        else if (iter == vec.end()) vec.push_back(num);
        else vec[iter - vec.begin()] = num;
    }
    cout << vec.size() << endl;
    return 0;
}

 

www.acmicpc.net/problem/11053

 

11053번: 가장 긴 증가하는 부분 수열

수열 A가 주어졌을 때, 가장 긴 증가하는 부분 수열을 구하는 프로그램을 작성하시오. 예를 들어, 수열 A = {10, 20, 10, 30, 20, 50} 인 경우에 가장 긴 증가하는 부분 수열은 A = {10, 20, 10, 30, 20, 50} 이

www.acmicpc.net

www.acmicpc.net/problem/12015

 

12015번: 가장 긴 증가하는 부분 수열 2

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

www.acmicpc.net

www.acmicpc.net/problem/12738

 

12738번: 가장 긴 증가하는 부분 수열 3

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

www.acmicpc.net

 

'백준 알고리즘' 카테고리의 다른 글

백준 5639(이진 검색 트리)  (0) 2020.11.16
가장 긴 증가하는 부분 수열4, 5  (0) 2020.11.11
백준 11000 (강의실 배정)  (0) 2020.06.29
백준 1327(소트 게임)  (0) 2020.06.04
백준 1484 (다이어트)  (0) 2020.05.29
Posted by rycbar2592
프로그래머스2020. 11. 10. 21:03

programmers.co.kr/learn/courses/30/lessons/42895

 

코딩테스트 연습 - N으로 표현

 

programmers.co.kr

 

#include <iostream>
#include <string>
#include <vector>
#include <set>
#define ll long long 
using namespace std;
vector<set<int>> dp(10);

int makeNumber(int N, int cnt) {
	//숫자 N을 cnt번 이어서 반환한다.
	//N이 2이고 cnt가 5라면 22222값을 반환
    int n = N;
    for(int i = 0; i < cnt - 1; i++) {
        n *= 10;
        n += N;
    }
    return n;
}

int solution(int N, int number) {
    int answer = 0;
    dp[1].insert(N);
    for(int i = 2; i <= 8; i++) {	//최대 8개의 숫자를 사용할 수 있으므로
        dp[i].insert(makeNumber(N, i));
        for(int j = 1; j < i; j++) {
            for(auto iter: dp[j]) {
                for(auto iter2: dp[i - j]) {
                //dp[j]에는 숫자를 j개 사용해서 만들 수 있는 값들이 저장되어 있다.
                //dp[j]와 dp[i - j]를 이용해서 i개를 사용해서 만들 수 있는 값들을 구할 수 있다.
                    dp[i].insert(iter + iter2);
                    dp[i].insert(iter - iter2);
                    dp[i].insert(iter * iter2);
                    if(iter2 != 0) dp[i].insert(iter / iter2);
                }
            }
        }
    }
    
    for(int i = 1; i < 10; i++) 
        for(auto iter: dp[i]) 
            if(iter == number) 
                return i;
    return -1;
}

 

Posted by rycbar2592
leetcode2020. 8. 21. 00:50

https://leetcode.com/problems/letter-combinations-of-a-phone-number/

 

Letter Combinations of a Phone Number - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

시간 복잡도: O(N)

재귀를 이용해 한 문자씩 더해서 출력한다.

#include<iostream>
#include<string>
#include<vector>
using namespace std;

class Solution {
public:
    vector<string> answer;    
    
    void recursive(string str, string digits, int depth) {
        if(depth == digits.length()) {      //문자열의 끝에 도달하면 answer에 push해주기
            if(str != "") answer.push_back(str);
            return ;
        }
        switch(digits[depth]) {     //한 단어씩 더하면서 재귀를 돌린다.
            case '2':
                recursive(str + 'a', digits, depth + 1);
                recursive(str + 'b', digits, depth + 1);
                recursive(str + 'c', digits, depth + 1);                
                break;
            case '3':
                recursive(str + 'd', digits, depth + 1);
                recursive(str + 'e', digits, depth + 1);
                recursive(str + 'f', digits, depth + 1);
                break;
            case '4':
                recursive(str + 'g', digits, depth + 1);
                recursive(str + 'h', digits, depth + 1);
                recursive(str + 'i', digits, depth + 1);
                break;
            case '5':
                recursive(str + 'j', digits, depth + 1);
                recursive(str + 'k', digits, depth + 1);
                recursive(str + 'l', digits, depth + 1);                
                break;
            case '6':
                recursive(str + 'm', digits, depth + 1);
                recursive(str + 'n', digits, depth + 1);
                recursive(str + 'o', digits, depth + 1);                
                break;
            case '7':
                recursive(str + 'p', digits, depth + 1);
                recursive(str + 'q', digits, depth + 1);
                recursive(str + 'r', digits, depth + 1);
                recursive(str + 's', digits, depth + 1);
                break;
            case '8':
                recursive(str + 't', digits, depth + 1);
                recursive(str + 'u', digits, depth + 1);
                recursive(str + 'v', digits, depth + 1);
                break;
            case '9':
                recursive(str + 'w', digits, depth + 1);
                recursive(str + 'x', digits, depth + 1);
                recursive(str + 'y', digits, depth + 1);
                recursive(str + 'z', digits, depth + 1);
                break;
        }
        return ;
    }
    
    vector<string> letterCombinations(string digits) {
        recursive("", digits, 0);
        return answer;
    }
};

int main(void){
  return 0;
}

'leetcode' 카테고리의 다른 글

929. Unique Email Addresses  (0) 2020.08.21
791. Custom Sort String  (0) 2020.08.20
Posted by rycbar2592
leetcode2020. 8. 21. 00:21

https://leetcode.com/problems/unique-email-addresses/

 

Unique Email Addresses - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

시간 복잡도: O(N)

조건 1)    '+'를 만나면 @를 만날 때 까지 문자를 무시할 수 있다.

조건 2)    '@'뒤에 있는 .은 생략하면 안된다.

조건 3)    '@'앞에 있는 .은 포함하면 안된다.(afterDot변수로 구분지음)

조건 4)    중복되는 문자열은 제거해야 한다.

#include<iostream>
#include<string>
#include<set>
#include<vector>
using namespace std;

class Solution {
public:
    string uniqueEmail(string str){
        string answer = "";
        bool afterDot = false;
        for(int i = 0; i < str.length(); i++){
            if(str[i] == '+'){
                while(1) {      //+를 만나면 @를 만날 때까지 넘어간다.
                    if(str[i] == '@'){
                        answer += '@';
                        afterDot = true;
                        break;
                    }
                    i++;
                }
            } else if(str[i] == '@'){   //+를 안만나고 @를 만났을 때
                afterDot = true;
                answer += '@';
            } else if(str[i] == '.') {
                if(afterDot) answer += str[i];  //@이후 .은 저장하고 이전 .은 저장하지 않는다.
            } else answer += str[i];
        }
        return answer;
    }

    int numUniqueEmails(vector<string>& emails) {
        set<string> s;
        for(int i = 0; i < emails.size(); i++)
            s.insert(uniqueEmail(emails[i]));
        return s.size();
    }
};

int main(void){
  return 0;
} 

 

'leetcode' 카테고리의 다른 글

17. Letter Combinations of a Phone Number  (0) 2020.08.21
791. Custom Sort String  (0) 2020.08.20
Posted by rycbar2592
leetcode2020. 8. 20. 18:11

1. 문자열 T에서 S에 있는 단어들의 개수만큼 cntAlpha에 저장한다.

2. S에 들어있는 단어들부터 cntAlpha의 개수만큼 answer에 더해준다.

3. 나머지 문자들을 answer에 더해준다.

// 791. Custom Sort String

#include<iostream>
#include<string>
using namespace std;
class Solution {
public:
    string customSortString(string S, string T) {
        string answer = "";
        int cntAlpha[26] = { 0, };
        for(int i = 0; i < T.length(); i++)     //T문자열에서 각 알파뱃의 개수를 cntAlpha배열에 저장
            cntAlpha[T[i] - 'a']++;

        for(int i = 0; i < S.length(); i++){        //S에 있는 문자를 cntAlpha에 저장된 수 만큼 더해준다.
            for(int j = 0; j < cntAlpha[S[i] - 'a']; j++)
                answer += S[i];
            cntAlpha[S[i] - 'a'] = 0;
        }

        for(int i = 0; i < 26; i++){        //남은 문자열을 더해준다.
            char c = i + 'a';
            for(int j = 0; j < cntAlpha[i]; j++)
                answer += c;
        }
        return answer;
    }
};

int main(void){
  return 0;
} 

https://leetcode.com/problems/custom-sort-string/

 

Custom Sort String - LeetCode

Level up your coding skills and quickly land a job. This is the best place to expand your knowledge and get prepared for your next interview.

leetcode.com

 

'leetcode' 카테고리의 다른 글

17. Letter Combinations of a Phone Number  (0) 2020.08.21
929. Unique Email Addresses  (0) 2020.08.21
Posted by rycbar2592
백준 알고리즘2020. 6. 29. 12:41

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

 

11000번: 강의실 배정

첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000) 이후 N개의 줄에 Si, Ti가 주어진다. (1 ≤ Si < Ti ≤ 109)

www.acmicpc.net

 

백준 1931(회의실 배정)문제와 비슷한 문제라고 생각해서 회의가 끝나는 시간을 기준으로 잡고 정렬(오름차순)을 해서 접근을 했다.

 

 

1차 시도. (결과: 시간초과)

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int N;
vector<pair<pair<int, int>, bool>> vec;

void input(){
    cin >> N;
    int start, finish;
    for(int i = 0; i < N; i++){
        cin >> start >> finish;
        vec.push_back({{start, finish}, false});
    }
}

bool compare(pair<pair<int, int>, bool> a, pair<pair<int, int>, bool> b){
    if(a.first.second < b.first.second) return true;
    else if(a.first.second == b.first.second){
        if(a.first.first < b.first.first) return true;
        return false;
    }
    return false;
}

int main(void){
    cin.tie(NULL);
    ios::sync_with_stdio(false);
    input();
    sort(vec.begin(), vec.end(), compare);
    int result = 0;
    while(N) {
        int finish = 0;
        result++;
        for(int i = 0; i < vec.size(); i++){
            if(!vec[i].second && vec[i].first.first >= finish){
                vec[i].second = true;
                finish = vec[i].first.second;
                N--;
            }
        }
    }
    cout << result << endl;
    return 0;
}

배정이 된 시간표는 true로 표시하며 강의실 개수를 구하려고 했다.

그런데 이렇게 구현을 하게 되면 최악의 경우 200000 * 200000의 연산을 수행하기 때문에 시간 초과가 발생한다.

 

 

2차 시도 (결과: 시간 초과)

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
int N;
queue<pair<pair<int, int>, int>> q;
vector<pair<int, int>> vec;

void input(){
    cin >> N;
    int start, finish;
    for(int i = 0; i < N; i++){
        cin >> start >> finish;
        vec.push_back({start, finish});
    }
}

bool compare(pair<int, int> a, pair<int, int> b){
    if(a.first < b.first) return true;
    else if(a.first == b.first) {
        if(a.second < b.second) return true;
        return false;
    }
    return false;
}

int main(void){
    cin.tie(NULL);
    ios::sync_with_stdio(false);
    input();
    sort(vec.begin(), vec.end(), compare);
    for(auto i: vec) q.push({i, 1});        //queue에 정렬된 데이터들을 복사

    int result = 1;
    int finish_time = 0;
    while(!q.empty()) {
        int start = q.front().first.first;
        int finish = q.front().first.second;
        int room = q.front().second;        //몇번째 방인가
        q.pop();      
        if(result < room) {  //다음 방에 배치해야 됨
            result = room;
            finish_time = finish;
        } else if(finish_time <= start) {      //방에 들어올 수 있다면
            finish_time  = finish;
        } else if(finish_time > start) {
            q.push({{start, finish}, ++room});
        }
    }
    cout << result << endl;
    return 0;
}

두 번째는 vector의 중복되는 true, false를 계산하지 않기 위해 queue를 이용해서 구하려고 했다.

그런데 이 또한

5
5 6
4 6
3 6
2 6
1 6

와 같은 경우에서 O(N^2)의 연산이 나와 시간초과가 발생했다.

 

그래서 다른 블로그를 참고해서 문제를 해결하였다.

 

강의가 시작하는 시간을 기준으로 오름차순 정렬을 한 후 priority_queue를 이용해서 강의실 개수만 추가해주면 되는 문제였다.

#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
int N;
vector<pair<int, int>> vec;

void input(){
    cin >> N;
    int start, finish;
    for(int i = 0; i < N; i++) {
        cin >> start >> finish;
        vec.push_back({start, finish});
    }
}

bool compare(pair<int, int> a, pair<int, int> b){	//강의 시작 시간을 기준으로 정렬
    if(a.first < b.first) return true;
    else if(a.first == b.first) {
        if(a.second < b.second) return true;
        return false;
    }
    return false;
}

int main(void){
    cin.tie(NULL);
    ios::sync_with_stdio(false);
    input();
    sort(vec.begin(), vec.end(), compare);
    priority_queue<int, vector<int>, greater<int>> pq;
    pq.push(vec[0].second);
    for(int i = 1; i < N; i++){
        if(pq.top() <= vec[i].first)
            pq.pop();
        pq.push(vec[i].second);
    }
    cout << pq.size() << endl;
    return 0;
}

 

 

참고 블로그

https://hyeonnii.tistory.com/181

 

[백준 11000] 강의실 배정

문제 : https://www.acmicpc.net/problem/11000 11000번: 강의실 배정 첫 번째 줄에 N이 주어진다. (1 ≤ N ≤ 200,000) 이후 N개의 줄에 Si, Ti가 주어진다. (1 ≤ Si < Ti ≤ 109) www.acmicpc.net 정답 소스..

hyeonnii.tistory.com

 

'백준 알고리즘' 카테고리의 다른 글

가장 긴 증가하는 부분 수열4, 5  (0) 2020.11.11
가장 긴 증가하는 부분 수열  (0) 2020.11.11
백준 1327(소트 게임)  (0) 2020.06.04
백준 1484 (다이어트)  (0) 2020.05.29
백준 2075(N번째 큰 수)  (0) 2020.05.28
Posted by rycbar2592