GPT 계열 토크나이저는 바이트 페어 인코딩을 사용합니다. 한 글자씩에서 시작해, 가장 흔한 이웃 쌍을 새로운 기호로 반복해서 합칩니다.
words의 각 단어를 문자로 나눕니다. 반복되는 단어는 여러 번 셉니다.- 모든 단어에서 인접한 기호 쌍을 모두 셉니다.
- 가장 자주 나오는 쌍을 고릅니다. 동률이면 (첫 기호, 두 번째 기호)를 문자열로 비교해 가장 작은 쌍을 고릅니다.
- 그 쌍이 나오는 곳을 왼쪽에서 오른쪽으로 모두 합친 기호로 바꾸고, 합친 기호를 기록합니다.
- 이를
num_merges번 반복하며, 기호가 두 개 이상 남은 단어가 없으면 일찍 멈춥니다.
bpe_merges(words, num_merges)를 구현하세요.
입력
words: 학습용 단어 (소문자).
num_merges: 학습할 병합 횟수.
출력
합친 기호를 학습한 순서대로 반환하세요.
제약 조건
1 ≤ 단어 수 ≤ 1,000, 1 ≤ 각 단어의 길이 ≤ 30
0 ≤ num_merges ≤ 200
예시
입력:
words = ["low", "lower", "lowest"]
num_merges = 2
예상 출력:
["lo", "low"]
설명
쌍: "l o"와 "o w"가 각각 3번 나옵니다. 동률이므로 "l o"를 고르고("l" < "o") "lo"가 됩니다. 이제 "lo w"가 3번 나와 "low"가 됩니다. 결과: ["lo", "low"].
입력:
words = ["aaa"]
num_merges = 3
예상 출력:
["aa", "aaa"]
설명
"aaa"에는 "a a" 쌍이 두 번 있습니다. 왼쪽부터 합치면 "aa" + "a"가 됩니다. 그다음 "aa a"가 "aaa"로 합쳐지고 단어가 기호 하나만 남으므로, 세 번째 병합은 할 것이 없습니다. 결과: ["aa", "aaa"].
참고 자료
-
예시 1 미실행입력:
words = ["low", "lower", "lowest"] num_merges = 2예상 출력:["lo", "low"]내 출력 -
예시 2 미실행입력:
words = ["aaa"] num_merges = 3예상 출력:["aa", "aaa"]내 출력
제출 시 4개의 숨겨진 테스트도 실행됩니다.
온라인 C++ 컴파일러 및 디버거
서버 모드 GDB에서 중단점, 변수 확인과 단계별 실행으로 C++를 디버깅하세요.
주제별 탐색
실용 코드, 출력, 메모리 모델, 자료 구조, 알고리즘과 모던 C++를 통해 두 언어를 함께 학습하세요.
💻 이 C++ 온라인 실행기 소개
CodeUtility C++ Executor는 브라우저에서 바로 C++ 코드를 작성하고 실행할 수 있게 해줍니다 — 설치나 컴파일러 설정이 전혀 필요 없습니다. 안전한 샌드박스에서 동작하며, C++11, C++14, C++17부터 최신 버전까지 실제 C++ 표준을 지원합니다.
이 도구는 클라우드에서 실제 C++ 컴파일러로 코드를 컴파일하고 실행하므로, 버전 간에 정확하고 일관된 동작을 보장합니다. 변수, 함수, 반복문, 조건문, 객체지향 프로그래밍 같은 핵심 C++ 개념을 자유롭게 실험해 보세요.
인터뷰 대비, 최신 C++ 기능 학습, 알고리즘 로직 검증 등 어떤 목적이든, CodeUtility C++ Executor는 어떤 기기에서든 즉시 코드를 실행할 수 있는 간단하면서도 강력한 환경을 제공합니다.
하나의 실행기에서 다중 파일 편집기, 격리된 실행 터미널, 런타임별 라이브러리, 영구 작업 공간, 공유 및 실시간 협업을 이용하세요.
이 실행기는 어떻게 사용하나요?
런타임을 선택하고 파일을 열거나 만든 다음 코드를 작성하고 실행을 선택하세요. 출력은 터미널에 표시되며, 로그인한 사용자는 작업 공간에 파일을 보관하고 라이브러리를 설치하며 공유를 통해 협업할 수 있습니다.
- 버전을 선택하고 현재 파일을 편집하거나 작업 공간의 다른 파일을 여세요.
- 코드를 실행하고 요청 시 터미널에 입력한 다음 저장된 실행 기록을 확인하세요.
- 작업에 둘 이상의 코드 조각이 필요하면 라이브러리, 작업 공간 도구, 공유 및 채팅을 사용하세요.
💡 위에서 바로 시도해볼 수 있는 C++ 기본기와 예제
1. 변수와 상수 선언
C++에서는 각 변수의 타입을 선언해야 합니다. 초기화 후 변경할 수 없는 읽기 전용 값을 정의하려면 const를 사용하세요.
int age = 30;
double pi = 3.14159;
char grade = 'A';
std::string name = "Alice";
bool isActive = true;
// 상수
const int MAX_USERS = 100;
const std::string COMPANY = "CodeUtility";
// const 값을 변경하려 하면 컴파일 타임 오류가 발생합니다
// MAX_USERS = 200; // ❌ 오류
2. 조건문 (if / switch)
분기에는 if, else if, else를 사용합니다. 여러 값 분기에는 switch를 사용합니다.
int x = 2;
if (x == 1) {
std::cout << "하나\n";
} else if (x == 2) {
std::cout << "둘\n";
} else {
std::cout << "기타\n";
}
// switch-case
switch (x) {
case 1:
std::cout << "하나\n";
break;
case 2:
std::cout << "둘\n";
break;
default:
std::cout << "기타\n";
}
3. 반복문
for, while, do-while로 코드 블록을 반복하세요.
for (int i = 0; i < 3; i++) {
std::cout << i << "\n";
}
int n = 3;
while (n > 0) {
std::cout << n << "\n";
n--;
}
4. 배열
배열은 같은 타입의 여러 요소를 저장합니다.
int numbers[3] = {10, 20, 30};
std::cout << numbers[1] << "\n";
5. 배열/벡터 다루기
동적 배열에는 std::vector를 사용하세요.
#include <vector>
std::vector nums = {1, 2, 3};
nums.push_back(4);
nums.pop_back();
for (int n : nums) {
std::cout << n << " ";
}
6. 콘솔 입력/출력
std::cin은 입력, std::cout은 출력에 사용합니다.
std::string name;
std::cout << "이름을 입력하세요: ";
std::cin >> name;
std::cout << "안녕하세요, " << name << "\n";
7. 함수
함수는 재사용 가능한 로직을 묶습니다. 매개변수와 반환 타입을 사용하세요.
int add(int a, int b) {
return a + b;
}
std::cout << add(3, 4);
8. 맵
std::map은 딕셔너리처럼 키-값 쌍을 저장합니다.
#include <map>
std::map ages;
ages["Alice"] = 30;
std::cout << ages["Alice"];
9. 예외 처리
try와 catch로 런타임 오류를 처리하세요.
try {
throw std::runtime_error("오류가 발생했습니다");
} catch (const std::exception& e) {
std::cout << e.what();
}
10. 파일 입출력
fstream으로 파일을 읽고 쓸 수 있습니다.
#include <fstream>
std::ofstream out("file.txt");
out << "안녕 파일";
out.close();
std::ifstream in("file.txt");
std::string line;
getline(in, line);
std::cout << line;
in.close();
11. 문자열 다루기
C++ 문자열은 length(), substr(), find() 같은 메서드를 제공합니다.
std::string text = "Hello World";
std::cout << text.length();
std::cout << text.substr(0, 5);
std::cout << text.find("World");
12. 클래스와 객체
C++는 클래스를 사용한 객체지향 프로그래밍을 지원합니다.
class Person {
public:
std::string name;
Person(std::string n) : name(n) {}
void greet() { std::cout << "안녕하세요, 저는 " << name; }
};
Person p("Alice");
p.greet();
13. 포인터
포인터는 다른 변수의 메모리 주소를 저장합니다. 주소를 얻으려면 &를,
역참조(그 주소의 값을 접근)하려면 *를 사용합니다.
int x = 10;
int* ptr = &x;
std::cout << "x의 값: " << x << "\n";
std::cout << "x의 주소: " << ptr << "\n";
std::cout << "포인터로 읽은 값: " << *ptr << "\n";
// 포인터를 통해 x 수정
*ptr = 20;
std::cout << "변경된 x: " << x << "\n";
🐞 %{language} 코드를 온라인으로 디버깅하는 방법
온라인 %{language} 디버거로 컴파일러나 IDE를 설치하지 않고 런타임 및 논리 오류를 찾으세요. 서버 모드는 디버그 심볼로 컴파일하고 GDB에서 프로그램을 실행합니다.
- 줄 번호 옆에 중단점을 설정합니다.
- Debug를 선택해 컴파일하고 첫 중단점에서 멈춥니다.
- 현재 줄, 호출 스택과 변수를 확인합니다.
- Continue, Step Over, Step Into, Step Out으로 실행을 제어합니다.
- 종료하려면 Stop을 선택합니다.
재현 가능한 작은 예제로 시작하고 예상 밖의 동작 직전에 중단점을 설정하세요.