본문 바로가기
패스트캠퍼스 챌린지(C++ 올인원)

패스트캠퍼스 챌린지 최종 후기

by 승욱은 2021. 12. 8.

패스트캠퍼스 챌린지 데일리 미션을 모두 성공하고 최종 후기를 쓰게 되었다..! 환급 받으면 또 좋은 강의를 수강해야겠다..! 히히 >< 

 

매일 하나씩은 꼭 듣기, 이게 쉬운 일은 아니었지만, 그래도 역시 돌아보면 보람찼던 것 같다. 근데 만약 휴학하고 있는 상태가 아니었다면.. 조금 힘들었을지도 모르겠다.. ㅎㅎ 결국 모든 강의를 다 듣는 것에는 실패했지만, 그래도 주요 골자는 알게되었고, 기존에 목표했던 'PS를 위한 c++ 공부'라는 목적에는 잘 도달했던 것 같다. 물론 아직은 문법에 조금 덜 익숙하긴 하지만.. 그래도 c++을 이용해서 파이썬으로는 풀지 못했던 몇 문제들을 해결했다. 

 

1. 단어 검색 (플레티넘 1)

 

단어 검색 AC

모든 문제 통틀어서 가장 많이 시도한 문제가 바로 이것일 것이다. 파이썬으로 거의 3일간 씨름했던 것 같은데 결국 해결하지 못했다. 내가 c++을 배워야겠다고 생각하게 된 이유이기도 하다. 

다음은 코드이다.

#include <iostream>
#include <string>
#include <vector>
#include <tuple>
#include <algorithm>

using namespace std;

const int AL = 27;
int n;

struct Node
{
    vector<pair<char, Node *>> child;
    int visit;
    int end;
    Node() : visit(0), end(n - 1) {}
    ~Node()
    {
        for (auto &p : child)
        {
            delete p.second;
        }
    }

    void insert(string &s, int i, int &idx)
    {
        if (s.size() == i)
        {
            child.push_back(make_pair(0, new Node()));
            child.back().second->visit += 1;
            end = idx;
            return;
        }
        for (auto &p : child)
        {
            if (p.first == s[i])
            {
                p.second->visit += 1;
                p.second->insert(s, i + 1, idx);
                return;
            }
        }
        child.push_back(make_pair(s[i], new Node()));
        child.back().second->visit += 1;
        child.back().second->insert(s, i + 1, idx);
    }

    int find(string &s, int i)
    {
        if (s.size() == i)
            return end;
        for (auto &p : child)
        {
            if (s[i] == p.first)
                return p.second->find(s, i + 1);
        }
        return n - 1;
    }

    int value(string &s, int i)
    {
        int result = 0;
        for (auto &p : child)
        {
            result += p.second->visit;
        }
        if (s.size() == i)
            return result;
        for (auto &p : child)
        {
            if (p.first == s[i])
            {
                result += p.second->value(s, i + 1);
                break;
            }
        }
        return result;
    }
};

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    cin >> n;
    string word[n];
    Node *root;
    root = new Node();
    for (int i = 0; i < n; i++)
    {
        cin >> word[i];
        root->insert(word[i], 0, i);
    }
    int q;
    string search;
    cin >> q;
    int idx;
    vector<tuple<int, string, int>> query;
    Node *nroot = new Node();
    for (int i = 0; i < q; i++)
    {
        cin >> search;
        idx = root->find(search, 0);
        query.push_back(make_tuple(idx, search, i));
    }
    sort(query.begin(), query.end());
    int li = -1, ni = 0;
    int result[q]{};
    for (auto &p : query)
    {
        ni = get<0>(p);
        for (int i = li + 1; i <= ni; i++)
        {
            nroot->insert(word[i], 0, i);
        }
        result[get<2>(p)] = nroot->value(get<1>(p), 0);
        li = ni;
    }
    for (int r : result)
        cout << r << '\n';

    delete root, nroot;

} // namespace std;

