알고리즘 부셔버렷/ProblemSolving

[프로그래머스] [1차] 뉴스 클러스터링 (문제 설명, 해결 과정, 코드 전문, c++)

Unagi_zoso 2022. 6. 6. 19:43

 

  문제 설명

 

 

본 문제는 프로그래머스의 [1차] 뉴스 클러스터링 문제입니다.

 

출 처 : https://programmers.co.kr/learn/courses/30/lessons/17677

 

  해결 과정

 

 

입력형식에서 볼 수 있듯 대소문자에 대한 구분을 하지 않습니다. 모든 알파벳을 소문자로 바꾸고

각 문자열에서 앞 뒤 모두 알파벳인 경우를 추출해 배열에 담습니다. 

이후 합집합과 교집합의 수를 구해야하는데 합집합은 두 배열의 사이즈의 합에서 교집합의 수 만큼 뺸 것이니

교집합만을 구하면 됩니다. 교집합을 구하기 위해 두 배열 중 하나가 다 탐색될 때까지 순회합니다.

이 과정에서 중복을 허용해야하기 때문에 한 번 접근했던 부분은 visited 배열을 두어 똑같은 위치에 대한 중복을 방지합니다. 그리고 이 과정이 끝나고 나면 출력 형식에 맞춰 연산하고 반환합니다.

 

 

 

 

 

  코드 전문

 

 

#include <string>
#include <vector>
#include <cctype>
#include <algorithm>

using namespace std;

void parser_alpha_lower(string& str)
{
    for (char& ch : str)
        if (ch >= 'A' && ch <= 'Z') ch += ('a' - 'A');
}

vector<string> get_parser_vec(string &str)
{
    vector<string> v;
    string t_str{ "" };
    for (int i = 0; i < str.size() - 1; i++)
    {
        if (isalpha(str[i]) == 1024 && isalpha(str[i+1]) == 1024) // isalpha는 컴파일러마다 반환값 달라 대문자1 소문자2 반환, 대소문자 구분 없이 1024반환
        {
            t_str += str[i]; t_str += str[i+1];
            v.emplace_back(t_str);
            t_str.clear();
        }
    }
    return v;
}
int solution(string str1, string str2) {
    int answer = 0;
    vector<string> v1;
    vector<string> v2;
    parser_alpha_lower(str1);
    parser_alpha_lower(str2);
    //transform(str1.begin(), str1.end(), str1.begin(), ::tolower);
    //transform(str2.begin(), str2.end(), str2.begin(), ::tolower);
    v1 = get_parser_vec(str1);
    v2 = get_parser_vec(str2);

    int sum_size = 0;
    int prod_size = 0;
    vector<int> visited(v2.size(), 0);
    for (int i = 0; i < v1.size(); i++)
    {
        for (int j = 0; j < v2.size(); j++)
        {
            if (visited[j] == 1) continue;
            if (v1[i] == v2[j])
            {
                visited[j] = 1;
                prod_size++;
                break;
            }
        }
    }
    sum_size = v1.size() + v2.size() - prod_size;

    if (prod_size == 0 && sum_size == 0) return 65536;
    answer = (int)(65536 * ((double)prod_size / (double)sum_size));
	// return sum_size ? 65536 * prod_size / sum_size : 65536;

    return answer;
}

 

 

 

 

  느낀 점 (잡설 99% , 배운점 1%(많은 편))

 

 

중복이란 말에 multiset, map을 사용하여 만들다가 코드가 너무 복잡해져 그만뒀습니다. set, map의 key로 string을 넘길 때 rvalue만 넣으라고 뜨는데 lvalue는 왜 못 넣는건가 의문이 들었네요. template argument deduction 으로 좀 알아봐도 감이 안 잡히네요.  요번에 범한 실수는 string에서 추출한 문자들을  string의 + 연산과 햇갈려 그냥 더하기 연산을 시킨 것이 인상 적입니다. cctype의 isalpha 함수는 컴파일러에 따라 반환값이 달랐습니다. vsstudio에서는 nonalpha : 0, 대문자 : 1, 소문자 : 2, clang에서는 nonalpha : 0, 대소문자 :1024이었습니다.

이번 문제를 풀며 기억에 남는건 중복을 위해 visited 배열을 사용하였던 것 그리고 문제의 키워드에 너무 빠져 코드를 복잡하게 만들지 않을 것.

 

 

 

 

 

 

긴 글 읽어주셔서 감사합니다. 

부족한 점이 있다면 부디 알려주시면 감사하겠습니다.