CPP01-2

JUSTICE_DER·2023년 3월 27일
0

⏲ CPP - 코딩테스트

목록 보기
4/41

7. 16205 - 문자열

언어마다 천차만별인 문자열 관련 기능들을 알아야만 풀 수 있는 문제이므로..
기초적인 대략의 풀이만 참고한다.


소문자가 대문자+32 라는 것을 알아야만 할 것이다.

시도

#include <iostream>
using namespace std;

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

    int var_mode;
    string input;
    string camel, snake, pascal;

    cin >> var_mode >> input;

    switch (var_mode)
    {
    // camel
    case 1:
        camel = input;

        //snake
        for(int i=0; i<input.size();i++){
            if('a' <= input[i] && input[i]<= 'z'){
                snake+=input[i];
            }
            else{
                snake+='_';
                snake+= input[i]+32;
            }
        }

        //pascal
        pascal = input;
        pascal[0] = pascal[0]-32;
        break;

    // snake
    case 2:
        snake = input;

        //camel
        for(int i=0; i<input.size();i++){
            if('a' <= input[i] && input[i]<= 'z'){
                camel+=input[i];
            }
            else{
                camel+= input[i+1]-32;
                i=i+2;
            }
        }

        //pascal
        pascal = camel;
        pascal[0] = pascal[0]-32;
        break;

    // pascal
    case 3:
        pascal = input;

        //camel
        camel = pascal;
        camel[0] = camel[0] + 32;

        //snake
        for(int i=0; i<input.size();i++){
            if('a' <= input[i] && input[i]<= 'z'){
                snake+=input[i];
            }
            else{
                if(i!=0){
                    snake+= '_';
                }
                snake+= input[i]+32;
            }
        }

        break;
    }
    cout << camel << "\n" << snake << "\n" << pascal;

    return 0;   
}

틀렸는데 왜인지 모르겠다.
반례도 적다. 심지어 저 반례도 통과했다.

위기다.

카멜표기법을 스네이크나 파스칼로 변환하는 것에는 문제가 없을 듯 하다.
카멜에서 파스칼로 변환시, 그냥 맨 앞문자만 대문자로 바꾸면 되고, 작동하고,
카멜에서 스네이크로 변환시, 카멜의 맨 앞글자가 소문자라서 Camel _camel 이런 경우도 존재할 수가 없다.


스네이크를 카멜, 파스칼로 변환하는 것에는?
스네이크를 카멜로 바꾸는데에, 언더바를 무시하고, i+1인 다음 문자의 값을 -32를 하여 대문자로 만든다. 그리고, i를 문자의 2칸 뒤로 간다.
이 경우, 맨 앞문자가 대문자가 될 일은 절대 없으므로 여기서 오류는 나지 않을 것이다.

i를 문자의 2칸 뒤로 간다는 부분이 문제가 될 수도 있겠다는 생각이다.
length 이후의 값으로 넘어간다면?
hello_c인 경우가 되겠다.

전혀 문제 없다.
그리고 카멜이 문제가 없다면 파스칼도 있을 수가 없는데,
카멜의 맨 앞글자만 또 바꾸면 파스칼이 되기 때문이다.


파스칼을 카멜로 바꾸는 경우, 역시 맨 앞글자만 소문자로 만들면 된다.

파스칼을 스네이크로 바꾸는 경우, 대문자인 부분을 _ 를 추가하고,
소문자인 문자로 바꿔서 추가하면 되는데,

PasCal인 경우, _pas_cal일 수가 있어서 if문으로 인덱스가 0이면 추가하지 않도록 했다.
그리고 snake라서 소문자를 추가하도록 했는데...음..

문제를 모르겠다!!


조건을 봐도, 연속해서 _ _ 이렇게 언더바가 사용되는 경우도 없을 뿐더러,
마지막에 언더바가 나올 수가 없다. 항상 소문자를 추가하므로..

해결

#include <iostream>
using namespace std;

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

    int var_mode;
    string input;
    string camel, snake, pascal;

    cin >> var_mode >> input;

    switch (var_mode)
    {
    // camel
    case 1:
        camel = input;

        //snake
        for(int i=0; i<input.size();i++){
            if('a' <= input[i] && input[i]<= 'z'){
                snake+=input[i];
            }
            else{
                snake+='_';
                snake+= input[i]+32;
            }
        }

        //pascal
        pascal = input;
        pascal[0] = pascal[0]-32;
        break;

    // snake
    case 2:
        snake = input;

        //camel
        for(int i=0; i<input.size();i++){
            if('a' <= input[i] && input[i]<= 'z'){
                camel+=input[i];
            }
            else{
                camel+= input[i+1]-32;
                i=i+1;
            }
        }

        //pascal
        pascal = camel;
        pascal[0] = pascal[0]-32;
        break;

    // pascal
    case 3:
        pascal = input;

        //camel
        camel = pascal;
        camel[0] = camel[0] + 32;

        //snake
        for(int i=0; i<input.size();i++){
            if('a' <= input[i] && input[i]<= 'z'){
                snake+=input[i];
            }
            else{
                if(i!=0){
                    snake+= '_';
                }
                snake+= input[i]+32;
            }
        }

        break;
    }
    cout << camel << "\n" << snake << "\n" << pascal;

    return 0;   
}