아이디어는 우선 Trie 구조를 이용한다. Trie 구조에 문자 하나씩 하나씩, 받고, 그 안에 몇 번 방문했는지도 기록한다. 그러고 나서는 검색 문자열들을 받아주고, 각각의 문자열들이 몇 번째에 위치했는지를 기록하고, 그 순으로 정리해주었다. 그 다음에는 Trie를 하나 더 생성해서, 각 문자열 순서들이 될때까지 삽입하면서, 총 몇 번 비교해야하는 지 더하고, result에 넣어주었다. (result에 넣을 때는 쿼리 순으로)

이렇게 해주면 단 2번 trie 생성으로 메모리, 속도를 모두 가져갈 수 있었다. (물론 이 마저도 파이썬에서는 메모리초과) 근데 생각해보니, 단 1번의 Trie 생성으로도 해결할 수 있는 것 같은데, 그 코드는 추후에..

 

2. 큰 수 곱셈 2

300000만 자리 수의 곱셈을 해야하는 문제이다. FFT를 공부해보고 싶기도 했고, 또 c++만 제출하라고 했기에, 이 녀석도 c++을 공부하고 싶게 만든 조연이기도 하다. 아무튼 이 문제를 해결하기 위해서는 FFT를 공부해야만 했고, 그 과정이 역시 쉽지가 않았지만.. 그래도 결국에는 해결했다.

큰 수 곱셈 AC

스스로 공부해가며 짠 코드는 다음과 같다. 

#include <iostream>
#include <vector>
#include <string>
#include <math.h>
#include <complex>
#include <vector>

using namespace std;
using ull = unsigned long long;

const double PI = acos(-1);
typedef complex<double> cpx;

void FFT(vector<cpx> &f, cpx w)
{
    int n = f.size();
    if (n == 1)
        return;

    vector<cpx> even(n / 2), odd(n / 2);
    for (int i = 0; i < n; ++i)
        (i & 1 ? odd : even)[i / 2] = f[i];

    FFT(even, w * w);
    FFT(odd, w * w);

    cpx wp(1, 0);
    for (int i = 0; i < n / 2; ++i)
    {
        f[i] = even[i] + wp * odd[i];
        f[i + n / 2] = even[i] - wp * odd[i];
        wp *= w;
    }
}

vector<cpx> multiply(vector<cpx> a, vector<cpx> b)
{
    int n = 1;
    while (n < a.size() + 1 || n < b.size() + 1)
        n <<= 1;
    n <<= 1;
    a.resize(n);
    b.resize(n);
    vector<cpx> c(n);

    cpx w(cos(2 * PI / n), sin(2 * PI / n));
    FFT(a, w);
    FFT(b, w);
    for (int i = 0; i < n; i++)
        c[i] = a[i] * b[i];

    FFT(c, cpx(1, 0) / w);
    for (int i = 0; i < n; ++i)
    {
        c[i] /= cpx(n, 0);
        c[i] = cpx(round(c[i].real()), round(c[i].imag()));
    }
    return c;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    string a, b;
    cin >> a >> b;
    vector<cpx> A;
    vector<cpx> B;

    for (int i = a.size() - 1; i >= 0; i--)
    {
        A.push_back(cpx(int(a[i]) - 48, 0));
    }
    for (int i = b.size() - 1; i >= 0; i--)
    {
        B.push_back(cpx(int(b[i]) - 48, 0));
    }
    vector<cpx> C = multiply(A, B);
    C.push_back(cpx(0, 0));
    vector<int> result;
    for (int i = 0; i < C.size() - 1; i++)
    {
        C[i + 1] += cpx(C[i].real() / 10, 0);
        result.push_back(int(C[i].real()) % 10);
    }
    bool check = false;
    for (int i = result.size() - 1; i >= 0; i--)
    {
        if (check || result[i])
        {
            check = true;
            cout << result[i];
        }
    }
    if (!check){
        cout << 0;
    }
    cout << '\n';

} // namespace std;

