├── 코딩테스트 합격자 되기 C++편 - 책 소개.pptx ├── solution ├── 30.cpp ├── 91.cpp ├── 68.cpp ├── 57.cpp ├── 73-2.cpp ├── 73.cpp ├── 34.cpp ├── 82.cpp ├── 11.cpp ├── 01.cpp ├── 97.cpp ├── 54.cpp ├── 15.cpp ├── 85.cpp ├── 02.cpp ├── 83.cpp ├── 76.cpp ├── 09.cpp ├── 74.cpp ├── 75.cpp ├── 77.cpp ├── 56.cpp ├── 03.cpp ├── 22.cpp ├── 80.cpp ├── 71.cpp ├── 20-2.cpp ├── 58.cpp ├── 59.cpp ├── 70.cpp ├── 69.cpp ├── 100.cpp ├── 49.cpp ├── 65.cpp ├── 67.cpp ├── 42.cpp ├── 08.cpp ├── 55.cpp ├── 12.cpp ├── 87.cpp ├── 93.cpp ├── 20.cpp ├── 98.cpp ├── 78.cpp ├── 66.cpp ├── 13.cpp ├── 84.cpp ├── 96.cpp ├── 52.cpp ├── 21.cpp ├── 23.cpp ├── 16.cpp ├── 72.cpp ├── 05.cpp ├── 17.cpp ├── 99.cpp ├── 86.cpp ├── 50.cpp ├── 47.cpp ├── 90.cpp ├── 24.cpp ├── 79.cpp ├── 36.cpp ├── 18.cpp ├── 04.cpp ├── 10.cpp ├── 95.cpp ├── 92.cpp ├── 19.cpp ├── 26.cpp ├── 89.cpp ├── 37.cpp ├── 81.cpp ├── 94.cpp ├── 25.cpp ├── 62.cpp ├── 39.cpp ├── 44.cpp ├── 46.cpp ├── 07.cpp ├── 27.cpp ├── 88.cpp ├── 28.cpp ├── 53.cpp ├── 38.cpp ├── 64.cpp ├── 35.cpp ├── 06.cpp ├── 60.cpp ├── 43.cpp ├── 41.cpp ├── 61.cpp ├── 51.cpp ├── 29.cpp └── 33.cpp ├── performance ├── ReadMe.md └── vector_vs_set.cpp ├── event.md ├── Example ├── frequency_word.cpp ├── stairproblem_dp.cpp ├── backtracking_sturcure.cpp ├── Algorithm_with_DataStructure │ └── bactracking_structure.cpp ├── managing_stdudent_one_score.cpp ├── squarecount.cpp ├── chageCoin.cpp └── factorial_iterative.cpp ├── STL ├── count.cpp ├── reverse.cpp ├── min_element.cpp ├── max_element.cpp ├── call_by_ref.cpp ├── priority_queue.cpp ├── queue.cpp ├── deque.cpp ├── binary_search.cpp ├── ReadMe.md ├── template.cpp ├── priority_queue_with_priority.cpp └── next_permutation.cpp ├── reference ├── ReadMe.md ├── callback.cpp ├── variable.cpp ├── decay.cpp ├── loop.cpp ├── reference.cpp ├── function.cpp ├── array.cpp ├── dynamic_alloc.cpp ├── variable_scope.cpp ├── sizeof.cpp ├── if_statement.cpp └── type_conversion.cpp ├── Algorithm_with_DataStructure ├── queue_josephuse.cpp ├── ReadMe.md ├── matching_bracket.cpp ├── dfs_recursive.cpp ├── selectionsort.cpp ├── tree_array.cpp ├── adjacencyarray.cpp ├── eratosthenes_sieve.cpp ├── adjacencylist.cpp ├── preorder_tree_array.cpp ├── parenthesesBalanced.cpp └── insertionsort.cpp ├── ReadMe.md └── algorithm_performance.md /코딩테스트 합격자 되기 C++편 - 책 소개.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dremdeveloper/codingtest_cpp/HEAD/코딩테스트 합격자 되기 C++편 - 책 소개.pptx -------------------------------------------------------------------------------- /solution/30.cpp: -------------------------------------------------------------------------------- 1 | int solution(int n, int a, int b) 2 | { 3 | int answer = 0; 4 | 5 | do { 6 | a = (a + 1) / 2; 7 | b = (b + 1) / 2; 8 | ++answer; 9 | } while (a != b); 10 | 11 | return answer; 12 | } 13 | 14 | //아래 코드는 테스트 코드 입니다. 15 | #include 16 | 17 | using namespace std; 18 | 19 | int main() 20 | { 21 | cout << solution(8, 4, 7) << endl; //출력값 : 3 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /solution/91.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 0부터 9까지의 수 중에서 입력된 배열에 없는 수의 합을 반환합니다. 7 | int solution(vector numbers) { 8 | // 0부터 9까지의 합은 45이므로 기본값을 45로 설정합니다. 9 | int answer = 45; 10 | 11 | // 입력된 numbers 배열의 각 요소를 answer에서 차감합니다. 12 | for (int number : numbers) { 13 | answer -= number; 14 | } 15 | 16 | // numbers 배열에 없는 수의 총합을 반환합니다. 17 | return answer; 18 | } 19 | -------------------------------------------------------------------------------- /solution/68.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int solution(int N) { 6 | return bitset<32>(N).count(); // 2진수로 변환한 N의 1의 개수를 반환 7 | } 8 | 9 | 10 | 11 | 12 | //아래 코드는 테스트 코드 입니다. 13 | #include 14 | 15 | using namespace std; 16 | 17 | int main() 18 | { 19 | cout << solution(5) << endl; //출력값 : 2 20 | cout << solution(6) << endl; //출력값 : 2 21 | cout << solution(5000) << endl; //출력값 : 5 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /solution/57.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | long long solution(long long n) { 7 | //❶ 숫자를 문자열로 변환 8 | string str = to_string(n); 9 | 10 | //❷ 역순으로 정렬 11 | sort(str.rbegin(), str.rend()); 12 | return stoll(str); 13 | } 14 | 15 | 16 | //아래 코드는 테스트 코드 입니다. 17 | #include 18 | 19 | using namespace std; 20 | 21 | int main() 22 | { 23 | cout << solution(118372) << endl; // 출력값 : 873211 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /solution/73-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; // using 지시문 추가 3 | 4 | int solution(int n) { 5 | vector fib = {0, 1}; // F(0) = 0, F(1) = 1 6 | for (int i = 2; i <= n; i++) { 7 | fib.push_back(fib[i - 1] + fib[i - 2]); 8 | } 9 | return fib[n] % 1234567; 10 | } 11 | 12 | 13 | //아래 코드는 테스트 코드 입니다. 14 | #include 15 | 16 | using namespace std; 17 | 18 | int main() 19 | { 20 | cout << solution(3) << endl; //출력값 : 2 21 | cout << solution(5) << endl; //출력값 : 5 22 | 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /solution/73.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // 피보나치 수열의 n번째 값을 계산하는 함수 6 | int solution(int n) { 7 | vector fib = {0, 1}; // fib(0) = 0, fib(1) = 1 8 | for (int i = 2; i <= n; ++i) { 9 | fib.push_back((fib[i - 1] + fib[i - 2]) % 1234567); 10 | } 11 | return fib[n]; 12 | } 13 | 14 | //아래 코드는 테스트 코드 입니다. 15 | #include 16 | 17 | using namespace std; 18 | 19 | int main() 20 | { 21 | cout << solution(3) << endl; //출력값 : 2 22 | cout << solution(5) << endl; //출력값 : 5 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /performance/ReadMe.md: -------------------------------------------------------------------------------- 1 | | 파일 이름 | 설명 | 2 | |-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| 3 | | `set_vs_unordered_set.cpp` | `std::set`와 `std::unordered_set`의 성능 비교: 각 컨테이너의 특성과 성능 측정을 통한 삽입, 검색 시간 비교를 설명합니다. | 4 | | `vector_vs_set.cpp` | `std::vector`와 `std::set`의 사용 시나리오와 성능 차이를 비교: 요소 접근, 삽입, 삭제 작업의 효율성을 분석합니다. | 5 | | `map_vs_unordered_map.cpp` | `std::map`과 `std::unordered_map`의 성능 차이를 설명: 삽입 및 검색 작업에서의 시간 복잡도 및 실제 사용 예를 통해 각 컨테이너의 장단점을 비교합니다. | 6 | -------------------------------------------------------------------------------- /solution/34.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int solution(vector nums) { 7 | //❶ s는 nums의 중복값을 제거한 집합 8 | unordered_set s(nums.begin(), nums.end()); 9 | 10 | //❷ 중복을 제거한 개수와 nums의 개수중 작은 값을 반환 11 | return min(nums.size() / 2, s.size()); 12 | } 13 | 14 | //아래 코드는 테스트 코드 입니다. 15 | #include 16 | 17 | using namespace std; 18 | 19 | int main() 20 | { 21 | cout << solution({3, 1, 2 ,3}) << endl; //출력값 : 2 22 | cout << solution({3, 3, 3, 2, 2, 4}) << endl; //출력값 : 3 23 | cout << solution({3, 3, 3, 2, 2, 2}) << endl; //출력값 : 2 24 | 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /solution/82.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int solution(vector d, int budget) { 7 | sort(d.begin(), d.end()); //❶ 벡터 d를 오름차순으로 정렬 8 | int count = 0; //❷ 지원할 수 있는 부서의 개수를 세는 변수 9 | 10 | for (int amount : d) { 11 | if (budget < amount) { 12 | break; //❸ 남은 예산이 신청한 금액보다 작으면 더 이상 지원할 수 없으므로 종료 13 | } 14 | budget -= amount; //❹ 예산에서 신청한 금액을 차감 15 | count += 1; 16 | } 17 | 18 | return count; 19 | } 20 | 21 | //아래 코드는 테스트 코드 입니다. 22 | #include 23 | 24 | int main() 25 | { 26 | cout << solution({1, 3, 2, 5, 4}, 9) << endl; //출력값 : 3 27 | cout << solution({2, 2, 3, 3}, 10) << endl; //출력값 : 4 28 | 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /solution/11.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int solution(string s) 6 | { 7 | stack st; 8 | 9 | for(int i=0;i 25 | 26 | int main() 27 | { 28 | cout << solution("baabaa") << endl; // 1 29 | cout << solution("cdcd") << endl; // 0 30 | return 0; 31 | } -------------------------------------------------------------------------------- /event.md: -------------------------------------------------------------------------------- 1 | # 스터디 진행사항 2 | 3 | 4 | ## 그룹 스터디 모집 5 | 같이 공부할 스터디원을 모집해드립니다. 참석 누르고, 댓글 다시면 연락 드립니다.(디스코드로 연락 드립니다.) 6 | | 스터디명 | 링크 | 기간 | 7 | | --- | --- | ---| 8 | | 모각코 | [참석](https://discord.com/invite/JhBB9wYgWw) | 상시 ( 오전 10시, 오후 11시 매일) | 9 | |코딩 테스트 합격자 되기 - 자바스크립트 | [참석](https://discord.com/channels/1190334577248583791/1265644208203763713) | ~07/31까지 모집 | 10 | |코테 문제 플랫폼(백준,codeleet,프로그래머스)에서 문제풀이 | [참석](https://discord.com/channels/1190334577248583791/1265644805057417217) |~07/31까지 모집 | 11 | | 코딩 테스트 합격자 되기 - 자바 | [참석](https://discord.com/channels/1190334577248583791/1265644208203763713) |~07/31까지 모집 | 12 | | 코딩 테스트 합격자 되기 - C++ | [참석](https://discord.com/channels/1190334577248583791/1265647941511680070) |~07/31까지 모집 | 13 | 14 | -------------------------------------------------------------------------------- /solution/01.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include //sort를 위해 선언 3 | 4 | using namespace std; 5 | 6 | vector solution(vector arr) { 7 | sort(arr.begin(), arr.end()); 8 | return arr; 9 | } 10 | 11 | 12 | //아래 코드는 테스트 코드 입니다. 13 | 14 | #include 15 | #include 16 | void print(vector vec) 17 | { 18 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 19 | cout << endl; 20 | } 21 | 22 | int main() 23 | { 24 | print(solution({1, -5, 2, 4, 3})); // -5 1 2 3 4 25 | print(solution({2, 1, 1, 3, 2, 5, 4})); // 1 1 2 2 3 4 5 26 | print(solution({6, 1, 7})); // 1 6 7 27 | 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /solution/97.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // A 팀이 이길 수 있는 최대 경기 수를 계산하는 함수 7 | int solution(vector A, vector B) { 8 | // A와 B를 오름차순으로 정렬 9 | sort(A.begin(), A.end()); 10 | sort(B.begin(), B.end()); 11 | 12 | int AwinCount = 0; // A가 이길 수 있는 경기 수 13 | int Ai = 0; // A 팀의 현재 비교할 선수 인덱스 14 | int Bi = 0; // B 팀의 현재 비교할 선수 인덱스 15 | 16 | // A와 B의 모든 선수를 비교 17 | while (Bi < B.size()) { 18 | // A 팀의 선수가 B 팀의 선수보다 능력치가 낮은 경우, A 팀 승리 19 | if (A[Ai] < B[Bi]) { 20 | AwinCount++; 21 | Ai++; 22 | } 23 | Bi++; // B 팀의 다음 선수로 이동 24 | } 25 | 26 | return AwinCount; // A 팀이 이길 수 있는 최대 경기 수 반환 27 | } 28 | -------------------------------------------------------------------------------- /solution/54.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | string solution(string s) { 7 | //❶ 알파벳 개수(26개)만큼 빈도수 배열 생성 8 | vector counts(26, 0); 9 | 10 | //❷ 문자열의 각 문자에 대한 빈도수를 빈도수 배열에 저장 11 | for (char c : s) { 12 | counts[c - 'a']++; 13 | } 14 | 15 | //❸ 빈도수 배열을 순회하면서 정렬된 문자열을 생성 16 | string sorted_str = ""; 17 | for (int i = 0; i < 26; i++) { 18 | sorted_str += string(counts[i], i + 'a'); 19 | } 20 | 21 | return sorted_str; 22 | } 23 | 24 | //아래 코드는 테스트 코드 입니다. 25 | #include 26 | 27 | using namespace std; 28 | 29 | int main() 30 | { 31 | cout << solution("hello") << endl; // 출력값 : ehllo 32 | cout << solution("algorithm") << endl; // 출력값 : aghilmort 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /solution/15.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int solution(int N, int K) { 6 | queue q; 7 | 8 | // ❶ 1부터 N까지의 번호를 큐에 추가 9 | for (int i = 1; i <= N; i++) { 10 | q.push(i); 11 | } 12 | 13 | //❷ 큐에 하나의 요소가 남을 때까지 순회 14 | while (q.size() > 1) { 15 | for (int i = 0; i < K - 1; i++) { 16 | //❸ K번째 사람을 찾기 위해 앞에서부터 제거하고 뒤에 추가 17 | q.push(q.front()); 18 | q.pop(); 19 | } 20 | //❹ K번째 사람 제거 21 | q.pop(); 22 | } 23 | 24 | //❺ 마지막으로 남은 요소 반환 25 | return q.front(); 26 | } 27 | 28 | 29 | //아래 코드는 테스트 코드 입니다. 30 | #include 31 | 32 | int main() 33 | { 34 | 35 | cout << solution(5, 2) << endl; // 3 36 | 37 | } 38 | -------------------------------------------------------------------------------- /solution/85.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int solution(int N, vector stations, int W) { 6 | int answer = 0; 7 | int location = 1; // ❶ 현재 탐색하는 아파트의 위치 8 | int idx = 0; // ❷ 설치된 기지국의 인덱스 9 | 10 | while (location <= N) { 11 | // ❸ 기지국이 설치된 위치에 도달한 경우 12 | if (idx < stations.size() && location >= stations[idx] - W) { 13 | location = stations[idx] + W + 1; 14 | idx++; 15 | } 16 | // ❹ 기지국이 설치되지 않은 위치인 경우 17 | else { 18 | // ➎ 기지국을 설치하고 해당 범위를 넘어감 19 | location += 2 * W + 1; 20 | answer++; 21 | } 22 | } 23 | 24 | return answer; 25 | } 26 | 27 | //아래 코드는 테스트 코드 입니다. 28 | #include 29 | 30 | int main() 31 | { 32 | cout << solution(11, {4, 11}, 1) << endl; // 3 33 | cout << solution(16, {9}, 1) << endl; // 5 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /solution/02.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include // sort, unique를 위해 선언 3 | 4 | using namespace std; 5 | 6 | bool compare(int a, int b) { // ❶ 정렬 기준 정의 7 | return a > b; 8 | } 9 | 10 | vector solution(vector lst) { 11 | sort(lst.begin(), lst.end(), compare); // ❷ 내림차순으로 정렬 12 | lst.erase(unique(lst.begin(), lst.end()), lst.end()); // ❸ 중복값 제거 13 | 14 | return lst; 15 | } 16 | 17 | 18 | 19 | //아래 코드는 테스트 코드 입니다. 20 | #include 21 | #include 22 | void print(vector vec) 23 | { 24 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 25 | cout << endl; 26 | } 27 | 28 | int main() 29 | { 30 | print(solution({4, 2, 2, 1, 1, 3, 4})); // 4 3 2 1 31 | print(solution({2, 1, 1, 3, 2, 5, 4})); // 5 4 3 2 1 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /solution/83.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int solution(vector people, int limit) { 7 | sort(people.begin(), people.end()); //❶ 몸무게를 오름차순으로 정렬 8 | int count = 0; //❷ 필요한 보트 개수 9 | int i = 0; //❸ 가장 가벼운 사람을 가리키는 인덱스 10 | int j = people.size() - 1; //❹ 가장 무거운 사람을 가리키는 인덱스 11 | 12 | while (i <= j) { 13 | //❺ 가장 무거운 사람과 가장 가벼운 사람을 같이 태울 수 있으면 두 사람 모두 보트에 태움 14 | if (people[j] + people[i] <= limit) { 15 | i++; 16 | } 17 | //❻ 무거운 사람만 태울 수 있으면 무거운 사람만 보트에 태움 18 | j--; 19 | count++; 20 | } 21 | 22 | return count; 23 | } 24 | 25 | 26 | //아래 코드는 테스트 코드 입니다. 27 | #include 28 | 29 | int main() 30 | { 31 | cout << solution({70, 50, 80, 50}, 100) << endl; //출력값 : 3 32 | cout << solution({70, 80, 50}, 100) << endl; //출력값 : 3 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /solution/76.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int solution(vector> land) { 6 | // ➊ 각 행마다 이전 행에서의 최대 점수를 더해가며 최대 점수 누적 7 | for (int i = 1; i < land.size(); ++i) { 8 | for (int j = 0; j < 4; ++j) { 9 | // ➋ 이전 행에서 현재 열의 값을 제외한 나머지 열들 중에서 가장 큰 값을 더함 10 | int maxVal = 0; 11 | for (int k = 0; k < 4; ++k) { 12 | if (k != j) { 13 | maxVal = max(maxVal, land[i - 1][k]); 14 | } 15 | } 16 | land[i][j] += maxVal; 17 | } 18 | } 19 | // ➌ 마지막 행에서 얻을 수 있는 최대 점수를 반환 20 | return *max_element(land.back().begin(), land.back().end()); 21 | } 22 | 23 | 24 | 25 | //아래 코드는 테스트 코드 입니다. 26 | #include 27 | 28 | using namespace std; 29 | 30 | int main() 31 | { 32 | cout << solution({{1, 2, 3, 5}, {5, 6, 7, 8}, {4, 3, 2, 1}}) << endl; //출력값 : 16 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /solution/09.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | string solution(int decimal) { 6 | //❶입력 값이 0인 경우 바로 처리 7 | if (decimal == 0) return "0"; 8 | 9 | stack stack; 10 | while (decimal > 0) { 11 | //❷ 2로 나눈 나머지를 스택에 삽입 12 | stack.push(decimal % 2); 13 | decimal /= 2; 14 | } 15 | 16 | string binary = ""; 17 | while (!stack.empty()) { 18 | //❸ 스택에서 차례대로 top()에 해당되는 값을 binary에 추가 19 | binary += to_string(stack.top()); 20 | stack.pop(); 21 | } 22 | return binary; 23 | } 24 | 25 | 26 | //아래 코드는 테스트 코드 입니다. 27 | #include 28 | int main() 29 | { 30 | cout << solution(10) << endl; // 1010 31 | cout << solution(27) << endl; // 11011 32 | cout << solution(12345) << endl; // 11000000111001 33 | 34 | return 0; 35 | } -------------------------------------------------------------------------------- /solution/74.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | long long solution(int n) { 6 | // ❶ 바닥의 가로 길이가 1인 경우, 바닥을 채우는 방법의 수는 1 7 | if (n == 1) { 8 | return 1; 9 | } 10 | // ❷ 바닥의 가로 길이가 2인 경우, 바닥을 채우는 방법의 수는 2 11 | if (n == 2) { 12 | return 2; 13 | } 14 | // ❸ 동적 계획법을 위한 배열 초기화 15 | // dp[i]는 가로 길이가 i일 때 바닥을 채우는 방법의 수 16 | vector dp(n + 1, 0); 17 | dp[1] = 1; 18 | dp[2] = 2; 19 | // ❹ 가로 길이가 3부터 n까지의 각각의 경우에 대해 바닥을 채우는 방법의 수를 구함 20 | for (int i = 3; i <= n; i++) { 21 | // ❺ dp[i]는 dp[i-1]과 dp[i-2]를 더한 값 22 | dp[i] = (dp[i - 1] + dp[i - 2]) % 100Q0000007; 23 | } 24 | // ❻ 바닥의 가로 길이가 n일 때 바닥을 채우는 방법의 수인 dp[n]을 반환 25 | return dp[n]; 26 | } 27 | 28 | 29 | //아래 코드는 테스트 코드 입니다. 30 | #include 31 | 32 | using namespace std; 33 | 34 | int main() 35 | { 36 | cout << solution(4) << endl; //출력값 : 5 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /solution/75.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | int solution(vector> triangle) { 6 | int n = triangle.size(); 7 | vector> dp(n, vector(n, 0)); // ➊ dp 테이블 초기화 8 | 9 | // ➋ dp 테이블의 맨 아래쪽 라인 초기화 10 | for (int i = 0; i < n; i++) { 11 | dp[n - 1][i] = triangle[n - 1][i]; 12 | } 13 | 14 | // ➌ 아래쪽 라인부터 올라가면서 dp 테이블 채우기 15 | for (int i = n - 2; i >= 0; i--) { 16 | for (int j = 0; j <= i; j++) { 17 | dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j]; 18 | } 19 | } 20 | 21 | return dp[0][0]; // 꼭대기에서의 최댓값 반환 22 | } 23 | 24 | 25 | //아래 코드는 테스트 코드 입니다. 26 | #include 27 | 28 | using namespace std; 29 | 30 | int main() 31 | { 32 | cout << solution({{7}, {3, 8}, {8, 1, 0}, {2, 7, 4, 4}, {4, 5, 2, 6, 5}}) << endl; //출력값 : 30 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /solution/77.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int solution(vector money) { 7 | //❶ 점화식에 필요한 변수를 초기화 8 | int n = money.size(); 9 | vector dp1(n, 0); 10 | vector dp2(n, 0); 11 | 12 | //❷ 첫 번째 집을 터는 경우 13 | dp1[0] = money[0]; 14 | dp1[1] = money[0]; 15 | for (int i = 2; i < n - 1; ++i) { 16 | dp1[i] = max(dp1[i - 1], dp1[i - 2] + money[i]); 17 | } 18 | 19 | //❸ 첫 번째 집을 털지 않는 경우 20 | dp2[1] = money[1]; 21 | for (int i = 2; i < n; ++i) { 22 | dp2[i] = max(dp2[i - 1], dp2[i - 2] + money[i]); 23 | } 24 | 25 | //❹ 두 경우 중, 최대값 찾기 26 | int answer = max(dp1[n - 2], dp2[n - 1]); 27 | return answer; 28 | } 29 | 30 | 31 | 32 | //아래 코드는 테스트 코드 입니다. 33 | #include 34 | 35 | using namespace std; 36 | 37 | int main() 38 | { 39 | cout << solution({1, 2, 3, 1}) << endl; //출력값 : 4 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /solution/56.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int idx; 8 | 9 | //❶ 비교 함수 10 | bool compare (string a, string b) { 11 | return a[idx] == b[idx] ? a < b : a[idx] < b[idx]; 12 | } 13 | 14 | vector solution(vector strings, int n) { 15 | idx = n; 16 | 17 | //❷ 각 문자열의 idx번째 문자를 기준으로 정렬 18 | sort (strings.begin(), strings.end(), compare); 19 | return strings; 20 | } 21 | 22 | 23 | //아래 코드는 테스트 코드 입니다. 24 | #include 25 | #include 26 | 27 | using namespace std; 28 | 29 | void print(vector vec) 30 | { 31 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 32 | cout << endl; 33 | } 34 | 35 | int main() 36 | { 37 | print(solution({"sun", "bed", "car"}, 1)); //출력값 : car bed sun 38 | print(solution({"abce", "abcd", "cdx"}, 2)); // 출력값 : abcd abce cdx 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /solution/03.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector solution(vector numbers) { 7 | set sum; // ❶ 두 수의 합을 저장할 저장공간 선언 8 | 9 | for(int i = 0;i answer(sum.begin(), sum.end()); // ❸ 반환타입을 맞추기 위헤 벡터로 변환 14 | return answer; 15 | } 16 | 17 | 18 | 19 | //아래 코드는 테스트 코드 입니다. 20 | 21 | #include 22 | #include 23 | void print(vector vec) 24 | { 25 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 26 | cout << endl; 27 | } 28 | 29 | int main() 30 | { 31 | print(solution({2, 1, 3, 4, 1})); // 2 3 4 5 6 7 32 | print(solution({5, 0, 2, 7})); // 2 5 7 9 12 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /solution/22.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | bool solution(vector phoneBook) { 8 | //❶ 전화번호 목록을 오름차순으로 정렬 9 | sort(phoneBook.begin(), phoneBook.end()); 10 | 11 | //❷ 모든 전화번호를 순회하면서 다음 번호와 비교 12 | for (int i = 0; i < phoneBook.size() - 1; ++i) { 13 | //❸ 현재 번호가 다음 번호의 접두어인 경우 false 반환 14 | if (phoneBook[i] == phoneBook[i + 1].substr(0, phoneBook[i].size())) { 15 | return false; 16 | } 17 | } 18 | 19 | //❹ 어떤 번호도 다른 번호의 접두어가 아닌 경우 true 반환 20 | return true; 21 | } 22 | 23 | //아래 코드는 테스트 코드 입니다. 24 | #include 25 | 26 | using namespace std; 27 | 28 | int main() 29 | { 30 | //bool 반환할 때 true는 1, false는 0 입니다. 31 | cout << solution({"119", "97674223", "1195524421"}) << endl; //출력값 : 0 32 | cout << solution({"123", "456", "789"}) << endl; //출력값 : 1 33 | cout << solution({"12", "123", "1235", "567", "88"}) << endl; //출력값 : 0 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /solution/80.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector solution(int amount) { 7 | vector denominations = {1, 10, 50, 100}; 8 | sort(denominations.rbegin(), denominations.rend()); //❶ 화폐 단위를 큰 순서대로 정렬 9 | 10 | vector change; //❷ 거스름돈을 담을 벡터 11 | for (int coin : denominations) { 12 | while (amount >= coin) { //❸ 해당 화폐 단위로 거스름돈을 계속 나눠줌 13 | change.push_back(coin); //❹ 거스름돈 벡터 업데이트 14 | amount -= coin; //❺ 정산이 완료된 거스름돈 뺌 15 | } 16 | } 17 | return change; //❻ 거스름돈 반환 18 | } 19 | 20 | 21 | 22 | //아래 코드는 테스트 코드 입니다. 23 | #include 24 | #include 25 | 26 | using namespace std; 27 | 28 | void print(vector vec) 29 | { 30 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 31 | cout << endl; 32 | } 33 | 34 | 35 | int main() 36 | { 37 | print(solution(123)); //출력값 : 100 10 10 1 1 1 38 | print(solution(350)); //출력값 : 100 100 100 50 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /solution/71.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 최장 증가 부분 수열(LIS)의 길이를 계산하는 함수 7 | int solution(const vector nums) { 8 | int n = nums.size(); 9 | // ❶ dp[i]는 nums[i]를 마지막으로 하는 LIS의 길이를 저장하는 배열입니다. 10 | vector dp(n, 1); 11 | 12 | for (int i = 1; i < n; ++i) { 13 | for (int j = 0; j < i; ++j) { 14 | // ❷ nums[i]와 nums[j]를 비교하여, nums[i]가 더 큰 경우에만 처리합니다. 15 | if (nums[i] > nums[j]) { 16 | // ❸ nums[i]를 이용하여 만든 부분 수열의 길이와 17 | // nums[j]를 이용하여 만든 부분 수열의 길이 + 1 중 최댓값을 저장합니다. 18 | dp[i] = max(dp[i], dp[j] + 1); 19 | } 20 | } 21 | } 22 | 23 | // ❹ dp 벡터에서 최댓값을 찾아 최장 증가 부분 수열의 길이를 반환합니다. 24 | return *max_element(dp.begin(), dp.end()); 25 | } 26 | 27 | //아래 코드는 테스트 코드 입니다. 28 | #include 29 | 30 | using namespace std; 31 | 32 | int main() 33 | { 34 | cout << solution({1, 4, 2, 3, 1, 5, 7, 3}) << endl; //출력값 : 5 35 | cout << solution({3, 2, 1}) << endl; //출력값 : 1 36 | 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /solution/20-2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | string solution(vector participant, vector completion) { 8 | 9 | sort(participant.begin(), participant.end()); 10 | sort(completion.begin(), completion.end()); 11 | 12 | for(int i=0;i 26 | 27 | int main() 28 | { 29 | cout << solution({"leo", "kiki", "eden"}, {"eden", "kiki"}) << endl; // "leo" 30 | cout << solution({"marina", "josipa", "nikola", "vinko", "filipa"}, {"josipa", "filipa", "marina", "nikola"}) << endl; // "vinko" 31 | cout << solution({"mislav", "stanko", "mislav", "ana"}, {"stanko", "ana", "mislav"}) << endl; // "mislav" 32 | return 0; 33 | 34 | } 35 | -------------------------------------------------------------------------------- /solution/58.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | vector solution(vector array, vector> commands) { 8 | vector answer; 9 | vector subArray; 10 | 11 | for (const auto& cmd : commands) { 12 | //❶ array에서 각 cmd에 해당되는 영역만 subArray로 복사후 정렬 13 | subArray.assign(array.begin() + (cmd[0] - 1), array.begin() + cmd[1]); 14 | sort(subArray.begin(), subArray.end()); 15 | 16 | //❷ subArray에서 k번 째 answer에 추가 17 | answer.push_back(subArray[cmd[2] - 1]); 18 | } 19 | 20 | return answer; 21 | } 22 | 23 | 24 | 25 | //아래 코드는 테스트 코드 입니다. 26 | #include 27 | #include 28 | 29 | using namespace std; 30 | 31 | void print(vector vec) 32 | { 33 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 34 | cout << endl; 35 | } 36 | 37 | int main() 38 | { 39 | print(solution({1, 5, 2, 6, 3, 7, 4}, {{2, 5, 3}, {4, 4, 1}, {1, 7, 3}})); // 출력값 : 5 6 3 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /solution/59.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | //❶ 문자열로 바뀐 두 수를 조합해서 크기를 비교 8 | bool compare(const string& lhs, const string& rhs) { 9 | return (lhs + rhs) > (rhs + lhs); 10 | } 11 | 12 | string solution(vector numbers) { 13 | string answer = ""; 14 | vector strings; 15 | 16 | for (auto elem : numbers) { 17 | //❷ numbers의 원소를 문자열로 변형해서 푸시 18 | strings.push_back(to_string(elem)); 19 | } 20 | //❸ 정렬함수를 기준으로 정렬 21 | sort(strings.begin(), strings.end(), compare); 22 | 23 | //❹ 정렬된 문자열을 앞에서 부터 추가 24 | for (auto elem : strings) { 25 | answer += elem; 26 | } 27 | 28 | //❺ 최종 숫자가 0이면 0을 반환하고 그렇지 않으면 answer 반환 29 | return answer[0] == '0' ? "0" : answer; 30 | } 31 | 32 | 33 | 34 | 35 | //아래 코드는 테스트 코드 입니다. 36 | #include 37 | 38 | using namespace std; 39 | 40 | int main() 41 | { 42 | cout << solution({6, 10, 2}) << endl; // 출력값 : 6210 43 | cout << solution({3, 30, 34, 5, 9}) << endl; // 출력값 : 9534330 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /Example/frequency_word.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | int main() { 13 | // 문자열 내 각 문자의 빈도를 저장할 unordered_map 선언 14 | unordered_map frequency; 15 | 16 | // 분석할 문자열 17 | string str = "hello world"; 18 | 19 | // 문자열의 각 문자를 순회하면서 빈도를 계산 20 | for (char ch : str) { 21 | frequency[ch]++; 22 | } 23 | 24 | // 각 문자의 빈도 출력 25 | for (const auto& pair : frequency) { 26 | cout << pair.first << ": " << pair.second << "\n"; 27 | } 28 | 29 | // 출력값: 30 | // h: 1 31 | // e: 1 32 | // l: 3 33 | // o: 2 34 | // : 1 35 | // w: 1 36 | // r: 1 37 | // d: 1 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /solution/70.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 두 문자열의 LCS 길이를 계산하는 함수 8 | int solution(string str1, string str2) { 9 | // ❶ 두 문자열의 길이를 저장 10 | int m = str1.length(); 11 | int n = str2.length(); 12 | 13 | // ❷ LCS를 저장할 테이블 초기화 14 | vector> dp(m + 1, vector(n + 1, 0)); 15 | 16 | // ❸ 동적 프로그래밍을 통해 LCS 길이 계산 17 | for (int i = 1; i <= m; ++i) { 18 | for (int j = 1; j <= n; ++j) { 19 | // ❹ 현재 비교하는 문자가 같으면 20 | if (str1[i - 1] == str2[j - 1]) { 21 | dp[i][j] = dp[i - 1][j - 1] + 1; 22 | } 23 | // ❺ 현재 비교하는 문자가 같지 않으면 24 | else { 25 | dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); 26 | } 27 | } 28 | } 29 | 30 | // ❻ LCS 길이 반환 31 | return dp[m][n]; 32 | } 33 | 34 | 35 | //아래 코드는 테스트 코드 입니다. 36 | #include 37 | 38 | using namespace std; 39 | 40 | int main() 41 | { 42 | cout << solution("ABCBDAB","BDCAB") << endl; //출력값: 4 43 | cout << solution("AGGTAB", "GXTXAYB") << endl; //출력값 :4 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /solution/69.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector solution(vector keyinput, vector board) 7 | { 8 | //❶ 현재 위치를 나타 내는 크기가 2이고 값이 모두 0인 벡터 선언 9 | vector v(2,0); 10 | 11 | //❷ 키 입력순으로 캐릭터 이동 12 | for(string s : keyinput) 13 | { 14 | if (s=="up" && v[1]<+board[1]/2) v[1]++; 15 | else if(s=="down" && v[1]>-board[1]/2) v[1]--; 16 | else if(s=="left" && v[0]>-board[0]/2) v[0]--; 17 | else if(s=="right" && v[0]<+board[0]/2) v[0]++; 18 | } 19 | 20 | return v; 21 | } 22 | 23 | 24 | //아래 코드는 테스트 코드 입니다. 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | void print(vector vec) 31 | { 32 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 33 | cout << endl; 34 | } 35 | 36 | int main() 37 | { 38 | print(solution({"left", "right", "up", "right", "right"}, {11, 11})); //출력값 : 2 1 39 | print(solution({"down", "down", "down", "down", "down"}, {7, 9})); //출력값 : 0 -4 40 | 41 | return 0; 42 | } 43 | -------------------------------------------------------------------------------- /solution/100.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 로또의 최고 순위와 최저 순위를 찾는 함수 8 | vector solution(vector lottos, vector win_nums) { 9 | // 로또 순위를 정의 (0개 맞춤부터 6개 맞춤까지의 순위) 10 | int rank[7] = {6, 6, 5, 4, 3, 2, 1}; 11 | unordered_map winMap; // 당첨 번호를 저장하는 해시맵 12 | 13 | // 당첨 번호를 해시맵에 저장 14 | for (int win_num : win_nums) { 15 | winMap[win_num]++; 16 | } 17 | 18 | vector answer(2, 0); // 최저 순위와 최고 순위를 저장할 벡터 19 | // 로또 번호를 확인하여 최고 순위와 최저 순위 계산 20 | for (int lotto : lottos) { 21 | // 0인 경우 미지의 번호로 최고 순위에만 영향을 줌 22 | if (lotto == 0) { 23 | answer[0]++; 24 | continue; 25 | } 26 | // 당첨 번호인 경우 최고 순위와 최저 순위에 모두 영향을 줌 27 | if (winMap.find(lotto) != winMap.end()) { 28 | answer[0]++; 29 | answer[1]++; 30 | } 31 | } 32 | 33 | // 최종 순위를 순위 테이블을 이용하여 업데이트 34 | answer[0] = rank[answer[0]]; 35 | answer[1] = rank[answer[1]]; 36 | 37 | return answer; // 최고 순위와 최저 순위 반환 38 | } 39 | -------------------------------------------------------------------------------- /solution/49.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int maxDepth = 0; 8 | bool visited[8] = {false, }; 9 | 10 | //❶ 최대방문 던전수를 갱신하면서 깊이우선탐색으로 던전을 탐험 11 | void exploreDungeon(int depth, int power, vector>& dungeons) { 12 | if(maxDepth < depth) 13 | maxDepth = depth; 14 | 15 | for(int i = 0; i < dungeons.size(); i++) { 16 | //❷ 이미 방문한 던전이거나, 최소 필요 피로도가 현재 남은 피로도 보다 많은 경우 17 | if(visited[i] || dungeons[i][0] > power) 18 | continue; 19 | 20 | //❸ 방문이 가능한 가능한 모든 경우를 확인 21 | visited[i] = true; 22 | exploreDungeon(depth + 1, power - dungeons[i][1], dungeons); 23 | visited[i] = false; 24 | } 25 | } 26 | 27 | int solution(int initialPower,vector> dungeons) { 28 | //❹ 던전탐색 시작 29 | exploreDungeon(0, initialPower, dungeons); 30 | 31 | return maxDepth; 32 | } 33 | 34 | 35 | 36 | 37 | //아래 코드는 테스트 코드 입니다. 38 | #include 39 | 40 | using namespace std; 41 | 42 | int main() 43 | { 44 | cout << solution(80, {{80, 20}, {50, 40}, {30, 10}}) << endl; // 출력값 : 3 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /solution/65.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | vector solution(string s) { 9 | int transforms = 0; 10 | int removedZeros = 0; 11 | //❶ s가 “1”이 될때까지 계속 반복 12 | while (s != "1") { 13 | transforms++; 14 | 15 | //❷ '0' 개수를 세어 removedZeros에 누적 16 | removedZeros += count(s.begin(), s.end(), '0'); 17 | 18 | //❸ '1' 개수를 세고, 이를 이진수로 변환 19 | int onesCount = count(s.begin(), s.end(), '1'); 20 | s = bitset<32>(onesCount).to_string(); 21 | s = s.substr(s.find('1')); 22 | } 23 | 24 | return {transforms, removedZeros}; 25 | } 26 | 27 | 28 | 29 | //아래 코드는 테스트 코드 입니다. 30 | #include 31 | #include 32 | 33 | using namespace std; 34 | 35 | void print(vector vec) 36 | { 37 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 38 | cout << endl; 39 | } 40 | 41 | int main() 42 | { 43 | print(solution("110010101001")); //출력값 : 3 8 44 | print(solution("01110")); //출력값 : 3 3 45 | print(solution("1111111")); //출력값 : 4 1 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /solution/67.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector solution(int green, int white) { 7 | // ❶ 격자의 총 개수 (파란색 격자 + 흰색 격자) 8 | int total_size = green + white; 9 | // ❷ 세로 길이의 범위는 3부터 (파란색 격자 + 흰색 격자)의 제곱근 10 | for (int vertical = 3; vertical <= sqrt(total_size); ++vertical) { 11 | // ❸ 사각형 구성이 되는지 확인 12 | if (total_size % vertical == 0) { 13 | int horizontal = total_size / vertical; // ❹ 사각형의 가로 길이 14 | // ❺ 카펫 형태로 만들 수 있는지 확인 15 | if (green == (horizontal + vertical - 2) * 2) { 16 | return {horizontal, vertical}; // ❻ {가로 길이, 세로 길이} 17 | } 18 | } 19 | } 20 | return {}; // ❼ 만약 답을 찾지 못했다면 빈 벡터를 반환 21 | } 22 | 23 | 24 | //아래 코드는 테스트 코드 입니다. 25 | #include 26 | #include 27 | 28 | using namespace std; 29 | 30 | void print(vector vec) 31 | { 32 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 33 | cout << endl; 34 | } 35 | 36 | int main() 37 | { 38 | print(solution(10, 2)); //출력값 : 4 3 39 | print(solution(8, 1)); //출력값 : 3 3 40 | print(solution(24, 24)); //출력값 : 8 6 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /solution/42.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector visited; 7 | 8 | //❶ 깊이 우선 탐색(DFS)을 수행하는 함수 9 | void dfs(const vector>& network, int node) { 10 | visited[node] = true; 11 | 12 | for (int i = 0; i < network[node].size(); i++) { 13 | if (network[node][i] && !visited[i]) { 14 | dfs(network, i); 15 | } 16 | } 17 | } 18 | 19 | int solution(int n, vector> computers) { 20 | visited = vector(computers.size(), false); 21 | 22 | int networkCount = 0; 23 | 24 | //❷ 네트워크의 수를 확인 25 | for (int i = 0; i < computers.size(); i++) { 26 | if (!visited[i]) { 27 | dfs(computers, i); 28 | networkCount++; 29 | } 30 | } 31 | 32 | return networkCount; 33 | } 34 | 35 | 36 | 37 | //아래 코드는 테스트 코드 입니다. 38 | #include 39 | 40 | using namespace std; 41 | 42 | void init() 43 | { 44 | visited.clear(); 45 | } 46 | int main() 47 | { 48 | 49 | cout << solution(3, {{1, 1, 0}, {1, 1, 0}, {0, 0, 1}}) << endl; //출력값 : 2 50 | init(); 51 | cout << solution(3, {{1, 1, 0}, {1, 1, 1}, {0, 1, 1}}) << endl; //출력값 : 1 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /Example/stairproblem_dp.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 문제의 정의: 5 | // N개의 계단이 존재하고, 한 번에 1개 또는 2개의 계단을 오를 수 있을 때, 6 | // 계단을 오르는 방법의 총 수를 구하는 문제입니다. 7 | 8 | // 최적 부분 구조: 9 | // 현재 계단에 도달하는 방법은 이전 계단에서 한 계단 오르거나, 10 | // 두 계단 아래에서 두 계단 오르는 두 가지 방법으로 나뉩니다. 11 | // 즉, f(n) = f(n-1) + f(n-2)의 형태로 나타낼 수 있습니다. 12 | 13 | // 중복 부분 문제: 14 | // 동일한 부분 문제(예: f(n-1), f(n-2))가 여러 번 반복되어 계산됩니다. 15 | // 동적 계획법을 사용하면 이러한 중복 계산을 피할 수 있습니다. 16 | 17 | int countWays(int n); 18 | 19 | int main() { 20 | int n; 21 | std::cout << "계단의 수를 입력하세요: "; 22 | std::cin >> n; 23 | 24 | int result = countWays(n); 25 | std::cout << "계단을 오르는 방법의 총 수: " << result << std::endl; 26 | 27 | return 0; 28 | } 29 | 30 | // 계단을 오르는 방법의 총 수를 계산하는 함수 31 | int countWays(int n) { 32 | // 동적 계획법을 위한 배열 선언 33 | std::vector dp(n + 1); 34 | 35 | // 초기값 설정 36 | dp[1] = 1; // 계단 1개를 오르는 방법은 1가지 37 | dp[2] = 2; // 계단 2개를 오르는 방법은 2가지 (1+1 또는 2) 38 | 39 | // 동적 계획법을 이용한 계산 40 | // 점화식: dp[i] = dp[i - 1] + dp[i - 2] 41 | for (int i = 3; i <= n; ++i) { 42 | dp[i] = dp[i - 1] + dp[i - 2]; 43 | } 44 | 45 | return dp[n]; 46 | } 47 | -------------------------------------------------------------------------------- /Example/backtracking_sturcure.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | /* 8 | 상태 정의 : 문제의 각 단계에서 가능한 상태를 정의 9 | 유망 함수(isPromising) : 현재 상태가 유망한지 판단, 유망하지 않으면 더 이상 탐색 x 10 | 해결책 확인(isSolution) : 현재 상태가 문제의 해결책인지 판단 11 | 재귀 호출 : 유망한 상태로 이동하면서 문제 해결 12 | */ 13 | 14 | // 유망성 판단 함수 15 | bool isPromising(int level, State state) { 16 | // 현재 상태가 유망한지 판단하는 로직을 구현합니다. 17 | } 18 | 19 | // 해결책 확인 함수 20 | bool isSolution(State state) { 21 | // 현재 상태가 문제의 해결책인지 판단하는 로직을 구현합니다. 22 | } 23 | 24 | // 백트래킹 함수 25 | void backtrack(int level, State state) { 26 | // 현재 상태가 해결책이면 처리 27 | if (isSolution(state)) { 28 | processSolution(state); 29 | return; 30 | } 31 | // 다음 가능한 상태를 탐색 32 | for (State nextState : possibleStates(state)) { 33 | if (isPromising(level, nextState)) { 34 | backtrack(level + 1, nextState); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Example/Algorithm_with_DataStructure/bactracking_structure.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | /* 8 | 상태 정의 : 문제의 각 단계에서 가능한 상태를 정의 9 | 유망 함수(isPromising) : 현재 상태가 유망한지 판단, 유망하지 않으면 더 이상 탐색 x 10 | 해결책 확인(isSolution) : 현재 상태가 문제의 해결책인지 판단 11 | 재귀 호출 : 유망한 상태로 이동하면서 문제 해결 12 | */ 13 | // 유망성 판단 함수 14 | bool isPromising(int level, State state) { 15 | // 현재 상태가 유망한지 판단하는 로직을 구현합니다. 16 | } 17 | 18 | // 해결책 확인 함수 19 | bool isSolution(State state) { 20 | // 현재 상태가 문제의 해결책인지 판단하는 로직을 구현합니다. 21 | } 22 | 23 | // 백트래킹 함수 24 | void backtrack(int level, State state) { 25 | // 현재 상태가 해결책이면 처리 26 | if (isSolution(state)) { 27 | processSolution(state); 28 | return; 29 | } 30 | // 다음 가능한 상태를 탐색 31 | for (State nextState : possibleStates(state)) { 32 | if (isPromising(level, nextState)) { 33 | backtrack(level + 1, nextState); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /solution/08.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // 'solution' 함수는 문자열 's'가 올바른 괄호 구조를 가지고 있는지 확인합니다. 5 | // '(' 괄호가 나오면 스택에 푸시하고, ')' 괄호가 나오면 스택에서 팝합니다. 6 | // 모든 문자를 확인한 후 스택이 비어있다면 괄호가 올바르게 닫힌 것입니다. 7 | bool solution(string s) { 8 | stack stack; 9 | 10 | for (char c : s) { 11 | //❶ '(' 괄호를 스택에 푸시합니다. 12 | if (c == '(') { 13 | stack.push(c); 14 | } 15 | else if (c == ')') { 16 | // ❷ ')' 괄호가 나오면 스택이 비어있는지 확인 17 | if (stack.empty()) { 18 | //❸ 스택이 비어있다면 괄호 짝이 맞지 않으므로 false반환 19 | return false; 20 | } else { 21 | //❹ 비어있지 않다면 팝 연산(짝을 찾으므로 여는괄호 스택에서 제거) 22 | stack.pop(); 23 | } 24 | } 25 | } 26 | 27 | //❺ 스택이 비어있다면 괄호가 올바르게 닫힌 것이므로 true 반환, 아니라면 false 반환 28 | return stack.empty(); 29 | } 30 | 31 | //아래 코드는 테스트 코드 입니다. 32 | #include 33 | int main() 34 | { 35 | //(true를 출력하면 1 이고, false를 출력하면 0입니다. 36 | 37 | cout << solution("(())()") << endl; // 1 38 | cout << solution("((())()") << endl; // 0 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /solution/55.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | vector solution(vector arr1, vector arr2) { 6 | //❶ 두 배열을 정렬된 상태로 병합하는 배열 7 | vector merged; 8 | int i = 0, j = 0; 9 | 10 | //❷ 두 배열을 순회하면서 정렬된 배열을 생성 11 | while (i < arr1.size() && j < arr2.size()) { 12 | if (arr1[i] <= arr2[j]) { 13 | merged.push_back(arr1[i]); 14 | i++; 15 | } else { 16 | merged.push_back(arr2[j]); 17 | j++; 18 | } 19 | } 20 | 21 | //❸ arr1이나 arr2 중 남아있는 원소들을 정렬된 배열 뒤에 추가 22 | while (i < arr1.size()) { 23 | merged.push_back(arr1[i]); 24 | i++; 25 | } 26 | while (j < arr2.size()) { 27 | merged.push_back(arr2[j]); 28 | j++; 29 | } 30 | 31 | return merged; 32 | } 33 | 34 | 35 | //아래 코드는 테스트 코드 입니다. 36 | #include 37 | #include 38 | 39 | using namespace std; 40 | 41 | void print(vector vec) 42 | { 43 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 44 | cout << endl; 45 | } 46 | 47 | int main() 48 | { 49 | print(solution({1, 3, 5}, {2, 4, 6})); // 출력값 : 1 2 3 4 5 6 50 | print(solution({1, 2, 3}, {4, 5, 6})); // 출력값 : 1 2 3 4 5 6 51 | 52 | return 0; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /STL/count.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include // for std::count 9 | using namespace std; 10 | 11 | int main() { 12 | // 예시 벡터 생성 13 | vector v = {1, 2, 3, 4, 5, 1, 2, 1}; 14 | 15 | // count 함수 사용 예시 16 | // std::count 함수는 주어진 범위에서 특정 값이 몇 번 나타나는지 센다. 17 | // 여기서 v.begin()과 v.end()는 벡터의 시작과 끝을 나타내며, 18 | // 1은 찾고자 하는 값이다. 19 | int count_of_1 = count(v.begin(), v.end(), 1); 20 | 21 | // 결과 출력 22 | cout << "벡터에서 1의 개수: " << count_of_1 << endl; 23 | 24 | // 출력값: 25 | // 벡터에서 1의 개수: 3 26 | 27 | // 시간 복잡도: 28 | // std::count 함수의 시간 복잡도는 O(N)이다. 29 | // 여기서 N은 주어진 범위의 요소 수를 나타낸다. 30 | 31 | // count 함수를 사용해야 하는 경우 32 | // 데이터 집합에서 특정 값의 출현 빈도를 알고 싶을 때 유용하다. 33 | // 예를 들어, 설문조사 결과에서 특정 답변이 몇 번 나왔는지 확인할 때 사용할 수 있다. 34 | 35 | return 0; 36 | } 37 | 38 | -------------------------------------------------------------------------------- /solution/12.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | vector solution(vector prices) { 8 | //❶ 가격이 떨어지지 않은 기간을 저장한 벡터 9 | vector answer(prices.size()); 10 | // 스택에는 prices의 인덱스가 들어감, 이전 가격과 현재 가격을 비교하기 위한 용도로 사용됨 11 | stack s; 12 | 13 | int priceNum = prices.size(); 14 | 15 | for(int i=0;iprices[i]){ 17 | //❷ 가격이 떨어졌으므로 이전 가격의 기간 계산 18 | answer[s.top()] = i-s.top(); 19 | s.pop(); 20 | } 21 | s.push(i); 22 | } 23 | //❸ 스택에 남아있는 가격들은 가격이 떨어지지 않은 경우 24 | while(!s.empty()){ 25 | answer[s.top()] = priceNum-s.top()-1; 26 | s.pop(); 27 | } 28 | return answer; 29 | } 30 | 31 | 32 | 33 | 34 | //아래 코드는 테스트 코드 입니다. 35 | #include 36 | #include 37 | void print(vector vec) 38 | { 39 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 40 | cout << endl; 41 | } 42 | 43 | int main() 44 | { 45 | print(solution({1, 2, 3, 2, 3})); // 4 3 1 1 0 46 | return 0; 47 | 48 | } 49 | -------------------------------------------------------------------------------- /solution/87.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | // v 벡터에서 dx 용량만큼 제거하는 함수 7 | void RemoveCargo(vector &cargo, int capacity) { 8 | while (!cargo.empty() && capacity) { 9 | // 현재 용량이 마지막 화물의 무게보다 크거나 같으면 화물을 제거 10 | if (cargo.back() <= capacity) { 11 | capacity -= cargo.back(); 12 | cargo.pop_back(); 13 | } else { 14 | // 현재 용량으로 화물의 무게를 감소시키고, 용량을 0으로 설정 15 | cargo.back() -= capacity; 16 | capacity = 0; 17 | } 18 | } 19 | } 20 | 21 | // 항구에서 화물을 옮기는 데 필요한 최소 시간을 계산하는 함수 22 | long long solution(int cap, int n, vector A, vector B) { 23 | long long int answer = 0; 24 | while (!A.empty() || !B.empty()) { 25 | // A, B에서 무게가 0인 화물 제거 26 | while (!A.empty() && A.back() == 0) A.pop_back(); 27 | while (!B.empty() && B.back() == 0) B.pop_back(); 28 | 29 | // A와 B 중 더 긴 벡터의 길이를 dx로 설정 30 | int trips = max(A.size(), B.size()); 31 | // 왕복 횟수를 계산하여 정답에 추가 32 | answer += trips * 2; 33 | 34 | // A, B에서 cap 용량만큼 화물 제거 35 | RemoveCargo(A, cap); 36 | RemoveCargo(B, cap); 37 | } 38 | 39 | return answer; 40 | } 41 | -------------------------------------------------------------------------------- /solution/93.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | // 주어진 숫자가 소수인지 판별하는 함수 9 | bool isPrime(long long num) { 10 | if (num == 1) return false; // 1은 소수가 아님 11 | for (long long i = 2; i * i <= num; i++) { 12 | if (num % i == 0) return false; // 나누어 떨어지면 소수가 아님 13 | } 14 | return true; 15 | } 16 | 17 | // n을 k진수로 변환했을 때, 조건을 만족하는 소수의 개수를 반환하는 함수 18 | int solution(int n, int k) { 19 | int answer = 0; // 조건을 만족하는 소수의 개수 20 | long long currentNum = 0; // 현재 확인 중인 숫자 21 | long long multiplier = 1; // k진수에서의 자릿수를 계산하기 위한 배수 22 | 23 | // n을 k진수로 변환하면서 소수를 확인 24 | while (n) { 25 | if (n % k == 0) { // k로 나누어떨어지면, 현재까지의 숫자를 소수 판별 26 | if (currentNum && isPrime(currentNum)) { 27 | answer++; 28 | } 29 | multiplier = 1; // 배수와 현재 숫자를 초기화 30 | currentNum = 0; 31 | } else { // k로 나누어떨어지지 않으면, 숫자를 생성 32 | currentNum += (n % k) * multiplier; 33 | multiplier *= 10; 34 | } 35 | n /= k; // 다음 자리 숫자로 36 | } 37 | 38 | // 마지막으로 남은 숫자에 대한 소수 판별 39 | if (currentNum && isPrime(currentNum)) { 40 | answer++; 41 | } 42 | 43 | return answer; 44 | } 45 | -------------------------------------------------------------------------------- /Example/managing_stdudent_one_score.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | int main() { 13 | // unordered_map을 사용하여 학생 ID를 키로, 성적을 값으로 저장 14 | unordered_map students; 15 | 16 | // 학생 정보 추가 17 | students["12345"] = "A"; // 학생 ID "12345"의 성적은 "A" 18 | students["67890"] = "B"; // 학생 ID "67890"의 성적은 "B" 19 | students["54321"] = "A+"; // 학생 ID "54321"의 성적은 "A+" 20 | 21 | // 특정 학생 정보 검색 22 | string student_id = "12345"; // 검색할 학생 ID 설정 23 | if (students.find(student_id) != students.end()) { 24 | // 학생 ID가 존재하면 성적을 출력 25 | cout << "학생 ID: " << student_id << "\n"; // 학생 ID 출력 26 | cout << "성적: " << students[student_id] << "\n"; // 해당 학생의 성적 출력 27 | // 출력값: 성적: A 28 | } else { 29 | // 학생 ID가 존재하지 않으면 에러 메시지 출력 30 | cout << "학생 정보를 찾을 수 없습니다.\n"; 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /solution/20.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | string solution(vector participant, vector completion) { 8 | //❶ participant를 나타낼 해시테이블 9 | unordered_map ph; 10 | 11 | //❷ 각 참가자들을 해시 테이블에 추가( 키 : 이름, 값 : 해당 이름의 명 수) 12 | for (int i = 0; i < participant.size(); i++) 13 | ph[participant[i]]++; 14 | 15 | 16 | //❸ 참가자 정보가 저장된 해시 테이블에서, 완주한 선수들을 제외 17 | for (int i = 0; i < completion.size(); i++) 18 | { 19 | ph[completion[i]]--; 20 | //❹ 해시테이블에서 특정 이름의 인원이 0명이면, 해시 테이블에서 삭제 21 | if (ph[completion[i]] == 0) 22 | ph.erase(ph.find(completion[i])); 23 | } 24 | //❺ 마지막 남은 한 선수의 이름을 반환 25 | return ph.begin()->first; 26 | } 27 | 28 | 29 | 30 | //아래 코드는 테스트 코드 입니다. 31 | 32 | #include 33 | 34 | int main() 35 | { 36 | cout << solution({"leo", "kiki", "eden"}, {"eden", "kiki"}) << endl; // "leo" 37 | cout << solution({"marina", "josipa", "nikola", "vinko", "filipa"}, {"josipa", "filipa", "marina", "nikola"}) << endl; // "vinko" 38 | cout << solution({"mislav", "stanko", "mislav", "ana"}, {"stanko", "ana", "mislav"}) << endl; // "mislav" 39 | return 0; 40 | 41 | } 42 | -------------------------------------------------------------------------------- /STL/reverse.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace std; 11 | 12 | // std::reverse는 C++ STL의 algorithm 헤더에 포함된 순서 반전 함수입니다. 13 | // - 주어진 범위의 요소 순서를 반대로 만듭니다. 14 | // 좋은 사용 시기: 15 | // - 배열이나 컨테이너의 요소 순서를 반전하고 싶을 때. 16 | // 성능 이슈: 17 | // - reverse는 선형 시간 복잡도를 갖는 알고리즘입니다. 대부분의 사용 사례에서 효율적으로 동작합니다. 18 | 19 | int main() { 20 | 21 | vector v = {1, 2, 3, 4, 5}; 22 | 23 | // 기본 동작: 범위 내 요소의 순서 반전, O(n) 24 | reverse(v.begin(), v.end()); 25 | for(int i : v) cout << i << " "; // 출력: 5 4 3 2 1 26 | cout << endl; 27 | 28 | // 부분 범위의 요소 순서 반전 29 | reverse(v.begin() + 1, v.end() - 1); 30 | for(int i : v) cout << i << " "; // 출력: 5 2 3 4 1 31 | cout << endl; 32 | 33 | // 성능 저하 예제: 34 | // reverse는 일반적으로 선형 시간 내에 완료되므로 성능 저하를 걱정할 필요가 적습니다. 35 | // 그러나 매우 큰 데이터 셋에서는 다른 연산과 결합될 때 성능에 영향을 줄 수 있습니다. 36 | 37 | return 0; 38 | 39 | } 40 | 41 | -------------------------------------------------------------------------------- /solution/98.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 보석 쇼핑을 위해 선택해야 하는 구간을 찾는 함수 8 | vector solution(vector gems) { 9 | vector answer(2, 0); // 정답을 저장할 벡터, 시작 위치와 끝 위치를 저장 10 | map gemTypes; // 모든 보석 종류와 개수 11 | map possession; // 현재 구간에 있는 보석의 종류와 개수 12 | int start = 0, end = 0; // 탐색할 구간의 시작과 끝 13 | int minLen = gems.size() + 1; // 최소 구간 길이를 최대로 설정 14 | 15 | // 모든 보석 종류 파악 16 | for (const auto& gem : gems) { 17 | gemTypes[gem]++; 18 | } 19 | 20 | while (end < gems.size()) { 21 | possession[gems[end]]++; // 현재 보석 추가 22 | end++; // 구간의 끝을 확장 23 | 24 | // 현재 구간에 모든 종류의 보석이 포함되지 않은 경우 25 | if (possession.size() < gemTypes.size()) { 26 | continue; 27 | } 28 | 29 | // 시작점을 최대한 앞으로 30 | while (possession[gems[start]] > 1) { 31 | possession[gems[start]]--; 32 | start++; 33 | } 34 | 35 | // 최소 구간 길이보다 현재 구간이 더 작은 경우 결과 갱신 36 | if (end - start < minLen) { 37 | minLen = end - start; 38 | answer[0] = start + 1; // 시작점 조정 (1부터 시작) 39 | answer[1] = end; // 끝점 40 | } 41 | } 42 | 43 | return answer; 44 | } 45 | -------------------------------------------------------------------------------- /solution/78.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int solution(vector> board) { 6 | //❶ 주어진 2차원 보드의 행과 열의 개수를 변수에 저장합니다. 7 | int ROW = board.size(), COL = board[0].size(); 8 | 9 | //❷ 각 행과 열을 순회하며 가장 큰 정사각형의 길이 확인 10 | for (int i = 1; i < ROW; ++i) { 11 | for (int j = 1; j < COL; ++j) { 12 | //❸ 현재 위치의 값이 1인 경우 13 | if (board[i][j] == 1) { 14 | //❹ 현재 위치에서 위, 왼쪽, 대각선 왼쪽 위의 값을 구함 15 | int up = board[i - 1][j]; 16 | int left = board[i][j - 1]; 17 | int up_left = board[i - 1][j - 1]; 18 | 19 | //❺ 현재 위치의 값을 이전 위치들의 값들 중 가장 작은 값에 1을 더한 값으로 업데이트 20 | board[i][j] = min(min(up, left), up_left) + 1; 21 | } 22 | } 23 | } 24 | 25 | //❻ 보드에서 가장 큰 값(최대 정사각형의 한 변의 길이) 확인 26 | int max_val = 0; 27 | for (const auto& row : board) { 28 | max_val = max(max_val, *max_element(row.begin(), row.end())); 29 | } 30 | //❼ 최대 정사각형 넓이 반환 31 | return max_val * max_val; 32 | } 33 | 34 | 35 | 36 | 37 | //아래 코드는 테스트 코드 입니다. 38 | #include 39 | 40 | using namespace std; 41 | 42 | int main() 43 | { 44 | cout << solution({{0, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {0, 0, 1, 0}}) << endl; //출력값 : 9 45 | cout << solution({{0, 0, 1, 1}, {1, 1, 1, 1}}) << endl; //출력값 : 4 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /solution/66.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int solution(vector topping) { 9 | int answer = 0; 10 | 11 | //❶ 남아있는 각 토핑의 개수 12 | unordered_map topping_cnt; 13 | //❷ 절반에 속한 토핑의 종류 14 | unordered_set half_topping; 15 | 16 | //❸ 카운터에 각 토핑의 개수를 저장 17 | for (auto top : topping) { 18 | if (topping_cnt.find(top) == topping_cnt.end()) { 19 | topping_cnt[top] = 1; 20 | } else { 21 | topping_cnt[top]++; 22 | } 23 | } 24 | 25 | //❹ 앞에서 부터 토핑을 순서대로 순회 26 | for (int i = 0; i < topping.size(); i++) { 27 | //❺ 절반에 속하는 토핑에 추가하고, 남은 토핑개수에서 제외 28 | half_topping.insert(topping[i]); 29 | topping_cnt[topping[i]]--; 30 | //❻ 현재 토핑이 남아있지 않은 경우 남은 토핑 목록에서 삭제 31 | if (topping_cnt[topping[i]] == 0) { 32 | topping_cnt.erase(topping[i]); 33 | } 34 | //❼ 공평한 경우 카운팅 35 | if (topping_cnt.size() == half_topping.size()) { 36 | answer++; 37 | } 38 | } 39 | 40 | return answer; 41 | } 42 | 43 | 44 | //아래 코드는 테스트 코드 입니다. 45 | #include 46 | 47 | using namespace std; 48 | 49 | 50 | int main() 51 | { 52 | cout << solution({1, 2, 1, 3, 1, 4, 1, 2}) << endl; // 출력값 : 2 53 | cout << solution({1, 2, 3, 1, 4}) << endl; // 출력값 : 0 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /solution/13.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int solution(vector> board, vector moves) { 7 | //❶ 보드판의 열의 크기만큼 스택을 생성 8 | stack lanes[board[0].size()]; 9 | //❷ 보드의 가장 밑의 행부터 위로 올라가먼서 순회 10 | for(int i = board.size()-1 ; i >= 0; --i) { 11 | for(int j = 0; j bucket; 21 | int answer = 0; 22 | 23 | for(int m : moves) { 24 | //❹ 해당 lane에 블럭이 있으면 25 | if(lanes[m-1].size()){ 26 | int doll = lanes[m-1].top(); 27 | lanes[m-1].pop(); 28 | //❺ 버킷에 블럭이 있고, 가장 최근에 들어간 블럭과 현재 블럭이 같은지 확인 29 | if (bucket.size() && bucket.top() == doll) { 30 | bucket.pop(); 31 | answer += 2; 32 | } else { 33 | bucket.push(doll); 34 | } 35 | } 36 | } 37 | 38 | return answer; 39 | } 40 | 41 | //아래 코드는 테스트 코드 입니다. 42 | #include 43 | 44 | int main() 45 | { 46 | 47 | cout << solution( { {0, 0, 0, 0, 0}, {0, 0, 1, 0, 3}, {0, 2, 5, 0, 1}, {4, 2, 4, 4, 2}, {3, 5, 1, 3, 1} }, {1, 5, 3, 5, 1, 2, 1, 4} ) << endl; // 4 48 | return 0; 49 | } -------------------------------------------------------------------------------- /STL/min_element.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include // for std::min_element 9 | using namespace std; 10 | 11 | int main() { 12 | // 예시 벡터 생성 13 | vector v = {1, 3, 4, 5, 7, 9, 10}; 14 | 15 | // 최소값 찾기 16 | auto min_it = min_element(v.begin(), v.end()); 17 | 18 | // 결과 출력 19 | cout << "최소값: " << *min_it << " (위치: " << distance(v.begin(), min_it) << ")" << endl; 20 | 21 | return 0; 22 | } 23 | 24 | /* 25 | 출력값: 26 | 27 | 최소값: 1 (위치: 0) 28 | */ 29 | 30 | // min_element에 대한 설명 31 | /* 32 | std::min_element 함수는 주어진 범위에서 가장 작은 요소를 찾는 데 사용됩니다. 33 | 이 함수는 선형 탐색 알고리즘을 사용하여 값을 찾습니다. 34 | 35 | 설명: 36 | 1. 반환값: 가장 작은 값을 가리키는 반복자를 반환합니다. 37 | 반환된 반복자를 사용하여 해당 값에 접근할 수 있습니다. 38 | 2. 범위: 시작 반복자와 끝 반복자를 인자로 받아, 이 범위 내에서 탐색을 수행합니다. 39 | 40 | 시간복잡도: 41 | - std::min_element 함수의 시간복잡도는 O(N)입니다. 여기서 N은 범위 내의 요소 수입니다. 42 | 43 | 예제: 44 | 벡터가 {1, 3, 4, 5, 7, 9, 10}로 주어졌을 때, 45 | min_element(v.begin(), v.end())를 호출하면 반복자가 1을 가리킵니다. 46 | */ 47 | 48 | -------------------------------------------------------------------------------- /STL/max_element.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include // for std::max_element 9 | using namespace std; 10 | 11 | int main() { 12 | // 예시 벡터 생성 13 | vector v = {1, 3, 4, 5, 7, 9, 10}; 14 | 15 | // 최대값 찾기 16 | auto max_it = max_element(v.begin(), v.end()); 17 | 18 | // 결과 출력 19 | cout << "최대값: " << *max_it << " (위치: " << distance(v.begin(), max_it) << ")" << endl; 20 | 21 | return 0; 22 | } 23 | 24 | /* 25 | 출력값: 26 | 27 | 최대값: 10 (위치: 6) 28 | */ 29 | 30 | // max_element에 대한 설명 31 | /* 32 | std::max_element 함수는 주어진 범위에서 가장 큰 요소를 찾는 데 사용됩니다. 33 | 이 함수는 선형 탐색 알고리즘을 사용하여 값을 찾습니다. 34 | 35 | 설명: 36 | 1. 반환값: 가장 큰 값을 가리키는 반복자를 반환합니다. 37 | 반환된 반복자를 사용하여 해당 값에 접근할 수 있습니다. 38 | 2. 범위: 시작 반복자와 끝 반복자를 인자로 받아, 이 범위 내에서 탐색을 수행합니다. 39 | 40 | 시간복잡도: 41 | - std::max_element 함수의 시간복잡도는 O(N)입니다. 여기서 N은 범위 내의 요소 수입니다. 42 | 43 | 예제: 44 | 벡터가 {1, 3, 4, 5, 7, 9, 10}로 주어졌을 때, 45 | max_element(v.begin(), v.end())를 호출하면 반복자가 10을 가리킵니다. 46 | */ 47 | 48 | 49 | -------------------------------------------------------------------------------- /reference/ReadMe.md: -------------------------------------------------------------------------------- 1 | | 파일 이름 | 설명 | 2 | |-------------------------|-----------------------------------------------------------------------------| 3 | | `if_statement.cpp` | if문 사용법: 조건에 따라 다르게 실행되는 코드 블록을 만드는 if, if-else, 및 if-else if-else 문을 설명합니다. | 4 | | `loop.cpp` | 반복문 사용법: for, while, do-while 반복문을 사용하여 코드를 반복 실행하는 방법을 설명합니다. | 5 | | `reference.cpp` | 참조 사용법: C++에서 참조를 사용하여 변수의 별칭을 생성하고, 함수의 매개변수로 참조를 사용하는 예제를 보여줍니다. | 6 | | `string.cpp` | 문자열 사용법: std::string 클래스를 사용하여 문자열을 생성, 수정, 조작하는 다양한 방법을 설명합니다. | 7 | | `type_conversion.cpp` | 타입 변환: 암시적 및 명시적 타입 변환, 그리고 static_cast, dynamic_cast를 사용한 변환 예제를 제공합니다. | 8 | | `variable.cpp` | 변수 정의: C++에서 변수를 정의하고 초기화하는 방법, 변수의 유효 범위와 생명주기를 설명합니다. | 9 | | `variable_scope.cpp` | 변수 범위: 전역 변수, 지역 변수, 정적 변수의 범위와 사용 시 주의점을 다룹니다. | 10 | | `decay.cpp` | 타입 감쇠: 함수 템플릿과 배열, 함수 포인터 매개변수에서의 타입 감쇠 현상을 설명합니다. | 11 | | `dynamic_alloc.cpp` | 동적 할당: new와 delete를 사용하여 힙 메모리를 할당하고 해제하는 방법을 설명합니다. | 12 | | `function.cpp` | 함수 사용법: 함수의 정의, 호출, 매개변수 전달, 반환 값과 함수 오버로딩에 대해 설명합니다. | 13 | | `callback.cpp` | 콜백 함수 사용법: 함수를 다른 함수의 인자로 전달하고, 이벤트 발생 시 호출하는 방법을 설명합니다. | 14 | | `variables.cpp` | 변수 선언과 초기화: 다양한 데이터 타입의 변수를 선언하고 초기화하는 방법을 설명합니다. | 15 | | `array.cpp` | 배열 사용법: 동일한 타입의 여러 데이터를 연속적인 메모리 공간에 저장하는 배열의 선언, 접근 및 동적 할당 방법을 설명합니다. | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/queue_josephuse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | int josephus(int N, int K) { 7 | // Step 1: 큐 초기화 및 요소 삽입 8 | // 시간복잡도: O(N) 9 | // 큐를 초기화하고 1부터 N까지의 요소를 삽입합니다. 10 | // 예시: N = 5일 경우, 큐는 [1, 2, 3, 4, 5]로 초기화됩니다. 11 | queue q; 12 | for (int i = 1; i <= N; ++i) { 13 | q.push(i); 14 | } 15 | 16 | // Step 2: 제거 과정 시뮬레이션 17 | // 시간복잡도: O(N * K) 18 | // 큐의 크기가 1이 될 때까지 반복합니다. 19 | while (q.size() > 1) { 20 | // 첫 번째 K-1개의 요소를 큐의 뒤로 이동시킵니다. 21 | for (int i = 0; i < K - 1; ++i) { 22 | q.push(q.front()); 23 | q.pop(); 24 | } 25 | // K번째 요소를 제거합니다. 26 | q.pop(); 27 | } 28 | 29 | // 마지막으로 남은 요소가 생존자입니다. 30 | return q.front(); 31 | } 32 | 33 | int main() { 34 | int N = 5; // 예시: 5명의 사람이 있을 때 35 | int K = 2; // 예시: 매 2번째 사람을 제거할 때 36 | 37 | // 생존자를 출력합니다. 38 | cout << "The survivor is: " << josephus(N, K) << endl; 39 | return 0; 40 | } 41 | 42 | /* 43 | 동작 과정 예시: 44 | 1. 큐 초기화: [1, 2, 3, 4, 5] 45 | 2. 첫 번째 반복: 46 | - [1, 2, 3, 4, 5] -> [2, 3, 4, 5, 1] -> [3, 4, 5, 1] 47 | 3. 두 번째 반복: 48 | - [3, 4, 5, 1] -> [4, 5, 1, 3] -> [5, 1, 3] 49 | 4. 세 번째 반복: 50 | - [5, 1, 3] -> [1, 3, 5] -> [3, 5] 51 | 5. 네 번째 반복: 52 | - [3, 5] -> [5, 3] -> [3] 53 | 6. 생존자: 3 54 | */ 55 | -------------------------------------------------------------------------------- /reference/callback.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | /* 6 | 콜백함수 (Callback Function): 7 | - 다른 함수의 인자로 전달되는 함수를 의미합니다. 8 | - 주로 어떤 이벤트가 발생했을 때 호출될 함수를 등록해두거나, 특정 알고리즘에서 사용자 정의 연산을 제공할 때 활용됩니다. 9 | */ 10 | 11 | // 콜백함수로 사용될 함수 예시 12 | void myCallbackFunction(int data) { 13 | cout << "Callback function called with value: " << data << endl; 14 | } 15 | 16 | // 콜백함수를 인자로 받는 함수 17 | //############################################################ 18 | // | cafe | http://cafe.naver.com/dremdelover | 19 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 20 | // | business | ultrasuperrok@gmail.com | 21 | //############################################################ 22 | void process(int value, void (*callbackFunc)(int)) { 23 | // 어떤 처리를 한 후에 24 | // 콜백함수를 호출한다. 25 | callbackFunc(value); 26 | } 27 | 28 | int main() { 29 | cout << "Starting program..." << endl; 30 | 31 | // process 함수 호출 시, myCallbackFunction를 콜백 함수로 전달 32 | process(5, myCallbackFunction); 33 | 34 | cout << "Ending program..." << endl; 35 | 36 | return 0; 37 | } 38 | 39 | /* 40 | 주의사항: 41 | 1. 콜백함수는 함수 포인터 형태로 전달되므로, 함수 포인터의 문법과 관련된 오류에 주의해야 합니다. 42 | 2. 콜백함수 내에서 전역 상태나 외부 변수를 변경할 때는 사이드 이펙트를 주의해야 합니다. 43 | 3. 잦은 호출이 필요한 경우에는 콜백의 오버헤드로 인한 성능 저하가 발생할 수 있습니다. 44 | */ 45 | 46 | -------------------------------------------------------------------------------- /solution/84.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int solution(int k, vector tangerine) { 8 | //❶ 각 크기에 따른 귤의 개수는 세는 counter 9 | unordered_map counter; 10 | 11 | //❷ 크기별로 귤의 개수를 셈 12 | for (int i = 0; i < tangerine.size(); ++i) { 13 | counter[tangerine[i]]++; 14 | } 15 | 16 | //❸ 각 귤의 개수만 저장 후, 이를 내림차순 정렬 17 | vector sorted_counts; 18 | for (const auto& kv : counter) { 19 | sorted_counts.push_back(kv.second); 20 | } 21 | sort(sorted_counts.rbegin(), sorted_counts.rend()); 22 | 23 | 24 | int num_types = 0; // 현재까지 고른 귤의 종류 25 | int count_sum = 0; // 현재까지 귤 개수의 총 합 26 | 27 | //❹ 가장 많은 귤의 개수부터 순회 28 | for (int count : sorted_counts) { 29 | count_sum += count; 30 | num_types++; 31 | 32 | //❺ 귤의 개수 합이 k 이상 되는 순간 종료 33 | if (count_sum >= k) { 34 | break; 35 | } 36 | } 37 | 38 | return num_types; 39 | } 40 | 41 | //아래 코드는 테스트 코드 입니다. 42 | #include 43 | 44 | using namespace std; 45 | 46 | int main() 47 | { 48 | cout << solution(6, {1, 3, 2, 5, 4, 5, 2, 3}) << endl; //출력값 : 3 49 | cout << solution(4, {1, 3, 2, 5, 4, 5, 2, 3}) << endl; //출력값 : 2 50 | cout << solution(2, {1, 1, 1, 1, 2, 2, 2, 3}) << endl; //출력값 : 1 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /solution/96.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 두 큐의 합을 같게 만들기 위해 필요한 최소 이동 횟수를 반환합니다. 8 | int solution(vector queue1, vector queue2) { 9 | long long sum1 = accumulate(queue1.begin(), queue1.end(), 0LL); // 첫 번째 큐의 합 10 | long long sum2 = accumulate(queue2.begin(), queue2.end(), 0LL); // 두 번째 큐의 합 11 | int idx1 = 0, idx2 = 0; // 각 큐에서의 현재 인덱스 12 | int totalMoves = 0; // 총 이동 횟수 13 | 14 | int qSize = queue1.size(); // 큐의 크기 (두 큐의 크기는 같습니다) 15 | int limit = qSize * 3; // 탐색할 최대 이동 횟수 (두 큐의 합을 맞추기 위한 이론적 최대 이동 횟수) 16 | 17 | while (totalMoves <= limit) { 18 | if (sum1 == sum2) return totalMoves; // 두 큐의 합이 같은 경우, 현재까지의 이동 횟수 반환 19 | if (sum1 < sum2) { 20 | long long elem = idx2 < qSize ? queue2[idx2] : queue1[idx2 - qSize]; // 다음에 이동할 원소 21 | sum1 += elem; // 첫 번째 큐의 합을 증가 22 | sum2 -= elem; // 두 번째 큐의 합을 감소 23 | idx2++; // 두 번째 큐의 인덱스 증가 24 | } else { 25 | long long elem = idx1 < qSize ? queue1[idx1] : queue2[idx1 - qSize]; // 다음에 이동할 원소 26 | sum1 -= elem; // 첫 번째 큐의 합을 감소 27 | sum2 += elem; // 두 번째 큐의 합을 증가 28 | idx1++; // 첫 번째 큐의 인덱스 증가 29 | } 30 | totalMoves++; // 총 이동 횟수 증가 31 | } 32 | 33 | return -1; // 두 큐의 합을 같게 만들 수 없는 경우 -1 반환 34 | } 35 | -------------------------------------------------------------------------------- /solution/52.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | int solution(int n, vector weak, vector dist) { 6 | int length = weak.size(); 7 | //❶ weak 리스트 확장 8 | for (int i = 0; i < length; ++i) { 9 | weak.push_back(weak[i] + n); 10 | } 11 | 12 | //❷ 초기화 13 | int answer = dist.size() + 1; 14 | 15 | //❸ 시작점 설정 및 친구 순열 생성 16 | for (int start = 0; start < length; ++start) { 17 | do { 18 | //❹ 친구 배치 및 수 계산 19 | int cnt = 1; 20 | int position = weak[start] + dist[cnt - 1]; 21 | 22 | //❺ 다음 weak 지점 확인 23 | for (int index = start; index < start + length; ++index) { 24 | if (position < weak[index]) { 25 | cnt += 1; 26 | //❻ 친구 수 초과 확인 27 | if (cnt > dist.size()) break; 28 | position = weak[index] + dist[cnt - 1]; 29 | } 30 | } 31 | 32 | //❼ 최소 친구 수 업데이트 33 | answer = min(answer, cnt); 34 | } while (next_permutation(dist.begin(), dist.end())); // 순열 생성 35 | } 36 | 37 | //❽ 결과 반환 38 | return answer > dist.size() ? -1 : answer; 39 | } 40 | 41 | 42 | //아래 코드는 테스트 코드 입니다. 43 | #include 44 | 45 | using namespace std; 46 | 47 | int main() 48 | { 49 | cout << solution(12, {1, 5, 6, 10},{1, 2, 3, 4}) << endl; //출력값 : 2 50 | cout << solution(12, {1, 3, 4, 9, 10},{3, 5, 7}) << endl; //출력값 : 1 51 | 52 | return 0; 53 | } 54 | -------------------------------------------------------------------------------- /STL/call_by_ref.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | // Call by Value: 이 함수는 벡터를 값으로 받습니다. 12 | // 큰 데이터 구조를 값으로 받게 되면 복사가 발생하기 때문에 성능상의 오버헤드가 발생할 수 있습니다. 13 | // 메모리 사용량이 증가하고, CPU도 더 많은 작업을 해야하기 때문에 프로그램의 성능에 부정적인 영향을 줄 수 있습니다. 14 | void callByValue(vector v) { 15 | v[0] = 999; // 복사된 벡터에만 영향을 줍니다. 16 | cout << "Inside callByValue: " << v[0] << endl; // 출력: 999 17 | } 18 | 19 | // Call by Reference: 이 함수는 벡터를 참조로 받습니다. 20 | // 데이터를 복사하지 않기 때문에 메모리 사용량이 증가하지 않고, CPU도 더 적은 작업만을 수행하면 됩니다. 21 | // 큰 데이터 구조를 다룰 때는 참조를 사용하여 성능상의 이점을 얻을 수 있습니다. 22 | void callByReference(vector& v) { 23 | v[0] = 888; // 원본 벡터에 직접 영향을 줍니다. 24 | cout << "Inside callByReference: " << v[0] << endl; // 출력: 888 25 | } 26 | 27 | int main() { 28 | vector vec = {1, 2, 3}; 29 | 30 | callByValue(vec); 31 | cout << "After callByValue: " << vec[0] << endl; // 출력: 1 (원본은 변경되지 않음) 32 | 33 | callByReference(vec); 34 | cout << "After callByReference: " << vec[0] << endl; // 출력: 888 (원본이 변경됨) 35 | 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /reference/variable.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | // 1. 기본 데이터 타입 변수 12 | int a = 10; // 정수형 변수 13 | double b = 20.5; // 실수형 변수 14 | char c = 'A'; // 문자형 변수 15 | bool d = true; // 불리언 변수 (참/거짓) 16 | 17 | /* 18 | 변수란? 19 | - 변수는 메모리상에 값을 저장하는 공간을 의미합니다. 20 | - 변수를 선언할 때는 해당 변수의 타입을 지정해야 하며, 그 타입에 따라 저장할 수 있는 값의 종류와 크기가 결정됩니다. 21 | - 변수는 프로그램 내에서 데이터를 저장하고 참조하기 위해 사용됩니다. 22 | */ 23 | 24 | // 2. 변수의 초기화 25 | int uninitialized; // 초기화되지 않은 변수 26 | int initialized = 100; // 초기값을 가진 변수 27 | 28 | /* 29 | 주의사항: 30 | - 초기화되지 않은 변수는 그 안에 쓰레기 값이 들어있을 수 있으므로 사용하기 전에 반드시 초기화하는 것이 좋습니다. 31 | - C++에서는 변수를 선언하면서 동시에 초기화할 수 있습니다. 이렇게 하면 나중에 실수로 초기화를 잊어버리는 문제를 예방할 수 있습니다. 32 | */ 33 | 34 | cout << "Value of a: " << a << endl; // 출력: 10 35 | cout << "Value of b: " << b << endl; // 출력: 20.5 36 | cout << "Value of c: " << c << endl; // 출력: A 37 | cout << "Value of d: " << d << endl; // 출력: 1 (true는 1로, false는 0으로 출력됩니다.) 38 | } 39 | 40 | -------------------------------------------------------------------------------- /solution/21.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | vector solution(int n, vector words) { 8 | 9 | vector answer(2, 0); 10 | unordered_set usedWords; 11 | 12 | usedWords.insert(words[0]); 13 | 14 | //❶ 두 번째 단어부터 끝까지 반복 15 | for (int i = 1; i < words.size(); ++i) { 16 | //❷ 단어가 이미 사용되었거나, 끝말잇기 규칙에 맞지 않는 경우 17 | if (!usedWords.insert(words[i]).second || words[i].front() != words[i - 1].back()) { 18 | //❸ 플레이어 번호와 턴 번호 저장 후 바로 반환 19 | answer[0] = i % n + 1; 20 | answer[1] = i / n + 1; 21 | return answer; 22 | } 23 | } 24 | 25 | //❹ 중간에 탈락하는 플레이어가 없으면 [0, 0] 반환 26 | return answer; 27 | } 28 | 29 | //아래 코드는 테스트 코드 입니다. 30 | #include 31 | #include 32 | 33 | using namespace std; 34 | 35 | void print(vector vec) 36 | { 37 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 38 | cout << endl; 39 | } 40 | 41 | int main() 42 | { 43 | print(solution(3, {"tank", "kick", "know", "wheel", "land", "dream", "mother", "robot", "tank"})); // 결과값 : 3 3 44 | print(solution(5, {"hello", "observe", "effect", "take", "either", "recognize", "encourage", "ensure", "establish", "hang", "gather", "refer", "reference", "estimate", "executive"})); // 결과값 : 0 0 45 | print(solution(2, {"hello", "one", "even", "never", "now", "world", "draw"})); // 결과값 : 1 3 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /solution/23.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int solution(vector want, vector number, vector discount) { 8 | int answer = 0; 9 | 10 | unordered_map wantMap; 11 | //❶ want를 키로 number를 값으로 해서 wantMap을 선언 12 | for (int i = 0; i < want.size(); i++) 13 | wantMap[want[i]] = number[i]; 14 | 15 | 16 | for (int i = 0; i < discount.size() - 9; i++) { 17 | // ❷ i일 회원가입 시, 할인받을 수 있는 품목을 키로, 개수를 값으로 해서 discount_10d 선언 18 | unordered_map discount_10d; 19 | 20 | // ❸ 각 할인하는 품목을 키로 개수를 저장 21 | for (int j = i; j < 10 + i; j++) 22 | discount_10d[discount[j]]++; 23 | 24 | // ❹ 할인하는 상품의 품목및 개수가 원하는 상품의 품목 및 개수와 일치하면 카운트 증가 25 | if (wantMap == discount_10d) answer++; 26 | } 27 | 28 | return answer; 29 | } 30 | 31 | //여기부터는 테스트 코드 입니다. 32 | #include 33 | 34 | int main() 35 | { 36 | cout << solution( {"banana", "apple", "rice", "pork", "pot"}, 37 | {3, 2, 2, 2, 1}, 38 | {"chicken", "apple", "apple", "banana", "rice","apple", "pork", "banana", "pork", "rice", "pot","banana", "apple", "banana"}) << endl; // 3 39 | 40 | cout << solution( {"apple"}, 41 | {10}, 42 | {"banana", "banana", "banana", "banana","banana", "banana", "banana", "banana", "banana","banana"}) << endl; // 0 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /solution/16.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | vector solution(vector progresses, vector speeds) { 6 | vector answer; 7 | int n = progresses.size(); 8 | vector days_left(n); 9 | 10 | //❶ 각 작업에 대한 완료까지 남은 일수 계산 11 | for (int i = 0; i < n; ++i) { 12 | days_left[i] = ceil((100.0 - progresses[i]) / speeds[i]); 13 | } 14 | 15 | int count = 0; //❷ 배포 될 작업의 수 16 | int max_day = days_left[0]; // ❸ 현재 배포될 작업 중 가장 늦게 배포될 작업의 가능일 17 | 18 | 19 | for (int i = 0; i < n; ++i) { 20 | if (days_left[i] <= max_day) { //❹ 배포 가능일이 가장 늦은 배포일보다 빠르면 21 | count++; 22 | } else { //❺ 배포 예정일이 기준 배포일보다 느리면 23 | answer.push_back(count); 24 | count = 1; 25 | max_day = days_left[i]; 26 | } 27 | } 28 | 29 | answer.push_back(count); //❻ 마지막으로 카운트된 작업들을 함께 배포 30 | return answer; 31 | } 32 | 33 | 34 | 35 | 36 | 37 | 38 | //아래 코드는 테스트 코드 입니다. 39 | #include 40 | #include 41 | 42 | void print(vector vec) 43 | { 44 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 45 | cout << endl; 46 | } 47 | 48 | int main() 49 | { 50 | 51 | print(solution({93, 30, 55}, {1, 30, 5})); // 2 1 52 | print(solution({95, 90, 99, 99, 80, 99}, {1, 1, 1, 1, 1, 1})); // 1 3 2 53 | 54 | return 0; 55 | 56 | } 57 | -------------------------------------------------------------------------------- /solution/72.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 조약돌 배치 패턴에 대해 최대 가중치를 계산하는 함수 7 | int solution(vector> arr) { 8 | // ❶ 입력 벡터의 열의 개수 9 | int n = arr[0].size(); 10 | // ❷ dp 벡터 초기화 11 | vector> dp(4, vector(n, 0)); 12 | 13 | // ❸ 첫 번째 열의 가중치 초기화 (0: 상단, 1: 중앙, 2: 하단, 3: 상단과 하단) 14 | dp[0][0] = arr[0][0]; 15 | dp[1][0] = arr[1][0]; 16 | dp[2][0] = arr[2][0]; 17 | dp[3][0] = arr[0][0] + arr[2][0]; 18 | 19 | // ❹ 두 번째 열부터 마지막 열까지 가중치를 구함 20 | for (int i = 1; i < n; ++i) { 21 | // 패턴 0이 선택된 경우, 이전은 패턴 {1, 2} 가능 22 | dp[0][i] = arr[0][i] + max(dp[1][i - 1], dp[2][i - 1]); 23 | // 패턴 1이 선택된 경우, 이전은 패턴 {0, 2, 3} 가능 24 | dp[1][i] = arr[1][i] + max({dp[0][i - 1], dp[2][i - 1], dp[3][i - 1]}); 25 | // 패턴 2가 선택된 경우, 이전은 패턴 {0, 1}이 가능 26 | dp[2][i] = arr[2][i] + max(dp[0][i - 1], dp[1][i - 1]); 27 | // 패턴 3이 선택된 경우, 이전은 패턴 {1}이 가능 28 | dp[3][i] = arr[0][i] + arr[2][i] + dp[1][i - 1]; 29 | } 30 | 31 | // ❺ 마지막 열의 가중치 중, 최대 가중치를 반환합니다. 32 | return max({dp[0][n - 1], dp[1][n - 1], dp[2][n - 1], dp[3][n - 1]}); 33 | } 34 | 35 | 36 | //아래 코드는 테스트 코드 입니다. 37 | #include 38 | 39 | using namespace std; 40 | 41 | int main() 42 | { 43 | cout << solution({{1, 3, 3, 2}, {2, 1, 4, 1}, {1, 5, 2, 3}}) << endl; //출력값 : 19 44 | cout << solution({{1, 7, 13, 2, 6}, {2, -4, 2, 5, 4}, {5, 3, 5, -3, 1}}) << endl; //출력값 : 32 45 | 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /STL/priority_queue.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | // priority_queue는 힙(기본적으로는 최대 힙)을 기반으로 한 STL 컨테이너입니다. 12 | // - 가장 높은 우선순위를 가진 요소에 빠르게 접근할 수 있습니다. 13 | // 좋은 사용 시기: 14 | // - 데이터 중에서 가장 높은 (또는 낮은) 우선순위를 가진 요소에 빠르게 접근하고자 할 때. 15 | // 성능 이슈: 16 | // - 모든 요소를 정렬된 상태로 유지하는 것보다 우선순위 큐의 힙 구조가 더 효율적입니다. 17 | 18 | int main() { 19 | 20 | // priority_queue 선언 (기본적으로 최대 힙) 21 | priority_queue pq; 22 | 23 | // push: O(log n) 24 | pq.push(3); 25 | pq.push(1); 26 | pq.push(4); 27 | 28 | // top: O(1) 29 | cout << pq.top() << endl; // 출력: 4 (가장 높은 우선순위) 30 | 31 | // pop: O(log n) 32 | pq.pop(); 33 | 34 | // size: O(1) 35 | cout << pq.size() << endl; // 출력: 2 36 | 37 | // 힙의 우선순위에 따라 순회 : O(n) 38 | while(!pq.empty()) { 39 | cout << pq.top() << " "; // 출력: 3 1 40 | pq.pop(); 41 | } 42 | cout << endl; 43 | 44 | // clear: priority_queue에는 clear 메서드가 없습니다. 대신, 새로운 빈 큐로 교체하는 방식을 사용할 수 있습니다. 45 | priority_queue empty; 46 | swap(pq, empty); 47 | 48 | return 0; 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /solution/05.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector > solution(vector >arr1, vector >arr2) 7 | { 8 | // ❶ 최종 행렬곱의 결과를 저장할 벡터 선언 9 | vector >answer; 10 | 11 | // ❷ arr1과 arr2의 행렬곱을 수행했을때 최종적인 행렬의 크기만큼 공간을 할당 12 | answer.assign(arr1.size(), vector(arr2[1].size(), 0)); 13 | 14 | // ❸ arr1의 각 행과 arr2의 각 열에 대해 반복문 수행 15 | for(int i = 0;i < arr1.size(); i++) 16 | for(int j = 0;j < arr2[1].size(); j++) 17 | for(int k = 0;k < arr2.size(); k++) 18 | // ❹ 두 행렬을 곱을 수행 19 | answer[i][j] += arr1[i][k] * arr2[k][j]; 20 | 21 | return answer; 22 | } 23 | 24 | 25 | //아래 코드는 테스트 코드 입니다. 26 | 27 | #include 28 | #include 29 | void print2D(vector> vec) 30 | { 31 | for(const auto& innerVec : vec){ 32 | copy(innerVec.begin(), innerVec.end(), std::ostream_iterator(cout, " ")); 33 | cout << endl; 34 | } 35 | 36 | cout << endl; 37 | } 38 | 39 | int main() 40 | { 41 | print2D(solution({{1, 4}, {3, 2}, {4, 1}} ,{{3, 3}, {3,3}})); 42 | /* 43 | 15 15 44 | 15 15 45 | 15 15 46 | */ 47 | print2D(solution({{2, 3, 2}, {4, 2, 4}, {3, 1,4}}, {{5, 4, 3}, {2, 4, 1}, {3, 1, 1}} )); // 1 2 3 48 | /* 49 | 22 22 11 50 | 36 28 18 51 | 29 20 14 52 | */ 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /solution/17.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | string solution(vector cards1, vector cards2, vector goal) { 9 | queue c1, c2, g; 10 | 11 | // ❶cards와 goal을 queue로 나타냄 12 | for (const string& s : cards1) c1.push(s); 13 | for (const string& s : cards2) c2.push(s); 14 | for (const string& s : goal) g.push(s); 15 | 16 | //❷ 단어 배열을 앞에서 부터 순회 17 | while (!g.empty()) { 18 | //❸ c1의 현재 문자열과 g의 현재 문자열이 일치하는 경우 19 | if (!c1.empty() && c1.front() == g.front()) { 20 | c1.pop(); 21 | g.pop(); 22 | } 23 | //❹ c2의 현재문자열과 g의 현재 문자열이 일치하는 경우 24 | else if (!c2.empty() && c2.front() == g.front()) { 25 | c2.pop(); 26 | g.pop(); 27 | } 28 | //❺ 일치하는 카드뭉치가 없는 경우 반복문을 빠져나감 29 | else { 30 | break; 31 | } 32 | } 33 | //❻ 원하는 문자열을 카드뭉치에서 만들었으면 Yes 아니면 No 반환 34 | return g.empty() ? "Yes" : "No"; 35 | } 36 | 37 | 38 | 39 | 40 | 41 | //아래 코드는 테스트 코드 입니다. 42 | #include 43 | 44 | int main() 45 | { 46 | cout<< solution({"i", "drink", "water"}, {"want", "to"}, {"i", "want", "to", "drink", "water"}) << endl; // "Yes" 47 | cout<< solution({"i", "water", "drink"}, {"want", "to"}, {"i", "want", "to", "drink", "water"}) << endl; // "No" 48 | return 0; 49 | 50 | } 51 | -------------------------------------------------------------------------------- /solution/99.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 보드 게임의 최종 상태에서 파괴되지 않은 건물의 수를 계산하는 함수 8 | int solution(vector> board, vector> skill) { 9 | int n = board.size(); // 보드의 세로 크기 10 | int m = board[0].size(); // 보드의 가로 크기 11 | vector> diff(n, vector(m, 0)); // 보드의 각 위치에 대한 누적 영향력 차이를 저장할 2차원 벡터 12 | 13 | // 스킬을 적용하여 diff 배열에 누적 영향력 차이를 계산 14 | for(auto& s : skill) { 15 | int type = s[0], r1 = s[1], c1 = s[2], r2 = s[3], c2 = s[4], degree = (type == 1) ? -s[5] : s[5]; 16 | diff[r1][c1] += degree; 17 | if(c2 + 1 < m) diff[r1][c2 + 1] -= degree; 18 | if(r2 + 1 < n) diff[r2 + 1][c1] -= degree; 19 | if(r2 + 1 < n && c2 + 1 < m) diff[r2 + 1][c2 + 1] += degree; 20 | } 21 | 22 | // diff 배열을 이용하여 각 행의 누적 영향력을 계산 23 | for(int i = 0; i < n; ++i) { 24 | for(int j = 1; j < m; ++j) { 25 | diff[i][j] += diff[i][j - 1]; 26 | } 27 | } 28 | 29 | // diff 배열을 이용하여 각 열의 누적 영향력을 계산 30 | for(int j = 0; j < m; ++j) { 31 | for(int i = 1; i < n; ++i) { 32 | diff[i][j] += diff[i - 1][j]; 33 | } 34 | } 35 | 36 | // 최종 상태의 보드를 계산하며 파괴되지 않은 건물의 수를 세기 37 | int answer = 0; 38 | for(int i = 0; i < n; ++i) { 39 | for(int j = 0; j < m; ++j) { 40 | if(board[i][j] + diff[i][j] > 0) ++answer; // 파괴되지 않은 경우 41 | } 42 | } 43 | 44 | return answer; 45 | } 46 | -------------------------------------------------------------------------------- /solution/86.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int maxHeight, maxWidth, targetRow, targetCol, maxSteps; 8 | int dx[4] = { 1, 0, 0, -1 }; 9 | int dy[4] = { 0, -1, 1, 0 }; 10 | char dir[4] = { 'd', 'l', 'r', 'u' }; 11 | string path = ""; 12 | bool found = false; 13 | 14 | // 보드 내에 있는지 확인 15 | bool InBounds(int x, int y) { 16 | return x > 0 && x <= maxHeight && y > 0 && y <= maxWidth; 17 | } 18 | 19 | // 남은 이동 횟수로 도달 가능한지 확인 20 | bool CanReach(int x, int y, int steps) { 21 | return abs(x - targetRow) + abs(y - targetCol) <= steps; 22 | } 23 | 24 | // 경로 찾기 25 | void Search(int x, int y, int steps, string currPath) { 26 | if (steps == 0 && x == targetRow && y == targetCol) { 27 | found = true; 28 | path = currPath; 29 | return; 30 | } 31 | 32 | for (int i = 0; i < 4; i++) { 33 | int nextX = x + dx[i]; 34 | int nextY = y + dy[i]; 35 | if (!InBounds(nextX, nextY) || !CanReach(nextX, nextY, steps - 1)) continue; 36 | Search(nextX, nextY, steps - 1, currPath + dir[i]); 37 | if (found) return; 38 | } 39 | } 40 | 41 | // 메인 함수 42 | string solution(int n, int m, int x, int y, int r, int c, int k) { 43 | maxHeight = n; 44 | maxWidth = m; 45 | targetRow = r; 46 | targetCol = c; 47 | maxSteps = k; 48 | 49 | if (!CanReach(x, y, k) || ((abs(x - r) + abs(y - c)) % 2) != (k % 2)) return "impossible"; 50 | Search(x, y, k, ""); 51 | return path; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /solution/50.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | //❶ 현재 행에 이미 다른 퀸이 있는지 확인하는 함수 7 | bool isSameRow(int placedRow, int currentRow) { 8 | return placedRow == currentRow; 9 | } 10 | 11 | //❷ 대각선에 다른 퀸이 있는지 확인하는 함수 12 | bool isDiagonalAttack(int placedCol, int placedRow, int currentCol, int currentRow) { 13 | return abs(placedCol - currentCol) == abs(placedRow - currentRow); 14 | } 15 | 16 | //❸ 퀸을 안전하게 배치할 수 있는지 확인하는 함수 17 | bool isSafePosition(const vector &queen, int col, int row) { 18 | for (int i = 0; i < col; ++i) { 19 | if (isSameRow(queen[i], row) || isDiagonalAttack(i, queen[i], col, row)) { 20 | return false; 21 | } 22 | } 23 | return true; 24 | } 25 | 26 | //❹ 퀸을 배치하는 함수 27 | long long placeQueens(vector &queen, int col) { 28 | int n = queen.size(); 29 | if (col == n) { 30 | return 1; 31 | } 32 | 33 | long long count = 0; 34 | for (int row = 0; row < n; ++row) { 35 | //❺ 퀸을 놓을수 있는 위치인 경우 퀸을 놓음 36 | if (isSafePosition(queen, col, row)) { 37 | queen[col] = row; 38 | count += placeQueens(queen, col + 1); 39 | queen[col] = -1; 40 | } 41 | } 42 | return count; 43 | } 44 | 45 | long long solution(int n) { 46 | vector queen(n, -1); 47 | 48 | //❻ 퀸을 놓을수 있는 경우의 수를 반환 49 | return placeQueens(queen, 0); 50 | } 51 | 52 | 53 | 54 | 55 | 56 | //아래 코드는 테스트 코드 입니다. 57 | #include 58 | 59 | using namespace std; 60 | 61 | int main() 62 | { 63 | cout << solution(4) << endl; // 출력값 : 2 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/ReadMe.md: -------------------------------------------------------------------------------- 1 | # 프로젝트 파일 설명 2 | 3 | | 파일 이름 | 설명 | 4 | |-----------------------|------------------| 5 | | `matching_bracket.cpp`| 괄호 매칭 알고리즘: 주어진 문자열의 모든 종류의 괄호가 올바르게 닫히고 중첩되었는지 확인합니다. | 6 | | `mergesort.cpp` | 병합 정렬 알고리즘: 배열을 정렬하기 위한 병합 정렬 기술을 구현합니다. 병합 정렬에서 사용되는 분할 정복 방법을 설명합니다. | 7 | | `nqueen.cpp` | N-퀸 문제 알고리즘: 백트래킹을 사용하여 N-퀸 문제를 해결합니다. 단계별 접근 방식과 복잡도 분석을 자세히 설명합니다. | 8 | | `selectionsort.cpp` | 선택 정렬 알고리즘: 선택 정렬 방법을 시연하며 정렬 메커니즘과 효율성에 대한 자세한 설명이 포함되어 있습니다. | 9 | | `adjacencyarray.cpp` | 인접 배열 표현: 그래프를 표현하기 위한 인접 배열 접근 방식을 설명합니다. 밀집 그래프에 적합합니다. | 10 | | `adjacencylist.cpp` | 인접 리스트 표현: 그래프 표현을 위해 인접 리스트의 사용을 자세히 설명합니다. 희소 그래프에 이상적입니다. | 11 | | `eratosthenes_sieve.cpp` | 에라토스테네스의 체 알고리즘: 주어진 한계까지 모든 소수를 찾는 고대 알고리즘을 구현합니다. | 12 | | `heapsort.cpp` | 힙 정렬 알고리즘: 힙 정렬의 구현 세부사항을 제공하며, 최대 힙을 구성하고 요소들을 정렬하는 방법을 포함합니다. | 13 | | `insertionsort.cpp` | 삽입 정렬 알고리즘: 삽입 정레의 기본 개념과 구현을 다루며, 그 과정을 반복적으로 집중적으로 설명합니다. | 14 | | `kruskal.cpp` | 크루스칼 알고리즘: 그래프의 최소 신장 트리를 찾기 위해 크루스칼 알고리즘을 구현합니다. 유니온-파인드 자료 구조를 사용합니다. | 15 | | `subsum.cpp` | 부분합 알고리즘: 배열에서 특정 합을 가지는 부분 배열을 찾는 백트래킹 알고리즘입니다. 최악의 경우 시간 복잡도는 O(2^n)입니다. | 16 | | `tree_array.cpp` | 트리 배열 구조: 배열을 사용하여 트리 구조를 표현하고, 트리 연산을 수행하는 방법을 설명합니다. | 17 | | `tree_travel.cpp` | 트리 순회 알고리즘: 전위 순회, 중위 순회, 후위 순회 등 다양한 트리 순회 방법을 구현합니다. | 18 | | `unionfind.cpp` | 유니온-파인드 자료구조: 두 요소의 집합을 합치고, 요소가 속한 집합을 찾는 연산을 효율적으로 수행합니다. 경로 압축과 랭크를 사용하여 최적화된 버전을 제공합니다. | 19 | 20 | ## 추가 정보 21 | - 각 파일에는 알고리즘의 목적과 기능을 설명하는 자세한 주석이 포함되어 있어 코드와 그 적용을 이해하기 쉽습니다. 22 | -------------------------------------------------------------------------------- /solution/47.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | vector> results; 6 | vector selected_nums; 7 | 8 | void backtrack(int N, int sum, int start) { 9 | //❶ 합이 10인경우, 조합을 결과에 추가하고 종료 10 | if (sum == 10) { 11 | results.push_back(selected_nums); 12 | return; 13 | } 14 | for (int i = start; i <= N; ++i) { 15 | //❷ 합이 10보다 적은 경우, 가능한 조합을 계속 확인 16 | if (sum + i <= 10) { 17 | selected_nums.push_back(i); 18 | backtrack(N, sum + i, i + 1); 19 | selected_nums.pop_back(); 20 | } 21 | } 22 | } 23 | 24 | vector> solution(int N) { 25 | //❸ 숫자 1부터 백트래킹 시작 26 | backtrack(N, 0, 1); 27 | return results; 28 | } 29 | 30 | 31 | 32 | //아래 코드는 테스트 코드 입니다. 33 | #include 34 | #include 35 | 36 | using namespace std; 37 | 38 | void init() 39 | { 40 | results.clear(); 41 | selected_nums.clear(); 42 | } 43 | 44 | void print(vector> vec) 45 | { 46 | 47 | for(int i = 0; i < vec.size(); i++ ){ 48 | copy(vec[i].begin(), vec[i].end(), std::ostream_iterator(cout, " ")); 49 | cout << endl; 50 | } 51 | 52 | } 53 | 54 | int main() 55 | { 56 | print(solution(5)); 57 | init(); 58 | /* 59 | 출력값 60 | 1 2 3 4 61 | 1 4 5 62 | 2 3 5 63 | */ 64 | print(solution(2)); 65 | init(); 66 | /* 67 | 출력값(없음) 68 | */ 69 | print(solution(7)); 70 | /* 71 | 출력값 72 | 1 2 3 4 73 | 1 2 7 74 | 1 3 6 75 | 1 4 5 76 | 2 3 5 77 | 3 7 78 | 4 6 79 | */ 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /solution/90.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | struct CompressionResult { 7 | int zeros = 0; 8 | int ones = 0; 9 | }; 10 | 11 | CompressionResult compress(const vector>& arr, int y, int x, int size) { 12 | CompressionResult result; 13 | 14 | if (size == 1) { 15 | arr[y][x] == 0 ? result.zeros++ : result.ones++; 16 | return result; 17 | } 18 | 19 | int firstValue = arr[y][x]; 20 | bool canCompress = true; 21 | 22 | for (int i = y; i < y + size && canCompress; i++) { 23 | for (int j = x; j < x + size; j++) { 24 | if (arr[i][j] != firstValue) { 25 | canCompress = false; 26 | break; 27 | } 28 | } 29 | } 30 | 31 | if (canCompress) { 32 | firstValue == 0 ? result.zeros++ : result.ones++; 33 | } else { 34 | int halfSize = size / 2; 35 | CompressionResult parts[4]; 36 | int offsets[4][2] = {{0, 0}, {0, halfSize}, {halfSize, 0}, {halfSize, halfSize}}; 37 | 38 | for (int i = 0; i < 4; i++) { 39 | parts[i] = compress(arr, y + offsets[i][0], x + offsets[i][1], halfSize); 40 | result.zeros += parts[i].zeros; 41 | result.ones += parts[i].ones; 42 | } 43 | } 44 | 45 | return result; 46 | } 47 | 48 | vector solution(vector> arr) { 49 | CompressionResult finalResult = compress(arr, 0, 0, arr.size()); 50 | return {finalResult.zeros, finalResult.ones}; 51 | } 52 | -------------------------------------------------------------------------------- /solution/24.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | vector solution(vector record) { 9 | vector answer; 10 | unordered_map uid; 11 | 12 | for (const auto& line : record) { 13 | //❶ 각 record에 대해서, cmd에는 명령어를 저장하고 id에는 닉네임을 저장 14 | stringstream ss(line); 15 | string cmd, id, nickname; 16 | ss >> cmd >> id; 17 | //❷ 명령어가 Enter 혹은 Change일 경우 nickname에 닉네임을 저장 18 | if (cmd != "Leave") { 19 | ss >> nickname; 20 | uid[id] = nickname; 21 | } 22 | } 23 | 24 | for (const auto& line : record) { 25 | stringstream ss(line); 26 | string cmd, id; 27 | ss >> cmd >> id; 28 | //❸ Enter 및 Change 명령어의 경우 최종 닉네임과 정해진 문자열을 answer에 추가 29 | if (cmd == "Enter") { 30 | answer.push_back(uid[id] + "님이 들어왔습니다."); 31 | } else if (cmd == "Leave") { 32 | answer.push_back(uid[id] + "님이 나갔습니다."); 33 | } 34 | // "Change"는 메시지 생성에 영향을 주지 않으므로 무시 35 | } 36 | 37 | return answer; 38 | } 39 | 40 | //아래 코드는 테스트 코드 입니다. 41 | #include 42 | #include 43 | void print(vector vec) 44 | { 45 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 46 | cout << endl; 47 | } 48 | 49 | int main() 50 | { 51 | print(solution( {"Enter uid1234 Muzi", "Enter uid4567 Prodo","Leave uid1234", "Enter uid1234 Prodo","Change uid4567 Ryan"} )); 52 | // Prodo님이 들어왔습니다. Ryan님이 들어왔습니다. Prodo님이 나갔습니다. Prodo님이 들어왔습니다. 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /solution/79.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | int solution(vector strs, string t) { 10 | int INF = numeric_limits::max(); 11 | int n = t.length(); //❶ 타겟 문자열 t의 길이 12 | vector dp(n + 1, INF); //❷ 각 위치에서 필요한 최소 조각수를 저장할 벡터(초깃값은 INF) 13 | dp[0] = 0; //❸ 빈 문자열을 얻기 위한 최소 조각수는 0 14 | 15 | unordered_set sizes; //❹ strs 조각들의 길이를 저장한 집합 16 | for (const auto& s : strs) { 17 | sizes.insert(s.length()); 18 | } 19 | 20 | unordered_set strsSet(strs.begin(), strs.end()); //❺ strs의 원소를 저장한 집합 21 | 22 | 23 | 24 | for (int i = 1; i <= n; ++i) { 25 | for (int size : sizes) { //❻ 각 str 조각의 문자열 길이에 대하여 26 | //❼ 이미 구한 해와 str 조각을 추가해서 문자열을 만들 수 있다면 27 | if (i >= size && strsSet.count(t.substr(i - size, size))) { 28 | dp[i] = min(dp[i], dp[i - size] + 1); //❽ 해당 위치의 최소 조각수를 갱신 29 | } 30 | } 31 | } 32 | return dp[n] != INF ? dp[n] : -1; //➒ 최소 조각수를 반환(만들 수 없으면 -1) 33 | } 34 | 35 | 36 | 37 | 38 | 39 | //아래 코드는 테스트 코드 입니다. 40 | #include 41 | 42 | using namespace std; 43 | 44 | int main() 45 | { 46 | cout << solution({"ba", "na", "n", "a"}, "banana") << endl; //출력값 : 3 47 | cout << solution({"app", "ap", "p", "l", "e", "ple", "pp"}, "apple") << endl; //출력값 : 2 48 | cout << solution({"ba", "an", "nan", "ban", "n"}, "banana") << endl; //출력값 : -1 49 | 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /Example/squarecount.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | const int ROW = 3; 8 | const int COL = 4; 9 | 10 | // 문제의 정의: 11 | // ROW x COL 크기의 사각형에서 만들 수 있는 모든 정사각형의 개수를 구하는 문제입니다. 12 | 13 | // 최적 부분 구조: 14 | // 현재 셀에서 만들 수 있는 정사각형의 크기는 15 | // 위쪽, 왼쪽, 왼쪽 위 대각선 셀에서 만들 수 있는 정사각형 크기의 최솟값에 1을 더한 값입니다. 16 | 17 | // 중복 부분 문제: 18 | // 동일한 부분 문제(예: 위쪽, 왼쪽, 왼쪽 위 대각선 셀)가 여러 번 계산됩니다. 19 | 20 | // 점화식: 21 | // dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 22 | 23 | int countSquares(); 24 | 25 | int main() { 26 | int result = countSquares(); 27 | cout << "만들 수 있는 정사각형의 총 개수: " << result << endl; 28 | return 0; 29 | } 30 | 31 | // ROW x COL 크기의 사각형에서 만들 수 있는 모든 정사각형의 개수를 계산하는 함수 32 | int countSquares() { 33 | vector> dp(ROW, vector(COL, 1)); // 모든 값을 1로 초기화 34 | 35 | // 동적 계획법을 이용한 계산 36 | for (int i = 1; i < ROW; ++i) { 37 | for (int j = 1; j < COL; ++j) { 38 | // dp[i][j]는 현재 셀에서 만들 수 있는 가장 큰 정사각형의 크기를 나타냄 39 | dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]}) + 1; 40 | } 41 | } 42 | 43 | int totalSquares = 0; 44 | // 모든 dp 값 합산 45 | for (int i = 0; i < ROW; ++i) { 46 | for (int j = 0; j < COL; ++j) { 47 | totalSquares += dp[i][j]; 48 | } 49 | } 50 | 51 | return totalSquares; 52 | } 53 | 54 | /* 55 | 예제 출력: 56 | 20 57 | 58 | 예제 설명: 59 | 3x4 행렬에서 만들 수 있는 정사각형의 개수는 다음과 같습니다: 60 | - 1x1 크기의 정사각형: 12개 61 | - 2x2 크기의 정사각형: 6개 62 | - 3x3 크기의 정사각형: 2개 63 | 총 합계: 12 + 6 + 2 = 20개 64 | */ 65 | -------------------------------------------------------------------------------- /solution/36.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | unordered_map> adjList; 8 | vector result; 9 | unordered_set visited; 10 | 11 | void dfs(char node) { 12 | //❶ 현재 node를 방문한 목록 및 방문한 경로 추가 13 | visited.insert(node); 14 | result.push_back(node); 15 | 16 | //❷ 현재 node와 인접한 노드 중, 방문하지 않은 node들에 대해 깊이우선탐색을 계속 진행 17 | for (char neighbor : adjList[node]) { 18 | if (visited.find(neighbor) == visited.end()) { 19 | dfs(neighbor); 20 | } 21 | } 22 | } 23 | 24 | vector solution(vector> graph, char start) { 25 | //❸ 인접 리스트 생성 26 | for (auto& edge : graph) { 27 | char u = edge.first; 28 | char v = edge.second; 29 | adjList[u].push_back(v); 30 | } 31 | 32 | //❹ 시작 노드부터 깊이우선탐색 시작 33 | dfs(start); 34 | return result; 35 | } 36 | 37 | 38 | //아래 코드는 테스트 코드 입니다. 39 | #include 40 | #include 41 | 42 | using namespace std; 43 | 44 | 45 | void init() 46 | { 47 | adjList.clear(); 48 | result.clear(); 49 | visited.clear(); 50 | } 51 | void print(vector vec) 52 | { 53 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 54 | cout << endl; 55 | 56 | } 57 | 58 | int main() 59 | { 60 | //bool 반환할 때 true는 1, false는 0 입니다. 61 | print(solution({{'A', 'B'}, {'B', 'C'}, {'C', 'D'}, {'D', 'E'}}, 'A')); //출력값 : A B C D E 62 | init(); 63 | print(solution({{'A', 'B'}, {'A', 'C'}, {'B', 'D'}, {'B', 'E'}, {'C', 'F'}, {'E', 'F'}}, 'A')); //출력값 : A B D E F C 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /solution/18.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | 6 | void mapping(vector& hash, const vector& arr, int target ) 7 | { 8 | for(int i = 0; i < arr.size(); i++){ 9 | //❶ target보다 큰 값은 담지 않음(답이 될 가능성이 없음) 10 | if(arr[i] > target) continue; 11 | //❷현재 원소의 값을 hash의 인덱스로 활용, 해당 위치의 값을 1로 설정 12 | hash[arr[i]] = 1; 13 | } 14 | } 15 | bool solution(vector arr, int target) 16 | { 17 | //❸ target+1개의 공간이 있는 hash벡터 선언 18 | vector hash(target+1,0); 19 | 20 | //❹arr의 원소들 값에 대해서 hash table 생성 21 | mapping(hash,arr,target); 22 | 23 | 24 | for(int i = 0 ; i < arr.size(); i++) 25 | { 26 | 27 | //❺ target에서 arr[i]를 뺀 값이 있는지 확인하기 위해 num 선언 28 | int num = target - arr[i]; 29 | 30 | //❻ arr[i]가 num과 같은 경우는 답이 될수 없음(제약사항에 중복 숫자가 존재하지 않음) 31 | if(arr[i] == num) continue; //중복되는 숫자가 없는데 특정값이 현재 숫자가 같은 경우 32 | 33 | //❼ 음수는 존재할 수 없으므로 답이 될 수 없음 34 | if(num < 0 ) continue; // 특정값이 0보다 작을경우 35 | 36 | //❽ num이 있다면 합이 target이 되는 변수를 찾은것이므로, true를 반환 37 | if(hash[num]) return true; // 값을 찾은 경우 38 | } 39 | //❾ 두 수의 합이 target이 되는 경우를 찾지 못하면 false 반환 40 | return false; 41 | 42 | } 43 | 44 | 45 | 46 | 47 | 48 | //아래 코드는 테스트 코드 입니다. 49 | #include 50 | 51 | int main() 52 | { 53 | //true를 출력하면 1이되고 false를 출력하면 0 54 | cout<< solution({1, 2, 3, 4, 8}, 6) << endl; // 1 55 | cout<< solution({2, 3, 5,9}, 10) << endl; // 0 56 | return 0; 57 | 58 | } 59 | -------------------------------------------------------------------------------- /solution/04.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // ❶ 각 수포자가 찍는 패턴을 정의 8 | vector firstPattern = {1,2,3,4,5}; 9 | vector secondPattern = {2,1,2,3,2,4,2,5}; 10 | vector thirdPattern = {3,3,1,1,2,2,4,4,5,5}; 11 | 12 | vector solution(vector answers) { 13 | // ❷ 최종적으로 가장 많이 문제를 맞힌 사람이 저장될 벡터 14 | vector answer; 15 | 16 | // ❸ 각 수포자들의 패턴대로 답안을 작성할때 문제를 맞힌 갯수가 저장될 벡터 17 | vector matchCnt(3); 18 | 19 | // ❹ 실제 정답과 각 수포자들의 패턴을 비교해서 맞춘 갯수 20 | for(int i=0; i 42 | #include 43 | void print(vector vec) 44 | { 45 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 46 | cout << endl; 47 | } 48 | 49 | int main() 50 | { 51 | print(solution({1, 2, 3, 4, 5})); // 1 52 | print(solution({1, 3, 2, 4, 2})); // 1 2 3 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /reference/decay.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include // decay를 사용하기 위해 포함 8 | 9 | using namespace std; 10 | 11 | void printSize(int* ptr) { 12 | // 배열이 함수로 전달될 때 decay되어 포인터 크기만을 가지게 된다. 13 | cout << "함수 내에서 ptr의 크기: " << sizeof(ptr) << endl; 14 | } 15 | 16 | int main() { 17 | // 1. Decay란? 18 | // Decay는 특정 타입이 다른 상황에서 다른 타입으로 암시적으로 변환되는 것을 의미합니다. 19 | // 가장 일반적인 예는 배열 이름이 포인터로 변환되는 것과 함수 이름이 함수 포인터로 변환되는 것입니다. 20 | 21 | int arr[5] = {1, 2, 3, 4, 5}; 22 | 23 | // 배열의 이름 'arr'은 주소로 해석되며 포인터로 decay됩니다. 24 | int* ptr = arr; 25 | 26 | cout << "arr[0]: " << arr[0] << " *ptr: " << *ptr << endl; // arr[0]: 1 *ptr: 1 27 | cout << "arr의 크기: " << sizeof(arr) << endl; // arr의 크기: 20 (int가 4바이트라 가정) 28 | 29 | printSize(arr); // 함수 내에서 ptr의 크기: 8 (64비트 머신에서 포인터 크기는 8바이트) 30 | 31 | // 2. `std::decay` 32 | // `std::decay`는 주어진 타입의 가장 적절한 decayed 버전을 반환합니다. 33 | // 주로 템플릿 메타프로그래밍에서 사용됩니다. 34 | 35 | bool isSame = is_same::type>::value; 36 | cout << "배열 타입이 decay 후에 동일한가요? " << (isSame ? "네" : "아니요") << endl; // 아니요 37 | 38 | // 주의사항: 39 | // 배열이 포인터로 decay되면 원래 배열의 크기 정보를 잃게 됩니다. 40 | // 따라서 decay된 포인터만 가지고는 원래 배열의 크기를 알 수 없습니다. 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /STL/queue.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | // std::queue는 C++ STL에 포함된 컨테이너 어댑터입니다. 12 | // - FIFO(First-In-First-Out) 원칙에 따라 동작하는 데이터 구조입니다. 13 | // 좋은 사용 시기: 14 | // - 데이터를 순서대로 처리해야 할 때, 예를 들면, 너비 우선 탐색(BFS) 알고리즘, 대기열 구현 등. 15 | // 성능 이슈: 16 | // - STL queue는 일반적으로 빠른 연산을 제공합니다. 하지만, 중간 요소에 직접 접근할 수 없습니다. 중간 요소를 검색하거나 수정하려면 다른 자료구조를 사용하는 것이 좋습니다. 17 | 18 | int main() { 19 | 20 | queue q; 21 | 22 | // push: 큐의 끝에 요소 추가, O(1) 23 | q.push(1); 24 | q.push(2); 25 | q.push(3); 26 | 27 | // front: 큐의 첫 번째 요소에 접근, O(1) 28 | cout << "Front element: " << q.front() << endl; // 출력: Front element: 1 29 | 30 | // pop: 큐의 첫 번째 요소 제거, O(1) 31 | q.pop(); 32 | cout << "Front element after pop: " << q.front() << endl; // 출력: Front element after pop: 2 33 | 34 | // empty: 큐가 비어 있는지 확인, O(1) 35 | if (!q.empty()) { 36 | cout << "Queue is not empty" << endl; // 출력: Queue is not empty 37 | } 38 | 39 | // size: 큐의 크기 확인, O(1) 40 | cout << "Queue size: " << q.size() << endl; // 출력: Queue size: 2 41 | 42 | // 성능 저하 예제: 43 | // queue는 중간 요소에 직접 접근할 수 없으므로, 중간 요소를 검색하거나 수정하는 연산이 필요한 경우 44 | // queue보다는 다른 자료 구조를 사용하는 것이 좋습니다. 45 | 46 | return 0; 47 | 48 | } 49 | 50 | -------------------------------------------------------------------------------- /solution/10.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | 7 | // ❶ 닫힌 괄호의 짝을 바로 확인할 수 있도록 맵 선언 8 | unordered_map bracketPair = { 9 | {')', '('}, 10 | {']', '['}, 11 | {'}', '{'} 12 | }; 13 | 14 | //❷현자 인자로 받은 문자열 기준 괄호짝이 맞는지 확인 15 | bool isValid(string& s, int start) { 16 | stack stk; 17 | unsigned int sz = s.size(); 18 | 19 | //❸ 문자열을 순회하면서 20 | for(int i = 0 ; i < sz ; i++) { 21 | char ch = s[(start + i) % sz]; 22 | //❹ ch가 닫힌 괄호 인경우 23 | if(bracketPair.count(ch)) { 24 | // ❺ 스택이 비었거나 top 원소가 ch와 짝이 맞는 열린괄호가 아닌 경우 false 반환 25 | if(stk.empty() || stk.top() != bracketPair[ch]) return false; 26 | //❻ ch와 짝이 맞는 열린괄호일경우 해당 열린괄호를 제거 27 | stk.pop(); 28 | } else { 29 | //❼ 열린 괄호일경우 스택이 푸시 30 | stk.push(ch); 31 | } 32 | } 33 | //❽스택이 비었으면 true를 반환(비었다는것은 괄호 짝이 맞다는 것을 의미) 34 | return stk.empty(); 35 | } 36 | 37 | int solution(string s) { 38 | int answer = 0; 39 | int n = s.size(); 40 | 41 | //❾ 문자열을 rotation하면서 괄호짝이 맞으면 answer를 1증가 시킴 42 | for(int i = 0; i < n; i++) { 43 | answer += isValid(s,i); 44 | } 45 | return answer; 46 | } 47 | 48 | 49 | //아래 코드는 테스트 코드 입니다. 50 | #include 51 | int main() 52 | { 53 | cout << solution("[](){}") << endl; // 3 54 | cout << solution("}]()[{") << endl; // 2 55 | cout << solution("[)(]") << endl; // 0 56 | cout << solution("}}}") << endl; // 0 57 | return 0; 58 | } -------------------------------------------------------------------------------- /solution/95.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | vector> dp; // DP 테이블 8 | int maxAlp = 0, maxCop = 0; // 필요한 최대 알고력과 코딩력 9 | 10 | // 현재 알고력(a)와 코딩력(b)에서 필요한 최소 학습 시간을 구하는 함수 11 | int solve(int a, int b, vector> &problems) { 12 | // 기저 사례: 현재 알고력과 코딩력이 목표를 달성한 경우 13 | if (a >= maxAlp && b >= maxCop) { 14 | return 0; 15 | } 16 | int &ret = dp[a][b]; // 메모이제이션 17 | if (ret != -1) return ret; // 이미 계산된 경우 18 | 19 | ret = 1e9; // 최소 값을 찾기 위해 큰 값으로 초기화 20 | // 모든 문제를 순회하며 풀 수 있는 문제를 찾아 시도 21 | for (int i = 0; i < problems.size(); i++) { 22 | if (a >= problems[i][0] && b >= problems[i][1]) { // 문제를 풀 수 있는 경우 23 | int nextA = min(maxAlp, a + problems[i][2]); // 다음 알고력 24 | int nextB = min(maxCop, b + problems[i][3]); // 다음 코딩력 25 | ret = min(ret, solve(nextA, nextB, problems) + problems[i][4]); // 문제를 풀어 알고력과 코딩력을 향상시키는 경우 26 | } 27 | } 28 | // 알고력 또는 코딩력을 1씩 올리는 경우 중 최소값 찾기 29 | ret = min(ret, min(solve(min(maxAlp, a + 1), b, problems) + 1, 30 | solve(a, min(maxCop, b + 1), problems) + 1)); 31 | return ret; 32 | } 33 | 34 | int solution(int alp, int cop, vector> problems) { 35 | int answer = 0; 36 | // 필요한 최대 알고력과 코딩력을 구함 37 | for (int i = 0; i < problems.size(); i++) { 38 | maxAlp = max(maxAlp, problems[i][0]); 39 | maxCop = max(maxCop, problems[i][1]); 40 | } 41 | dp.resize(151, vector(151, -1)); // DP 테이블 초기화 42 | answer = solve(alp, cop, problems); // 최소 학습 시간 계산 43 | return answer; 44 | } 45 | -------------------------------------------------------------------------------- /reference/loop.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | // 1. for 문: 초기식, 조건식, 증감식을 가지는 반복문. 12 | // 초기식을 실행한 후, 조건식이 참일 경우 반복문 내의 코드를 실행하고, 증감식을 실행한다. 13 | // 조건식이 거짓이 될 때까지 이 과정을 반복한다. 14 | for (int i = 0; i < 5; ++i) { 15 | cout << "For loop, iteration " << i + 1 << endl; 16 | } 17 | cout << endl; 18 | 19 | // 2. while 문: 조건식만을 가지는 반복문. 20 | // 조건식이 참일 경우 반복문 내의 코드를 실행한다. 21 | // 조건식이 거짓이 될 때까지 이 과정을 반복한다. 22 | int j = 0; 23 | while (j < 3) { 24 | cout << "While loop, iteration " << j + 1 << endl; 25 | j++; 26 | } 27 | cout << endl; 28 | 29 | // 3. do-while 문: 조건식을 루프의 끝에서 평가하는 반복문. 30 | // 루프 내의 코드를 최소한 한 번은 실행한다. 이후에 조건식을 평가한다. 31 | int k = 0; 32 | do { 33 | cout << "Do-while loop, iteration " << k + 1 << endl; 34 | k++; 35 | } while (k < 2); 36 | cout << endl; 37 | 38 | // 4. 무한 루프는 아래와 같이 가능합니다. 39 | // 예: for(;;) 또는 while(true) 40 | 41 | // 2. 반복문 내에서 조건변수의 값을 바꾸면 예기치 않은 결과가 발생할 수 있습니다. 42 | for (int l = 0; l < 5; ++l) { 43 | if (l == 3) { 44 | l = 0; // 주의: 이렇게 하면 무한 루프에 빠진다. 45 | } 46 | cout << "Potentially infinite loop, iteration " << l + 1 << endl; 47 | } 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /reference/reference.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | 12 | /* 13 | 레퍼런스(Reference)란? 14 | - 레퍼런스는 변수의 별명으로 생각할 수 있습니다. 15 | - 레퍼런스는 원래의 변수와 동일한 메모리 주소를 공유하며, 레퍼런스를 통해 변수를 변경하면 원래 변수의 값도 변경됩니다. 16 | - 레퍼런스는 선언 시점에 반드시 초기화되어야 하며, 한 번 초기화된 레퍼런스는 다른 변수를 참조할 수 없습니다. 17 | */ 18 | 19 | int x = 10; 20 | int &y = x; // y는 x의 레퍼런스 21 | 22 | y += 5; // y를 통해 x의 값을 변경 23 | 24 | cout << "x: " << x << endl; // 출력: x: 15 25 | cout << "y: " << y << endl; // 출력: y: 15 26 | 27 | /* 28 | 주의사항: 29 | 1. 레퍼런스는 선언과 동시에 초기화되어야 합니다. 30 | */ 31 | // int &z; // 오류: 레퍼런스가 초기화되지 않았습니다. 32 | 33 | /* 34 | 2. 레퍼런스는 한 번 초기화되면 그 이후에 다른 변수를 참조할 수 없습니다. 35 | */ 36 | int z = 20; 37 | // y = z; // 이렇게 해도 y는 x를 계속 참조하게 됩니다. y의 값은 변경되지만 y가 참조하는 대상은 변경되지 않습니다. 38 | 39 | /* 40 | 3. NULL 레퍼런스는 허용되지 않습니다. 즉, 레퍼런스는 항상 유효한 변수를 참조해야 합니다. 41 | */ 42 | // int &nullRef = nullptr; // 오류: 레퍼런스는 nullptr로 초기화할 수 없습니다. 43 | 44 | /* 45 | 4. 배열의 각 원소에 대한 레퍼런스를 생성할 수 있습니다. 하지만 전체 배열에 대한 레퍼런스는 생성할 수 없습니다. 46 | */ 47 | int arr[3] = {1, 2, 3}; 48 | int &ref1 = arr[0]; // 배열의 첫 번째 원소에 대한 레퍼런스 49 | // int &refArr[3] = arr; // 오류: 배열에 대한 레퍼런스 배열은 허용되지 않습니다. 50 | 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /solution/92.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | bool visited[1 << 8]; // 방문한 조합을 기록하는 배열 8 | 9 | // 깊이 우선 탐색(DFS)을 사용해 가능한 모든 경우의 수를 탐색합니다. 10 | void dfs(int banIdx, int totalBans, int bit, const vector>& candidates) { 11 | if (totalBans == banIdx) { 12 | visited[bit] = true; // 해당 조합을 방문했음을 표시 13 | return; 14 | } 15 | for (auto p : candidates[banIdx]) { 16 | if (bit & (1 << p)) continue; // 이미 선택된 사용자인 경우 건너뜁니다. 17 | dfs(banIdx + 1, totalBans, bit | (1 << p), candidates); 18 | } 19 | } 20 | 21 | // 불량 사용자 ID와 사용자 ID가 일치하는지 확인합니다. 22 | bool matches(const string& banned, const string& user) { 23 | if (banned.size() != user.size()) return false; 24 | for (int i = 0; i < banned.size(); i++) { 25 | if (!(banned[i] == user[i] || banned[i] == '*' || user[i] == '*')) { 26 | return false; 27 | } 28 | } 29 | return true; 30 | } 31 | 32 | int solution(vector user_id, vector banned_id) { 33 | int answer = 0; 34 | vector> candidates(banned_id.size()); 35 | 36 | // 각 불량 사용자 ID에 대해 일치하는 사용자 ID의 인덱스를 저장합니다. 37 | for (int i = 0; i < banned_id.size(); i++) { 38 | for (int j = 0; j < user_id.size(); j++) { 39 | if (matches(banned_id[i], user_id[j])) { 40 | candidates[i].push_back(j); 41 | } 42 | } 43 | } 44 | 45 | dfs(0, banned_id.size(), 0, candidates); 46 | 47 | // 방문한 모든 조합을 계산합니다. 48 | for (int i = 0; i < (1 << 8); i++) { 49 | if (visited[i]) answer++; 50 | } 51 | 52 | return answer; 53 | } 54 | -------------------------------------------------------------------------------- /solution/19.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // ❶ 다항 해시 함수 구현 8 | long long polynomial_hash(const string& str) { 9 | const int p = 31; // 소수 10 | const long long m = 1000000007; // 버킷 크기 11 | long long hash_value = 0; 12 | 13 | for (char c : str) { 14 | hash_value = (hash_value * p + c) % m; 15 | } 16 | 17 | return hash_value; 18 | } 19 | 20 | vector solution(vector string_list, vector query_list) { 21 | unordered_set hash_set; 22 | 23 | //❷ string_list의 각 문자열에 대해 다항 해시값을 계산하고 저장 24 | for (const string& str : string_list) { 25 | long long hash = polynomial_hash(str); 26 | hash_set.insert(hash); 27 | } 28 | 29 | vector result; 30 | 31 | //❸ query_list의 각 문자열이 string_list에 있는지 확인하고 result에 추가 32 | for (const string& query : query_list) { 33 | long long query_hash = polynomial_hash(query); 34 | bool found = (hash_set.find(query_hash) != hash_set.end()); 35 | result.push_back(found); 36 | } 37 | // ❹ query_list의 문자열이 hash에 있는지 결과가 저장된 result를 반환 38 | return result; 39 | } 40 | 41 | 42 | //아래 코드는 테스트 코드 입니다. 43 | #include 44 | #include 45 | void print(vector vec) 46 | { 47 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 48 | cout << endl; 49 | } 50 | 51 | int main() 52 | { 53 | //true를 출력하면 1이되고 false를 출력하면 0 54 | print(solution({"apple", "banana", "cherry"}, {"banana", "kiwi", "melon", "apple"})); // 1 0 0 1 55 | return 0; 56 | 57 | } 58 | -------------------------------------------------------------------------------- /solution/26.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | vector solution(vector id_list, vector report, int k) { 10 | unordered_map> reported_user; // 신고당한 유저 - 신고 유저 집합 11 | unordered_map count; // 처리 결과 메일을 받은 유저 - 받은 횟수 12 | 13 | // 신고 기록 순회 14 | for (string& r : report) { 15 | // ❶ 각 report에서 user_id와 report_id를 분리하고 reported_user에 추가 16 | stringstream ss(r); 17 | string user_id, reported_id; 18 | ss >> user_id >> reported_id; 19 | reported_user[reported_id].insert(user_id); 20 | } 21 | 22 | for (auto& [reported_id, user_id_lst] : reported_user) { 23 | //❷ k명 이상에게 신고당했는지 확인 24 | if (user_id_lst.size() >= k) { 25 | //❸ 각 uid가 신고 결과를 받은 횟수를 기록 26 | for (const string& uid : user_id_lst) { 27 | count[uid]++; 28 | } 29 | } 30 | } 31 | 32 | vector answer; 33 | //❹ 각 아이디별 메일을 받은 횟수를 id_list 순서대로 answer에 추가 34 | for (string& id : id_list) { 35 | answer.push_back(count[id]); 36 | } 37 | 38 | return answer; 39 | } 40 | 41 | //아래 코드는 테스트 코드 입니다. 42 | #include 43 | #include 44 | void print(vector vec) 45 | { 46 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 47 | cout << endl; 48 | } 49 | 50 | int main() 51 | { 52 | print(solution({"muzi", "frodo","apeach", "neo"}, {"muzi frodo", "apeach frodo", "frodo neo", "muzi neo", "apeach muzi"}, 2)); //출력값 : 2 1 1 0 53 | print(solution({"con", "ryan"}, {"ryan con", "ryan con", "ryan con", "ryan con"}, 3)); //출력값 : 0 0 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /STL/deque.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | // 덱(deque)은 "double-ended queue"의 약자입니다. 12 | // - 덱은 양쪽 끝에서 원소의 삽입과 삭제가 가능한 선형 컨테이너입니다. 13 | // 좋은 사용 시기: 14 | // - 양쪽 끝에서의 원소 접근, 삽입, 삭제가 빈번할 때 사용하면 좋습니다. 15 | // 성능 이슈: 16 | // - 덱의 중간에서의 원소 삽입 또는 삭제는 O(n)의 시간 복잡도를 가집니다. 중간 위치의 연산이 빈번하면 성능 저하가 발생할 수 있습니다. 17 | 18 | int main() { 19 | deque dq; 20 | 21 | // push_front: 덱의 앞쪽에 원소 추가, O(1) 22 | dq.push_front(1); 23 | dq.push_front(2); 24 | 25 | // push_back: 덱의 뒤쪽에 원소 추가, O(1) 26 | dq.push_back(3); 27 | dq.push_back(4); 28 | 29 | // front: 덱의 첫 번째 원소 접근, O(1) 30 | cout << "Front element: " << dq.front() << endl; // 출력: Front element: 2 31 | 32 | // back: 덱의 마지막 원소 접근, O(1) 33 | cout << "Back element: " << dq.back() << endl; // 출력: Back element: 4 34 | 35 | // pop_front: 덱의 앞쪽 원소 제거, O(1) 36 | dq.pop_front(); 37 | 38 | // pop_back: 덱의 뒤쪽 원소 제거, O(1) 39 | dq.pop_back(); 40 | 41 | // 순회 예제 42 | for (int num : dq) { 43 | cout << num << " "; // 출력: 1 3 44 | } 45 | cout << endl; 46 | 47 | // 성능 저하 예제: 48 | // 덱의 중간 위치에서 원소를 삽입하거나 삭제하는 연산은 O(n)의 시간 복잡도를 가집니다. 49 | // 예: 50 | // deque::iterator it = dq.begin() + 1; 51 | // dq.insert(it, 5); // 중간 위치에 5 삽입 52 | 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /solution/89.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 문자열에서 마지막 '0'의 위치를 찾는 함수 7 | int findLastZero(const string& str) { 8 | for (int i = str.length() - 1; i >= 0; i--) { 9 | if (str[i] == '0') return i; 10 | } 11 | return -1; 12 | } 13 | 14 | vector solution(vector s) { 15 | vector answer; 16 | 17 | for (const string& originalStr : s) { 18 | string processedStr = ""; // 처리된 문자열을 저장할 변수 19 | int count110 = 0; // "110"이 나타난 횟수 20 | 21 | // 주어진 문자열에서 "110"을 찾아 제거하고 개수를 센다 22 | for (char ch : originalStr) { 23 | processedStr += ch; 24 | if (processedStr.length() >= 3 && processedStr.substr(processedStr.length() - 3) == "110") { 25 | processedStr.erase(processedStr.length() - 3); 26 | count110++; 27 | } 28 | } 29 | 30 | int lastZeroIndex = findLastZero(processedStr); // 마지막 '0'의 위치 찾기 31 | 32 | string result; // 최종 문자열을 저장할 변수 33 | if (lastZeroIndex == -1) { 34 | // '0'이 없는 경우, "110"을 모두 앞에 추가 35 | while (count110--) result += "110"; 36 | result += processedStr; 37 | } else { 38 | // '0'이 있는 경우, 마지막 '0' 뒤에 "110"을 모두 추가 39 | for (int j = 0; j < processedStr.length(); j++) { 40 | if (j == lastZeroIndex) { 41 | result += processedStr[j]; 42 | while (count110--) result += "110"; 43 | } else { 44 | result += processedStr[j]; 45 | } 46 | } 47 | } 48 | answer.push_back(result); 49 | } 50 | 51 | return answer; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /STL/binary_search.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include // for std::binary_search and std::sort 9 | using namespace std; 10 | 11 | int main() { 12 | // 예시 벡터 생성 13 | vector v = {1, 3, 4, 5, 7, 9, 10}; 14 | 15 | // 찾고자 하는 값 16 | int value1 = 5; 17 | int value2 = 6; 18 | 19 | // 이진 탐색 사용 예시 20 | bool found1 = binary_search(v.begin(), v.end(), value1); 21 | bool found2 = binary_search(v.begin(), v.end(), value2); 22 | 23 | // 결과 출력 24 | cout << "값 " << value1 << "를 찾는 중: " << (found1 ? "찾음" : "찾지 못함") << endl; 25 | cout << "값 " << value2 << "를 찾는 중: " << (found2 ? "찾음" : "찾지 못함") << endl; 26 | 27 | return 0; 28 | } 29 | 30 | /* 31 | 출력값: 32 | 33 | 값 5를 찾는 중: 찾음 34 | 값 6를 찾는 중: 찾지 못함 35 | */ 36 | 37 | // binary_search에 대한 설명 38 | /* 39 | std::binary_search 함수는 정렬된 범위에서 특정 값을 찾는 데 사용됩니다. 40 | 이진 탐색 알고리즘을 사용하여 값의 존재 여부를 확인합니다. 41 | 42 | 주의해야 할 점: 43 | 1. 정렬된 상태에서 사용: binary_search 함수는 정렬된 범위에서만 올바르게 동작합니다. 44 | 정렬되지 않은 범위에서 사용하면 결과가 올바르지 않습니다. 45 | 2. 반환값: 찾고자 하는 값이 존재하면 true를 반환하고, 존재하지 않으면 false를 반환합니다. 46 | 47 | 시간복잡도: 48 | - std::binary_search 함수의 시간복잡도는 O(log N)입니다. 여기서 N은 범위 내의 요소 수입니다. 49 | 50 | 예제: 51 | 벡터가 {1, 3, 4, 5, 7, 9, 10}로 주어졌을 때, 52 | binary_search(v.begin(), v.end(), 5)를 호출하면 true를 반환하고, 53 | binary_search(v.begin(), v.end(), 6)를 호출하면 false를 반환합니다. 54 | */ 55 | 56 | -------------------------------------------------------------------------------- /ReadMe.md: -------------------------------------------------------------------------------- 1 | # 코딩 테스트 합격자 되기(CPP 편) 2 | - 프로그래머스에서 엄선한 기출문제에 대한 상세한 풀이 제공 3 | - 들고 다닐수 있는 요약노트 제공 4 | - 실전문제 위주로 출제왼 기출문제 5회본 제공 5 | 6 | ![코딩 테스트 합격자 되기(C++ 편)_입체표지](https://github.com/dremdeveloper/codingtest_cpp/assets/131899974/380f732f-174d-4fc3-a552-bb74f8478b24) 7 | 8 | 9 | # 진행중인 이벤트 10 | | Event | 세부내용 |기간 | 11 | | ---------- | ---------------------------------------------- |---------------------------------------------- | 12 | |코딩테스트 강의신청 |[세부사항](https://bit.ly/4aPfz5P) | 구매자 한 무료로 진행 | 13 | |코테 정리노트 증정(100프로 당첨) |[참여하러가기](https://bit.ly/3VWUjGO) | 구매자 한 무료로 진행 | 14 | 15 | 16 | # 코딩테스트 소통공간(저자가 직접운영) 17 | - 카카오톡 오픈채팅 : https://open.kakao.com/o/gX0WnTCf 18 | 19 | 20 | ![image](https://github.com/dremdeveloper/codingtest_python/assets/131899974/ba74f116-ddb6-4cb4-956e-147d35e10336) 21 | 22 | # 연락처 23 | - 해당 코드들에 대해 문의사항이 있거나, 연락이 필요한 경우 아래 참조 24 | 25 | | Title | Description | 26 | | ---------- | ---------------------------------------------- | 27 | |Cafe |http://cafe.naver.com/dremdeveloper | 28 | |Business Mail |ultrasuperrok@gmail.com | 29 | 30 | 31 | # 폴더 구조 32 | - 깃 허브의 폴더 구조에 대한 설명 33 | 34 | | Title | Description | 35 | | ---------- | ---------------------------------------------- | 36 | | STL | 코딩테스트에서 사용되는 STL 정리 | 37 | | solution | 책에 있는 문제에 대한 해설 | 38 | | Algorithm DataStructure | 코테에 자주나오는 알고리즘과자료구조 설명 | 39 | | reference | C++기본 문법설명 | 40 | | performance | C++에서 유의해야할 성능비교 | 41 | 42 | -------------------------------------------------------------------------------- /solution/37.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | unordered_map> adjList; 9 | vector result; 10 | 11 | void bfs(int start) { 12 | unordered_set visited; 13 | queue q; 14 | 15 | // ❶ 시작 노드 방문 16 | q.push(start); 17 | visited.insert(start); 18 | result.push_back(start); 19 | 20 | while (!q.empty()) { 21 | int node = q.front(); 22 | q.pop(); 23 | 24 | // ❷ 현재 노드와 인접한 노드 중 아직 방문하지 않는 노드 방문 25 | for (int neighbor : adjList[node]) { 26 | if (visited.find(neighbor) == visited.end()) { 27 | q.push(neighbor); 28 | visited.insert(neighbor); 29 | result.push_back(neighbor); 30 | } 31 | } 32 | } 33 | } 34 | 35 | vector solution(vector> graph, int start) { 36 | // ❸ 인접 리스트 생성 37 | for (auto &edge : graph) { 38 | int u = edge.first; 39 | int v = edge.second; 40 | adjList[u].push_back(v); 41 | } 42 | 43 | // ❹ 시작 노드부터 너비 우선 탐색 시작 44 | bfs(start); 45 | 46 | return result; 47 | } 48 | 49 | //아래 코드는 테스트 코드 입니다. 50 | #include 51 | #include 52 | 53 | using namespace std; 54 | 55 | 56 | void init() 57 | { 58 | adjList.clear(); 59 | result.clear(); 60 | 61 | } 62 | void print(vector vec) 63 | { 64 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 65 | cout << endl; 66 | 67 | } 68 | 69 | int main() 70 | { 71 | 72 | print(solution({{1, 2}, {1, 3}, {2, 4}, {2, 5}, {3, 6}, {3, 7}, {4, 8}, {5, 8}, {6, 9}, {7, 9}}, 1)); //출력값 : 1 2 3 4 5 6 7 8 9 73 | init(); 74 | print(solution({{0, 1}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 0}}, 1)); //출력값 : 1 2 3 4 5 0 75 | return 0; 76 | } 77 | -------------------------------------------------------------------------------- /solution/81.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | //❶ 각 물건의 단위 무게당 가치를 계산하여 items 벡터에 추가 7 | void calculate_unit_value(vector> &items) { 8 | for (auto &item : items) { 9 | item.push_back(item[1] / item[0]); 10 | } 11 | } 12 | 13 | //❷ 단위 무게당 가치가 높은 순으로 물건을 정렬 14 | void sort_by_unit_value(vector> &items) { 15 | sort(items.begin(), items.end(), [](const vector &a, const vector &b) { 16 | return a[2] > b[2]; 17 | }); 18 | } 19 | 20 | double knapsack(vector> &items, double weight_limit) { 21 | double total_value = 0; //❸ 선택한 물건들의 총 가치를 저장 22 | double remaining_weight = weight_limit; //❹남은 무게 한도를 저장 23 | 24 | //❺ items을 순회하며 물건을 선택 25 | for (const auto &item : items) { 26 | if (item[0] <= remaining_weight) { 27 | //❻ 남은 무게 한도 내에서 물건을 통째로 선택 28 | total_value += item[1]; 29 | remaining_weight -= item[0]; 30 | } else { 31 | //❼ 남은 무게 한도가 물건의 무게보다 작으면 쪼개서 일부분만 선택 32 | double fraction = remaining_weight / item[0]; 33 | total_value += item[1] * fraction; 34 | break; //❽ 이미 배낭의 무게 한도를 모두 사용한 경우 35 | } 36 | } 37 | return total_value; 38 | } 39 | 40 | double solution(vector> items, double weight_limit) { 41 | calculate_unit_value(items); 42 | sort_by_unit_value(items); 43 | //➒ 배낭의 무게 한도 내에서 담을 수 있는 물건들의 최대 가치를 반환(소수점 둘째자리 까지만 나타냄) 44 | return round(knapsack(items, weight_limit) * 100) / 100; 45 | } 46 | 47 | //아래 코드는 테스트 코드 입니다. 48 | #include 49 | 50 | int main() 51 | { 52 | cout << solution({{10, 19}, {7, 10}, {6, 10}}, 15) << endl; //출력값 : 27.3333 53 | cout << solution({{10, 60}, {20, 100}, {30, 120}}, 50) << endl; //출력값 : 240 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /solution/94.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // x, y 위치에서 주변에 'P'가 있는지 검사 8 | bool hasClosePerson(const vector& map, int N, int M, int x, int y) { 9 | const int dx[4] = { -1, 0, 1, 0 }; // 상하좌우 이동 10 | const int dy[4] = { 0, -1, 0, 1 }; 11 | 12 | queue> q; 13 | bool visited[5][5] = {}; // 방문 여부 14 | visited[x][y] = true; 15 | q.push({ x, y }); 16 | 17 | for (int layer = 0; layer < 2; layer++) { 18 | int size = q.size(); 19 | while (size--) { 20 | pair cur = q.front(); 21 | q.pop(); 22 | 23 | for (int dir = 0; dir < 4; dir++) { 24 | int nextX = cur.first + dx[dir], nextY = cur.second + dy[dir]; 25 | if (!(0 <= nextX && nextX < 5 && 0 <= nextY && nextY < 5)) continue; 26 | if (visited[nextX][nextY] || map[nextX][nextY] == 'X') continue; 27 | if (map[nextX][nextY] == 'P') return true; 28 | visited[nextX][nextY] = true; 29 | q.push({ nextX, nextY }); 30 | } 31 | } 32 | } 33 | return false; 34 | } 35 | 36 | // 지도 전체에서 'P'들이 규칙에 맞게 배치되었는지 확인 37 | bool isSafe(const vector& map, int N, int M) { 38 | for (int i = 0; i < N; i++) { 39 | for (int j = 0; j < M; j++) { 40 | if (map[i][j] == 'P' && hasClosePerson(map, N, M, i, j)) return false; 41 | } 42 | } 43 | return true; 44 | } 45 | 46 | // 각 대기실 별로 안전한지 검사하여 결과 반환 47 | vector solution(vector> places) { 48 | vector answer; 49 | for (const auto& place : places) { 50 | answer.push_back(isSafe(place, 5, 5) ? 1 : 0); 51 | } 52 | return answer; 53 | } 54 | 55 | -------------------------------------------------------------------------------- /Example/chageCoin.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 문제의 정의: 7 | // 주어진 거스름돈을 1원, 5원, 10원, 50원, 100원, 500원의 동전을 사용하여 8 | // 최소 개수의 동전으로 거슬러 주는 문제입니다. 9 | 10 | // 왜 그리디로 풀리는지: 11 | // 탐욕적 선택 속성: 매 단계에서 가장 큰 단위의 동전을 선택하여, 12 | // 나머지 금액을 거슬러 줍니다. 큰 단위의 동전을 선택하는 것이 항상 13 | // 최적의 해를 보장합니다. 14 | // 최적 부분구조: 현재 금액을 가장 큰 단위로 거슬러 준 후, 15 | // 남은 금액에 대해 같은 문제를 반복하여 해결할 수 있습니다. 16 | // 즉, 부분 문제의 최적해가 전체 문제의 최적해로 이어집니다. 17 | 18 | // 왜 최적의 해를 보장하는가: 19 | // 1. 탐욕적 선택 속성: 가장 큰 단위의 동전을 선택하는 것이 20 | // 최적의 해를 보장하는 이유는, 큰 단위의 동전이 작은 단위의 동전보다 21 | // 더 많은 금액을 커버할 수 있기 때문입니다. 예를 들어, 500원을 선택하면 22 | // 100원을 5개 사용하는 것보다 적은 개수의 동전으로 같은 금액을 커버할 수 있습니다. 23 | // 2. 최적 부분구조: 주어진 문제를 작은 부분 문제로 나눌 수 있으며, 24 | // 각 부분 문제의 최적해가 전체 문제의 최적해를 구성합니다. 예를 들어, 25 | // 837원을 거슬러 줄 때, 500원을 선택하면 남은 337원을 거슬러 주는 문제로 26 | // 축소됩니다. 이때, 337원을 최적으로 거슬러 주는 방법이 전체 문제를 최적으로 27 | // 해결하는 방법이 됩니다. 28 | 29 | int main() { 30 | // 거스름돈 변수 (예: 837원) 31 | int change = 837; 32 | 33 | // 동전 단위 배열 (큰 단위부터) 34 | vector coins = {500, 100, 50, 10, 5, 1}; 35 | vector count(coins.size(), 0); 36 | 37 | // 코드 상세 동작: 38 | // 큰 단위의 동전부터 차례로 거스름돈을 나누어 줍니다. 39 | for (int i = 0; i < coins.size(); i++) { 40 | if (change >= coins[i]) { 41 | // 현재 동전 단위로 거슬러 줄 수 있는 최대 개수를 계산합니다. 42 | count[i] = change / coins[i]; 43 | // 거슬러 준 금액을 제외한 나머지 금액을 계산합니다. 44 | change %= coins[i]; 45 | } 46 | } 47 | 48 | // 결과 출력: 각 동전 단위별로 사용된 개수를 출력합니다. 49 | cout << "최소 동전 개수: " << endl; 50 | for (int i = 0; i < coins.size(); i++) { 51 | if (count[i] != 0) { 52 | cout << coins[i] << "원: " << count[i] << "개" << endl; 53 | } 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /solution/25.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | bool compareGenre(const pair& a, const pair& b) { 9 | return a.second > b.second; 10 | } 11 | 12 | bool compareSong(const pair& a, const pair& b) { 13 | if (a.second == b.second) return a.first < b.first; 14 | return a.second > b.second; 15 | } 16 | 17 | vector solution(vector genres, vector plays) { 18 | vector answer; 19 | unordered_map>> genres_dict; 20 | unordered_map play_dict; 21 | 22 | //❶ 장르별 총 재생 횟수와 각 곡의 재생 횟수 저장 23 | for (int i = 0; i < genres.size(); ++i) { 24 | genres_dict[genres[i]].push_back({i, plays[i]}); 25 | play_dict[genres[i]] += plays[i]; 26 | } 27 | 28 | //❷ 총 재생 횟수가 많은 장르순으로 정렬 29 | vector> sorted_genres(play_dict.begin(), play_dict.end()); 30 | sort(sorted_genres.begin(), sorted_genres.end(), compareGenre); 31 | 32 | //❸ 각 장르 내에서 노래를 재생 횟수 순으로 정렬해 최대 2곡 까지 선택 33 | for (auto& genre : sorted_genres) { 34 | auto& songs = genres_dict[genre.first]; 35 | sort(songs.begin(), songs.end(), compareSong); 36 | 37 | for (int i = 0; i < min(2, (int)songs.size()); ++i) { 38 | answer.push_back(songs[i].first); 39 | } 40 | } 41 | 42 | return answer; 43 | } 44 | 45 | //아래 코드는 테스트 코드 입니다. 46 | #include 47 | #include 48 | void print(vector vec) 49 | { 50 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 51 | cout << endl; 52 | } 53 | 54 | int main() 55 | { 56 | print(solution({"classic", "pop", "classic", "classic", "pop"}, {500, 600, 150, 800, 2500})); //출력값 : 1 0 0 1 57 | return 0; 58 | 59 | } 60 | -------------------------------------------------------------------------------- /STL/ReadMe.md: -------------------------------------------------------------------------------- 1 | | 파일 이름 | 설명 | 2 | |-----------------------|------------------| 3 | | `sort.cpp` | 정렬 알고리즘: std::sort를 사용하여 배열을 오름차순과 내림차순으로 정렬하고, partial_sort를 사용한 부분 정렬을 설명합니다. | 4 | | `stack.cpp` | 스택 구현: std::stack을 사용하여 LIFO 원칙에 따라 동작하는 스택의 기본 동작을 설명합니다. | 5 | | `template.cpp` | 템플릿 사용 예제: C++ 템플릿을 사용하여 함수와 클래스의 템플릿 예제를 보여줍니다. | 6 | | `unordered_map.cpp` | 언오더드 맵 사용법: std::unordered_map의 기본 사용법을 설명하며, 해시 테이블 기반으로 작동하는 방식을 설명합니다. | 7 | | `unordered_set.cpp` | 언오더드 셋 사용법: std::unordered_set의 사용을 통해 중복 없이 요소를 저장하는 방법을 설명합니다. | 8 | | `vector.cpp` | 벡터 사용법: std::vector의 기능과 사용법을 설명하며, 동적 배열로서의 장점을 강조합니다. | 9 | | `priority_queue.cpp` | 우선순위 큐 사용법: std::priority_queue를 사용하여 요소를 우선순위에 따라 관리하는 방법을 설명합니다. | 10 | | `queue.cpp` | 큐 구현: std::queue를 사용하여 FIFO 원칙에 따라 동작하는 큐의 기본 동작을 설명합니다. | 11 | | `reverse.cpp` | 배열 뒤집기: std::reverse를 사용하여 배열의 요소 순서를 뒤집는 방법을 설명합니다. | 12 | | `set.cpp` | 셋 사용법: std::set을 사용하여 요소를 정렬 상태로 유지하며 중복 없이 저장하는 방법을 설명합니다. | 13 | | `map.cpp` | 맵 사용법: std::map을 사용하여 키-값 쌍을 저장하고 관리하는 예제를 보여줍니다. 키는 유일하며 정렬된 순서로 저장됩니다. | 14 | | `max_element.cpp` | 최대 요소 찾기: 컨테이너에서 최대값을 찾는 std::max_element 사용법을 설명합니다. | 15 | | `min_element.cpp` | 최소 요소 찾기: 컨테이너에서 최소값을 찾는 std::min_element 사용법을 설명합니다. | 16 | | `next_permutation.cpp` | 다음 순열 찾기: 컨테이너의 가능한 순열을 생성하는 std::next_permutation 함수를 사용합니다. | 17 | | `binary_search.cpp` | 이진 검색 알고리즘: 정렬된 데이터에 대한 이진 검색을 수행하는 방법을 설명합니다. | 18 | | `call_by_ref.cpp` | 참조에 의한 호출: 함수에서 참조를 통해 변수를 전달하고 변경하는 방법을 보여줍니다. | 19 | | `count.cpp` | 요소 개수 세기: std::count를 사용하여 특정 값의 개수를 세는 방법을 설명합니다. | 20 | | `deque.cpp` | 덱 사용법: 양쪽 끝에서 요소를 추가하거나 제거할 수 있는 std::deque의 사용법을 설명합니다. | 21 | | `iterator.cpp` | 이터레이터 사용법: STL 컨테이너를 순회하는 데 사용되는 이터레이터의 다양한 사용법을 보여줍니다. | 22 | 23 | -------------------------------------------------------------------------------- /reference/function.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | // 함수 정의의 기본 구조 11 | // 반환형 함수명(매개변수 목록) { 12 | // 함수 본문 13 | // return 반환값; 14 | // } 15 | 16 | /* 17 | 함수(Function)이란? 18 | - 함수는 특정 작업을 수행하는 코드 블록의 모음입니다. 19 | - 코드의 재사용성을 높이고, 프로그램의 구조를 체계적으로 만들어 주며, 디버깅을 용이하게 합니다. 20 | - 함수는 반환형, 함수명, 매개변수 목록, 함수 본문으로 구성됩니다. 21 | */ 22 | 23 | // 반환형이 void인 경우, 함수는 값을 반환하지 않습니다. 24 | void sayHello() { 25 | cout << "Hello, World!" << endl; 26 | } 27 | 28 | // 매개변수로 값을 받아서 처리할 수 있습니다. 29 | void displayNumber(int num) { 30 | cout << "Number: " << num << endl; 31 | } 32 | 33 | // 함수는 값을 반환할 수 있습니다. 34 | int add(int a, int b) { 35 | return a + b; 36 | } 37 | 38 | // 함수의 오버로딩: 같은 이름을 가진 함수를 여러 개 정의하는 것. 매개변수의 타입이나 개수가 달라야 합니다. 39 | void show(double d) { 40 | cout << "Double: " << d << endl; 41 | } 42 | 43 | void show(int i) { 44 | cout << "Int: " << i << endl; 45 | } 46 | 47 | /* 48 | 주의사항: 49 | 1. 함수의 선언(프로토타입)과 정의는 다릅니다. 선언은 함수의 원형만을 나타내며, 정의는 함수의 실제 동작을 구현합니다. 50 | 2. 함수를 호출하기 전에 함수가 선언되어 있어야 합니다. 51 | 3. 값을 전달받는 매개변수는 함수 내에서 값이 변경되더라도 원래 변수에는 영향을 미치지 않습니다. 52 | */ 53 | 54 | int main() { 55 | sayHello(); // 출력: Hello, World! 56 | 57 | displayNumber(5); // 출력: Number: 5 58 | 59 | int result = add(3, 4); 60 | cout << "Sum: " << result << endl; // 출력: Sum: 7 61 | 62 | show(5); // 출력: Int: 5 63 | show(3.14); // 출력: Double: 3.14 64 | 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /solution/62.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | // ❶ 2차원 벡터를 인자로 받고 90도 회전 6 | vector> rotate_90(const vector> &arr) { 7 | int n = arr.size(); 8 | // ❷ 인자로 받은 벡터와 크기가 같은 2차원 백터 생성(초깃값은 0) 9 | vector> rotated_arr(n, vector(n, 0)); 10 | // ❸ 2차원 벡터를 90도로 회전 11 | for (int i = 0; i < n; ++i) { 12 | for (int j = 0; j < n; ++j) { 13 | rotated_arr[j][n - i - 1] = arr[i][j]; 14 | } 15 | } 16 | return rotated_arr; 17 | } 18 | 19 | vector> solution(vector> arr, int n) { 20 | vector> rotated_arr = arr; 21 | 22 | // ❹ 2차원 벡터를 90도로 n번 회전 23 | for (int i = 0; i < n; ++i) { 24 | rotated_arr = rotate_90(rotated_arr); 25 | } 26 | return rotated_arr; 27 | } 28 | 29 | //아래 코드는 테스트 코드 입니다. 30 | #include 31 | #include 32 | 33 | using namespace std; 34 | 35 | void print(vector> vec) 36 | { 37 | for(int i = 0 ; i < vec.size(); i++){ 38 | copy(vec[i].begin(), vec[i].end(), std::ostream_iterator(cout, " ")); 39 | cout << endl; 40 | } 41 | 42 | } 43 | 44 | int main() 45 | { 46 | print(solution({ 47 | {1, 2, 3, 4}, 48 | {5, 6, 7, 8}, 49 | {9, 10, 11, 12}, 50 | {13, 14, 15, 16} 51 | }, 1)); 52 | /* 53 | 출력값 54 | 13 9 5 1 55 | 14 10 6 2 56 | 15 11 7 3 57 | 16 12 8 4 58 | */ 59 | 60 | print(solution({ 61 | {1, 2, 3, 4}, 62 | {5, 6, 7, 8}, 63 | {9, 10, 11, 12}, 64 | {13, 14, 15, 16} 65 | }, 3)); 66 | /* 67 | 출력값 68 | 4 8 12 16 69 | 3 7 11 15 70 | 2 6 10 14 71 | 1 5 9 13 72 | */ 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /reference/array.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | 12 | /* 13 | 배열(Array)이란? 14 | - 배열은 동일한 타입의 여러 데이터를 연속적인 메모리 공간에 저장할 수 있는 데이터 구조입니다. 15 | - 배열의 각 요소는 인덱스를 통해 접근할 수 있습니다. 16 | - 배열의 크기는 선언 시에 지정되며, 이후 크기 변경이 불가능합니다. 17 | - 배열은 스택 메모리에 할당됩니다(동적으로 힙 메모리에 할당하려면 동적 배열을 사용해야 합니다). 18 | */ 19 | 20 | int arr[5] = {1, 2, 3, 4, 5}; // 크기가 5인 int 타입의 배열 선언 및 초기화 21 | 22 | for (int i = 0; i < 5; i++) { 23 | cout << arr[i] << " "; // 배열의 요소 접근 및 출력 24 | } 25 | cout << endl; // 출력: 1 2 3 4 5 26 | 27 | /* 28 | 주의사항: 29 | 1. 배열의 범위를 벗어나는 인덱스에 접근하면 정의되지 않은 동작(Undefined Behavior)가 발생합니다. 30 | */ 31 | // arr[10] = 50; // 오류: 배열의 범위를 벗어난 인덱스에 접근 32 | 33 | /* 34 | 2. 배열의 크기를 동적으로 할당하려면 new와 delete 연산자를 사용해야 합니다. 35 | */ 36 | int* dynamicArray = new int[10]; // 크기가 10인 동적 배열 생성 37 | for (int i = 0; i < 10; i++) { 38 | dynamicArray[i] = i; 39 | } 40 | delete[] dynamicArray; // 동적 배열 메모리 해제 41 | 42 | /* 43 | 3. 배열의 크기는 컴파일 시에 결정되어야 하므로, 실행 시간에 크기를 지정할 수 없습니다. 44 | 이런 경우 동적 배열을 사용해야 합니다. 45 | */ 46 | int size; 47 | cout << "Enter the size of array: "; 48 | cin >> size; 49 | int* arraySizeDynamic = new int[size]; 50 | delete[] arraySizeDynamic; 51 | 52 | /* 53 | 4. 배열은 할당된 크기 변경이 불가능합니다. 크기 변경이 필요한 경우, 새로운 크기의 배열을 만들고 데이터를 복사해야 합니다. 54 | */ 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /solution/39.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | const int INF = numeric_limits::max(); 8 | 9 | vector solution(int num_vertices, vector> edges, int source) { 10 | vector>> graph(num_vertices); 11 | 12 | //❶ 간선정보를 활용해서 인접리스트를 생성 13 | for (auto& edge : edges) { 14 | int from, to, weight; 15 | tie(from, to, weight) = edge; 16 | graph[from].emplace_back(to, weight); 17 | } 18 | 19 | //❷ 현재까지 구한 최소비용을 INF로 설정(시작노드는 제외) 20 | vector distance(num_vertices, INF); 21 | distance[source] = 0; 22 | 23 | //❸ 정점의 개수 -1 만큼 최소비용을 갱신 24 | for (int i = 0; i < num_vertices - 1; ++i) { 25 | for (int u = 0; u < num_vertices; ++u) { 26 | for (const auto& [v, weight] : graph[u]) { 27 | if (distance[u] + weight < distance[v]) { 28 | distance[v] = distance[u] + weight; 29 | } 30 | } 31 | } 32 | } 33 | 34 | //❹ 음의 순환이 있는지 확인 35 | for (int u = 0; u < num_vertices; ++u) { 36 | for (const auto& [v, weight] : graph[u]) { 37 | if (distance[u] + weight < distance[v]) { 38 | return vector(1, -1); 39 | } 40 | } 41 | } 42 | 43 | return distance; 44 | } 45 | 46 | 47 | //아래 코드는 테스트 코드 입니다. 48 | #include 49 | #include 50 | 51 | using namespace std; 52 | 53 | 54 | void print(vector vec) 55 | { 56 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 57 | cout << endl; 58 | 59 | } 60 | 61 | int main() 62 | { 63 | 64 | print(solution(5, {{0, 1, 4}, {0, 2, 3}, {0, 4, -6}, {1, 3, 5}, {2, 1, 2}, {3, 0, 7}, {3, 2, 4},{4, 2, 2}}, 0)); //출력값 : 0 -2 -4 3 -6 65 | print(solution(4, {{0, 1, 5}, {0, 2, -1}, {1, 2, 2}, {2, 3,-2}, {3, 0, 2}, {3, 1, 6}}, 0)); //출력값 : -1 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/matching_bracket.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | /* 7 | 괄호 짝 검사 알고리즘: 8 | - 시간 복잡도: O(n) 9 | - 용도: 괄호가 올바르게 짝을 이루고 있는지 검사하는 데 사용합니다. 10 | - 동작 과정: 11 | 1. 문자열의 각 문자를 차례대로 확인합니다. 12 | 2. 여는 괄호('(')를 만나면 스택에 푸시합니다. 13 | 3. 닫는 괄호(')')를 만나면 스택이 비어있는지 확인하고, 비어있지 않다면 스택의 탑을 팝합니다. 14 | 4. 문자열의 모든 문자를 처리한 후 스택이 비어있으면 짝이 맞는 것으로, 비어있지 않다면 짝이 맞지 않는 것으로 판단합니다. 15 | 16 | 도식화 예: 17 | 입력: "(()(())())" 18 | 스택: [ "(" ] 19 | -> 첫 번째 ')'를 만날 때: 스택에서 "(" 팝 20 | 스택: [ "(" ] 21 | -> 두 번째 ')'를 만날 때: 스택에서 "(" 팝 22 | 스택: [ "(", "(", "(" ] 23 | -> 세 번째 ')'를 만날 때: 스택에서 "(" 팝 24 | ... (계속) 25 | 스택: [ ] 26 | -> 모든 문자를 처리하고, 스택이 비어있으므로 괄호 짝이 맞습니다. 27 | */ 28 | 29 | #include 30 | #include 31 | using namespace std; 32 | 33 | bool areParenthesesBalanced(const string& expr) { 34 | stack s; // 스택 생성 35 | for (char ch : expr) { 36 | if (ch == '(') { // 여는 괄호를 만나면 스택에 푸시 37 | s.push(ch); 38 | } else if (ch == ')') { // 닫는 괄호를 만나면 39 | if (s.empty()) { // 스택이 비어있으면 괄호 짝이 맞지 않습니다. 40 | return false; 41 | } 42 | s.pop(); // 스택의 탑 원소를 팝 43 | } 44 | } 45 | // 문자열의 모든 문자를 처리한 후 스택이 비어있으면 괄호 짝이 맞습니다. 46 | return s.empty(); 47 | } 48 | 49 | int main() { 50 | string expr = "(()(())())"; 51 | if (areParenthesesBalanced(expr)) { 52 | cout << "The parentheses are balanced.\n"; 53 | } else { 54 | cout << "The parentheses are NOT balanced.\n"; 55 | } 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /solution/44.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using namespace std; 5 | 6 | int solution(int N, vector> road, int K) { 7 | vector> graph[N + 1]; 8 | vector distances(N + 1, numeric_limits::max()); 9 | vector visited(N + 1, false); 10 | distances[1] = 0; 11 | 12 | //❶ 방향이 따로 없으므로, 양방향 모두 동일한 가중치 입력 13 | for (const auto& r : road) { 14 | int a = r[0], b = r[1], cost = r[2]; 15 | graph[a].push_back({b, cost}); 16 | graph[b].push_back({a, cost}); 17 | } 18 | 19 | //❷ 출발점을 heap에 추가 20 | priority_queue, vector>, greater>> heap; 21 | heap.push({0, 1}); 22 | 23 | while (!heap.empty()) { 24 | int dist = heap.top().first; 25 | int node = heap.top().second; 26 | heap.pop(); 27 | 28 | //❸ 이미 방문한 노드는 무시 29 | if (visited[node]) continue; 30 | visited[node] = true; 31 | 32 | for (const auto& next : graph[node]) { 33 | int next_node = next.first; 34 | int next_dist = next.second; 35 | int cost = dist + next_dist; 36 | 37 | //❹ 거쳐가는 노드로 가는 경로의 비용이 더 짧은 경우 38 | if (cost < distances[next_node]) { 39 | distances[next_node] = cost; 40 | heap.push({cost, next_node}); 41 | } 42 | } 43 | } 44 | 45 | int count = 0; 46 | 47 | //❺거리가 K 이하인 장소를 카운트 48 | for (int i = 1; i <= N; i++) { 49 | if (distances[i] <= K) count++; 50 | } 51 | 52 | return count; 53 | } 54 | 55 | 56 | //아래 코드는 테스트 코드 입니다. 57 | #include 58 | 59 | using namespace std; 60 | 61 | int main() 62 | { 63 | 64 | cout << solution(5, {{1, 2, 1}, {2, 3, 3}, {5, 2, 2}, {1, 4, 2}, {5, 3, 1}, {5, 4, 2}}, 3) << endl; //출력값 : 4 65 | cout << solution(6, {{1, 2, 1}, {1, 3, 2}, {2, 3, 2}, {3, 4, 3}, {3, 5, 2}, {3, 5, 3}, {5, 6, 1}}, 4) << endl; //출력값 : 4 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /solution/46.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | int dfs(int node, int parent, const vector>& graph) { 9 | int cnt = 1; 10 | //❶ 인접노드에 대해 깊이우선탐색 계속 진행 11 | for (int child : graph[node]) { 12 | //❷ 무한탐색을 방지하기 위해 인접한 노드 중, 부모노드는 탐색하지 않음 13 | if (child != parent) { 14 | cnt += dfs(child, node, graph); 15 | } 16 | } 17 | return cnt; 18 | } 19 | 20 | int solution(int n, vector> wires) { 21 | vector> graph(n + 1); 22 | //❸ wire정보를 활용해서 그래프 구축 23 | for (auto &wire : wires) { 24 | int a = wire[0]; 25 | int b = wire[1]; 26 | graph[a].push_back(b); 27 | graph[b].push_back(a); 28 | } 29 | 30 | int min_diff = INT_MAX; 31 | for (auto &wire : wires) { 32 | int a = wire[0]; 33 | int b = wire[1]; 34 | 35 | //❹ 특정 전선을 임시로 삭제 36 | graph[a].erase(remove(graph[a].begin(), graph[a].end(), b), graph[a].end()); 37 | graph[b].erase(remove(graph[b].begin(), graph[b].end(), a), graph[b].end()); 38 | 39 | //❺ 전력망을 단절하고 각 전력망의 송전탑 개수의 차를 구함 40 | int cnt_a = dfs(a, b, graph); 41 | int cnt_b = n - cnt_a; 42 | 43 | //❻ 현재까지 구한 송전탑의 차의 절대값의 최소값과 현재 값중 더 적은값을 택함 44 | min_diff = min(min_diff, abs(cnt_a - cnt_b)); 45 | 46 | //❼ 임시로 제거했던 제거했던 전선을 복구 47 | graph[a].push_back(b); 48 | graph[b].push_back(a); 49 | } 50 | 51 | return min_diff; 52 | } 53 | 54 | 55 | 56 | 57 | //아래 코드는 테스트 코드 입니다. 58 | #include 59 | 60 | using namespace std; 61 | 62 | int main() 63 | { 64 | 65 | cout << solution(9, {{1, 3}, {2, 3}, {3, 4}, {4, 5}, {4, 6}, {4, 7}, {7, 8}, {7, 9}}) << endl; //출력값 : 3 66 | cout << solution(4, {{1, 2}, {2, 3}, {3, 4}}) << endl; //출력값 : 0 67 | cout << solution(7, {{1, 2}, {2, 7}, {3, 7}, {3, 4}, {4, 5}, {6, 7}}) << endl; //출력값 : 1 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /solution/07.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | bool visited[11][11][4]; // ❶ 특정 좌표에서 특정 방향으로 이동한 적이 있는지 체크하는 배열 6 | 7 | // ❷ 상하좌우로 좌표를 이동할 때 필요한 좌표의 오프셋 배열 8 | int dx[] = {0, 1, 0, -1}; 9 | int dy[] = {-1, 0, 1, 0}; 10 | 11 | // ❸ 각 문자에 해당하는 오프셋 배열의 인덱스를 반환 12 | int todir(char dir) { 13 | int ret; 14 | if (dir == 'U') ret = 0; 15 | else if (dir == 'R') ret = 1; 16 | else if (dir == 'D') ret = 2; 17 | else ret = 3; 18 | return ret; 19 | } 20 | 21 | // ❹ 특정좌표가 주어진 좌표평면을 벗어나는지 확인 22 | bool isNotValid(int x, int y) 23 | { 24 | return x < 0 || y < 0 || x > 10 || y > 10; 25 | } 26 | // ❺ 현재와 반대 방향의 오프셋 배열 인덱스 반환 27 | int opposite_direction(int dir) 28 | { 29 | return (dir+2) % 4; 30 | } 31 | 32 | int solution(string dirs) 33 | { 34 | int answer = 0; 35 | int x = 5, y = 5; // ❻ 시작 좌표를 설정 36 | 37 | for (auto c : dirs) { 38 | // ❼ 반복문을 순회하며 nx, ny는 x, y가 dirs대로 움직였을 때 위치가 됨 39 | int dir = todir(c); 40 | int nx = x + dx[dir]; 41 | int ny = y + dy[dir]; 42 | // ❽ 좌표평면을 벗어난 경우 더 이상 이동하지 않음 43 | if (isNotValid(nx,ny)) { 44 | continue; 45 | } 46 | 47 | // ❾ 다음 좌표가 아직 방문하지 않은 좌표인 경우 48 | if(visited[y][x][dir] == false) { 49 | // ❿ 방문이 중복 체크되지 않도록 해당 경로의 양방향을 방문 체크 50 | visited[y][x][dir] = true; 51 | visited[ny][nx][opposite_direction(dir)] = true; 52 | answer++; 53 | } 54 | // ⓫ 현재좌표를 이동한 좌표로 업데이트 55 | x = nx; 56 | y = ny; 57 | } 58 | return answer; 59 | } 60 | 61 | 62 | 63 | 64 | //아래 코드는 테스트 코드 입니다. 65 | #include 66 | 67 | int main() 68 | { 69 | cout << solution("ULURRDLLU") << endl; // 7 70 | cout << solution("LULLLLLLU") << endl; // 7 71 | 72 | return 0; 73 | } 74 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/dfs_recursive.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // 전역 인접 리스트 및 방문 리스트 7 | vector> adj; 8 | vector visited; 9 | 10 | // 그래프에 간선을 추가하는 함수 11 | // 인자: v (정점), w (연결된 정점) 12 | void add_edge(int v, int w) { 13 | adj[v].push_back(w); // 정점 v의 인접 리스트에 정점 w를 추가 14 | } 15 | 16 | // 깊이 우선 탐색(DFS)을 수행하는 함수 17 | // 인자: v (현재 정점) 18 | void dfs(int v) { 19 | // 현재 정점을 방문했다고 표시하고 출력 20 | visited[v] = true; 21 | cout << v << " "; 22 | 23 | // 현재 정점에 인접한 모든 정점을 순회 24 | for (int i = 0; i < adj[v].size(); ++i) { 25 | if (!visited[adj[v][i]]) { 26 | dfs(adj[v][i]); 27 | } 28 | } 29 | } 30 | 31 | 32 | // 메인 함수: 그래프 생성 및 DFS 수행 33 | int main() { 34 | // 정점의 개수 35 | int V = 5; 36 | adj.resize(V); 37 | 38 | // 그래프에 간선 추가 (주어진 다이어그램에 따라) 39 | add_edge(0, 1); // A -> B 40 | add_edge(0, 2); // A -> C 41 | add_edge(1, 3); // B -> D 42 | add_edge(1, 4); // B -> E 43 | 44 | cout << "깊이 우선 탐색 (정점 0에서 시작):\n"; 45 | 46 | visited.assign(V, false); 47 | dfs(0); 48 | /* 49 | 재귀 호출 과정 설명 (예: 정점 0에서 시작): 50 | dfs(0) 호출 -> 0 출력 51 | dfs(1) 호출 -> 1 출력 52 | dfs(3) 호출 -> 3 출력 53 | dfs(4) 호출 -> 4 출력 54 | dfs(2) 호출 -> 2 출력 55 | - dfs_traversal 종료 56 | */ 57 | 58 | return 0; 59 | } 60 | 61 | /* 62 | 깊이 우선 탐색(DFS)의 개념: 63 | - DFS는 그래프 탐색 알고리즘 중 하나로, 시작 정점에서 출발하여 한 방향으로 가능한 깊이까지 탐색한 후, 64 | 더 이상 갈 곳이 없으면 이전 정점으로 되돌아와 다른 방향으로 탐색을 계속하는 방식이다. 65 | - 시간 복잡도는 O(V + E)이며, 여기서 V는 정점의 수, E는 간선의 수를 의미한다. 66 | 67 | DFS를 사용해야 하는 경우: 68 | - 그래프의 모든 정점을 방문해야 하는 경우 69 | - 경로 찾기 (예: 미로 탐색) 70 | - 사이클 검출 71 | - 위상 정렬 72 | - 강한 연결 요소 찾기 73 | 74 | BFS를 사용할 수 없고 DFS를 사용해야 하는 경우: 75 | - 재귀적 성질을 이용해야 할 때 (예: 백트래킹 문제) 76 | - 공간 복잡도가 중요한 경우 (BFS는 큐를 사용하여 더 많은 메모리를 필요로 함) 77 | 78 | */ 79 | -------------------------------------------------------------------------------- /solution/27.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | using namespace std; 7 | 8 | map combi; // 주문의 조합 - 조합의 빈도 9 | 10 | // 실제 주문의 조합을 구하는 함수 11 | void combination(string src, string dst, int depth) { 12 | if (dst.size() == depth) combi[dst]++; 13 | 14 | else for (int i = 0; i < src.size(); i++) 15 | combination(src.substr(i+1), dst+src[i], depth); 16 | } 17 | 18 | vector solution(vector orders, vector course) { 19 | vector answer; 20 | // ❶ 각 주문들을 오름차순으로 정렬 21 | for (string &order : orders) 22 | sort(order.begin(), order.end()); 23 | 24 | for (int len : course) { 25 | for (string order : orders) 26 | // ❷ course의 길이에 해당되는 조합 생성 27 | combination(order, "", len); 28 | 29 | // ❸ 각 주문의 빈도수를 순회하면서 가장 많은 빈도수를 maxOrder에 저장 30 | int maxOrder = 0; 31 | for (auto it : combi) 32 | maxOrder = max(maxOrder, it.second); 33 | 34 | // ❹ 주문 횟수가 2회 이상이면서, 가장 많이 주문된 주문의 구성은 answer에 추가 35 | for (auto it : combi) 36 | if (maxOrder >= 2 && it.second == maxOrder) 37 | answer.push_back(it.first); 38 | 39 | combi.clear(); 40 | } 41 | // ❺ 반환 전, 문제의 조건에 따라 주문의 구성들을 오름차순 정렬해서 반환 42 | sort(answer.begin(), answer.end()); 43 | return answer; 44 | } 45 | 46 | 47 | //아래 코드는 테스트 코드 입니다. 48 | #include 49 | #include 50 | void print(vector vec) 51 | { 52 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 53 | cout << endl; 54 | } 55 | 56 | int main() 57 | { 58 | print(solution({"ABCFG", "AC", "CDE", "ACDE", "BCFG", "ACDEH"}, {2, 3, 4})); //출력값 : AC ACDE BCFG CDE 59 | print(solution({"ABCDE", "AB", "CD", "ADE", "XYZ", "XYZ", "ACD"}, {2, 3, 5})); //출력값 : ACD AD ADE CD XYZ 60 | print(solution({"XYZ", "XWY", "WXA"}, {2, 3, 4})); //출력값 : WX XY 61 | 62 | return 0; 63 | } 64 | -------------------------------------------------------------------------------- /solution/88.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 날짜를 연, 월, 일로 파싱하는 함수 8 | void parseDate(const string& date, int& year, int& month, int& day) { 9 | year = stoi(date.substr(0, 4)); 10 | month = stoi(date.substr(5, 2)); 11 | day = stoi(date.substr(8, 2)); 12 | } 13 | 14 | // 약관 기간을 매핑하는 함수 15 | unordered_map mapTerms(const vector& terms) { 16 | unordered_map termMap; 17 | for (const string& term : terms) { 18 | char type = term[0]; 19 | int duration = stoi(term.substr(2)); 20 | termMap[type] = duration; 21 | } 22 | return termMap; 23 | } 24 | 25 | // 개인정보 만료 여부를 확인하는 함수 26 | vector solution(string today, vector terms, vector privacies) { 27 | vector expiredIndexes; 28 | int todayYear, todayMonth, todayDay; 29 | parseDate(today, todayYear, todayMonth, todayDay); 30 | 31 | auto termMap = mapTerms(terms); 32 | 33 | int index = 1; // 만료된 개인정보 인덱스를 추적 34 | for (const string& privacy : privacies) { 35 | int privacyYear, privacyMonth, privacyDay; 36 | parseDate(privacy, privacyYear, privacyMonth, privacyDay); 37 | 38 | char type = privacy[11]; // 개인정보 유형 39 | int durationMonths = termMap[type]; // 해당 유형의 약관 기간 40 | 41 | // 만료 날짜 계산 42 | privacyYear += (privacyMonth + durationMonths - 1) / 12; 43 | privacyMonth = (privacyMonth + durationMonths - 1) % 12 + 1; // 월이 0이 되는 경우 방지 44 | 45 | // 만료 여부 확인 46 | if (todayYear > privacyYear || 47 | (todayYear == privacyYear && todayMonth > privacyMonth) || 48 | (todayYear == privacyYear && todayMonth == privacyMonth && todayDay >= privacyDay)) { 49 | expiredIndexes.push_back(index); 50 | } 51 | index++; 52 | } 53 | 54 | return expiredIndexes; 55 | } 56 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/selectionsort.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | #include 8 | #include 9 | using namespace std; 10 | 11 | /* 12 | 선택 정렬 알고리즘: 13 | - 시간 복잡도: O(n^2) 14 | - 용도: 작은 리스트에서 활용 가능하며 메모리가 제한적인 경우에 유리합니다. 15 | - 동작 과정: 16 | 1. 주어진 리스트 중에서 최소값을 찾습니다. 17 | 2. 그 값을 맨 앞에 위치한 값과 교체합니다. 18 | 3. 맨 처음 위치를 제외한 나머지 리스트를 같은 방법으로 교체합니다. 19 | 20 | 도식화 및 동작 과정: 21 | 예) [29, 10, 14, 37, 13] 22 | 1. 전체 데이터 중 가장 작은 데이터(10)를 맨 앞 데이터(29)와 교체: [10, 29, 14, 37, 13] 23 | 2. 두 번째 데이터부터 마지막 데이터 중 가장 작은 데이터(13)를 두 번째 데이터(29)와 교체: [10, 13, 14, 37, 29] 24 | 3. 세 번째 데이터부터 마지막 데이터 중 가장 작은 데이터(14)를 세 번째 데이터(14)와 교체: [10, 13, 14, 37, 29] 25 | 4. 네 번째 데이터부터 마지막 데이터 중 가장 작은 데이터(29)를 네 번째 데이터(37)와 교체: [10, 13, 14, 29, 37] 26 | 5. 다섯 번째 데이터(37)는 그대로 둡니다: [10, 13, 14, 29, 37] 27 | */ 28 | 29 | void selectionSort(vector& arr) { 30 | int n = arr.size(); 31 | for (int i = 0; i < n-1; i++) { 32 | int min_idx = i; // 최소값의 인덱스를 저장 33 | for (int j = i+1; j < n; j++) { 34 | // 현재 선택된 최소값보다 작은 값이 있는 경우, 인덱스 갱신 35 | if (arr[j] < arr[min_idx]) { 36 | min_idx = j; 37 | } 38 | } 39 | // 최소값과 현재 정렬되지 않은 부분의 첫 번째 원소를 교체 40 | swap(arr[min_idx], arr[i]); 41 | } 42 | } 43 | 44 | int main() { 45 | vector arr = {29, 10, 14, 37, 13}; 46 | cout << "Original array: "; 47 | for (int a : arr) cout << a << " "; 48 | 49 | selectionSort(arr); 50 | 51 | cout << "\nSorted array: "; 52 | for (int a : arr) cout << a << " "; 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /solution/28.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 전위순회 8 | string preorder(const vector& nodes, int idx) { 9 | if (idx < nodes.size()) { 10 | string ret = to_string(nodes[idx]) + " "; 11 | ret += preorder(nodes, idx * 2 + 1); 12 | ret += preorder(nodes, idx * 2 + 2); 13 | return ret; 14 | } 15 | 16 | return ""; 17 | } 18 | 19 | // 중위순회 20 | string inorder(const vector& nodes, int idx) { 21 | if (idx < nodes.size()) { 22 | string ret = inorder(nodes, idx * 2 + 1); 23 | ret += to_string(nodes[idx]) + " "; 24 | ret += inorder(nodes, idx * 2 + 2); 25 | return ret; 26 | } 27 | 28 | return ""; 29 | } 30 | 31 | // 후위순회 32 | string postorder(const vector& nodes, int idx) { 33 | if (idx < nodes.size()) { 34 | string ret = postorder(nodes, idx * 2 + 1); 35 | ret += postorder(nodes, idx * 2 + 2); 36 | ret += to_string(nodes[idx]) + " "; 37 | return ret; 38 | } 39 | 40 | return ""; 41 | } 42 | 43 | vector solution(const vector& nodes) { 44 | vector result; 45 | string pre = preorder(nodes, 0); 46 | string in = inorder(nodes, 0); 47 | string post = postorder(nodes, 0); 48 | 49 | // 마지막 공백을 제거한 결과를 result에 추가 50 | pre.pop_back(); 51 | in.pop_back(); 52 | post.pop_back(); 53 | 54 | result.push_back(pre); 55 | result.push_back(in); 56 | result.push_back(post); 57 | 58 | return result; 59 | } 60 | 61 | //아래 코드는 테스트 코드 입니다. 62 | #include 63 | #include 64 | void print(vector vec) 65 | { 66 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, "\n")); 67 | cout << endl; 68 | } 69 | 70 | int main() 71 | { 72 | print(solution({1, 2, 3, 4, 5, 6, 7})); 73 | /** 74 | 출력값 75 | 1 2 4 5 3 6 7 76 | 4 2 5 1 6 3 7 77 | 4 5 2 6 7 3 1 78 | **/ 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /solution/53.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | const int dx[4] = {0, 0, -1, 1}; 8 | const int dy[4] = {-1, 1, 0, 0}; 9 | int n, m; 10 | 11 | //❶ 현재 위치가 게임판을 벗어나는지 확인 12 | bool isOutOfBounds(int r, int c) { 13 | return r < 0 || r >= n || c < 0 || c >= m; 14 | } 15 | int playGame(vector>& board, int curR, int curC, int opR, int opC) { 16 | //❷ 현재 위치가 0인 경우는 불가능하므로 스텝을 0으로 반환 17 | if (board[curR][curC] == 0) return 0; 18 | int bestSteps = 0; 19 | 20 | //❸ 현재 위치를 기준으로 가능한 방향 모두 확인 21 | for (int dir = 0; dir < 4; ++dir) { 22 | int nextR = curR + dx[dir]; 23 | int nextC = curC + dy[dir]; 24 | //❹ 다음 위치가 범위를 멋어난 경우는 탐색에서 제외 25 | if (isOutOfBounds(nextR, nextC) || board[nextR][nextC] == 0) continue; 26 | //❺ 현재 위치로 이동해보고 다음 턴 진행 27 | board[curR][curC] = 0; 28 | int steps = playGame(board, opR, opC, nextR, nextC) + 1; 29 | board[curR][curC] = 1; 30 | 31 | //❻ 현재까지 구한 최대 이동횟수와, 현재 이동횟수를 가지고 최선을 다하는 경우의 이동횟수를 구함 32 | if (bestSteps % 2 == 0 && steps % 2 == 1) bestSteps = steps; 33 | else if (bestSteps % 2 == 0 && steps % 2 == 0) bestSteps = max(bestSteps, steps); 34 | else if (bestSteps % 2 == 1 && steps % 2 == 1) bestSteps = min(bestSteps, steps); 35 | } 36 | return bestSteps; 37 | } 38 | 39 | int solution(vector> board, vector aloc, vector bloc) { 40 | n = board.size(); 41 | m = board[0].size(); 42 | 43 | //❼ 최선을 다한경우 이동횟수를 반환 44 | return playGame(board, aloc[0], aloc[1], bloc[0], bloc[1]); 45 | } 46 | 47 | //아래 코드는 테스트 코드 입니다. 48 | #include 49 | #include 50 | 51 | using namespace std; 52 | 53 | int main() 54 | { 55 | cout < 2 | #include 3 | 4 | using namespace std; 5 | 6 | const int INF = 99999; 7 | const int MAX_NODES = 100; 8 | int graph[MAX_NODES][MAX_NODES]; 9 | bool visited[MAX_NODES]; 10 | 11 | vector solution(int start, int numNodes, const vector> edges) { 12 | //❶ 그래프 및 방문 여부 초기화 13 | for (int i = 0; i < MAX_NODES; ++i) { 14 | fill_n(graph[i], MAX_NODES, INF); 15 | visited[i] = false; 16 | } 17 | 18 | //❷ 입력받은 간선 정보를 그래프로 표현 19 | for (const auto& [from, to, weight] : edges) { 20 | graph[from][to] = weight; 21 | } 22 | 23 | //❸ 시작 노드를 제외한 모든 노드의 최소 비용을 INF로 초기화 24 | vector distances(numNodes, INF); 25 | distances[start] = 0; 26 | 27 | for (int i = 0; i < numNodes - 1; ++i) { 28 | int minDistance = INF; 29 | int closestNode = -1; 30 | 31 | //❹ 최소 거리 노드 찾기 32 | for (int j = 0; j < numNodes; ++j) { 33 | if (!visited[j] && distances[j] < minDistance) { 34 | minDistance = distances[j]; 35 | closestNode = j; 36 | } 37 | } 38 | 39 | //❺ 찾은 노드를 방문 처리 40 | visited[closestNode] = true; 41 | 42 | //❻ 인접 노드에 대한 거리 업데이트 43 | for (int j = 0; j < numNodes; ++j) { 44 | int newDistance = distances[closestNode] + graph[closestNode][j]; 45 | if (!visited[j] && graph[closestNode][j] != INF && newDistance < distances[j]) { 46 | distances[j] = newDistance; 47 | } 48 | } 49 | } 50 | 51 | return distances; 52 | } 53 | 54 | 55 | //아래 코드는 테스트 코드 입니다. 56 | #include 57 | #include 58 | 59 | using namespace std; 60 | 61 | 62 | void print(vector vec) 63 | { 64 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 65 | cout << endl; 66 | 67 | } 68 | 69 | int main() 70 | { 71 | 72 | print(solution(0, 3, {{0, 1, 9},{0, 2, 3},{1, 0, 5},{2, 1, 1}})); //출력값 : 0 4 3 73 | print(solution(0, 4, {{0, 1, 1}, {1, 2, 5}, {2, 3, 1}})); //출력값 : 0 1 6 7 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /solution/64.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | vector> solution(int n) { 6 | 7 | //❶ N*N 2차원 벡터를 선언하고 초깃값을 0으로 함 8 | vector> snail_array(n, vector(n, 0)); 9 | int num = 1; 10 | // 행과 열의 시작과 끝 인덱스를 설정 11 | int start_row = 0, end_row = n - 1; 12 | int start_col = 0, end_col = n - 1; 13 | 14 | //❷ 제일 외각부터 달팽이 수열 규칙대로 채움 15 | while (start_row <= end_row && start_col <= end_col) { 16 | // 가장 왼쪽 윗부분 에서 가장 아래 바로 직전 까지 채우기 17 | for (int i = start_col; i <= end_col; ++i) { 18 | snail_array[start_row][i] = num++; 19 | } 20 | ++start_row; 21 | 22 | // 가장 왼쪽 아래부분 에서 가장 오른쪽 바로 직전 까지 채우기 23 | for (int i = start_row; i <= end_row; ++i) { 24 | snail_array[i][end_col] = num++; 25 | } 26 | --end_col; 27 | 28 | // 가장 오른쪽 아래부분 에서 가장 위 바로 직전 까지 채우기 29 | if (start_row <= end_row) { 30 | for (int i = end_col; i >= start_col; --i) { 31 | snail_array[end_row][i] = num++; 32 | } 33 | --end_row; 34 | } 35 | 36 | // 가장 윗부분 에서 가장 왼쪽 바로 직전 까지 채우기 37 | if (start_col <= end_col) { 38 | for (int i = end_row; i >= start_row; --i) { 39 | snail_array[i][start_col] = num++; 40 | } 41 | ++start_col; 42 | } 43 | } 44 | 45 | return snail_array; 46 | } 47 | 48 | 49 | 50 | //아래 코드는 테스트 코드 입니다. 51 | #include 52 | #include 53 | 54 | using namespace std; 55 | 56 | void print(vector> vec) 57 | { 58 | for(int i = 0 ; i < vec.size(); i++){ 59 | copy(vec[i].begin(), vec[i].end(), std::ostream_iterator(cout, " ")); 60 | cout << endl; 61 | } 62 | 63 | } 64 | 65 | int main() 66 | { 67 | print(solution(3)); 68 | /* 69 | 출력값 : 70 | 1 2 3 71 | 8 9 4 72 | 7 6 5 73 | */ 74 | 75 | print(solution(4)); 76 | /* 77 | 출력값: 78 | 1 2 3 4 79 | 12 13 14 5 80 | 11 16 15 6 81 | 10 9 8 7 82 | */ 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /reference/dynamic_alloc.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | 12 | /* 13 | 동적 할당(Dynamic Allocation)이란? 14 | - 동적 할당은 프로그램 실행 중에 메모리를 동적으로 할당(요청)하거나 해제하는 방법입니다. 15 | - C++에서는 'new'와 'delete' 연산자를 사용하여 동적 할당 및 메모리 해제를 수행합니다. 16 | - 동적으로 할당된 메모리는 힙(Heap) 영역에 저장됩니다. 17 | - 동적 할당은 배열의 크기나 객체의 수가 실행 시간에 결정되어야 할 때 유용합니다. 18 | */ 19 | 20 | int *ptr = new int; // 정수를 저장할 수 있는 메모리 동적 할당 21 | *ptr = 10; // 동적으로 할당된 메모리에 값 저장 22 | 23 | cout << "Value: " << *ptr << endl; // 출력: Value: 10 24 | 25 | delete ptr; // 동적으로 할당된 메모리 해제 26 | 27 | /* 28 | 주의사항: 29 | 1. 동적으로 할당된 메모리는 프로그래머의 책임으로 해제되어야 합니다. 그렇지 않으면 메모리 누수(memory leak)가 발생합니다. 30 | */ 31 | int *leakPtr = new int; 32 | // 메모리 해제 코드 없음. 메모리 누수 발생 33 | 34 | /* 35 | 2. 이미 해제된 메모리에 다시 접근하거나 해제하려고 시도하면 정의되지 않은 동작(Undefined Behavior)이 발생합니다. 36 | */ 37 | int *doubleDeletePtr = new int; 38 | delete doubleDeletePtr; 39 | // delete doubleDeletePtr; // 오류: 이미 해제된 메모리 다시 해제 시도 40 | 41 | /* 42 | 3. 동적 할당을 사용할 때는 항상 포인터를 초기화하고, 메모리 할당이 성공적으로 이루어졌는지 확인하는 것이 좋습니다. 43 | */ 44 | int *initPtr = nullptr; // 포인터 초기화 45 | initPtr = new (nothrow) int; // 메모리 할당 실패 시 nullptr 반환 46 | if (initPtr) { // 메모리 할당 확인 47 | *initPtr = 20; 48 | cout << "Value: " << *initPtr << endl; // 출력: Value: 20 49 | delete initPtr; 50 | } 51 | 52 | /* 53 | 4. 동적으로 할당된 배열을 해제할 때는 'delete[]'를 사용해야 합니다. 54 | */ 55 | int* arrPtr = new int[5]; 56 | delete[] arrPtr; // 배열 메모리 해제 57 | 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /solution/35.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 상호베타적 집합 정의 8 | class DisjointSet { 9 | private: 10 | vector parent, rank; 11 | 12 | public: 13 | DisjointSet(int size) : parent(size, -1), rank(size, 0) {} 14 | 15 | int find(int node) { 16 | if (parent[node] == -1) 17 | return node; 18 | 19 | //❶ 경로 압축을 하면서 루트노드 찾기 20 | return parent[node] = find(parent[node]); 21 | } 22 | 23 | void merge(int node1, int node2) { 24 | int root1 = find(node1); 25 | int root2 = find(node2); 26 | 27 | if (root1 != root2) { 28 | 29 | //❷ 랭크 기반으로 합치기 30 | if (rank[root1] > rank[root2]) { 31 | parent[root2] = root1; 32 | } else if (rank[root1] < rank[root2]) { 33 | parent[root1] = root2; 34 | } else { 35 | parent[root2] = root1; 36 | rank[root1]++; 37 | } 38 | } 39 | } 40 | 41 | //❸ 같은 집합에 있는지 확인 42 | bool isCycle(int node1, int node2) { 43 | return find(node1) == find(node2); 44 | } 45 | }; 46 | 47 | int solution(int n, vector> costs) { 48 | 49 | //❹ 비용을 기준으로 간선 정렬 50 | sort(costs.begin(), costs.end(), [](const vector& a, const vector& b) { 51 | return a[2] < b[2]; 52 | }); 53 | 54 | DisjointSet disjointSet(n); 55 | int totalCost = 0; 56 | 57 | for (const auto& edge : costs) { 58 | int cost = edge[2]; 59 | int node1 = edge[0]; 60 | int node2 = edge[1]; 61 | 62 | //❺ 사이클 확인 후 없을 경우 합병 63 | if (!disjointSet.isCycle(node1, node2)) { 64 | disjointSet.merge(node1, node2); 65 | totalCost += cost; 66 | } 67 | } 68 | 69 | return totalCost; 70 | } 71 | 72 | 73 | //아래 코드는 테스트 코드 입니다. 74 | #include 75 | 76 | using namespace std; 77 | 78 | int main() 79 | { 80 | //bool 반환할 때 true는 1, false는 0 입니다. 81 | cout << solution(4, {{0, 1, 1}, {0, 2, 2}, {1, 2, 5}, {1, 3, 1}, {2, 3, 8}}) << endl; //출력값 : 4 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /algorithm_performance.md: -------------------------------------------------------------------------------- 1 | 2 | # 알고리즘 성능 측정 및 공간 복잡도 고려 3 | 4 | ## 시간 복잡도(Time Complexity) 5 | 6 | 알고리즘의 성능을 측정하는 데 있어 중요한 척도는 시간 복잡도입니다. 시간 복잡도는 알고리즘이 실행되는 데 걸리는 시간을 입력값의 크기와 관련지어 표현한 것입니다. 입력값이 커질수록 알고리즘의 실행 시간이 어떻게 변하는지를 나타내며, 이를 통해 알고리즘의 효율성을 평가할 수 있습니다. 7 | 8 | ## 문제 요구 성능 파악 9 | 10 | 문제에서 요구하는 성능을 파악하기 위해서는 주어진 입력값을 통해 시간 복잡도를 구하고 이를 기준으로 성능을 분석해야 합니다. 이는 주어진 문제를 해결하는 데 있어 적합한 알고리즘을 선택하는 데 중요한 역할을 합니다. 11 | 12 | ## 재귀 함수와 공간 복잡도 13 | 14 | 재귀 함수를 사용할 때는 시간 복잡도뿐만 아니라 공간 복잡도도 고려해야 합니다. 재귀 함수는 호출될 때마다 함수 코드 영역, 함수에서 사용하는 변수 영역, 매개변수 영역이 메모리에 할당됩니다. 예를 들어, 10!을 구할 때는 메모리에 10개의 함수 호출이 쌓이게 됩니다. 15 | 16 | ### 주의사항: 17 | 1. **공간 복잡도**: 재귀 함수는 메모리 사용이 많을 수 있습니다. 18 | 2. **재귀 깊이 제한**: 일부 언어는 재귀 깊이 제한이 있습니다. (예: 파이썬) 19 | 20 | ## 자료구조와 시간 복잡도 21 | 22 | 각 언어에서 제공하는 자료구조의 메서드의 시간 복잡도를 이해하고 정리하는 것은 중요합니다. 단순히 GitHub에서 제공하는 코드를 복사해서 사용하는 것이 아니라, 직접 구현해보고 성능 차이를 이해해야 합니다. 이를 통해 문제 분석 후 요구하는 성능에 맞는 구현 전략을 세울 수 있습니다. 23 | 24 | ## 코드 개선과 시간 복잡도 25 | 26 | 시간 제한 초과(TLE) 문제를 해결하기 위해서는 시간 복잡도를 고려하여 연산 횟수가 많은 부분을 찾아 개선해야 합니다. 전체 코드에서 시간이 많이 소요되는 부분을 찾아 효율적인 알고리즘으로 대체함으로써 성능을 개선할 수 있습니다. 27 | 28 | ## 의사코드(Pseudocode) 29 | 30 | 의사코드는 구현하기 전 데이터의 흐름을 정리하고, 로직을 명확히 하는 데 사용됩니다. 이는 문제 해결 과정에서 중요한 단계로, 전체 시간의 60~70%를 할애할 가치가 있습니다. 구현 단계는 30~40% 정도로 시간 배분을 하면 좋습니다. 31 | 32 | --- 33 | 34 | # 시간 복잡도 정리 35 | 36 | 자료구조를 배울 때 각 메서드의 시간 복잡도를 정리해보겠습니다. 이는 직접 구현해보고 성능 차이를 이해하는 데 도움이 됩니다. 37 | 38 | ## 예시: 리스트(List) 39 | 40 | - **탐색**: O(n) 41 | - **삽입/삭제 (중간)**: O(n) 42 | - **삽입/삭제 (끝)**: O(1) 43 | 44 | ## 예시: 해시맵(HashMap) 45 | 46 | - **탐색**: O(1) 47 | - **삽입**: O(1) 48 | - **삭제**: O(1) 49 | 50 | 이해하고 직접 구현해보면서 성능 차이를 경험해보는 것이 중요합니다. 이를 통해 문제 분석 후 요구하는 성능에 맞는 구현 전략을 세울 수 있습니다. 51 | 52 | --- 53 | 54 | ## 결론 55 | 56 | - 시간 복잡도는 알고리즘 성능 측정의 중요한 척도입니다. 57 | - 재귀 함수를 사용할 때는 공간 복잡도도 고려해야 합니다. 58 | - 자료구조의 각 메서드의 시간 복잡도를 이해하고 정리하는 것이 중요합니다. 59 | - 코드 개선 시 시간 복잡도를 고려하여 주요 연산 부분을 최적화해야 합니다. 60 | - 의사코드를 통해 데이터 흐름을 정리하고 구현 전 로직을 명확히 해야 합니다. 61 | 62 | 학습 과정에서 복사 붙여넣기가 아니라 직접 구현하고 성능 차이를 이해하는 것이 중요합니다. 이를 통해 문제 분석 후 적절한 구현 전략을 세울 수 있는 능력을 키워야 합니다. 63 | -------------------------------------------------------------------------------- /solution/06.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | // ❶ 문제에서 요구하는 조건대로 실패율을 정렬하는 함수 7 | bool compare(pair& a, pair& b) { 8 | if (a.second == b.second) 9 | return a.first < b.first; 10 | return a.second > b.second; 11 | } 12 | 13 | vector solution(int N, vector stages) { 14 | 15 | vector answer; // ❷ answer는 최종 답 16 | vector challenger(N + 2, 0.0); // ❸ challenger는 각 스테이지에 도달한 적이 있는 도전자의 수 17 | vector fail(N + 2, 0.0); // ❹ fail는 특정 스테이지에 실패한 도전자의 수 18 | 19 | // ❺ 각 스테이지의 인원을 기준으로 특정 스테이지에서 실패한 인원수와, 각 스테이지에 도전한 적이 있는 인원수를 구함 20 | for (int i = 0; i < stages.size(); i++) { 21 | for (int j = 1; j <= stages[i]; j++) 22 | challenger[j]++; 23 | 24 | fail[stages[i]]++; 25 | } 26 | // ❻ failRatio는 실패율을 저장, first는 stage정보이고 second는 실패율 27 | vector> failRatio(N); 28 | 29 | // ❼ 스테이지 정보 및 실패율을 저장 30 | for (int i = 0; i < N; i++) { 31 | failRatio[i].first = i + 1; 32 | 33 | if (challenger[i + 1] == 0) 34 | failRatio[i].second = 0; 35 | else 36 | failRatio[i].second = fail[i + 1] / challenger[i + 1]; 37 | } 38 | 39 | // ➑ 계산한 실패율을 문제에서 제시한 조건에 맞게 정렬 40 | sort(failRatio.begin(), failRatio.end(), compare); 41 | 42 | // ❾ 최종 답을 반환하기 위해 실패율을 저장 43 | for (int i = 0; i < N; i++) { 44 | answer.push_back(failRatio[i].first); 45 | } 46 | 47 | return answer; 48 | } 49 | 50 | 51 | 52 | //아래 코드는 테스트 코드 입니다. 53 | 54 | #include 55 | #include 56 | void print(vector vec) 57 | { 58 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 59 | cout << endl; 60 | } 61 | 62 | int main() 63 | { 64 | print(solution(5, {2, 1, 2, 6, 2, 4, 3, 3})); // 3 4 2 1 5 65 | print(solution(4, {4, 4, 4, 4, 4})); // 4 1 2 3 66 | 67 | return 0; 68 | } 69 | -------------------------------------------------------------------------------- /solution/60.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int counts[100001] = {}; 8 | 9 | void updateCounts(const string& s) { 10 | string numStr; 11 | //❶ 인자로 받은 문자열을 순회 12 | for (char ch : s) { 13 | //❷ 현재 문자가 숫자인 경우 14 | if (isdigit(ch)) { 15 | numStr += ch; 16 | //❸ 현재 문자가 숫자가 아닌 경우 17 | } else { 18 | if (!numStr.empty()) { 19 | //❹ 계수정렬을 하기 위해 각 숫자의 개수를 저장 20 | counts[stoi(numStr)]++; 21 | numStr.clear(); 22 | } 23 | } 24 | } 25 | } 26 | 27 | vector solution(string s) { 28 | vector answer; 29 | //❺ 집합이 담긴 문자열의 각 원소를 계수정렬 30 | updateCounts(s); 31 | 32 | vector> freqPairs; 33 | for (int i = 1; i <= 100000; i++) { 34 | //❻ 집합에 있는 원소인 경우 (개수, 값) 형식으로 푸시 35 | if (counts[i] > 0) { 36 | freqPairs.push_back({counts[i], i}); 37 | } 38 | } 39 | 40 | //❼ 각 원소의 개수를 기준으로 내림차순 정렬 41 | sort(freqPairs.rbegin(), freqPairs.rend()); 42 | 43 | //➑ 원소의 개수로 내림차순 정렬된 벡터를 순회하며 원소를 푸시 44 | for (const auto& p : freqPairs) { 45 | answer.push_back(p.second); 46 | } 47 | 48 | return answer; 49 | } 50 | 51 | 52 | //아래 코드는 테스트 코드 입니다. 53 | #include 54 | #include 55 | 56 | using namespace std; 57 | 58 | void init() 59 | { 60 | for(int i = 0 ; i <= 100000; i++) 61 | counts[i] = 0; 62 | } 63 | 64 | void print(vector vec) 65 | { 66 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 67 | cout << endl; 68 | } 69 | 70 | 71 | int main() 72 | { 73 | print(solution("{{2}, {2, 1}, {2, 1, 3}, {2, 1, 3, 4}}")); // 출력값 : 2 1 3 4 74 | init(); 75 | print(solution("{{1, 2, 3}, {2, 1}, {1, 2, 4, 3}, {2}}")); // 출력값 : 2 1 3 4 76 | init(); 77 | print(solution("{{20, 111}, {111}}")); // 출력값 : 111 20 78 | init(); 79 | print(solution("{{123}}")); // 출력값 : 123 80 | init(); 81 | print(solution("{{4, 2, 3}, {3}, {2, 3, 4, 1}, {2, 3}}")); // 출력값 : 3 2 4 1 82 | 83 | return 0; 84 | } 85 | -------------------------------------------------------------------------------- /STL/template.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | // 템플릿은 C++에서 타입에 대해 일반화된 코드를 작성할 수 있게 해주는 기능입니다. 12 | // 이를 통해 다양한 데이터 타입에 대해 동작하는 함수나 클래스를 정의할 수 있습니다. 13 | // 템플릿은 "template" 키워드로 시작하며, 타입은 <> 안에 정의됩니다. 14 | 15 | // 1. 기본 템플릿 함수 16 | template // 여기서 T는 임의의 타입을 의미합니다. 17 | T add(T a, T b) { 18 | return a + b; 19 | } 20 | 21 | // 2. 템플릿 클래스 22 | template 23 | class MyVector { 24 | private: 25 | T* arr; 26 | int size; 27 | public: 28 | MyVector(int s) : size(s) { 29 | arr = new T[size]; 30 | } 31 | 32 | T& operator[](int index) { 33 | return arr[index]; 34 | } 35 | 36 | ~MyVector() { 37 | delete[] arr; 38 | } 39 | }; 40 | 41 | // 3. STL에서의 템플릿 사용 42 | // STL(Standard Template Library)은 C++의 표준 라이브러리로써, 다양한 컨테이너와 알고리즘을 제공합니다. 43 | // 대부분의 STL 컨테이너와 알고리즘은 템플릿으로 구현되어 있습니다. 44 | template 45 | void printVector(const vector& v) { 46 | for (const T& element : v) { 47 | cout << element << " "; 48 | } 49 | cout << endl; 50 | } 51 | 52 | int main() { 53 | // 기본 템플릿 함수 사용 54 | cout << add(3, 4) << endl; // 출력: 7 55 | cout << add(3.5, 4.2) << endl; // 출력: 7.7 56 | 57 | // 사용자 정의 템플릿 클래스 사용 58 | MyVector myVec(5); 59 | myVec[0] = 1; 60 | myVec[1] = 2; 61 | cout << myVec[0] << " " << myVec[1] << endl; // 출력: 1 2 62 | 63 | // STL에서의 템플릿 사용 예 64 | vector names = {"Alice", "Bob", "Charlie"}; 65 | printVector(names); // 출력: Alice Bob Charlie 66 | 67 | 68 | return 0; 69 | } 70 | 71 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/tree_array.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | /* 8 | Tree 구현 알고리즘 (배열 사용): 9 | - 시간 복잡도: O(1) (노드에 접근, 추가, 삭제 등의 기본 연산) 10 | - 용도: 트리를 메모리에 효율적으로 저장하고 접근하는데 사용됩니다. 11 | - 동작 과정: 12 | 1. 부모 노드의 인덱스를 i라고 할 때, 왼쪽 자식은 2*i, 오른쪽 자식은 2*i + 1의 인덱스를 가집니다. 13 | 2. 이를 기반으로 트리의 노드를 배열에 삽입하거나 접근합니다. 14 | 15 | 도식화 예: 16 | 1 17 | / \ 18 | 2 3 19 | / \ / \ 20 | 4 5 6 7 21 | 22 | 위 트리는 [1, 2, 3, 4, 5, 6, 7]의 배열로 표현할 수 있습니다. 23 | */ 24 | 25 | #include 26 | using namespace std; 27 | 28 | class Tree { 29 | private: 30 | int treeArray[100]; // 크기가 100인 정적 배열을 통해 트리를 구현 31 | int size; // 현재 트리의 크기 32 | 33 | public: 34 | Tree() { 35 | size = 0; 36 | // 배열 초기화 37 | for(int i=0; i<100; i++) 38 | treeArray[i] = -1; 39 | } 40 | 41 | void insert(int data) { 42 | // 루트 노드가 비어있다면, 43 | if(size == 0) { 44 | treeArray[1] = data; 45 | size = 1; 46 | } 47 | // 루트 노드가 차있다면, 48 | else { 49 | treeArray[size+1] = data; 50 | size++; 51 | } 52 | } 53 | 54 | void printTree() { 55 | cout << "Tree: "; 56 | for(int i=1; i<=size; i++) 57 | cout << treeArray[i] << " "; 58 | cout << endl; 59 | } 60 | }; 61 | 62 | int main() { 63 | Tree t; 64 | t.insert(1); 65 | t.insert(2); 66 | t.insert(3); 67 | t.insert(4); 68 | t.insert(5); 69 | t.insert(6); 70 | t.insert(7); 71 | 72 | t.printTree(); // 출력: Tree: 1 2 3 4 5 6 7 73 | 74 | return 0; 75 | } 76 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/adjacencyarray.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | using namespace std; 8 | 9 | // 인접 행렬의 노드 개수 (고정) 10 | const int numNodes = 2; 11 | 12 | // 인접 행렬 배열 13 | int adjMatrix[numNodes][numNodes]; 14 | 15 | // 인접 행렬을 초기화하는 함수 16 | // 모든 값을 0으로 설정 17 | void initializeMatrix() { 18 | for (int i = 0; i < numNodes; i++) { 19 | for (int j = 0; j < numNodes; j++) { 20 | adjMatrix[i][j] = 0; 21 | } 22 | } 23 | } 24 | 25 | // 간선을 추가하는 함수 26 | // u에서 v로 가는 간선의 가중치를 설정 27 | void addEdge(int u, int v, int weight) { 28 | adjMatrix[u][v] = weight; 29 | } 30 | 31 | // 인접 행렬을 출력하는 함수 32 | // 값이 0인 경우 '-'로 출력 33 | void printMatrix() { 34 | for (int i = 0; i < numNodes; i++) { 35 | for (int j = 0; j < numNodes; j++) { 36 | if (adjMatrix[i][j] == 0) 37 | cout << "- "; 38 | else 39 | cout << adjMatrix[i][j] << " "; 40 | } 41 | cout << endl; 42 | } 43 | } 44 | 45 | int main() { 46 | // 인접 행렬 초기화 47 | initializeMatrix(); 48 | 49 | // 엣지 추가: 서울(0)에서 부산(1)으로 가는 엣지, 가중치 400 50 | addEdge(0, 1, 400); 51 | 52 | // 인접 행렬 출력 53 | printMatrix(); 54 | 55 | /* 56 | 최종적인 인접 행렬의 모습: 57 | - 400 58 | - - 59 | */ 60 | 61 | return 0; 62 | } 63 | 64 | /* 65 | 인접 행렬 설명: 66 | - 인접 행렬은 그래프를 행렬 형태로 표현하는 방법입니다. 67 | - 행과 열의 인덱스는 각각의 노드를 나타내고, 행렬의 값은 간선의 가중치를 나타냅니다. 68 | - 만약 간선이 없는 경우 0으로 표시되며, 이 코드에서는 '-'로 출력됩니다. 69 | 70 | 인접 행렬의 시간 복잡도: 71 | - 인접 행렬을 사용하여 그래프를 표현할 경우, 공간 복잡도는 O(V^2)입니다. 여기서 V는 노드의 개수입니다. 72 | - 간선이 존재하는지 확인하는 작업은 O(1)의 시간 복잡도를 가집니다. 73 | - 모든 간선을 탐색하는 작업은 O(V^2)의 시간 복잡도를 가집니다. 74 | 75 | 최종적인 인접 행렬의 모습: 76 | - 400 77 | - - 78 | */ 79 | 80 | 81 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/eratosthenes_sieve.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | /* 7 | 에라토스테네스의 체 알고리즘 8 | - 시간 복잡도: O(n log(log n)) 9 | - 용도: 주어진 범위 내의 모든 소수를 찾음 10 | - 동작 과정: 11 | 1. 2부터 n까지의 숫자를 적습니다. 12 | 2. 2를 남기고 2의 배수를 모두 지웁니다. 13 | 3. 다음 소수(3)를 남기고, 3의 배수를 모두 지웁니다. 14 | 4. 이 과정을 n의 제곱근까지 반복합니다. 15 | 16 | 도식화 예: 17 | n = 30 일 때, 18 | [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30] 19 | -> 2의 배수 제거 20 | [2, 3, _, 5, _, 7, _, 9, _, 11, _, 13, _, 15, _, 17, _, 19, _, 21, _, 23, _, 25, _, 27, _, 29, _] 21 | -> 3의 배수 제거 22 | [2, 3, _, 5, _, 7, _, _, _, 11, _, 13, _, _, _, 17, _, 19, _, _, _, 23, _, 25, _, _, _, 29, _] 23 | -> 그 다음 소수(5)의 배수 제거 24 | ... 25 | */ 26 | 27 | #include 28 | #include 29 | using namespace std; 30 | 31 | void sieveOfEratosthenes(int n) { 32 | vector prime(n+1, true); // 모든 요소를 true로 초기화된 크기가 n+1인 벡터를 생성 33 | prime[0] = prime[1] = false; // 0과 1은 소수가 아니므로 false로 설정 34 | 35 | for (int i = 2; i*i <= n; i++) { 36 | if (prime[i]) { // i가 소수인 경우 37 | //i*i 미만의 수들은 이미 이전의 다른 소수들에 의해 체크됩니다. 따라서 i*i부터 시작합니다. 38 | for (int j = i*i; j <= n; j += i) { 39 | prime[j] = false; // i의 배수를 모두 false로 설정 40 | } 41 | } 42 | } 43 | 44 | // 소수 출력 45 | for (int i = 2; i <= n; i++) { 46 | if (prime[i]) { 47 | cout << i << " "; 48 | } 49 | } 50 | 51 | cout << endl; 52 | } 53 | 54 | int main() { 55 | int n = 30; // 30 이하의 소수를 찾습니다. 56 | cout << "The prime numbers less than or equal to " << n << " are: \n"; 57 | sieveOfEratosthenes(n); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /performance/vector_vs_set.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace std; 14 | using namespace std::chrono; 15 | 16 | //데이터가 이미 존재하는 vector와 set에서 원소를 찾는 시간 비교 17 | 18 | // std::vector는 동적 배열을 기반으로 하며, 원소 검색에 O(n)의 시간이 소요된다. 19 | // std::set은 레드-블랙 트리(Red-Black Tree)를 기반으로 하는 균형 이진 검색 트리로, 검색에 O(log n)의 시간이 소요된다. 20 | 21 | // 성능 차이의 주된 이유는 다음과 같다: 22 | // - vector는 선형 검색을 수행하기 때문에 원소의 수에 비례하는 시간이 소요된다. 23 | // - set은 이진 검색 트리를 사용하여 로그 시간 복잡도로 원소를 찾을 수 있기 때문에 검색이 빠르다. 24 | 25 | int main() { 26 | const int NUM_ELEMENTS = 2000000; // 원소 수 27 | 28 | vector myVector; 29 | set mySet; 30 | 31 | // 벡터와 셋에 원소 삽입 32 | for (int i = 0; i < NUM_ELEMENTS; i++) { 33 | myVector.push_back(i); 34 | mySet.insert(i); 35 | } 36 | 37 | // Vector 검색 시간 측정 38 | auto start = high_resolution_clock::now(); 39 | // 벡터는 원소가 정렬되어 있지 않기 때문에 sort 함수를 사용하여 정렬해야 한다. 40 | sort(myVector.begin(), myVector.end()); 41 | // 검색 테스트 42 | auto it = find(myVector.begin(), myVector.end(), NUM_ELEMENTS - 1); 43 | auto end = high_resolution_clock::now(); 44 | auto durationVectorSearch = duration_cast(end - start); 45 | cout << "Search in vector: " << durationVectorSearch.count() << " ms" << endl; 46 | 47 | // Set 검색 시간 측정 48 | start = high_resolution_clock::now(); 49 | // 셋에서 검색 테스트 50 | auto itSet = mySet.find(NUM_ELEMENTS - 1); 51 | end = high_resolution_clock::now(); 52 | auto durationSetSearch = duration_cast(end - start); 53 | cout << "Search in set: " << durationSetSearch.count() << " ms" << endl; 54 | 55 | 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /reference/variable_scope.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | // 전역변수: 프로그램의 어디서든 접근 가능한 변수. 프로그램 시작 시 초기화되며, 프로그램 종료 시 메모리에서 해제됩니다. 11 | int globalVariable = 10; 12 | 13 | /* 14 | 변수의 범위(Variable Scope): 15 | - 변수는 선언된 위치에 따라 그 접근 범위가 결정됩니다. 16 | - 전역변수, 지역변수, static 변수 등 다양한 범위의 변수가 있습니다. 17 | */ 18 | 19 | void exampleFunction() { 20 | // 지역변수: 함수 내에서만 접근 가능한 변수. 함수가 호출될 때 메모리에 할당되고, 함수 종료 시 메모리에서 해제됩니다. 21 | int localVariable = 5; 22 | cout << "Local Variable inside exampleFunction: " << localVariable << endl; 23 | 24 | // static 변수: 함수 내에서만 접근 가능하지만, 프로그램 종료 시까지 메모리에 남아있습니다. 25 | // 함수가 여러 번 호출되어도 값이 유지됩니다. 26 | static int staticVariable = 0; 27 | staticVariable++; 28 | cout << "Static Variable inside exampleFunction: " << staticVariable << endl; 29 | } 30 | 31 | int main() { 32 | cout << "Global Variable: " << globalVariable << endl; 33 | 34 | // main 함수 내의 지역변수 35 | int localInMain = 20; 36 | cout << "Local Variable inside main: " << localInMain << endl; 37 | 38 | exampleFunction(); // 출력: Local Variable inside exampleFunction: 5 39 | // 출력: Static Variable inside exampleFunction: 1 40 | exampleFunction(); // 출력: Local Variable inside exampleFunction: 5 41 | // 출력: Static Variable inside exampleFunction: 2 42 | 43 | // 다음 코드는 오류를 발생시킵니다. 왜냐하면 localVariable은 exampleFunction 내의 지역변수이기 때문입니다. 44 | // cout << localVariable << endl; 45 | 46 | return 0; 47 | } 48 | 49 | /* 50 | 주의사항: 51 | 1. 전역변수의 남발은 코드의 가독성과 유지보수성을 저하시킬 수 있습니다. 52 | 2. 같은 이름의 전역변수와 지역변수가 있다면, 지역변수가 우선순위를 가집니다. 53 | 3. static 변수는 특정 함수의 실행 사이에서 값을 유지해야 할 때 유용하게 사용됩니다. 하지만 과도한 사용은 피해야 합니다. 54 | */ 55 | 56 | -------------------------------------------------------------------------------- /reference/sizeof.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | // 기본 데이터 타입의 크기 출력 5 | std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl; 6 | std::cout << "Size of short: " << sizeof(short) << " bytes" << std::endl; 7 | std::cout << "Size of long: " << sizeof(long) << " bytes" << std::endl; 8 | std::cout << "Size of long long: " << sizeof(long long) << " bytes" << std::endl; 9 | std::cout << "Size of float: " << sizeof(float) << " bytes" << std::endl; 10 | std::cout << "Size of double: " << sizeof(double) << " bytes" << std::endl; 11 | std::cout << "Size of char: " << sizeof(char) << " bytes" << std::endl; 12 | std::cout << "Size of bool: " << sizeof(bool) << " bytes" << std::endl; 13 | 14 | // 포인터 타입의 크기 출력 15 | int* ptr = nullptr; 16 | std::cout << "Size of pointer: " << sizeof(ptr) << " bytes" << std::endl; 17 | 18 | // 사용자 정의 데이터 타입(구조체)의 크기 출력 19 | struct MyStruct { 20 | int i; 21 | double d; 22 | char c; 23 | }; 24 | std::cout << "Size of MyStruct: " << sizeof(MyStruct) << " bytes" << std::endl; 25 | 26 | // 주석으로 변수 타입과 크기를 테이블 형식으로 정리 27 | /* 28 | | Variable Type | Size in 32-bit (bytes) | Size in 64-bit (bytes) | 29 | |---------------|------------------------|------------------------| 30 | | int | 4 | 4 | 31 | | short | 2 | 2 | 32 | | long | 4 | 8 | 33 | | long long | 8 | 8 | 34 | | float | 4 | 4 | 35 | | double | 8 | 8 | 36 | | char | 1 | 1 | 37 | | bool | 1 | 1 | 38 | | pointer | 4 | 8 | 39 | | MyStruct | 12 | 16 | 40 | */ 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/adjacencylist.cpp: -------------------------------------------------------------------------------- 1 | //############################################################# 2 | //# | cafe | http://cafe.naver.com/dremdelover | 3 | //# | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | //# | business | ultrasuperrok@gmail.com | 5 | //############################################################# 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | int main() { 12 | // 정점의 수 13 | int V = 4; 14 | 15 | // 인접 리스트 생성 16 | vector> adjList[V + 1]; 17 | 18 | // 그래프에 간선 추가 19 | adjList[1].push_back({2, 3}); 20 | adjList[1].push_back({3, 5}); 21 | adjList[2].push_back({1, 6}); 22 | adjList[2].push_back({3, 5}); 23 | adjList[3].push_back({2, 1}); 24 | adjList[3].push_back({4, 13}); 25 | adjList[4].push_back({4, 9}); 26 | adjList[4].push_back({1, 42}); 27 | 28 | // 인접 리스트 출력 29 | for (int i = 1; i <= V; ++i) { 30 | cout << "Vertex " << i << ":"; 31 | for (auto edge : adjList[i]) { 32 | cout << " (" << edge.first << ", " << edge.second << ")"; 33 | } 34 | cout << endl; 35 | } 36 | 37 | return 0; 38 | } 39 | 40 | /* 41 | 인접리스트의 개념: 42 | - 인접리스트는 그래프를 표현하는 방법 중 하나로, 각 정점에 연결된 다른 정점들을 리스트 형태로 저장합니다. 43 | 이 리스트는 일반적으로 벡터, 배열 또는 링크드 리스트로 구현됩니다. 44 | 45 | 인접리스트의 시간 복잡도: 46 | - 그래프의 모든 간선을 순회하는데 걸리는 시간은 O(E)입니다. 여기서 E는 간선의 수를 의미합니다. 47 | - 정점의 수를 V라 할 때, 모든 정점을 순회하는데 O(V)의 시간이 걸립니다. 48 | - 특정 정점에 연결된 모든 정점을 순회하는 시간은 해당 정점에 연결된 간선의 수에 비례하며, 49 | 평균적으로 한 정점에 연결된 간선의 수는 E/V이므로 O(E/V)입니다. 50 | - 인접리스트를 사용하여 두 정점 사이에 간선이 존재하는지 확인하는 데는 최악의 경우 O(V)의 시간이 걸립니다. 51 | 이는 특정 정점에 연결된 모든 간선을 순회해야 하기 때문입니다. 52 | - 따라서, 그래프 전체를 순회하는 시간 복잡도는 O(V + E)입니다. 이는 각 정점과 각 간선을 한 번씩 방문하는 것을 의미합니다. 53 | 54 | 인접리스트의 장점: 55 | - 메모리 효율적: 인접 행렬에 비해 간선이 적은 희소 그래프에서 메모리를 더 효율적으로 사용합니다. 56 | - 동적 그래프: 간선의 추가와 삭제가 상대적으로 용이합니다. 57 | 58 | 완성된 인접리스트의 모습: 59 | - 위 코드에서 출력되는 인접리스트는 다음과 같은 형식을 가집니다. 60 | Vertex 1: (2, 3) (3, 5) 61 | Vertex 2: (1, 6) (3, 5) 62 | Vertex 3: (2, 1) (4, 13) 63 | Vertex 4: (4, 9) (1, 42) 64 | */ 65 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/preorder_tree_array.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | using namespace std; 8 | 9 | // 트리를 배열로 나타내기 위해서, 배열의 인덱스를 사용하는 전위 순회 함수 정의 10 | void preorderTraversal(int tree[], int index, int size) { 11 | if (index >= size || tree[index] == -1) return; // 유효하지 않은 인덱스나 값이 -1이면 종료 12 | 13 | // Step 1: 현재 노드 값 출력 14 | cout << tree[index] << " "; 15 | 16 | // Step 2: 왼쪽 자식 노드로 이동 (2*index) 17 | preorderTraversal(tree, 2 * index, size); 18 | 19 | // Step 3: 오른쪽 자식 노드로 이동 (2*index + 1) 20 | preorderTraversal(tree, 2 * index + 1, size); 21 | } 22 | 23 | int main() { 24 | // 트리를 배열로 나타내기 25 | // -1은 해당 위치에 노드가 없음을 나타냅니다. 26 | int tree[] = {-1, 1, 4, 8, 3, 5, -1, 7, 2, -1, -1, -1, -1, -1, 6}; 27 | int size = sizeof(tree) / sizeof(tree[0]); 28 | 29 | // 전위 순회 함수 호출 30 | preorderTraversal(tree, 1, size); 31 | 32 | return 0; 33 | } 34 | 35 | /* 36 | 트리 도식화 (배열 인덱스 기반): 37 | 38 | 1 (1) 39 | / \ 40 | 4 (2) 8 (3) 41 | / \ \ 42 | 3 (4) 5 (5) 7 (7) 43 | / / 44 | 2 (8) 6 (14) 45 | 46 | 전위 순회 과정: 47 | 1. 현재 노드 값 출력: 1 (index 1) 48 | - 왼쪽 자식: 4 (index 2) 49 | - 왼쪽 자식: 3 (index 4) 50 | - 왼쪽 자식: 2 (index 8) 51 | - 왼쪽 자식: 없음 (index 16, size 초과) 52 | - 오른쪽 자식: 없음 (index 17, size 초과) 53 | - 오른쪽 자식: 없음 (index 9, 값이 -1) 54 | - 오른쪽 자식: 5 (index 5) 55 | - 왼쪽 자식: 없음 (index 10, 값이 -1) 56 | - 오른쪽 자식: 없음 (index 11, 값이 -1) 57 | - 오른쪽 자식: 8 (index 3) 58 | - 왼쪽 자식: 없음 (index 6, 값이 -1) 59 | - 오른쪽 자식: 7 (index 7) 60 | - 왼쪽 자식: 6 (index 14) 61 | - 왼쪽 자식: 없음 (index 28, size 초과) 62 | - 오른쪽 자식: 없음 (index 29, size 초과) 63 | - 오른쪽 자식: 없음 (index 15, 값이 -1) 64 | 65 | 전위 순회 순서: 1 4 3 2 5 8 7 6 66 | */ 67 | -------------------------------------------------------------------------------- /solution/43.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace std; 5 | 6 | vector> tree; 7 | vector visited, comp; 8 | int n, answer = 0; 9 | 10 | // 깊이 우선 탐색 (DFS)를 수행하는 함수 11 | void dfs(vector cur) { 12 | int sheep = 0, wolf = 0; 13 | //❶ 현재 방문한 경로를 기준으로 양과늑대의 개수를 셈 14 | for (int c : cur) { 15 | if (comp[c] == 1) wolf++; 16 | else sheep++; 17 | } 18 | 19 | //❷ 늑대의 수가 양보다 많거나 같으면 종료 20 | if (sheep <= wolf) return; 21 | 22 | //❸ 최대 양의 수 갱신 23 | answer = max(answer, sheep); 24 | 25 | for (int i = 0; i < cur.size(); i++) { 26 | int node = cur[i]; 27 | //❹ 현재 노드와 인접한 노드를 순회 28 | for (int g : tree[node]) { 29 | 30 | //❺ 이미 방문한 노드는 재방문하지 않음 31 | if (visited[g]) continue; 32 | //❻ 현재노드를 방문한 경우, 하지 않은 경우 모두 확인 33 | visited[g] = true; 34 | cur.push_back(g); 35 | dfs(cur); 36 | cur.pop_back(); 37 | visited[g] = false; 38 | } 39 | } 40 | } 41 | 42 | int solution(vector info, vector> edges) { 43 | n = info.size(); 44 | tree.resize(n); 45 | visited.resize(n, false); 46 | comp = info; 47 | 48 | //❼ 입력값으로 부터 트리 생성 49 | for (auto e : edges) { 50 | tree[e[0]].push_back(e[1]); 51 | } 52 | 53 | visited[0] = true; 54 | //❽ 방문여부를 체크하고, 시작 노드부터 탐색을 시작합니다. 55 | dfs({0}); 56 | return answer; 57 | } 58 | 59 | 60 | //아래 코드는 테스트 코드 입니다. 61 | #include 62 | using namespace std; 63 | 64 | void init() 65 | { 66 | tree.clear(); 67 | visited.clear(); 68 | comp.clear(); 69 | n = 0; 70 | answer = 0; 71 | 72 | } 73 | 74 | int main() 75 | { 76 | cout << solution({0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1}, 77 | {{0, 1}, {1, 2}, {1, 4}, {0, 8}, {8, 7}, {9, 10}, {9, 11}, {4, 3}, {6, 5}, {4, 6}, {8, 9}} 78 | ) << endl; //출력값 : 5 79 | 80 | init(); // 전역변수를 초기화 해야함 81 | 82 | cout << solution({0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0}, 83 | {{0, 1}, {0, 2}, {1, 3}, {1, 4}, {2, 5}, {2, 6}, {3, 7}, {4, 8}, {6, 9}, {9, 10}} 84 | ) << endl; //출력값 : 5 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /reference/if_statement.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | int a = 10; 12 | int b = 20; 13 | 14 | /* 15 | if문이란? 16 | - 조건을 평가하여 그 결과가 true일 때 코드 블럭을 실행하는 제어문입니다. 17 | - 조건은 괄호 안에 작성되며, 조건 결과가 참이면 괄호 다음의 코드 블럭이 실행됩니다. 18 | */ 19 | if (a < b) { 20 | cout << "a is less than b." << endl; // 출력: a is less than b. 21 | } 22 | 23 | /* 24 | if-else문이란? 25 | - 조건을 평가하여 결과가 true일 때와 false일 때 각각 다른 코드 블럭을 실행하는 제어문입니다. 26 | - if의 조건이 참이면 if의 코드 블럭을, 거짓이면 else의 코드 블럭을 실행합니다. 27 | */ 28 | if (a > b) { 29 | cout << "a is greater than b." << endl; 30 | } else { 31 | cout << "a is not greater than b." << endl; // 출력: a is not greater than b. 32 | } 33 | 34 | /* 35 | if-else if-else문이란? 36 | - 여러 조건 중 하나를 평가하여 해당 조건에 맞는 코드 블럭을 실행하는 제어문입니다. 37 | - 조건은 위에서부터 차례대로 평가되며, 첫 번째로 참인 조건의 코드 블럭만 실행됩니다. 38 | */ 39 | int c = 10; 40 | if (c > b) { 41 | cout << "c is greater than b." << endl; 42 | } else if (c == a) { 43 | cout << "c is equal to a." << endl; // 출력: c is equal to a. 44 | } else { 45 | cout << "c is neither greater than b nor equal to a." << endl; 46 | } 47 | 48 | /* 49 | 주의사항: 50 | 1. 조건문 내에서 변수의 값이 변경되지 않도록 주의해야 합니다. 51 | 예: 52 | if (a = b) { ... } // 이렇게 쓰면 a에 b의 값을 할당하게 되어 항상 참으로 평가됩니다. 53 | 올바르게는 if (a == b) { ... } 와 같이 써야 합니다. 54 | 55 | 2. 조건문을 너무 복잡하게 중첩하지 않도록 주의합니다. 56 | 너무 많은 중첩은 코드를 읽기 어렵게 만듭니다. 57 | 58 | 3. 비교 연산자와 논리 연산자를 혼동하지 않도록 주의해야 합니다. 59 | 예: if (a & b) { ... } // 이렇게 쓰면 a와 b의 비트 연산을 수행합니다. 60 | 올바르게는 if (a && b) { ... } 와 같이 논리 연산자를 사용해야 합니다. 61 | */ 62 | 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/parenthesesBalanced.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | // 두 문자가 짝이 맞는 괄호인지 확인하는 함수 8 | bool isMatchingPair(char first, char second) { 9 | // 각 괄호 쌍을 비교하여 일치하면 true 반환 10 | if (first == '(' && second == ')') return true; 11 | else if (first == '{' && second == '}') return true; 12 | else if (first == '[' && second == ']') return true; 13 | // 일치하지 않으면 false 반환 14 | return false; 15 | // 시간 복잡도: O(1) 16 | } 17 | 18 | // 주어진 괄호 문자열이 올바르게 짝이 맞는지 확인하는 함수 19 | bool areParenthesesBalanced(string expression) { 20 | stack stack; // 여는 괄호를 저장할 스택 21 | 22 | // 문자열의 각 문자를 순회 23 | for (int i = 0; i < expression.length(); i++) { 24 | // 여는 괄호는 스택에 푸시 25 | if (expression[i] == '{' || expression[i] == '(' || expression[i] == '[') { 26 | stack.push(expression[i]); 27 | } 28 | 29 | // 닫는 괄호가 나왔을 때 30 | if (expression[i] == '}' || expression[i] == ')' || expression[i] == ']') { 31 | // 스택이 비어있으면 짝이 맞지 않음 32 | if (stack.empty()) { 33 | return false; 34 | } 35 | // 스택의 top과 현재 닫는 괄호가 짝이 맞는지 확인 36 | else if (!isMatchingPair(stack.top(), expression[i])) { 37 | return false; 38 | } 39 | // 짝이 맞으면 스택에서 여는 괄호를 팝 40 | else { 41 | stack.pop(); 42 | } 43 | } 44 | } 45 | 46 | // 스택이 비어있으면 모든 괄호가 짝이 맞음, 아니면 짝이 맞지 않음 47 | return stack.empty(); 48 | // 시간 복잡도: O(n), n은 입력 문자열의 길이 49 | } 50 | 51 | // 주어진 괄호 문자열을 테스트하는 함수 52 | void do_test(string expression) { 53 | if (areParenthesesBalanced(expression)) 54 | std::cout << "괄호가 올바르게 짝이 맞습니다." << std::endl; 55 | else 56 | std::cout << "괄호가 올바르게 짝이 맞지 않습니다." << std::endl; 57 | } 58 | 59 | int main() { 60 | // 테스트 케이스 실행 61 | do_test("{}({})"); // 올바르게 짝이 맞는 경우 62 | do_test("{{({})"); // 여는 괄호가 더 많은 경우 63 | do_test("{}({))"); // 닫는 괄호가 더 많은 경우 64 | 65 | return 0; 66 | // 시간 복잡도: O(n) 각 테스트 케이스에 대해 67 | } 68 | -------------------------------------------------------------------------------- /reference/type_conversion.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | 8 | using namespace std; 9 | 10 | int main() { 11 | 12 | /* 13 | 형변환이란? 14 | - 변수나 리터럴의 데이터 타입을 다른 데이터 타입으로 변환하는 것을 의미합니다. 15 | - C++에서는 명시적 형변환과 암시적 형변환의 두 가지 방법이 있습니다. 16 | */ 17 | 18 | // 1. 암시적 형변환 (Implicit Type Conversion) 19 | double d = 3.14; 20 | int i = d; // double에서 int로 암시적 형변환. 소수 부분이 손실됨. 21 | cout << "i: " << i << endl; // 출력: i: 3 22 | 23 | // 2. 명시적 형변환 (Explicit Type Conversion) 24 | double e = 5.67; 25 | int j = static_cast(e); // double에서 int로 명시적 형변환. 소수 부분이 손실됨. 26 | cout << "j: " << j << endl; // 출력: j: 5 27 | 28 | /* 29 | 주의사항: 30 | 1. 형변환으로 인해 데이터의 손실이 발생할 수 있습니다. 31 | 예: double에서 int로 형변환 시, 소수 부분이 손실됩니다. 32 | 33 | 2. 음수와 unsigned 데이터 타입의 비교는 주의가 필요합니다. 34 | unsigned 데이터 타입은 항상 양수이기 때문에 음수를 unsigned 타입으로 형변환하면 큰 양수값이 됩니다. 35 | */ 36 | int negative = -3; 37 | unsigned int u = 2; 38 | 39 | if (negative < u) { // true로 예상되지만, 음수가 큰 양수값으로 변환되므로 false입니다. 40 | cout << "negative is less than u." << endl; 41 | } else { 42 | cout << "negative is NOT less than u." << endl; // 출력: negative is NOT less than u. 43 | } 44 | 45 | /* 46 | 3. sizeof 연산자를 사용할 때 주의가 필요합니다. 47 | sizeof는 변수나 타입의 크기를 반환하며, 반환값은 size_t 타입입니다. 48 | size_t는 일반적으로 unsigned int나 unsigned long과 같은 양수만을 가질 수 있는 타입입니다. 49 | 따라서 음수와 비교 시, 의도하지 않은 결과가 발생할 수 있습니다. 50 | */ 51 | int arr[10]; 52 | int n = -5; 53 | 54 | if (n < sizeof(arr)) { // true로 예상되지만, 음수가 큰 양수값으로 변환되므로 false입니다. 55 | cout << "n is less than size of arr." << endl; // 출력: n is less than size of arr. 56 | } else { 57 | cout << "n is NOT less than size of arr." << endl; 58 | } 59 | 60 | return 0; 61 | } 62 | -------------------------------------------------------------------------------- /solution/41.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | using namespace std; 4 | 5 | const int MAX_SIZE = 100; 6 | const int dx[4] = {-1, 0, 1, 0}; 7 | const int dy[4] = {0, 1, 0, -1}; 8 | int check[MAX_SIZE][MAX_SIZE]; 9 | 10 | //❶ 좌표 정보 및 관련 연산을 하기 위한 구조체 11 | struct Point { 12 | int y, x; 13 | 14 | Point(int y, int x) : y(y), x(x) {} 15 | 16 | bool isValid(int width, int height) const { 17 | return y >= 0 && y < height && x >= 0 && x < width; 18 | } 19 | 20 | Point move(int i) const { 21 | return Point(y + dy[i], x + dx[i]); 22 | } 23 | 24 | bool canMoveTo(const vector>& maps) const { 25 | return maps[y][x] == 1 && check[y][x] == 0; 26 | } 27 | }; 28 | 29 | queue q; // BFS를 위한 큐 30 | 31 | int solution(vector> maps) { 32 | int width = maps[0].size(), height = maps.size(); 33 | q.push({0, 0}); 34 | check[0][0] = 1; 35 | 36 | // ❷ 너비우선탐색 진행 37 | while (!q.empty()) { 38 | Point current = q.front(); 39 | q.pop(); 40 | //❸ 현재좌표 기준으로 상하좌우를 확인 41 | for (int i = 0; i < 4; i++) { 42 | Point next = current.move(i); 43 | //❹ 범위나 좌표이고 벽이 아닌 경우 44 | if (next.isValid(width, height) && next.canMoveTo(maps)) { 45 | check[next.y][next.x] = check[current.y][current.x] + 1; 46 | q.push({next.y, next.x}); 47 | } 48 | } 49 | } 50 | 51 | //❺ 목적지에 도달가능 여부를 확인 52 | int destinationX = width - 1, destinationY = height - 1; 53 | if (check[destinationY][destinationX] == 0) { 54 | return -1; // 도착 지점에 도달할 수 없음 55 | } 56 | 57 | return check[destinationY][destinationX]; // 도착 지점까지의 최단 거리 반환 58 | } 59 | 60 | 61 | //아래 코드는 테스트 코드 입니다. 62 | #include 63 | 64 | using namespace std; 65 | 66 | void init() 67 | { 68 | for(int i = 0 ; i < MAX_SIZE; i++) 69 | for(int j = 0 ; j < MAX_SIZE; j++) 70 | check[i][j] = false; 71 | } 72 | int main() 73 | { 74 | 75 | cout << solution({{1, 0, 1, 1, 1}, {1, 0, 1, 0, 1}, {1, 0, 1, 1, 1}, {1, 1, 1, 0, 1}, {0, 0, 0, 0, 1}}) << endl; //출력값 : 11 76 | init(); 77 | cout << solution({{1, 0, 1, 1, 1}, {1, 0, 1, 0, 1}, {1, 0, 1, 1, 1}, {1, 1, 1, 0, 0}, {0, 0, 0, 0, 1}}) << endl; //출력값 : -1 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /solution/61.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | //❶ 현재칸의 좌표와 이전칸에서 현재칸으로 가는 비용 8 | struct Pos { 9 | int r; 10 | int c; 11 | int heightDiff; 12 | bool operator<(const Pos &p) const { 13 | return heightDiff > p.heightDiff; 14 | } 15 | }; 16 | 17 | int dy[4] = {-1, 0, 1, 0}, dx[4] = {0, 1, 0, -1}; 18 | bool visited[301][301]; 19 | //❷ 다음 이동할 칸이 격자 내에 존재하는 좌표인지 확인 20 | bool isValid(int nr, int nc, int rows, int cols) { 21 | return nr >= 0 && nr < rows && nc >= 0 && nc < cols && !visited[nr][nc]; 22 | } 23 | 24 | int solution(vector> land, int height) { 25 | int totalCost = 0; 26 | int rows = land.size(), cols = land[0].size(); 27 | 28 | priority_queue pq; 29 | pq.push({0, 0, 0}); 30 | 31 | while (!pq.empty()) { 32 | Pos current = pq.top(); 33 | pq.pop(); 34 | 35 | //❸ 이미 방문한 칸은, 또 방문하지 않음 36 | if (visited[current.r][current.c]) 37 | continue; 38 | //❹ 현재 칸으로 이동하는 비용을 추가 39 | totalCost += current.heightDiff; 40 | //❺ 현재칸의 인접 칸을 순회 41 | for (int i = 0; i < 4; i++) { 42 | int nr = current.r + dy[i], nc = current.c + dx[i]; 43 | if (isValid(nr, nc, rows, cols)) { 44 | //❻ 이동가능한 칸과 현재칸의 높이차를 구함 45 | int diff = abs(land[current.r][current.c] - land[nr][nc]); 46 | //❼ 높이차가 사다리 설치 기준보다 큰 경우 47 | if (diff > height) 48 | pq.push({nr, nc, diff}); 49 | //❽ 높이차가 사다리 설치 기준보다 크지 않은 경우 50 | else 51 | pq.push({nr, nc, 0}); 52 | } 53 | } 54 | //❾ 현재 칸을 방문여부를 표시 55 | visited[current.r][current.c] = true; 56 | } 57 | 58 | return totalCost; 59 | } 60 | 61 | 62 | //아래 코드는 테스트 코드 입니다. 63 | #include 64 | 65 | using namespace std; 66 | 67 | void init() 68 | { 69 | for(int i = 0 ; i <= 300; i++) 70 | for(int j = 0; j <= 300; j++) 71 | visited[i][j] = 0; 72 | } 73 | 74 | int main() 75 | { 76 | cout << solution({{1, 4, 8, 10}, {5, 5, 5, 5}, {10, 10, 10, 10}, {10, 10, 10, 20}}, 3) << endl; //출력값 : 15 77 | init(); 78 | cout << solution({{10, 11, 10, 11}, {2, 21, 20, 10}, {1, 20, 21, 11}, {2, 1, 2, 1}}, 1) << endl; //출력값 : 18 79 | 80 | return 0; 81 | } 82 | -------------------------------------------------------------------------------- /STL/priority_queue_with_priority.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | // 표준 라이브러리 사용을 위한 네임스페이스 선언 12 | using namespace std; 13 | 14 | // 좌표를 나타내는 구조체 정의 15 | struct Point { 16 | int x, y; 17 | 18 | // 비교 연산자 정의 (내림차순) 19 | // 우선순위 큐에서 가장 큰 값을 우선 처리하기 위해 사용 20 | bool operator<(const Point& other) const { 21 | // 내림차순 정렬을 위해 x 좌표가 큰 순서대로, x 좌표가 같다면 y 좌표가 큰 순서대로 정렬 22 | if (x == other.x) { 23 | return y < other.y; 24 | } 25 | return x < other.x; 26 | } 27 | }; 28 | 29 | int main() { 30 | // 우선순위 큐 선언 (내림차순) 31 | // priority_queue: 32 | // - Point: 큐에 저장될 요소의 타입 (좌표 구조체) 33 | // 기본적으로 가장 큰 값이 높은 우선순위를 가집니다. 34 | priority_queue pq; 35 | 36 | // 좌표 삽입 37 | // push() 함수는 우선순위 큐에 요소를 삽입합니다. 38 | pq.push({10, 20}); // (10, 20) 삽입 39 | pq.push({30, 40}); // (30, 40) 삽입 40 | pq.push({20, 30}); // (20, 30) 삽입 41 | pq.push({5, 10}); // (5, 10) 삽입 42 | 43 | // 좌표 출력 (우선순위 순) 44 | // while 루프는 큐가 비어있지 않을 때까지 반복됩니다. 45 | // top() 함수는 우선순위 큐의 가장 위에 있는 요소(우선순위가 가장 높은 요소)를 반환합니다. 46 | // pop() 함수는 우선순위 큐의 가장 위에 있는 요소를 제거합니다. 47 | while (!pq.empty()) { 48 | Point p = pq.top(); // 우선순위가 가장 높은 좌표를 반환 49 | cout << "(" << p.x << ", " << p.y << ") "; // 좌표를 출력 50 | pq.pop(); // 우선순위가 가장 높은 좌표를 큐에서 제거 51 | } 52 | return 0; 53 | } 54 | 55 | // 출력 설명: 56 | // priority_queue는 기본적으로 최대 힙(Max-Heap) 구조로 동작하여 가장 큰 요소가 가장 높은 우선순위를 가집니다. 57 | // 좌표 구조체(Point)의 비교 연산자(operator<)를 사용하여 x 좌표가 큰 순서대로, 58 | // x 좌표가 같다면 y 좌표가 큰 순서대로 정렬됩니다. 59 | // 따라서, 위의 코드는 (30, 40), (20, 30), (10, 20), (5, 10) 순으로 좌표를 출력합니다. 60 | // pq.push() 함수를 통해 좌표를 삽입할 때마다 내부적으로 정렬이 이루어지며, 61 | // pq.top() 함수는 가장 큰 x 값을 가진 좌표를 반환하고, pq.pop() 함수는 반환된 좌표를 큐에서 제거합니다. 62 | // 결과적으로, 우선순위 큐에 삽입된 좌표들은 내림차순으로 정렬되어 출력됩니다. 63 | -------------------------------------------------------------------------------- /solution/51.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | vector answer; 6 | vector ryan(11, 0); 7 | int maxScore = -1; 8 | 9 | //❶ 어피치와 라이언의 점수차이를 계산 10 | int calcScoreDiff(const vector &apeach) { 11 | int scoreApeach = 0; 12 | int scoreLion = 0; 13 | 14 | for(int i = 0; i < 11; ++i) { 15 | if(apeach[i] == 0 && ryan[i] == 0) continue; 16 | if(apeach[i] >= ryan[i]) scoreApeach += 10 - i; 17 | else scoreLion += 10 - i; 18 | } 19 | 20 | return scoreLion - scoreApeach; 21 | } 22 | 23 | void dfs(const vector &apeach, int score, int arrow) { 24 | if(score == -1 || arrow == 0) { 25 | ryan[10] = arrow; 26 | int scoreDiff = calcScoreDiff(apeach); 27 | //❷ 현재 구한 점수차가 기존 최대 점수차보다 더 크고, 라이언의 점수가 더 높은 경우 갱신 28 | if(scoreDiff > 0 && maxScore < scoreDiff) { 29 | maxScore = scoreDiff; 30 | answer = ryan; 31 | } 32 | ryan[10] = 0; 33 | return; 34 | } 35 | 36 | //❸ 아직 어피치가 쏠 화살이 남은 경우 37 | if(arrow > apeach[score]) { 38 | ryan[score] = apeach[score] + 1; 39 | dfs(apeach, score - 1, arrow - apeach[score] - 1); 40 | ryan[score] = 0; 41 | } 42 | 43 | //❹ 어피치가 화살을 사용하지 않는 경우 44 | dfs(apeach, score - 1, arrow); 45 | } 46 | 47 | vector solution(int n, vector info) { 48 | //❺ 10점 과녁부터 모든 조합을 확인 49 | dfs(info, 10, n); 50 | 51 | //❻ 라이언이 이길 수 있는 경우가 없는 경우 52 | if(maxScore == -1) answer.push_back(-1); 53 | 54 | return answer; 55 | } 56 | 57 | 58 | 59 | 60 | 61 | //아래 코드는 테스트 코드 입니다. 62 | #include 63 | #include 64 | using namespace std; 65 | 66 | void init(){ 67 | answer.clear(); 68 | maxScore = -1; 69 | 70 | for(int i = 0 ; i < ryan.size(); i++) 71 | ryan[i] = 0; 72 | } 73 | 74 | void print(vector vec) 75 | { 76 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 77 | cout << endl; 78 | } 79 | 80 | int main() 81 | { 82 | print(solution(5, {2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0})); //출력값 : 0 2 2 0 1 0 0 0 0 0 0 83 | init(); 84 | print(solution(1, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})); //출력값 : -1 85 | init(); 86 | print(solution(9, {0, 0, 1, 2, 0, 1, 1, 1, 1, 1, 1})); //출력값 : 1 1 2 0 1 2 2 0 0 0 0 87 | return 0; 88 | } 89 | -------------------------------------------------------------------------------- /solution/29.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | // ❶ 노드를 정의 5 | class Node { 6 | public: 7 | int val; 8 | Node *left, *right; 9 | 10 | Node(int key) : val(key), left(nullptr), right(nullptr) {} 11 | }; 12 | 13 | //❷ 이진 탐색 트리 정의 14 | class BST { 15 | private: 16 | Node* root; 17 | 18 | 19 | Node* insertNode(Node* node, int key) { 20 | if (!node) { 21 | return new Node(key); 22 | } 23 | //❸ 키 값과 현재 노드의 값을 비교해서 이진탐색트리 규칙에 맞는 위치로 이동 24 | if (key < node->val) { 25 | node->left = insertNode(node->left, key); 26 | } else { 27 | node->right = insertNode(node->right, key); 28 | } 29 | return node; 30 | } 31 | 32 | bool searchNode(Node* node, int key) { 33 | //❹ 찾는 키 값이 없는 경우 34 | if (!node) { 35 | return false; 36 | } 37 | //❺ 이진탐색트리에서 키 값을 찾은 경우 38 | if (key == node->val) { 39 | return true; 40 | } 41 | //❻ 아직 값을 찾지 못한 경우, 현재 노드값과 key 값을 비교해서, 어느 노드에서 탐색할지 결정 42 | return key < node->val ? 43 | searchNode(node->left, key) : 44 | searchNode(node->right, key); 45 | } 46 | 47 | public: 48 | BST() : root(nullptr) {} 49 | 50 | void insert(int key) { 51 | root = insertNode(root, key); 52 | } 53 | 54 | bool search(int key) { 55 | return searchNode(root, key); 56 | } 57 | }; 58 | 59 | vector solution(vector lst, vector search_lst) { 60 | BST bst; 61 | // 이진 탐색 트리에 노드 삽입 62 | for (int key : lst) { 63 | bst.insert(key); 64 | } 65 | 66 | vector result; 67 | // 이진 탐색 트리에서 찾는 값이 있는지 확인하고 탐색결과를 result에 추가 68 | for (int search_val : search_lst) { 69 | result.push_back(bst.search(search_val)); 70 | } 71 | 72 | return result; 73 | } 74 | 75 | //아래 코드는 테스트 코드 입니다. 76 | #include 77 | #include 78 | void print(vector vec) 79 | { 80 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 81 | cout << endl; 82 | } 83 | 84 | int main() 85 | { 86 | // bool을 출력할 때 true는 1 false는 0 입니다. 87 | print(solution({5, 3, 8, 4, 2, 1, 7, 10}, {1, 2, 5, 6})); //출력값 : 1 1 1 0 88 | print(solution({1, 3, 5, 7, 9}, {2, 4, 6, 8, 10})); //출력값 : 0 0 0 0 0 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /STL/next_permutation.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | #include // for std::next_permutation and std::sort 9 | using namespace std; 10 | 11 | // 벡터의 모든 순열을 출력하는 함수 12 | void print_permutations(vector v) { 13 | do { 14 | // 현재 순열 출력 15 | for (int num : v) { 16 | cout << num << " "; 17 | } 18 | cout << endl; 19 | } while (next_permutation(v.begin(), v.end())); 20 | } 21 | 22 | int main() { 23 | // 예시 벡터 생성 24 | vector v = {3, 2, 1}; 25 | 26 | // 정렬되지 않은 경우 27 | cout << "정렬되지 않은 경우:\n"; 28 | vector v_unsorted = v; 29 | print_permutations(v_unsorted); 30 | 31 | // 벡터를 정렬된 상태로 만들기 32 | sort(v.begin(), v.end()); 33 | 34 | // 정렬된 경우 35 | cout << "\n정렬된 경우:\n"; 36 | vector v_sorted = v; 37 | print_permutations(v_sorted); 38 | 39 | return 0; 40 | } 41 | 42 | /* 43 | 출력값: 44 | 45 | 정렬되지 않은 경우: 46 | 3 2 1 47 | 48 | 정렬된 경우: 49 | 1 2 3 50 | 1 3 2 51 | 2 1 3 52 | 2 3 1 53 | 3 1 2 54 | 3 2 1 55 | */ 56 | 57 | // next_permutation에 대한 설명 58 | /* 59 | std::next_permutation 함수는 주어진 범위에서 사전식 순서로 다음 순열을 생성합니다. 60 | 이 함수는 내부적으로 요소의 순서를 비교하여 다음 순열을 만듭니다. 61 | 62 | 주의해야 할 점: 63 | 1. 정렬된 상태에서 사용: next_permutation 함수는 범위가 정렬된 상태에서 시작할 때 모든 순열을 64 | 올바르게 생성할 수 있습니다. 정렬되지 않은 상태에서 시작하면 모든 순열을 생성하지 못합니다. 65 | 2. 반환값: 다음 순열이 존재하면 true를 반환하고, 더 이상 다음 순열이 없으면 false를 반환하여 66 | 주어진 범위를 처음 순열(가장 작은 순열)로 재설정합니다. 67 | 3. 시간 복잡도: 함수 자체의 시간 복잡도는 O(N)입니다. 모든 순열을 생성하기 위해 반복적으로 68 | 호출하면 총 시간 복잡도는 O(N * N!)이 됩니다. 여기서 N은 요소의 수입니다. 69 | */ 70 | 71 | // next_permutation 사용 예: 72 | /* 73 | 벡터가 {1, 2, 3}로 주어졌을 때, 74 | next_permutation(v.begin(), v.end())를 호출하면, 75 | 벡터는 {1, 3, 2}로 변환됩니다. 76 | 77 | 벡터가 {3, 2, 1}로 주어졌을 때, 78 | next_permutation(v.begin(), v.end())를 호출하면, 79 | 벡터는 다시 {1, 2, 3}로 재설정됩니다. 80 | */ 81 | 82 | -------------------------------------------------------------------------------- /solution/33.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | vector parents; 6 | vector rankData; 7 | 8 | // 문자를 숫자로 변환 9 | int charToInt(char c) { 10 | return c - '0'; 11 | } 12 | 13 | int find(int x) { 14 | // x의 부모가 자신인 경우 루트노드를 찾았으므로 반환 15 | if (parents[x] == x) { 16 | return x; 17 | } 18 | 19 | // 파인드 연산 시, 경로압축 사용 20 | parents[x] = find(parents[x]); 21 | 22 | return parents[x]; 23 | } 24 | 25 | void unionSet(int x, int y) { 26 | int root1 = find(x); 27 | int root2 = find(y); 28 | 29 | // 루트 노드가 같을 경우 유니온 연산을 할 필요가 없음 30 | if (root1 != root2) { 31 | // 랭크기반 알고리즘으로 유니온 연산 수행 32 | if (rankData[root1] < rankData[root2]) { 33 | parents[root1] = root2; 34 | } 35 | else if (rankData[root1] > rankData[root2]) { 36 | parents[root2] = root1; 37 | } 38 | else { 39 | parents[root2] = root1; 40 | rankData[root1]++; 41 | } 42 | } 43 | } 44 | 45 | vector solution(int k, vector> operations) { 46 | parents.resize(k); 47 | rankData.resize(k, 0); 48 | 49 | // 초기에 각 노드는 자신을 부모로 설정 50 | for (int i = 0; i < k; ++i) { 51 | parents[i] = i; 52 | } 53 | 54 | vector results; 55 | for (const auto& op : operations) { 56 | if (op[0] == 'u') { 57 | int x = charToInt(op[1]); 58 | int y = charToInt(op[2]); 59 | unionSet(x, y); 60 | } 61 | else if (op[0] == 'f') { 62 | int x = charToInt(op[1]); 63 | int y = charToInt(op[2]); 64 | // 파인드 연산을 통화 x,y의 루트노드가 같은지 확인해서 결과 저장 65 | results.push_back(find(x) == find(y)); 66 | } 67 | } 68 | 69 | return results; 70 | } 71 | 72 | //아래 코드는 테스트 코드 입니다. 73 | #include 74 | #include 75 | 76 | using namespace std; 77 | 78 | void init() 79 | { 80 | parents.clear(); 81 | rankData.clear(); 82 | } 83 | void print(vector vec) 84 | { 85 | copy(vec.begin(), vec.end(), std::ostream_iterator(cout, " ")); 86 | cout << endl; 87 | } 88 | 89 | int main() 90 | { 91 | print(solution(3, {{'u', '0', '1'}, {'u', '1', '2'}, {'f', '0', '2'}})); // 결과값 : 1 92 | init(); 93 | print(solution(4, {{'u', '0', '1'}, {'u', '2', '3'}, {'f', '0', '1'}, {'f', '0', '2'}})); // 결과값 : 1 0 94 | 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/insertionsort.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | 7 | /* 8 | 삽입 정렬 알고리즘: 9 | - 시간 복잡도: 최악의 경우 O(n^2), 최선의 경우 O(n) 10 | - 용도: 작은 데이터 셋에서 효율적이며, 이미 부분적으로 정렬된 배열에서 높은 성능을 보입니다. 11 | - 동작 과정: 12 | 1. 첫 번째 원소를 정렬된 부분으로 간주합니다. 13 | 2. 다음 원소를 정렬된 부분과 비교하여, 올바른 위치에 삽입합니다. 14 | 3. 모든 원소가 정렬된 부분에 삽입될 때까지 2의 과정을 반복합니다. 15 | 16 | 도식화 예:(아래 코드 기준) 17 | 입력 배열: [5, 2, 9, 1, 5, 6] 18 | 첫 번째 패스: [5| 2, 9, 1, 5, 6] => |의 왼쪽은 정렬된 부분 19 | 두 번째 패스: [2, 5| 9, 1, 5, 6] => 2를 정렬된 부분의 올바른 위치에 삽입 20 | 세 번째 패스: [2, 5, 9| 1, 5, 6] => 9는 이미 올바른 위치에 있음 21 | 네 번째 패스: [2, 5, 9| 1, 5, 6] => 1을 정렬된 부분의 올바른 위치, 즉 배열의 맨 앞에 삽입 22 | 다섯 번째 패스: [1, 2, 5, 9| 5, 6] => 5를 정렬된 부분의 올바른 위치, 즉 5 바로 앞에 삽입 23 | 여섯 번째 패스: [1, 2, 5, 5, 9| 6] => 6을 정렬된 부분의 올바른 위치, 즉 9 바로 앞에 삽입 24 | 완료된 정렬: [1, 2, 5, 5, 6, 9] 25 | */ 26 | 27 | // 삽입정렬의 슈도코드: 28 | // for i = 1 to length(A) - 1 29 | // key = A[i] 30 | // j = i - 1 31 | // while j >= 0 and A[j] > key 32 | // A[j + 1] = A[j] 33 | // j = j - 1 34 | // A[j + 1] = key 35 | 36 | // 삽입정렬의 시간 복잡도: 37 | // 최선의 경우: O(n) - 이미 정렬된 배열의 경우 38 | // 평균의 경우: O(n^2) - 일반적인 경우 39 | // 최악의 경우: O(n^2) - 역순으로 정렬된 배열의 경우 40 | 41 | 42 | #include 43 | #include 44 | using namespace std; 45 | 46 | void insertionSort(vector& arr) { 47 | int n = arr.size(); 48 | for(int i=1; i= 0 && arr[j] > key) { 54 | arr[j + 1] = arr[j]; 55 | j = j - 1; 56 | } 57 | arr[j + 1] = key; 58 | } 59 | } 60 | 61 | int main() { 62 | vector arr = {5, 2, 9, 1, 5, 6}; 63 | 64 | insertionSort(arr); 65 | 66 | cout << "Sorted array: "; 67 | for(int i = 0; i < arr.size(); i++) 68 | cout << arr[i] << " "; 69 | cout << endl; 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /Example/factorial_iterative.cpp: -------------------------------------------------------------------------------- 1 | //############################################################ 2 | // | cafe | http://cafe.naver.com/dremdelover | 3 | // | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | // | business | ultrasuperrok@gmail.com | 5 | //############################################################ 6 | #include 7 | #include 8 | 9 | using namespace std; 10 | 11 | // 동적 계획법을 사용하여 팩토리얼을 계산하는 함수 12 | int factorial(int n) { 13 | // 크기 n+1의 벡터를 1로 초기화합니다. 14 | vector dp(n + 1, 1); 15 | 16 | // 팩토리얼 계산: dp[i]는 i! (i 팩토리얼)을 저장합니다. 17 | for (int i = 2; i <= n; ++i) { 18 | dp[i] = dp[i - 1] * i; 19 | } 20 | 21 | // 결과로 n!을 반환합니다. 22 | return dp[n]; 23 | } 24 | 25 | int main() { 26 | int n = 5; // 예시로 5의 팩토리얼을 계산 27 | cout << n << "! = " << factorial(n) << endl; 28 | 29 | n = 7; // 예시로 7의 팩토리얼을 계산 30 | cout << n << "! = " << factorial(n) << endl; 31 | 32 | return 0; 33 | } 34 | 35 | /* 36 | 동적 계획법(DP)와 팩토리얼 계산: 37 | 38 | 1. 동적 계획법(DP) 기본 원리: 39 | - 큰 문제를 작은 부분 문제로 분할하여 해결. 40 | - 동일한 부분 문제의 반복 계산을 피하기 위해 결과를 저장(memoization). 41 | - 시간 복잡도를 줄이고 효율성을 높이는 기법. 42 | 43 | 2. 중복 부분 문제(Overlapping Subproblems): 44 | - 동일한 작은 문제들이 여러 번 반복하여 계산되는 문제. 45 | - 예: 피보나치 수열에서 F(n) = F(n-1) + F(n-2) 계산 시, F(n-1)과 F(n-2)가 여러 번 중복 계산됨. 46 | - 동적 계획법은 이러한 중복 계산을 피하여 효율성을 높임. 47 | 48 | 3. 최적 부분 구조(Optimal Substructure): 49 | - 문제의 최적 해결 방법이 부분 문제의 최적 해결 방법으로 구성되는 성질. 50 | - 팩토리얼 계산에서 n! = n * (n-1)!의 형태로 나타남. 51 | - 예: 최단 경로 문제에서, 전체 경로의 최적해는 부분 경로의 최적해로 구성됨. 52 | 53 | 4. 팩토리얼 계산의 기본 원리: 54 | - 팩토리얼(n!)은 n * (n-1) * (n-2) * ... * 1의 곱셈으로 계산. 55 | - 즉, n! = n * (n-1)! 56 | 57 | 5. 팩토리얼 계산에 동적 계획법 적용: 58 | - dp[i]에 i!의 값을 저장하여 중복 계산을 피함. 59 | - 예: dp[3] = 3 * dp[2], dp[2] = 2 * dp[1] 등. 60 | 61 | 6. 팩토리얼 계산의 시간 복잡도: 62 | - 반복문을 사용하면 O(n) 시간 복잡도로 계산 가능. 63 | - 동적 계획법을 사용해도 시간 복잡도는 여전히 O(n). 64 | 65 | 7. 동적 계획법의 효율성 향상이 어려운 이유: 66 | - 팩토리얼 문제는 중복 부분 문제가 존재하지 않음. 67 | - 각 단계에서 이전 단계의 결과를 단순히 곱하는 형태. 68 | - 추가적인 메모리 공간 사용(dp 배열)이 필요하지만 시간 복잡도 개선 효과는 없음. 69 | 70 | 결론: 71 | - 팩토리얼 계산 문제는 최적 부분 구조를 가지지만, 중복 부분 문제가 없기 때문에 72 | 동적 계획법의 이점(시간 복잡도 감소)을 크게 활용할 수 없음. 73 | - 따라서, DP를 적용해도 효율성 개선은 미미함. 74 | */ 75 | --------------------------------------------------------------------------------