풀이

찾았다.


+1만 했었어야 했다. 왜?

_를 만나는 경우, 언더바가 있는 곳이 i번째이고,
i+1번째가 다음 문자인데, 다음 문자도 건너 뛴 곳으로 가려면,
i+1로 i를 만들어놔야, for문 줄에서 바로 1이 또 추가가 되므로 i+2로 예상한 곳으로 가게 된다.
그 전에는 i+3으로 갔던 것임..


백준에 반례가 없는 경우가 제일 무서운 것 같다.

  • 문자열 관해서는 +로 손쉽게 글자를 추가할 수 있다는 것과,
    숫자를 +할 시에는 32로 소문자 대문자를 바꿀 수 있다는 것,
    'a' < ch 이런식으로 범위지정도 가능하다는 것,
    그리고 size를 통해서 문자 하나하나마다 for문을 돌릴 수 있다는 것 정도를 배웠다.

8. 2592 - Map

해결

#include <iostream>
#include <map>
using namespace std;

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

    int sum = 0;
    int num;
    int max = 0;
    int max_key;
    map<int, int> appearMap;

    for(int i=0;i<10;i++){
        cin >> num;
        
        //찾지 못한 경우
        if(appearMap.find(num) == appearMap.end()){
            appearMap.insert({num, 1});
        }
        else{
            appearMap[num] += 1;
        }

        sum += num;
    }

    //map<int,int>::iterator == auto
    for(auto iter = appearMap.begin(); iter!=appearMap.end(); iter++){
        if(max < iter->second){
            max = iter->second;
            max_key = iter->first;
        }
    }

    cout << sum/10 << "\n" << max_key;

    return 0;   
}

풀이

한 번에 풀게 되었다.
평균과 최빈값을 구하는 문제인데, 평균은 어려운게 아니고,
최빈값을 어떻게 구할지가 까다로웠는데, map구조가 생각났고,
map을 통해서 쉽게 구현할 수 있었다.

map라이브러리를 추가하고, <int,int> 구조의 map을 만들었다.
각 입력 숫자들을 key로 사용할 것이고, 빈도수를 value로 사용할 것이다.

  • appearMap.find(num) == appearMap.end() 구문을 통해, 찾지 못한 경우를 알 수 있었다.
    map.find를 실패하면, map.end값으로 설정된다고 하여, 해당 if문을 작성할 수 있었다.

  • appearMap[num] += 1;
    기존에 key가 존재했다면, 해당 num이라는 key값에 해당하는 map의 인덱스의 값에, 1을 추가한다.
    당연히 value가 int형이기 때문에 가능한 일.
    string이었다면, 문자가 한개씩 뒤에 추가되도록 구현도 가능할 듯..

  • 이 부분이 가장 의미있다고 생각하는데, iterator를 사용한다.
    iterator는 간단히 말하면, 자료형을 순회할 목적으로 만들어졌고,
    자료형마다 쓰이는 이름이 iterator로 같지만 원리는 다르게 동작하도록 overload되었다.

  • 여기서 auto로 간단히 적었지만, map<int,int>::iterator의 자료형을 가지고 있고,
    map의 값을 pair로 담을 수 있는 듯 하다. 각 원소에 접근도 가능한데,
    first는 key값이고, second는 value값을 의미한다.

9. 2930

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

스킵 - 문제 자체가 설명도 부실하고, 모호한 표현이 많아서 이해가 되질 않는다.
심지어는 예시나 반례도 부족하고...

5
가위 가위 보 보 바위

보 보 바위 바위 가위
바위 바위 가위 가위 보

처음은 그냥 순서 그대로 감
승승승승승
패패패패패 => 10점

두번째는 상근이 순서바꿈

보 보 바위 가위 가위
보 보 바위 바위 가위
바위 바위 가위 가위 보

비비비패비 >4점
승승승비패 > 7점 => 11점?

9. 1157 - 문자열 / Map

시도