FFT 코드는 고속 푸리에 변환(Fast Fourier Transform) (수정: 2019-09-05) : 네이버 블로그 (naver.com) 블로그를 많이 참고했다. 아이디어는 사실 별거 없다. 한 글자 한 글자씩 뒤에서부터 따와서 그것을 계수로 하는 다항식을 만들고, 두 개의 다항식을 곱해주는 것을 FFT로 해결한다. 그렇게 생긴 새로운 다항식을 뒤에서부터 쭉 연결하면 그게 답이된다. 다만 큰 수 곱셈 (3)는 이 방법으로 해결하지 못했는데, 그 이유가 FFT 성능 때문이었다. 시간 초과가 났고, 여러 가지 시도를 해봤었는데, 결국 전명우님의 FFT 코드 고속 푸리에 변환 (Fast Fourier Theorem, FFT) (myungwoo.kr)를 사용해서 AC를 받았다. 다만 비재귀로 구현해서, 거기에 비트 연산 트릭까지 사용하는 이 코드를 이해하지는 못했다.. ㅠ 이건 새로운 과제가 될 듯 하다.

 

3. 수열과 쿼리 7

 

파이썬으로 PS를 하면서 가장 큰 벽과, 현타를 오게 만든 문제이다. 단 한명, teferi00이라는 분만 파이썬으로 AC를 받으셨는데, 그 분한데 직접 카톡까지 해서 코드를 받아오기도 했었다. 그 분의 아이디어도 분명 이해를 했지만, 어째선지 파이썬으로 도저히 AC를 받을 수가 없더라.. ㅠ 마음이 너무 아팠다. 그래서 결국 c++로 시도했는데.. 1큐.. ㅋㅋ;; 물론 내 풀이 방식이 조금 속도가 느린갑다.. 좀 더 효율적인 방식을 많이 공부해야하긴 하겠더라.. 

수열과 쿼리 7 AC

아래는 코드이다.

#include <math.h>
#include <iostream>
#include <list>
#include <vector>
#include <algorithm>
#include <tuple>

using ull = unsigned long long;
using namespace std;
typedef tuple<int, int, int> intp;
int n, k, m;
int sn;
vector<ull> pre;
vector<int> cnt;
vector<int> cnt_sq;
vector<intp> qry;
vector<list<int>> now;

bool comp(intp &a, intp &b)
{
    if (get<0>(a) / sn == get<0>(b) / sn)
        return get<1>(a) < get<1>(b);
    else
        return get<0>(a) < get<0>(b);
}

void insert(int x){
    ull y = pre[x];
    list<int> &d = now[y];
    if (d.empty()){
        d.push_back(x);
        cnt[0] ++; cnt_sq[0] ++;
    } else {
        int lm = d.back() - d.front();
        if (x < d.front()) d.push_front(x);
        else d.push_back(x);
        int nm = d.back() - d.front();
        cnt[lm] --; cnt_sq[lm/sn] --;
        cnt[nm] ++; cnt_sq[nm/sn] ++;
    }
}

void remove(int x){
    ull y = pre[x];
    list<int> &d = now[y];
    int lm = d.back() - d.front();
    cnt[lm] --; cnt_sq[lm/sn] --;
    if (d.front() == x) d.pop_front();
    else d.pop_back();
    if (!d.empty()){
        int nm = d.back() - d.front();
        cnt[nm] ++; cnt_sq[nm/sn] ++;
    }
}

int find_max(){
    int i,j;
    for (i=sn; i>=0; i--){
        if (cnt_sq[i]) break;
    }
    int k= min(n,(i+1)*sn-1);
    for (j=k; j>=i*sn; j--){
        if (cnt[j]) return j;
    }
}

