[C++/프로그래머스] 신규 아이디 추천

다곰·2022년 11월 29일
0

우당탕탕 코테준비

목록 보기
23/98

✅ LV.1

📌 2021 KAKAO BLIND RECRUITMENT

✏️ 솔루션

1-2단계

  1. 알파벳 대문자이면 tolower 함수로 소문자로 변경
  2. 비허용 문자인 경우 erase 함수로 해당 문자 지우기

3-4단계 ➡️ 문자가 . 인지 check

❗️ bool dup: 앞의 문자가 . 인지 확인하기 위한 변수
❗️ 문자 지우고 나면 idx++ 해주지 않음

  1. 첫번째 인덱스가 . ➡️ erase 함수로 문자 지우기
  2. 다른 인덱스가 .
    1) dup=false 이면 앞 자리가 . 이 아니기 때문에 idx++
    2) dup=true 이면 앞 자리가 . 이기 때문에 erase 함수로 문자 지우기
  3. 마지막 인덱스가 . ➡️ erase 함수로 문자 지우기

5단계 ➡️ new_id가 빈 문자열이면 a 삽입
6단계

  1. new_id가 16자 이상이면 substr 로 15자까지만 잘라주기
  2. 마지막 인덱스가 . ➡️ erase 함수로 문자 지우기

7단계

  1. 문자가 1자리이면 0번째 문자 두번 더 붙여주기
  2. 문자가 2자리이면 문자열 끝에 1번째 문자 붙여주기

📌 self feedback

구현은 단계를 어떻게 쪼개는가가 관건
인덱스 옮겨가면서 탐색하더라도 전체 길이가 가변적이면 for 문 보다는 while 문 쓰면서 idx 변수 따로 관리해주는 방법 사용하기

✏️ code

#include <string>
#include <vector>

using namespace std;

string solution(string new_id) {
    string answer = "";

    int idx=0;
    while(idx<new_id.size()) {
        // 1단계
        if(new_id[idx]>=65&&new_id[idx]<=90) {
            new_id[idx]=tolower(new_id[idx]);
            idx++;
        }
        //2단계
        else if((new_id[idx]>=97&&new_id[idx]<=122)||(new_id[idx]>=48&&new_id[idx]<=57)||new_id[idx] =='.' ||new_id[idx] =='_'||new_id[idx] =='-') {
            idx++;
        }
        else new_id.erase(idx,1);

    }
    
    // 3-4단계
    idx=0;
    bool dup=false;
    while(idx<new_id.size()) {

        if(new_id[idx]=='.') {
            if(idx==0) new_id.erase(0,1);
            else if(!dup) {
                dup=true;
                idx++;
            }
            else new_id.erase(idx,1);
        }
        else {
            dup=false;
            idx++;
        }

    }
    
    // 4단계
    if(new_id[new_id.size()-1]=='.') new_id.erase(new_id.size()-1,1);
    
    //5단계
    if(new_id=="") new_id="a";
    
    //6단계
    if(new_id.size()>=16) new_id=new_id.substr(0,15);
    if(new_id[new_id.size()-1]=='.') new_id.erase(new_id.size()-1,1);
    
    //7단계
    if(new_id.size()==1) {
        new_id+=new_id[0];
        new_id+=new_id[0];
    }
    else if(new_id.size()==2) new_id+=new_id[1];
    
    return new_id;
}

📌 아쉬운 부분

  1. if 문, while 문이 너무 많아서 비효율
  2. 코드가 너무 복잡하고 문자열 지울 때 erase 함수가 최선일까
  3. 연속 . 처리할 때, flag 처리하면서 또 while 문 쓰는 게 최선일가
  4. 문자열 처음과 마지막 . 인지 확인하는 것도 인덱스 조회해서 하는 방법이 최선일까

✏️ 개선 솔루션

new_id에서 비허용 문자를 지우는 방식이 아니라 허용 문자만 result 문자열에 붙이는 방식으로 전개

  1. char 형 범위 ➡️ 아스키코드 값 쓰지 않고도 비교 가능
    ex) 'A' <= ch && ch <= 'Z'
  2. 대문자 ➡️ 소문자 변환⭐️
    ex) ch |= 32 ➡️ |= 비트 연산자 사용해서 or 연산 결과 저장
  3. new_id 를 한 문자씩 검사할 때 해당 문자가 "-_." 이 문자열에 포함되는지 strchr 함수로 검사
  4. stringvector 처럼 멤버함수 사용 가능
    ➡️ 마지막 문자와 첫번째 문자 확인은 s.front(), s.back() 활용
    ➡️ 마지막 문자 삭제: s.pop_back()
    ➡️ 첫번째 문자 삭제: s.erase(s.begin())

🔗 strchr 함수
🔗 [C++] string 총정리

✏️ 개선 코드

#include <bits>
using namespace std;

string solution(string new_id) {
    for (char& ch : new_id) if ('A' <= ch && ch <= 'Z') ch |= 32;

    string ret;
    for (char& ch: new_id) {
        if ('a' <= ch && ch <= 'z' ||
            '0' <= ch && ch <= '9' ||
            strchr("-_.", ch)) ret += ch;
    }

    new_id = ret;
    ret.clear();
    for (char& ch: new_id) {
        if (!ret.empty() && ret.back() == '.' && ch == '.') continue;
        ret += ch;
    }

    if (ret.front() == '.') ret.erase(ret.begin());
    if (ret.back() == '.') ret.pop_back();

    if (ret.empty()) ret = "a";
    if (ret.size() >= 16) ret = ret.substr(0, 15);
    if (ret.back() == '.') ret.pop_back();
    while (ret.size() <= 2) ret += ret.back();

    return ret;
}
profile
다교미의 불꽃 에러 정복기

0개의 댓글