관리 메뉴

有希

HackerRank/Plus Minus 본문

프로그래밍/알고리즘+코딩테스트

HackerRank/Plus Minus

有希. 2022. 3. 29. 19:01

Interview Preparation Kits가 있길래 이것도 풀어보려 한다.

plusMinus함수 부분만 채우면 되는데, 기본적으로 작성된 코드가 꽤 재미있다.

find_if는 첫번째인자~두번째인자까지 순회하며 세번째 인자와 맞는 원소를 가리키는 iterator를 반환한다. 없다면 두번째 인자를 뱉는다. 그런데, 세번째 인자가 not1(어떤 함수객체에 붙어서 결과를 반대로. 2의 배수를 찾는 것이라면 2의 배수가 아닌 녀석일때 true가 된다) 붙어서 ptr_fun<int, int> 가 되어있다.

그럼 ptr_fun은 무엇인가 하고 또 의문이 생긴다.  이는 함수 포인터를 래핑해서 함수 포인터 어댑터로 만들어서 템플릿인수를 적용할 수 있도록 해준다. 즉, 템플릿 문법이 적용된 인자에 어떤 함수를 쓰고 싶을때 쓴다. 첫번째 int는 함수의 argument이고 두번째 int는 함수의 return이 되도록 해준다.

즉, 정리하면 ltrim과 rtrim에 있는 find_if는 처음부터 끝까지 순회하며 처음 등장하는 공백이 아닌 녀석의 위치를 반환한다. -> 처음과 끝에 있는 공백들을 모두 제거한다. 모던 C++을 굉장히 잘 활용하고 있다. 이런건 처음 봤는데 굉장히 우아하다.

예시로,  "    a b c "를 ltrim에 넣으면 "a b c "가 되고, rtrim에 넣으면 "    a b c"가 된다.

아무튼, 처음 들어오는 배열의 사이즈 값인 int하나를 저렇게 저장한다.

그리고 오른쪽의 공백을 모두 제거하고 문자열로 들어온 벡터를 split으로 저장한다.

split함수를 보면,

end = str.find(" ", start)) != string::npos가 있다.

find함수는 원하는 것을 찾지 못했을 때 npos를 반환한다. 즉, while문은 더이상 공백을 없을 때까지 계속해서 동작한다.

end는 공백의 위치를 저장한다. 즉, tokens 벡터에 앞에서부터 공백이전까지 밀어 넣는다.

그리고, 다음 루프에서는 공백 앞에서부터 다음 공백까지 밀어 넣는다. 

그리고, while에서 빠져나와서 tokens에 start부터 전부 넣는다. <- 이것을 하는 이유는  "1 2 3"을 생각해보자. 2까지 넣은 다음에는 다음 공백이 없기 때문에 3을 넣지 않고 그대로 빠져나온다. start는 4인 상태이고. 항상 마지막 녀석은 넣지 않고 나와버리기 때문에 이렇게 해준다. substr(start, len) 인데, start+len이 문자열을 오버한다면 끝까지만 넣고 반환한다.

아무튼, 이렇게 해서 다음과 같은 input을 처리하는 것이다.

#include <bits/stdc++.h>

using namespace std;

string ltrim(const string &);
string rtrim(const string &);
vector<string> split(const string &);

/*
 * Complete the 'plusMinus' function below.
 *
 * The function accepts INTEGER_ARRAY arr as parameter.
 */

void plusMinus(vector<int> arr) {
    short positive=0;
    short negative=0;
    short zero=0;
    
    for(char i=0; i<arr.size(); ++i)
    {
        if(arr[i] > 0) positive++;
        else if(arr[i] < 0) negative++;
        else zero++;
    }
    std::setprecision(6);
    cout << static_cast<float>(positive)/arr.size() << endl;
    cout << static_cast<float>(negative)/arr.size() << endl;
    cout << static_cast<float>(zero)/arr.size() << endl;
}

int main()
{
    string n_temp;
    getline(cin, n_temp);

    int n = stoi(ltrim(rtrim(n_temp)));

    string arr_temp_temp;
    getline(cin, arr_temp_temp);

    vector<string> arr_temp = split(rtrim(arr_temp_temp));

    vector<int> arr(n);

    for (int i = 0; i < n; i++) {
        int arr_item = stoi(arr_temp[i]);

        arr[i] = arr_item;
    }

    plusMinus(arr);

    return 0;
}

string ltrim(const string &str) {
    string s(str);

    s.erase(
        s.begin(),
        find_if(s.begin(), s.end(), not1(ptr_fun<int, int>(isspace)))
    );

    return s;
}

string rtrim(const string &str) {
    string s(str);

    s.erase(
        find_if(s.rbegin(), s.rend(), not1(ptr_fun<int, int>(isspace))).base(),
        s.end()
    );

    return s;
}

vector<string> split(const string &str) {
    vector<string> tokens;

    string::size_type start = 0;
    string::size_type end = 0;

    while ((end = str.find(" ", start)) != string::npos) {
        tokens.push_back(str.substr(start, end - start));

        start = end + 1;
    }

    tokens.push_back(str.substr(start));

    return tokens;
}