int main()
{
    cin >> n;
    cin >> k;
    sn = (int)sqrt(n + 1) + 1;
    cnt.resize(n+1);
    cnt_sq.resize(sn+1);
    pre.resize(n+1);
    now.resize(k);
    for (int i = 0; i < n; i++)
    {
        ull x;
        cin >> x;
        pre[i+1] += (pre[i] + x)%k;
    }
    cin >> m;
    for (int i = 0; i < m; i++)
    {
        int a, b;
        cin >> a >> b;
        qry.push_back(make_tuple(a-1,b,i));
    }
    sort(qry.begin(), qry.end(), comp);
    vector<int> result(m);
    int li=get<0>(qry[0]), lj=get<1>(qry[0]), lk=get<2>(qry[0]);
    for (int i=li; i<=lj; i++) insert(i);
    result[lk] = find_max();
    for (int w=1; w<m; w++){
        int ni=get<0>(qry[w]), nj=get<1>(qry[w]),nk=get<2>(qry[w]);
        if (ni/sn == li/sn){
            for (int x=lj+1; x<=nj; x++) insert(x);
            if (li<ni){
                for (int x=li; x<ni; x++) remove(x);
            } else {
                for (int x=li-1; x>=ni; x--) insert(x);
            }
        } else {
            if (lj<nj){
                for (int x=lj+1; x<=nj; x++) insert(x);
            } else{
                for (int x=lj; x>nj; x--) remove(x);
            }
            for (int x=li; x<ni; x++) remove(x);
        }
        li = ni; lj = nj;
        result[nk] = find_max();
    }
    for (int x : result){
        cout << x << '\n';
    }

} // namespace std;

mo's 알고리즘과 제곱근 분할법을 이용해 풀었다. 현재 갖고 있는 것에 하나씩 하나씩 idx를 deque에 삽입하면서 그 최댓값과 최솟값의 차이를 제곱근 분할로 기록하는 방식으로 해결했다. 최댓값을 찾을 때는, 제곱근 분할된 거 먼저 찾고, 그 분할 안에서 세부적으로 찾으면 O(Msqrt(N))으로 문제를 해결할 수 있다. 

 

4. suffix array와 lcp 배열

 

접미사 배열과 lcp배열을 공부해야지.. 해야지.. 하다가 이제야 공부 했다..! 이 알고리즘 보면 진짜..! 사람들 대단하다는 생각이 든다. 아래는 코드이다. 이해하는 데 진짜 오래걸렸다.. ㅠ 이건 파이썬으로 구현해보고 싶었는데, 시간복잡도가 좀 넘치는 문제이기도 하고, 아래 코드는 O(n(log n)^2)이기 때문에 c++로 구현했다. 파이썬으로는 계속 시간초과가 뜨길래 왜이러나.. 고민도 했었는데, 알고보니 내가 잘못 이해한거였다.. ㅎㅎ 나중에 다시 파이썬으로 해봐야지 싶다.

 

suffix array AC

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;

struct Comparator
{
    const vector<int> &group;
    int t;
    Comparator(const vector<int> &_group, int _t)
        : group(_group), t(_t) {}
    bool operator() (int a, int b){
        if (group[a] != group[b]) return group[a] < group[b];
        return group[a+t] < group[b+t];
    }
};

vector<int> getsa(const string& s){
    int n = s.size();
    int t =1;
    vector<int> group(n+1);
    for(int i=0;i<n;++i) group[i] = s[i];
    group[n] = -1;
    vector<int> sa(n);
    for (int i=0;i<n;++i) sa[i] = i;
    while (t<n){
        Comparator comp(group, t);
        sort(sa.begin(), sa.end(), comp);
        t <<= 1;
        if (t>=n) break;
        vector<int> ngroup(n+1);
        ngroup[n] = -1;
        ngroup[sa[0]] = 0;
        for (int i=1; i < n; ++i){
            if (comp(sa[i-1], sa[i]))
                ngroup[sa[i]] = ngroup[sa[i-1]]+1;
            else
                ngroup[sa[i]] = ngroup[sa[i-1]];
        }
        group = ngroup;
    }

    return sa;
}