#include <iostream>
#include <map>
using namespace std;

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

    map<char, int> strmap;
    int max = 0;
    char max_char;
    int same_count = 0; //같은 빈도수 체크

    string s_input;
    cin >> s_input;

    for(int i=0;i<s_input.length();i++){
        if('A' <= s_input[i] && s_input[i] <= 'Z'){
            if(strmap.find(s_input[i])==strmap.end()){
                strmap.insert({s_input[i], 1});
            }
            else{
                strmap[s_input[i]] += 1;
            }
        }
        else if('a' <= s_input[i] && s_input[i] <= 'z'){
            if(strmap.find(s_input[i]-32)==strmap.end()){
                strmap.insert({s_input[i]-32, 1});
            }
            else{
                strmap[s_input[i]-32] += 1;
            }
        }
    }

    map<char, int>::iterator iter;
    for(iter = strmap.begin(); iter!=strmap.end(); iter++){
        if(max <= iter->second){
            max = iter->second;
            max_char = iter->first;
        }
    }

    for(iter = strmap.begin(); iter!=strmap.end(); iter++){
        if(max == iter->second){
            same_count++;
        }
    }

    if(2 <= same_count){
        cout << '?' << same_count;
    } 
    else{
        cout<< max_char;
    }

    return 0;   
}

baaa가 다음과 같이 성공적으로 map이 되었다.

하지만 정답은 아님.

왜일까?

해결

가장 많이 사용된 알파벳이 여러 개 존재하는 경우에는 ?를 출력한다.
에서 ?만 출력해야했는데 이상한 코드를 작성했었던 것이다.

Mississipi

#include <iostream>
#include <map>
using namespace std;

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

    map<char, int> strmap;
    int max = 0;
    char max_char;
    int same_count = 0; //같은 빈도수 체크

    string s_input;
    cin >> s_input;

    for(int i=0;i<s_input.length();i++){
        if('A' <= s_input[i] && s_input[i] <= 'Z'){
            if(strmap.find(s_input[i])==strmap.end()){
                strmap.insert({s_input[i], 1});
            }
            else{
                strmap[s_input[i]] += 1;
            }
        }
        else if('a' <= s_input[i] && s_input[i] <= 'z'){
            if(strmap.find(s_input[i]-32)==strmap.end()){
                strmap.insert({s_input[i]-32, 1});
            }
            else{
                strmap[s_input[i]-32] += 1;
            }
        }
    }

    map<char, int>::iterator iter;
    for(iter = strmap.begin(); iter!=strmap.end(); iter++){
        if(max <= iter->second){
            max = iter->second;
            max_char = iter->first;
        }
    }

    for(iter = strmap.begin(); iter!=strmap.end(); iter++){
        if(max == iter->second){
            same_count++;
        }
    }

    if(2 <= same_count){
        cout << '?'; // 이부분..
    } 
    else{
        cout<< max_char; 
    }

    return 0;   
}

풀이

단순히 디버그용 출력 메세지를 그대로 붙여넣었던 것이었다.
확실히 Map이 시각적으로 보이니까 훨씬 동작원리를 빠르게 캐치할 수 있게 된다.


1일차 - 9문제

브론즈4부터 브론즈1까지 풀었다.
특별한 알고리즘을 사용하지는 않았고, 브루트포스, 버블정렬외에는 사용하지 않았다.
실버 4까지가 프로그래머스 1정도인데, 분발할 필요가 있어보인다.

알게된 것들

  • 입출력관련 2가지 명령어

  • CPP 이미 선언한 배열의 초기화는 fill_n을 사용할 것..

  • 브루트포스 - 무식하게 for문 돌림 / 그 for문에서 원하는 값만 가지고 빠져나오는 기술이 필요

  • 버블정렬 - 쉬움, 다만 헷갈릴 수도 있음.

  • 문자열 대소문자는 32차이, 소문자가 값이 더 큼

  • 문자열 + 문자 = 문자열 뒤에 문자 붙이기

  • 문자열 + 정수 = 문자열 아스키코드에 정수 더하기

  • 문자열의 비교연산자 = 문자열 아스키코드를 비교

  • 문자열.size를 통해서 0부터 문자열.size까지 문자열[i]를 돌 수 있다.
    해당 원소는 문자이다.

  • Map.find(키)로 해당 키값을 찾지 못한다면, Map.End()값과 같아진다.
    이를 활용하여 if문 가능

  • Map[키]로 직접 키에 해당하는 value값을 수정할 수 있다.
    value값처럼 연산도 가능하다.

  • iteraor를 사용하여 순회가 가능하다.

auto iter = Map.begin(); iter!=Map.end(); iter++

여기서 iter는 값의 쌍이고, first는 key, second는 value를 의미한다.

  • 문자열과 Map을 동시에 연마하고 싶다면 1157 문제를 풀어볼 것.
profile
Time Waits for No One

0개의 댓글