1번. 배열 원소 합하기
long long sum(const vector<int>& v) {
long long Sum = 0;
for(int i = 0; i < v.size(); i++)
{
Sum+= v[i];
}
return Sum;
}
벡터 사이즈는 size() 반드시 붙여준다...
C++은 무조건 length(), size()로 길이 구하는 건 다 함수니까 () 붙인다.
Array는 쓸 일 없으니 까먹어도 된다.
2번. 윤년 구하기
bool is_leap(int y) {
if(y%4 ==0 && y%100 != 0)
{
return true;
}
else if(y%400 == 0)
{
return true;
}
else
{
return false;
}
}
4의 배수지만 100의 배수는 아니면 true
100의 배수여도 400의 배수이면 트루
아니면 false
3번. 직사각형 클래스 구현하기
class Rect {
public:
Rect(int width, int height) : width(width < 0 ? 0 : width), height(height < 0 ? 0 : height) {}
int area() const {
return width * height;
}
void setWidth(int value)
{
if(value < 0)
this->width = 0;
else
this->width = value;
}
void setHeight(int value)
{
if(value < 0)
this->height = 0;
else
this->height = value;
}
private:
int width;
int height;
};
생성자 인수에서 int를 안 적을 뻔 했는데 주의하자.
4번. 은행 입출금
#include <iostream>
#include <string>
using namespace std;
class BankAccount {
private:
string owner;
double balance;
public:
BankAccount(const string& name, double initial) {
owner = name;
if(initial >= 0)
balance = initial;
else
balance = 0;
}
void deposit(double amount) {
if(amount >= 0)
{
balance += amount;
}
}
bool withdraw(double amount) {
if (balance < amount)
{
return false;
}
else
{
balance -= amount;
return true;
}
}
double getBalance() const {
return balance;
}
// 계좌 정보 출력하는 함수 (구현하실 필요 없음)
void printInfo() const {
cout << "Owner: " << owner << ", Balance: " << balance << " won\\n";
}
};
int main() {
BankAccount account("Alice", 1000);
account.printInfo(); // Owner: Alice, Balance: 1000 won
account.deposit(500);
account.printInfo(); // Owner: Alice, Balance: 1500 won
if (account.withdraw(2000)) {
cout << "Withdraw OK!\\n"; // 이건 출력 안됨
} else {
cout << "Withdraw FAILED!\\n"; // 이것이 출력됨
}
if (account.withdraw(1000)) {
cout << "Withdraw OK!\\n"; // 이것이 출력됨
}
account.printInfo(); // Owner: Alice, Balance: 500 won
}
5. 가상함수 오버라이드
#include <iostream>
#include <vector>
using namespace std;
class Animal {
virtual void speak(){
cout << "???" << endl;
};
};
class Dog : public Animal {
public:
void speak () override {
cout << "Woof" << endl;
}
};
class Cat : public Animal{
public:
void speak () override {
cout << "Meow" << endl;
}
};
int main() {
vector<Animal*> zoo{ new Dog, new Cat, new Animal };
for (auto p : zoo) p->speak(); // Woof / Meow / ???
for (auto p : zoo) delete p;
}
가상함수 구현 안 해두면 에러남. {} 빈칸이라도 넣어놔야함.
6. 제네릭 함수 템플릿 구현하기
#include <iostream>
#include <string>
using namespace std;
template <typename T>
const T& get_max(const T& a, const T& b){
return a > b ? a : b;
}
int main() {
cout << get_max(10, 20) << "\\n"; // 20
cout << get_max(3.14, 2.71) << "\\n"; // 3.14
string s1 = "Apple", s2 = "Banana";
cout << get_max(s1, s2) << "\\n"; // Banana
}
템플릿 함수 쓰는 법 잊지말자.
template <typename T>
그리고 이건 바로 한 파일에 구현을 해놔야한다.
7. 깊은 복사 생성자와 소멸자 구현
#include <iostream>
using namespace std;
class IntPtr {
int* ptr;
public:
IntPtr(int val) {
ptr = new int(val);
}
~IntPtr() {
if(ptr != nullptr)
{
delete ptr;
ptr = nullptr;
}
}
IntPtr(const IntPtr& other) {
if(other.ptr != nullptr)
{
this->ptr = new int(*other.ptr);
}
else
{
this->ptr = nullptr;
}
}
int getValue() const {
return *ptr;
}
};
int main() {
IntPtr p1(10);
IntPtr p2 = p1; // 복사 생성자 호출
cout << p1.getValue() << "\\n"; // 10
cout << p2.getValue() << "\\n"; // 10
}
소멸자에서는 클래스에서 갖고 있는 포인터가 nullptr이 아니면 삭제해준다.
IntPtr p1(10);
IntPtr p2 = p1; 이랑
IntPtr p1(10);
IntPtr p2(20);
p2 = p1;
이건 다른 거다.
🔥 1️⃣ 복사 vs 대입 차이
✅ 복사 (Copy)
👉 새 객체를 만들면서 값을 복사
IntPtr p1(10);
IntPtr p2 = p1; // 복사
또는
IntPtr p2(p1); // 복사
✔ 특징:
- 새로운 객체 생성됨
- 이때 복사 생성자 호출
✅ 대입 (Assignment)
👉 이미 있는 객체에 값을 덮어쓰기
IntPtr p1(10);
IntPtr p2(20);
p2 = p1; // 대입
✔ 특징:
- 객체는 이미 존재
- 값만 바뀜
- 대입 연산자 (operator=) 호출
🔥 2️⃣ 한눈에 비교
| 객체 생성 | ⭕ 새로 생성 | ❌ 이미 있음 |
| 호출 함수 | 복사 생성자 | 대입 연산자 |
| 코드 형태 | IntPtr p2 = p1; | p2 = p1; |
🔥 3️⃣ 복사 생성자란?
👉 같은 타입 객체로 새 객체를 만들 때 자동 호출되는 생성자
언제 호출됨?
👉 둘 다 복사 생성자
🔥 4️⃣ 복사 생성자는 원래 있는 거냐?
👉 있다 (컴파일러가 자동으로 만들어줌)
이걸 **기본 복사 생성자 (default copy constructor)**라고 함.
근데 문제는?
기본 복사 생성자는 이렇게 동작함:
👉 얕은 복사 (shallow copy)
그래서 생기는 문제 💥
IntPtr p2 = p1;
👉 둘 다 같은 ptr 공유
delete ptr;
}
👉 둘 다 delete → 💥 double delete
🔥 5️⃣ 직접 만드는 이유
ptr = new int(*other.ptr); // 깊은 복사
}
👉 각각 따로 메모리 사용 → 안전
8. 벡터에서 순서 유지하면서 중복 제거하기
vector<int> removeDuplicates(const vector<int>& v) {
vector<int> Result;
unordered_set<int> Dup;
for (int n: v)
{
if (Dup.find(n) == Dup.end())
{
Dup.insert(n);
Result.push_back(n);
}
}
return Result;
}
unordered_set<int> Dup;을 써서 문제를 해결하였다.
unordered_set이란?
👉 중복 없는 값을 저장하는 집합 (set)
👉 순서 없음 (unordered)
👉 해시 테이블 기반
using namespace std;
unordered_set<int> s;
2️⃣ 특징
✅ 1. 중복 허용 ❌
s.insert(10); // 무시됨
👉 같은 값 하나만 저장됨
✅ 2. 순서 없음
cout << x << " ";
👉 출력 순서 랜덤 (정렬 안 됨)
✅ 3. 빠른 속도 (중요 🔥)
| insert | O(1) |
| find | O(1) |
| erase | O(1) |
👉 해시 기반이라 엄청 빠름
3️⃣ 기본 사용법
삽입
탐색
cout << "있다";
}
👉 또는:
cout << "있다";
}
삭제
4️⃣ set vs unordered_set
| 내부 구조 | 트리 (RB-tree) | 해시 테이블 |
| 정렬 | ⭕ 자동 정렬 | ❌ 없음 |
| 속도 | O(log n) | O(1) |
| 순서 | 있음 | 없음 |
5️⃣ 언제 쓰냐?
👉 이런 상황에서 최고 👍
- 중복 제거
- 빠른 존재 확인 (검색)
- 순서 필요 없음
예:
👉 방문 체크 (그래프, BFS 등)
9. 두 문자열이 애너그램인지 판별하기
두 문자열이 애너그램 관계인지 판별하는 함수를 작성해주세요. 만약 애너그램이 아니라면, 한 문자열의 문자 몇 개를 바꿔야 다른 문자열과 애너그램 관계가 될 수 있을까요? 그 최소 횟수를 구해야 합니다.
- 애너그램이면 0을 반환합니다.
- 애너그램이 아니면 최소 변경 횟수를 반환합니다.
- 변경: 한 문자를 다른 문자로 바꾸는 것을 의미합니다. (문자 1개 변경 = 1회)
- 두 문자열의 길이가 다르면 1을 반환합니다.
- 자세한 내용은 아래 코드의 main 함수 출력 예시를 참고하세요.
int getMinChangesToAnagram(const string& s1, const string& s2) {
string s = s2;
if(s1.length() != s2.length())
{
return -1;
}
for (int i = 0; i < s1.length(); i++)
{
char a = s1[i];
size_t found = s.find(a);
if (found != string:: npos)
{
s.erase(found, 1);
}
}
return s.length();
}
const string&로 들어오는 s2는 바꿀 수 없어서 s2 따로 저장했다.
s1 글자 하나하나를 s2에서 pop 하듯이 꺼내면 남은 글자의 길이가 바꿔야하는 문자 수이다.
더 좋은 방법이 있다고 하는데 어려워서 이걸로 했다.
'코딩 학습 > C와 C++' 카테고리의 다른 글
| C++ 기초 - Console IO (0) | 2026.04.03 |
|---|---|
| C++ 배치고사 선택 문제 (0) | 2026.04.03 |
| C++ 팀프로젝트 - 텍스트 RPG 게임 만들기(4) (0) | 2026.03.31 |
| C++ 팀프로젝트 - 텍스트 RPG 게임 만들기(2) (0) | 2026.03.27 |
| C++ 팀프로젝트 - 텍스트 RPG 게임 만들기(1) (0) | 2026.03.26 |