vector<int> getlcp(const string& s, const vector<int>& sa){
    int n = s.size();
    vector<int> lcp(n), isa(n);
    for (int i=0; i<n; ++i) isa[sa[i]] = i;
    for(int k=0, i=0;i<n; ++i) if(isa[i]){
        for(int j=sa[isa[i]-1];s[i+k]==s[j+k]; ++k);
        lcp[isa[i]] = (k?k--:0);
    }
    return lcp;
}


int main()
{
    char s[500001];
    scanf("%s",&s);
    int n = strlen(s);
    vector<int> sa = getsa(s);
    for (int i =0; i<n; i++){
        printf("%d ",sa[i]+1);
    }
    printf("\n");
    vector<int> lcp = getlcp(s, sa);
    for (int i=0; i<n; i++){
        if (!i) printf("x ");
        else printf("%d ",lcp[i]);
    }


} // namespace std;

suffix array가 많이 헷갈렸던 이유는 문자열을 직접 다루지 않고, 인덱스로만 다루기 때문이었던 것 같다. 정말 나이브한 구현으로부터 100% 떨어져 있었던 것 같다.

 

(1) 접미사를 사전순으로 정렬해야하는데 이 때 S[i....] 를 i 인덱스로부터 끝까지의 접미사라고 했을 때, i만 가지고 정렬을 실행한다. 정렬하는 방법은 다음과 같다.

 

ㄱ. t길이 만큼을 기준으로 정렬했을 때, t길이 만큼이 같다면 같은 그룹에, 다르다면 다음 그룹에 넣는다. (이 때, 그룹별로 index를 부여한다.)

 

ㄴ. 그 다음에는 2*t 길이 만큼을 기준으로 정렬하는데, 이 때는 이미 그룹이 지어져 있다. 다른 그룹이면 사전순으로, 같은 그룹이면 t만큼 떨어진 접미사의 그룹끼리 정렬한다. 이게 가능한 이유는 현재의 접미사에서 t만큼 떨어진 접미사는 이미 이전 단계에서 그룹이 나누어졌기 때문이다.

 

ㄷ. 이 과정을 반복하여 t가 전체길이보다 길어지면 반복문을 탈출한다.

 

이렇게 해서 정렬을 log n 번 수행할 수 있고, 시간 복잡도는 O(n(logn)^2)이 된다. 파이썬으로는 퀵정렬로 구현 해봤는데 잘 안되더라.. ㅠ

 

(2) lcp(최장 공통 접두사 길이)를 구하는 방법 역시 인덱스로만 다루기 때문에 너무 어려웠던 것 같다. 이번에는 사전순으로 몇 번째 접미사가 들어있는지가 아니라, 접미사가 사전순으로 몇 번째인지를 알아야한다. 따라서 역변환이 가능한 배열을 하나 더 만들어주어야 한다. lcp배열을 구하는 과정은 다음과 같다.

 

ㄱ. 반복문을 사전순으로가 아니라, 인덱스 순으로 돌린다. 

ㄴ. i번째의 사전 순서를 p번째라고 하면, p-1번째와 최대로 접두사가 같아지는 길이를 구한다. 여기서 탐색이 완료 되어, lcp를 k라고 구했을 때, i+1번째 접미사의 개수는 최소 k-1개가 된다. 그 이유는 간단한데, 다음과 같이 보일 수 있을 것 같다.

 

예시:

 사전순 p-1번째, 인덱스 x번째 접미사 :  abc

 사전순 p번째 , 인덱스 i번째 접미사 :    abcde

 lcp : 3개

 

 사전순 ? 번째, 인덱스 x+1번째 접미사 :  bc

 사전순 ? 번째, 인덱스 i+1번째 접미사 :   bcde

 최소 lcp : 2개

 

여기서 '최소'인 이유는 bc와 bcde 사이에 다른 접미사가 올 수도 있기 때문이다. 

 

ㄷ. 그렇게 내가 비교하는 횟수를 전 단계에서 (k-1)개 이미 보충을 했으므로 k개부터 확인하면 된다. 이렇게 k가 최대 증가 하더라도 n을 넘지 않기 때문에 O(n)을 보장하게 되는 것이다. 

 

해당 코드는 알고리즘 문제 해결 전략에서 많은 부분 참고했다. 아무튼 suffix array와 lcp 배열을 이용해서 풀 수 있는 문제들이 많다고 한다. 그 중에서 내가 해결한 것은 부분 문자열의 개수다.

 

5. 부분 문자열의 개수

 

이 녀석은 꽤 애를 먹었는데, 사실.. 문자열 개수를 담은 변수를 충분히 크게 해야했던 것이었다. overflow가 나는 줄 모르고 멘붕이 왔었다. 

서로 다른 부분 문자열의 개수 2 AC

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>

using namespace std;

struct Comparator
{
    const vector<int> &group;
    int t;
    Comparator(const vector<int> &_group, int _t)
        : group(_group), t(_t) {}
    bool operator()(int a, int b)
    {
        if (group[a] != group[b])
            return group[a] < group[b];
        return group[a + t] < group[b + t];
    }
};

vector<int> getsa(const string &s)
{
    int n = s.size();
    int t = 1;
    vector<int> group(n + 1);
    for (int i = 0; i < n; ++i)
        group[i] = s[i];
    group[n] = -1;
    vector<int> sa(n);
    for (int i = 0; i < n; ++i)
        sa[i] = i;
    while (t < n)
    {
        Comparator comp(group, t);
        sort(sa.begin(), sa.end(), comp);
        t <<= 1;
        if (t >= n)
            break;
        vector<int> ngroup(n + 1);
        ngroup[n] = -1;
        ngroup[sa[0]] = 0;
        for (int i = 1; i < n; ++i)
        {
            if (comp(sa[i - 1], sa[i]))
                ngroup[sa[i]] = ngroup[sa[i - 1]] + 1;
            else
                ngroup[sa[i]] = ngroup[sa[i - 1]];
        }
        group = ngroup;
    }

    return sa;
}

vector<int> getlcp(const string &s, const vector<int> &sa)
{
    int n = s.size();
    vector<int> lcp(n), isa(n);
    for (int i = 0; i < n; ++i)
        isa[sa[i]] = i;
    for (int k = 0, i = 0; i < n; ++i)
        if (isa[i])
        {
            for (int j = sa[isa[i] - 1]; s[i + k] == s[j + k]; ++k);
            lcp[isa[i]] = (k ? k-- : 0);
        }
    return lcp;
}

int main()
{
    char s[1000200];
    scanf("%s", &s);
    int n = strlen(s);
    vector<int> sa = getsa(s);
    vector<int> lcp = getlcp(s, sa);
    long long result = (long long)n*(n+1)/2;
    for (int i = 0; i < n; i++)
    {
        result -= (i?lcp[i]:0);
    }
    printf("%lld",result);

} // namespace std;

문자열이 겹치는게 lcp배열의 갯수만큼이기 때문에 전체에서 lcp배열 만큼 빼주면 AC를 받을 수 있다.

 

6. 삼차방정식의 해

 

이 녀석은 상당히 애를 많이 먹은 문제인데, 사실 아직도 애를 먹고 있다.. 다이아 5에 삼차방정식이 하나 더 있는데 그건 도저히 해결을 못하고 있는 중이다... ㅠ 아무튼 이 녀석도 2억번 이상의 연산을 수행해야했기 때문에, c++로 문제를 해결했다. 

 

삼차방정식 AC

아래는 코드이다. 

#include <iostream>
#include <vector>
#include <math.h>
#include <algorithm>

using namespace std;
using lld = long double;
lld eps0 = 0.00000001;
lld eps = 0.000000001;
lld eps2 = 0.00000000001l;
lld a,b,c,d;
lld A,B,C;
int INF = 1000000;

lld f(lld x){
    return a*x*x*x+b*x*x+c*x+d;
}

lld det(lld a, lld b, lld c){
    return b*b-4*a*c;
}


int main()
{
    int N;
    cin >> N;
    while (N--){
        cin >> a >> b >> c >> d;
        int i;
        for (i=-INF;i<=INF;i++){
            lld fi= f(i);
            if (-eps0 < fi && fi < eps0) break;
        }
        A = a;
        B = b+A*i;
        C = c+B*i;
        lld D = det(A,B,C);
        if (D < -eps2){
            cout << i << '\n';
            continue;
        }
        vector<lld> result;
        result.push_back(i);
        if (-eps2 <= D && D <= eps2){
            lld x = -B/(2*A);
            if ((i-x) <-eps || (i-x) > eps) result.push_back(x);
        }
        else {
            lld x1 = (-B-sqrt(D))/(2*A);
            lld x2 = (-B+sqrt(D))/(2*A);
            if (x1>x2){
                lld tmp = x1;
                x1 = x2;
                x2 = tmp;
            }
            if ((i-x1) > eps || (i-x1) < -eps) result.push_back(x1);
            if ((i-x2) > eps || (i-x2) < -eps) result.push_back(x2);
        }
        sort(result.begin(), result.end());
        for (int i=0; i<result.size(); i++){
            printf("%.10Lf ", result[i]);
        }
        cout << '\n';



    }


} // namespace std;

아이디어는 인수분해를 이용한다. -1000000부터 1000000까지 반복문을 돌려서 f(x)가 0이 되는 x를 하나 찾는다. 그리고 조립제법을 이용해서 인수분해하고, 이차방정식 문제를 근의 공식을 이용해서 해결한다. 

 

다만 그대로 출력하면 안되고, 각 근의 차이가 10e-4가 나지 않는다면 적당히 끊어서 출력해야한다. 간단하게 10e-4정도의 정확도는 해결 가능하다. (하지만 10e-9은 도저히 해결이 안된다.. 선생님.. 계신다면 정답을 알려줘 ㅠㅠㅠㅠㅠ 독학러의 슬픔.. ㅠ) 고정 소수점 클래스를 직접 구현해서 구해봐야하나.. 싶기도 하다.. ㅠ 도전 의식이 풀타오르지만.. 너무 힘들다.. ㅋㅋ;;

 

 

7. Splay Tree

 

스플레이 트리는 내가 제일 좋아하는 자료구조 중에 하나지만.. 솔직히 좀 어렵다. 레드블랙트리나 AVL트리를 구현해보지 않아서 그럴수도 있는데, 아직 나한테는 구현 난이도가 좀 있는 편이다. 아무튼 현재 c++을 이용해서 열심히 스플레이 트리를 구현하고 문제를 해결해보고자 하고 있다. 빠른 시일 내에, '자료 구조' 문제랑 '수열과 쿼리 2'를 해결하기를 기원한다.. ㅎㅎ

 

스플레이 트리를 열심히 구현하고 있는 모습

 

앞으로 하고 싶은 것들

 

이번에 강의를 들으면서 하고 싶은게 여러개 생겼는데, 게임같은 걸 만들어보면 재밌겠다고 생각하게 되었다. 물론 게임을 좋아하지도 않는 내가 게임을 만든다는게 뭔가 이상하기도 한데.. 아무튼 그렇다. 강사님이 게임 업계에서 근무하셨던 분이라 그런지 게임에서 코드가 작동하는 방식으로 많은 설명을 해주셨다. 그러다보니 자연스레 흥미가 갔던 것 같다. unity로 게임을 만들어보고 싶기도 한데, 또 unity는 C#을 배워야하니까, 언리얼 엔진을 가지고 게임 공부를 해볼까 싶기도 하다. 다만 패스트캠퍼스에는 아직 언리얼 엔진을 가르쳐주는 강의는 없는 것 같더라 ㅠ 인프런에 좋은 강의가 있는 것 같아서 그 쪽에서 강의를 들을까 고민 중이기도 하다. MMORPG 같은 걸 만들어보면 나름 공부에 도움도 되고, 또 알고리즘을 비교적 많이 사용하기 때문에, 내 적성에도 좀 맞을 것 같다는 생각이 든다. c++을 사용하는 일을 더 해보고 싶다.

 

그리고 두 번째는 파이썬 데이터 분석 강의를 듣는 것이다. 데이터 분석은 갑자기? 라는 생각이 들지도 모르겠지만, 원래 코딩을 데이터 분석으로 시작했었다. 학교의 해양학 연구실에서 3개월 정도 데이터 처리를 해본 적이 있었다. 어차피 학교 졸업논문 쓰려면 파이썬으로 데이터 처리도 해봐야하고, 또 나중에 어찌되었건 데이터 분석은 도움이 될 것이기도 하기 때문에 고민 중이다. 패스트캠퍼스에서 들을 생각인데, '한 번에 끝내는 머신러닝과 데이터분석 A-Z' 개인적으로 이 강의가 좋지 않을라나 생각 중이다. 머신러닝도 궁금하기도 했으니 말이다. (근데 그러면 데이터 분석 쪽은 강의가 좀 약하려나..? ㅠ 추천좀 해줬으면 좋겠다..! ㅠ) 마침 12월 12일까지 1+1 이벤트도 하고 있으니, 지금 구매해두면 다음번에 좋은 강의를 하나 더 get할 수 있을 것 같다. 그 다음 강의는 '한 번에 끝내는 컴퓨터 공학 전공필수&인공지능 심화 초격차 패키지'로 생각 중이다. 컴공 관련된 공부는 평생할 것이기 때문에 지금이라도 조금씩 기초를 다져놓는게 좋지 않을까 싶다.

 

 

ㄱ. 그래서 패스트캠퍼스 챌린지. 추천하는가??

 

추천한다. 돈이 짱이다. 돈이 없으면 공부도 못하고, 연애도 못하고, 밥도 못먹는다. 

 

ㄴ. 이 프로그램 별점 10개로 매긴다고 하면 어느정도로 주겠는가?

 

★★★★★★★☆☆☆

 

7개 주겠다. 솔직하게 얘기하면 매일매일 주말도 없이 하는건.. ㅎㅎ 여간 쉬운일이 아니다. 시간적 여유가 있다면 정말 좋은 프로그램이다. 환급해주고, 공부도 하고, 이렇게 좋은 프로그램이 어디에 있겠는가..?

 

ㄷ. C++ 실력 완성 올인원 패키지. 어떤가?

 

★★★★★★★☆☆☆

 

이것도 별 7개 정도이다. 개인적으로 강사님이 좀 어눌하시고, 말씀을 잘 못하셨다.. ㅎㅎ 그래서 조금 알아듣기 어려울 때가 많았지만, 그래도 내용은 정말 알차고 좋았다. 그걸 전달하는 게 좀 아쉬웠을 뿐.. 프로그래밍 언어를 아예 처음 배우시는 분들은 조금 비추이고, 파이썬이나, 자바같은 언어만 공부하신 분들이라면 추천한다. 내용은 정말 좋으니 열심히 들으면 남는 것이 분명 있을 것이다. 

 

한 달 동안의 여정, 이것으로 마무리 짓는 것이 좋겠다. 혹시나 질문이 있으시다면 댓글 달도록 하겠다.

 

본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.

패스트캠퍼스 : https://bit.ly/3FVdhDa

 

수강료 100% 환급 챌린지 | 패스트캠퍼스

딱 5일간 진행되는 환급챌린지로 수강료 100% 환급받으세요! 더 늦기전에 자기계발 막차 탑승!

fastcampus.co.kr

 

#패스트캠퍼스 #패캠챌린지 #직장인인강 #직장인자기계발 #패스트캠퍼스후기 #C++실력완성올인원패키지

댓글