├── .gitignore ├── solution ├── 68.py ├── 56.py ├── 28.py ├── 73.py ├── 34.py ├── 57.py ├── 01.py ├── 58.py ├── 11.py ├── 02.py ├── 36.py ├── 76.py ├── 82.py ├── 60.py ├── 09.py ├── 08.py ├── 15.py ├── 83.py ├── 75.py ├── 20.py ├── 05.py ├── 85.py ├── 35.py ├── 54.py ├── 03.py ├── 12.py ├── 65.py ├── 77.py ├── 84.py ├── 67.py ├── 43.py ├── 80.py ├── 74.py ├── 22.py ├── 79.py ├── 17.py ├── 16.py ├── 69.py ├── 59.py ├── 06.py ├── 70.py ├── 04.py ├── 21.py ├── 66.py ├── 71.py ├── 55.py ├── 78.py ├── 29.py ├── 49.py ├── 23.py ├── 25.py ├── 10.py ├── 47.py ├── 46.py ├── 18.py ├── 07.py ├── 19.py ├── 13.py ├── 44.py ├── 50.py ├── 24.py ├── 38.py ├── 61.py ├── 52.py ├── 51.py ├── 14.py ├── 31.py ├── 39.py ├── 72.py ├── 62.py ├── 40-2.py ├── 41.py ├── 33.py ├── 81.py ├── 42.py ├── 64.py ├── 37.py ├── 63.py ├── 26.py ├── 30.py ├── 40.py ├── 45.py ├── 53.py ├── 27.py ├── 32.py └── 48.py ├── errorcode ├── type_error.py ├── name_error.py ├── string_number_addtion.py ├── indentation_error.py ├── import_missing_module.py ├── attribute_error.py ├── invalid_syntax.py ├── pop-from_empty_list.py ├── mutable_dict_key.py ├── value_error.py ├── function_argument_missing.py ├── key_error.py ├── index_out_of_range.py ├── value_error_in_list.py ├── division_by_zero.py ├── missing_dict_key.py ├── recursion_limit_exceed.py └── ReadMe.md ├── Algorithm_with_DataStructure ├── list_element_sum.py ├── string_reversal.py ├── interval_sum.py ├── remove_duplicates.py ├── combination_generation.py ├── permutation_generation.py ├── merge_list_to_dictionary.py ├── string_to_number_conversion.py ├── time_measurement.py ├── prime_number_detection.py ├── binary_search.py ├── deque.py ├── dfs_recursion.py ├── stack.py ├── fibonacci_recursion_memoization.py ├── tree_array.py ├── priority_queue.py ├── dictionary.py ├── LCS_DP.py ├── tree_adjacentlist.py ├── LIS_DP.py ├── eratosthenes_sieve.py ├── fibonacci_recursion.py ├── set.py ├── dfs_stack.py ├── list.py ├── heapq.py ├── bfs.py ├── bellmanford.py ├── union_find.py ├── dijkstra.py └── queue.py ├── reference ├── early_return.py ├── composition_fuction.py ├── mutable_immutable.py ├── range.py ├── for_loop.py ├── variable.py ├── counter.py ├── guard_clauses.py ├── while_loop.py ├── if_statement.py ├── variable_type.py ├── in.py ├── list_comprehension.py ├── zip.py ├── def.py ├── insertionsort.py ├── map_reduce.py ├── try_except.py ├── lambda.py ├── countsort.py ├── string.py ├── permutation_direct.py ├── combination_direct.py └── mergesort_recursive.py ├── mistake ├── zero_division_demo.py ├── power_methods_comparison.py ├── none_return_tutorial.py ├── index_error_demo.py ├── sorting_methods_comparison.py ├── indexing_convention_tutorial.py ├── operation_precedence_examples.py ├── binary_search_mistake.py ├── list_in_del_usage.py ├── range_function_usage.py ├── for_else_tutorial.py ├── variable_scope_tutorial.py.py └── ReadMe.md ├── study_guide.md ├── performance ├── append_vs_plus_performance.py ├── list_vs_set_in.py ├── string_concatenation_performance.py ├── for_loop_vs_list_comprehension.py ├── list_vs_deque_pop_performance.py ├── list_vs_heapq.py └── ReadMe.md ├── community.md ├── Coding_Test_Success_Guide.md ├── README.md └── discord.md /.gitignore: -------------------------------------------------------------------------------- 1 | reference/__pycache__/heapq.cpython-311.pyc 2 | -------------------------------------------------------------------------------- /solution/68.py: -------------------------------------------------------------------------------- 1 | def solution(N): 2 | return bin(N).count('1') # 2진수로 변환하고 1의 개수를 반환 3 | -------------------------------------------------------------------------------- /solution/56.py: -------------------------------------------------------------------------------- 1 | def solution(strings, n): 2 | return sorted(strings, key=lambda x: (x[n], x)) 3 | -------------------------------------------------------------------------------- /solution/28.py: -------------------------------------------------------------------------------- 1 | def solution(n, a, b): 2 | answer = 0 3 | while a != b: 4 | a = (a + 1) // 2 5 | b = (b + 1) // 2 6 | answer += 1 7 | return answer 8 | -------------------------------------------------------------------------------- /solution/73.py: -------------------------------------------------------------------------------- 1 | def solution(n): 2 | fib = [0, 1] # F(0) = 0, F(1) = 1 3 | for i in range(2, n + 1): 4 | fib.append((fib[i - 1] + fib[i - 2]) % 1234567) 5 | return fib[n] 6 | -------------------------------------------------------------------------------- /solution/34.py: -------------------------------------------------------------------------------- 1 | def solution(nums): 2 | num_set = set(nums) # ➊ nums 리스트에서 중복을 제거한 집합(set)을 구함 3 | n = len(nums) # ➋ 폰켓몬의 총 수 4 | k = n // 2 # ➌ 선택할 폰켓몬의 수 5 | return min(k, len(num_set)) # ➍ 중복을 제거한 폰켓몬의 종류 수와 선택할 폰켓몬의 수 중 작은값 반환 -------------------------------------------------------------------------------- /solution/57.py: -------------------------------------------------------------------------------- 1 | def solution(n): 2 | digits = list(str(n)) # ➊ 정수 n을 문자열로 변환하고 각 자릿수를 리스트로 저장합니다. 3 | digits.sort(reverse=True) # ➋ 내림차순으로 정렬합니다. 4 | answer = int("".join(digits)) # ➌ 정렬된 자릿수를 다시 하나의 문자열로 합쳐 정수로 변환합니다. 5 | return answer 6 | -------------------------------------------------------------------------------- /solution/01.py: -------------------------------------------------------------------------------- 1 | def solution(arr): 2 | arr.sort() 3 | return arr 4 | 5 | 6 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 7 | # print(solution([1,-5,2,4,3])) # 반환값 : [-5, 1, 2, 3, 4] 8 | # print(solution([2,1,1,3,2,5,4])) # 반환값 : [1, 1, 2, 2, 3, 4, 5] 9 | # print(solution([1,6,7])) # 반환값 : [1, 6, 7] 10 | -------------------------------------------------------------------------------- /solution/58.py: -------------------------------------------------------------------------------- 1 | def solution(array, commands): 2 | answer = [] 3 | for cmd in commands: 4 | i, j, k = cmd 5 | sliced_arr = array[i - 1 : j] # ➊ i번째부터 j번째까지 자르기 6 | sorted_arr = sorted(sliced_arr) # ➋ 자른 배열을 정렬하기 7 | answer.append(sorted_arr[k - 1]) # ➌ k번째 원소 구하기 8 | return answer 9 | -------------------------------------------------------------------------------- /solution/11.py: -------------------------------------------------------------------------------- 1 | def solution(s): 2 | stack = [ ] # 스택 초기화 3 | for c in s: 4 | if stack and stack[-1] == c: # ➊ 스택이 비어 있지 않고, 현재 문자와 스택의 맨 위 문자가 같으면 5 | stack.pop( ) # ➋ 스택의 맨 위 문자 제거 6 | else: 7 | stack.append(c) # ➌ 스택에 현재 문자 추가 8 | return int(not stack) # ➍ 스택이 비어 있으면 1, 그렇지 않으면 0 반환 9 | -------------------------------------------------------------------------------- /solution/02.py: -------------------------------------------------------------------------------- 1 | def solution(lst): 2 | unique_lst = list(set(lst)) # ➊ 중복값 제거 3 | unique_lst.sort(reverse=True) # ➋ 내림차순 정렬 4 | return unique_lst 5 | 6 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 7 | # print(solution([4, 2, 2, 1, 3, 4])) # 반환값 : [4, 3, 2, 1] 8 | # print(solution([2, 1, 1, 3, 2, 5, 4])) # 반환값 : [5, 4, 3, 2, 1] 9 | -------------------------------------------------------------------------------- /solution/36.py: -------------------------------------------------------------------------------- 1 | def solution(phone_book): 2 | # ➊ 전화번호부 정렬 3 | phone_book.sort( ) 4 | 5 | # ➋ 전화번호부에서 연속된 두 개의 전화번호 비교 6 | for i in range(len(phone_book) - 1): 7 | if phone_book[i + 1].startswith(phone_book[i]): 8 | return False 9 | 10 | # ➌ 모든 전화번호를 비교한 후에도 반환되지 않았다면, 접두어가 없는 경우이므로 True 반환 11 | return True 12 | -------------------------------------------------------------------------------- /solution/76.py: -------------------------------------------------------------------------------- 1 | def solution(land): 2 | # ➊ 각 행마다 이전 행에서의 최대 점수를 더해가며 최대 점수를 구합니다. 3 | for i in range(1, len(land)): 4 | for j in range(4): 5 | # ➋ 이전 행에서 현재 열의 값을 제외한 나머지 열들 중에서 가장 큰 값을 더해줍니다. 6 | land[i][j] += max(land[i - 1][:j] + land[i - 1][j + 1 :]) 7 | 8 | # ➌ 마지막 행에서 얻을 수 있는 최대 점수를 반환합니다. 9 | return max(land[-1]) 10 | -------------------------------------------------------------------------------- /solution/82.py: -------------------------------------------------------------------------------- 1 | def solution(d, budget): 2 | d.sort() # ➊ 배열 d를 오름차순으로 정렬 3 | count = 0 # ➋ 지원할 수 있는 부서의 개수를 세는 변수 4 | 5 | for amount in d: 6 | if budget < amount: 7 | break # ➌ 남은 예산이 신청한 금액보다 작으면 더 이상 지원할 수 없으므로 종료 8 | budget -= amount # ➍ 예산에서 신청한 금액을 차감 9 | count += 1 10 | 11 | return count if budget >= 0 else count - 1 12 | -------------------------------------------------------------------------------- /solution/60.py: -------------------------------------------------------------------------------- 1 | def solution(s): 2 | # ➊ 문자열 s를 파싱하여 리스트로 변환합니다. 3 | s = s[2:-2].split("}, {") 4 | s = sorted(s, key=len) 5 | answer = [] 6 | # ➋ 각 원소를 순회하면서 이전 원소와 차이가 나는 부분을 구합니다. 7 | for element in s: 8 | numbers = element.split(",") 9 | for number in numbers: 10 | if int(number) not in answer: 11 | answer.append(int(number)) 12 | 13 | return answer 14 | -------------------------------------------------------------------------------- /solution/09.py: -------------------------------------------------------------------------------- 1 | def solution(decimal): 2 | stack = [] 3 | while decimal > 0: 4 | remainder = decimal % 2 5 | stack.append(str(remainder)) 6 | decimal //= 2 7 | stack.reverse() 8 | return ''.join(stack) 9 | 10 | 11 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 12 | # print(solution(10)) #반환값 : 1010 13 | # print(solution(27)) #반환값 : 11011 14 | # print(solution(12345)) #반환값 : 11000000111001 15 | -------------------------------------------------------------------------------- /solution/08.py: -------------------------------------------------------------------------------- 1 | def solution(s): 2 | stack = [ ] 3 | for c in s: 4 | if c == "(": 5 | stack.append(c) 6 | elif c == ")": 7 | if not stack: 8 | return False 9 | else: 10 | stack.pop( ) 11 | if stack: 12 | return False 13 | else: 14 | return True 15 | 16 | 17 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 18 | #print(solution('(())()')) # 반환값 : True 19 | #print(solution('((())()')) # 반환값 : False 20 | -------------------------------------------------------------------------------- /solution/15.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def solution(N, K): 4 | #❶ 1부터 N까지의 번호를 deque에 추가 5 | queue = deque(range(1, N+1)) 6 | 7 | while len(queue) > 1: #❷ deque에 하나의 요소가 남을 때까지 8 | for _ in range(K-1): 9 | queue.append(queue.popleft()) #❸ K번째 요소를 찾기 위해 앞에서부터 제거하고 뒤에 추가 10 | queue.popleft() #❹ K번째 요소 제거 11 | return queue[0] #❺ 마지막으로 남은 요소 반환 12 | 13 | 14 | print(solution(5,2)) 15 | -------------------------------------------------------------------------------- /solution/83.py: -------------------------------------------------------------------------------- 1 | def solution(people, limit): 2 | people.sort() # ➊ 몸무게를 오름차순으로 정렬 3 | count = 0 # ➋ 필요한 보트 개수 4 | i = 0 # ➌ 가장 가벼운 사람을 가리키는 인덱스 5 | j = len(people) - 1 # ➍ 가장 무거운 사람을 가리키는 인덱스 6 | 7 | while i <= j: 8 | # ➎ 가장 무거운 사람과 가장 가벼운 사람을 같이 태울 수 있으면 두 사람 모두 보트에 태움 9 | if people[j] + people[i] <= limit: 10 | i += 1 11 | # ➏ 무거운 사람만 태울 수 있으면 무거운 사람만 보트에 태움 12 | j -= 1 13 | count += 1 14 | return count 15 | -------------------------------------------------------------------------------- /solution/75.py: -------------------------------------------------------------------------------- 1 | def solution(triangle): 2 | n = len(triangle) 3 | dp = [[0] * n for _ in range(n)] # ➊ dp 테이블 초기화 4 | 5 | # ➋ dp 테이블의 맨 아래쪽 라인 초기화 6 | for i in range(n): 7 | dp[n - 1][i] = triangle[n - 1][i] 8 | 9 | # ➌ 아래쪽 라인부터 올라가면서 dp 테이블 채우기 10 | for i in range(n - 2, -1, -1): 11 | for j in range(i + 1): 12 | dp[i][j] = max(dp[i + 1][j], dp[i + 1][j + 1]) + triangle[i][j] 13 | 14 | return dp[0][0] # 꼭대기에서의 최댓값 반환 15 | -------------------------------------------------------------------------------- /solution/20.py: -------------------------------------------------------------------------------- 1 | def solution(participant, completion): 2 | # ➊ 해시 테이블을 생성 3 | dic = { } 4 | 5 | # ➋ 참가자들의 이름을 해시 테이블에 추가 6 | for p in participant: 7 | if p in dic: 8 | dic[p] += 1 9 | else: 10 | dic[p] = 1 11 | 12 | # ➌ 완주한 선수들의 이름을 키로 하는 값을 1씩 감소 13 | for c in completion: 14 | dic[c] -= 1 15 | 16 | # ➍ 해시 테이블에 남아 있는 선수가 완주하지 못한 선수 17 | for key in dic.keys( ) : 18 | if dic[key] > 0: 19 | return key 20 | -------------------------------------------------------------------------------- /solution/05.py: -------------------------------------------------------------------------------- 1 | def solution(arr1, arr2): 2 | # ➊ 행렬 arr1과 arr2의 행과 열의 수 3 | r1, c1 = len(arr1), len(arr1[0]) 4 | r2, c2 = len(arr2), len(arr2[0]) 5 | 6 | # ➋ 결과를 저장할 2차원 리스트 초기화 7 | ret = [[0] * c2 for _ in range(r1)] 8 | 9 | # ➌ 첫 번째 행렬 arr1의 각 행과 두 번째 행렬 arr2의 각 열에 대해 10 | for i in range(r1): 11 | for j in range(c2): 12 | # ➍ 두 행렬의 데이터를 곱해 결과 리스트에 더해줌 13 | for k in range(c1): 14 | ret[i][j] += arr1[i][k] * arr2[k][j] 15 | return ret 16 | -------------------------------------------------------------------------------- /solution/85.py: -------------------------------------------------------------------------------- 1 | def solution(N, stations, W): 2 | answer = 0 3 | location = 1 # ➊ 현재 탐색하는 아파트의 위치 4 | idx = 0 # ➋ 설치된 기지국의 인덱스 5 | 6 | 7 | while location <= N: 8 | # ➌ 기지국이 설치된 위치에 도달한 경우 9 | if idx < len(stations) and location >= stations[idx] - W: 10 | location = stations[idx] + W + 1 11 | idx += 1 12 | # ➍ 기지국이 설치되지 않은 위치인 경우 13 | else: 14 | location += 2 * W + 1 # ➎ 기지국을 설치하고 해당 범위를 넘어감 15 | answer += 1 16 | return answer 17 | -------------------------------------------------------------------------------- /solution/35.py: -------------------------------------------------------------------------------- 1 | def solution(n, words): 2 | used_words = set( ) # ➊ 이미 사용한 단어를 저장하는 set 3 | prev_word = words[0][0] # ➋ 이전 단어의 마지막 글자 4 | 5 | for i, word in enumerate(words): 6 | # ➌ 이미 사용한 단어거나 첫 글자가 이전 단어와 일치하지 않으면 7 | if word in used_words or word[0] != prev_word: 8 | # ➍ 탈락하는 사람의 번호와 차례를 반환 9 | return [(i % n) + 1, (i // n) + 1] 10 | used_words.add(word) # ➎ 사용한 단어로 추가 11 | prev_word = word[-1] # ➏ 이전 단어의 마지막 글자 업데이트 12 | return [0, 0] # ➐ 모두 통과했을 경우 반환값 13 | -------------------------------------------------------------------------------- /solution/54.py: -------------------------------------------------------------------------------- 1 | def solution(s): 2 | counts = [0] * 26 # ❶ 알파벳 개수(26개)만큼 빈도수 배열 생성 3 | 4 | # ❷ 문자열의 각 문자에 대한 빈도수를 빈도수 배열에 저장 5 | for c in s: 6 | counts[ord(c) - ord("a")] += 1 7 | 8 | # ❸ 빈도수 배열을 순회하면서 정렬된 문자열을 생성 9 | sorted_str = "" 10 | for i in range(26): 11 | sorted_str += chr(i + ord("a")) * counts[i] 12 | 13 | return sorted_str 14 | 15 | 16 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 17 | print(solution('hello')) # 반환값 : 'ehllo' 18 | print(solution('algorithm')) # 반환값 : 'aghilmort' 19 | -------------------------------------------------------------------------------- /solution/03.py: -------------------------------------------------------------------------------- 1 | def solution(numbers): 2 | ret = [ ] # ➊ 빈 배열 생성 3 | # ➋ 두 수를 선택하는 모든 경우의 수를 반복문으로 구함 4 | for i in range(len(numbers)): 5 | for j in range(i + 1, len(numbers)): 6 | # ➌ 두 수를 더한 결과를 새로운 배열에 추가 7 | ret.append(numbers[i] + numbers[j]) 8 | # ➍ 중복된 값을 제거하고, 오름차순으로 정렬 9 | ret = sorted(set(ret)) 10 | return ret # ➎ 최종 결과 반환 11 | 12 | #TEST 코드입니다. 주석을 풀어서 확인해보세요 13 | # print(solution([2, 1, 3, 4, 1])) # 반환값 : [2, 3, 4, 5, 6, 7] 14 | # print(solution([5, 0, 2, 7])) # 반환값 : [2, 5, 7, 9, 12] 15 | -------------------------------------------------------------------------------- /solution/12.py: -------------------------------------------------------------------------------- 1 | def solution(prices): 2 | n = len(prices) 3 | answer = [0] * n # ➊ 가격이 떨어지지 않은 기간을 저장할 배열 4 | 5 | # 스택(stack)을 사용해 이전 가격과 현재 가격을 비교 6 | stack = [0] # ➋ 스택 초기화 7 | for i in range(1, n): 8 | while stack and prices[i] < prices[stack[-1]]: 9 | # ➌ 가격이 떨어졌으므로 이전 가격의 기간을 계산 10 | j = stack.pop( ) 11 | answer[j] = i - j 12 | stack.append(i) 13 | # ➍ 스택에 남아 있는 가격들은 가격이 떨어지지 않은 경우 14 | while stack: 15 | j = stack.pop( ) 16 | answer[j] = n - 1 - j 17 | return answer 18 | -------------------------------------------------------------------------------- /solution/65.py: -------------------------------------------------------------------------------- 1 | def solution(s): 2 | # ❶ 이진 변환 횟수를 저장하는 변수 3 | count_transform = 0 4 | # ❷ 제거된 모든 0의 개수를 저장하는 변수 5 | count_zero = 0 6 | 7 | # ❸ s가 '1'이 아닌 동안 계속 반복 8 | while s != "1": 9 | # ❹ 이진 변환 횟수를 1 증가 10 | count_transform += 1 11 | # ❺ s에서 '0'의 개수를 세어 count_zero에 누적 12 | count_zero += s.count("0") 13 | # ❻ s에서 '1'의 개수를 세고, 이를 이진수로 변환 14 | # 최종 결과값에서 "0b" 제거 15 | s = bin(s.count("1"))[2:] 16 | 17 | # ➐ 이진 변환 횟수와 제거된 모든 '0'의 개수를 리스트에 담아 반환 18 | return [count_transform, count_zero] 19 | -------------------------------------------------------------------------------- /solution/77.py: -------------------------------------------------------------------------------- 1 | def solution(money): 2 | # ➊ 점화식에 필요한 변수를 초기화 3 | n = len(money) 4 | dp1 = [0] * n 5 | dp2 = [0] * n 6 | 7 | # ➋ 첫 번째 집을 도둑질하는 경우 8 | dp1[0] = money[0] 9 | dp1[1] = money[0] 10 | for i in range(2, n - 1): 11 | dp1[i] = max(dp1[i - 1], dp1[i - 2] + money[i]) 12 | 13 | # ➌ 첫 번째 집을 도둑질하지 않는 경우 14 | dp2[1] = money[1] 15 | for i in range(2, n): 16 | dp2[i] = max(dp2[i - 1], dp2[i - 2] + money[i]) 17 | 18 | # ➍ 두 경우 중 최댓값 찾기 19 | answer = max(dp1[-2], dp2[-1]) 20 | return answer 21 | -------------------------------------------------------------------------------- /solution/84.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | def solution(k, tangerine): 4 | # ➊ 귤의 개수를 세는 Counter 객체 생성 5 | counter = Counter(tangerine) 6 | 7 | # ➋ 개수를 내림차순으로 정렬 8 | sorted_counts = sorted(counter.values(), reverse=True) 9 | 10 | num_types = 0 # ➌ 현재까지의 종류 수 11 | count_sum = 0 # ➍ 현재까지의 귤 개수 합 12 | 13 | for count in sorted_counts: 14 | count_sum += count 15 | num_types += 1 16 | 17 | # ➎ 귤 개수 합이 k 이상이 되는 순간 종료 18 | if count_sum >= k: 19 | break 20 | 21 | return num_types 22 | -------------------------------------------------------------------------------- /solution/67.py: -------------------------------------------------------------------------------- 1 | def solution(brown, yellow): 2 | # ❶ 격자의 총 개수 (갈색 격자 + 노란 격자) 3 | total_size = brown + yellow 4 | # ❷ 세로 길이의 범위는 3부터 (갈색 격자 + 노란 격자)의 제곱근 5 | for vertical in range(3, int(total_size**0.5) + 1): 6 | # ❸ 사각형 구성이 되는지 확인 7 | if total_size % vertical == 0: 8 | horizontal = (int)(total_size / vertical) # ❹ 사각형의 가로 길이 9 | # ❺ 카펫 형태로 만들 수 있는지 확인 10 | if brown == (horizontal + vertical - 2) * 2: 11 | return [horizontal, vertical] # ❻ [가로 길이, 세로 길이] 12 | return [] # ❼ 만약 답을 찾지 못했다면 빈 리스트를 반환 13 | -------------------------------------------------------------------------------- /solution/43.py: -------------------------------------------------------------------------------- 1 | def dfs(computers, visited, node): 2 | visited[node] = True # ➊ 현재 노드 방문 처리 3 | for idx, connected in enumerate(computers[node]): 4 | if connected and not visited[idx]: # ➋ 연결되어 있으며 방문하지 않은 노드라면 5 | dfs(computers, visited, idx) # ➌ 해당 노드를 방문하러 이동 6 | 7 | def solution(n, computers): 8 | answer = 0 9 | visited = [False] * n # ➍ 방문 여부를 저장하는 리스트 10 | for i in range(n): 11 | if not visited[i]: # ➎ 아직 방문하지 않은 노드라면 12 | dfs(computers, visited, i) # ➏ DFS로 연결된 노드들을 모두 방문하면서 네트워크 개수 증가 13 | answer += 1 14 | return answer 15 | -------------------------------------------------------------------------------- /solution/80.py: -------------------------------------------------------------------------------- 1 | def solution(amount): 2 | denominations = [1, 10, 50, 100] 3 | denominations.sort(reverse=True) # ❶ 화폐 단위를 큰 순서대로 정렬 4 | 5 | change = [] # ❷ 거스름돈을 담을 리스트 6 | 7 | for coin in denominations: 8 | while amount >= coin: # ❸ 해당 화폐 단위로 거스름돈을 계속 나눠줌 9 | change.append(coin) # ❹ 거스름돈 리스트 업데이트 10 | amount -= coin # ❺ 정산이 완료된 거스름돈 뺌 11 | # ❻ 거스름돈 리스트 반환 12 | return change 13 | 14 | 15 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 16 | # print(solution(123)) # 반환값 : [100, 10, 10, 1, 1, 1] 17 | # print(solution(350)) # 반환값 : [100, 100, 100, 50] 18 | -------------------------------------------------------------------------------- /solution/74.py: -------------------------------------------------------------------------------- 1 | def solution(n): 2 | # ➊ 바닥의 가로 길이가 1인 경우, 바닥을 채우는 방법의 수는 1 3 | if n == 1: 4 | return 1 5 | # ➋ 바닥의 가로 길이가 2인 경우, 바닥을 채우는 방법의 수는 2 6 | if n == 2: 7 | return 2 8 | # ➌ 동적 계획법을 위한 리스트 초기화 9 | # dp[i]는 가로 길이가 i일 때 바닥을 채우는 방법의 수 10 | dp = [0] * (n + 1) 11 | dp[1] = 1 12 | dp[2] = 2 13 | # ➍ 가로 길이가 3부터 n까지의 각각의 경우에 대해 바닥을 채우는 방법의 수를 구함 14 | for i in range(3, n + 1): 15 | # ➎ dp[i]는 dp[i-1]과 dp[i-2]를 더한 값 16 | dp[i] = (dp[i - 1] + dp[i - 2]) % 1000000007 17 | # ➏ 바닥의 가로 길이가 n일 때 바닥을 채우는 방법의 수인 dp[n]을 반환 18 | return dp[n] 19 | -------------------------------------------------------------------------------- /solution/22.py: -------------------------------------------------------------------------------- 1 | def solution(record): 2 | answer = [ ] 3 | uid = { } 4 | for line in record: # ➊ record의 각 줄을 하나씩 처리 5 | cmd = line.split(" ") 6 | if cmd[0] != "Leave": # ➋ Enter 또는 Change인 경우 7 | uid[cmd[1]] = cmd[2] 8 | for line in record: # ➌ record의 각 줄을 하나씩 처리 9 | cmd = line.split(" ") 10 | # ➍ 각 상태에 맞는 메시지를 answer에 저장 11 | if cmd[0] == "Enter": 12 | answer.append("%s님이 들어왔습니다." % uid[cmd[1]]) 13 | elif cmd[0] == "Change": 14 | pass 15 | else: 16 | answer.append("%s님이 나갔습니다." % uid[cmd[1]]) 17 | return answer 18 | -------------------------------------------------------------------------------- /errorcode/type_error.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: TypeError: unsupported operand type(s) for +: 'int' and 'str' 7 | # 의미: 두 개의 서로 다른 타입의 데이터를 연산하려고 할 때 발생하는 에러입니다. 8 | 9 | # 에러 발생 코드 10 | result = 5 + "10" 11 | 12 | # 해결 방법: 13 | # 연산 전에 데이터 타입을 일치시킵니다. 14 | # 예: 15 | # result = 5 + int("10") # 또는 str(5) + "10" 16 | -------------------------------------------------------------------------------- /errorcode/name_error.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: NameError: name 'variable_name' is not defined 7 | # 의미: 정의되지 않은 변수를 참조하려고 할 때 발생하는 에러입니다. 8 | 9 | # 에러 발생 코드 10 | print(variable_name) 11 | 12 | # 해결 방법: 13 | # 변수를 선언하거나 올바른 변수 이름을 사용합니다. 14 | # 예: 15 | # variable_name = "Hello, World!" 16 | # print(variable_name) 17 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/list_element_sum.py: -------------------------------------------------------------------------------- 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 | # Python의 내장 함수 sum을 이용하여 리스트의 모든 원소의 합을 손쉽게 계산할 수 있습니다. 8 | 9 | def list_element_sum(arr): 10 | return sum(arr) 11 | 12 | # 예시 사용법 13 | arr = [1, 2, 3, 4, 5] 14 | print(list_element_sum(arr)) # 출력: 15 15 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/string_reversal.py: -------------------------------------------------------------------------------- 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 | # Python에서는 문자열 슬라이싱을 이용해 이를 간단히 구현할 수 있으며, 8 | # s[::-1] 형태로 사용하면 문자열 s를 뒤집어 줍니다. 9 | 10 | def reverse_string(s): 11 | return s[::-1] 12 | 13 | # 예시 사용법 14 | print(reverse_string("Hello")) # 출력: "olleH" 15 | -------------------------------------------------------------------------------- /errorcode/string_number_addtion.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: TypeError: can only concatenate str (not "int") to str 7 | # 의미: 문자열과 숫자는 서로 더할 수 없으며, 이렇게 시도할 때 이 에러가 발생합니다. 8 | 9 | # 에러 발생 코드 10 | result = "string" + 123 11 | 12 | # 해결 방법: 13 | # 숫자를 문자열로 변환하여 오류를 방지할 수 있습니다. 14 | # 예: 15 | # result = "string" + str(123) 16 | -------------------------------------------------------------------------------- /solution/79.py: -------------------------------------------------------------------------------- 1 | def solution(strs, t): 2 | n = len(t) # ➊ 타겟 문자열 t의 길이 3 | dp = [float("inf")] * (n + 1) # ➋ 각 위치에서 필요한 최소 조각수를 저장할 배열(초기값은 INF로 함) 4 | dp[0] = 0 # ➌ 빈 문자열을 위해 필요한 최소 조각수는 0 5 | sizes = set(len(s) for s in strs) # ➍ strs 조각들의 길이를 저장한 집합 6 | 7 | for i in range(1, n + 1): # ➎ dp[i]부터 dp[n]까지 채우기 위한 반복문 8 | for size in sizes: # ➏ 각 str 조각의 문자열 길이에 대하여 9 | if ( 10 | i - size >= 0 and t[i - size : i] in strs 11 | ): # ➐ 이미 구한 해와 strs 조각을 추가해서 문자열을 만들 수 있다면 12 | dp[i] = min(dp[i], dp[i - size] + 1) # ➑ 해당 위치의 최소 조각수를 갱신 13 | return dp[n] if dp[n] < float("inf") else -1 # ➒ 최소 조각수를 반환 14 | -------------------------------------------------------------------------------- /errorcode/indentation_error.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: IndentationError: expected an indented block 7 | # 의미: 들여쓰기 오류가 발생했을 때 나타나는 에러입니다. 파이썬에서는 들여쓰기가 문법의 일부이므로 매우 중요합니다. 8 | 9 | # 에러 발생 코드 10 | for i in range(5): 11 | print(i) 12 | 13 | # 해결 방법: 14 | # 코드 블록을 올바르게 들여쓰기하여 에러를 해결합니다. 15 | # 예: 16 | # for i in range(5): 17 | # print(i) 18 | -------------------------------------------------------------------------------- /solution/17.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def solution(cards1, cards2, goal): 4 | # cards와 goal을 deque로 변환 5 | cards1 = deque(cards1) 6 | cards2 = deque(cards2) 7 | goal = deque(goal) 8 | 9 | # ➊ goal의 문자열을 순차적으로 순회 10 | while goal: 11 | if cards1 and cards1[0] == goal[0]: # ➋ card1의 front와 일치하는 경우 12 | cards1.popleft() 13 | goal.popleft() 14 | elif cards2 and cards2[0] == goal[0]: # ➌ card2의 front와 일치하는 경우 15 | cards2.popleft() 16 | goal.popleft() 17 | else: 18 | break # 일치하는 원소를 찾지 못했으므로 종료 19 | 20 | return "Yes" if not goal else "No" # ➍ goal이 비었으면 “Yes” 아니면 “No”를 반환 21 | -------------------------------------------------------------------------------- /solution/16.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | def solution(progresses, speeds): 4 | answer = [ ] 5 | n = len(progresses) 6 | # ➊ 각 작업의 배포 가능일 계산 7 | days_left = [math.ceil((100 - progresses[i]) / speeds[i]) for i in range(n)] 8 | 9 | count = 0 # ➋ 배포될 작업의 수 카운트 10 | max_day = days_left[0] # ➌ 현재 배포될 작업 중 가장 늦게 배포될 작업의 가능일 11 | 12 | for i in range(n): 13 | if days_left[i] <= max_day: # ➍ 배포 가능일이 가장 늦은 배포일보다 빠르면 14 | count += 1 15 | else: # ➎ 배포 예정일이 기준 배포일보다 느리면 16 | answer.append(count) 17 | count = 1 18 | max_day = days_left[i] 19 | 20 | answer.append(count) # ➏ 마지막으로 카운트된 작업들을 함께 배포 21 | return answer 22 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/interval_sum.py: -------------------------------------------------------------------------------- 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 | # 구간은 시작 인덱스와 종료 인덱스로 정의되며, sum 함수를 이용하여 해당 구간의 합을 계산할 수 있습니다. 8 | 9 | def interval_sum(arr, start, end): 10 | return sum(arr[start:end+1]) 11 | 12 | # 예시 사용법 13 | arr = [1, 2, 3, 4, 5] 14 | print(interval_sum(arr, 1, 3)) # 출력: 9 15 | -------------------------------------------------------------------------------- /solution/69.py: -------------------------------------------------------------------------------- 1 | def solution(keyinput, board): 2 | # ❶ 캐릭터의 초기 위치 3 | x, y = 0, 0 4 | # ❷ 각 방향에 대한 움직임 5 | moves = {"up": [0, 1], "down": [0, -1], "left": [-1, 0], "right": [1, 0]} 6 | # ❸ 게임 경계좌표 7 | width, height = board[0] // 2, board[1] // 2 8 | 9 | # ❹ 보드의 경계좌표를 벗어나는지 확인하는 함수 10 | def is_in_bounds(x, y, dx, dy): 11 | return -width <= x + dx <= width and -height <= y + dy <= height 12 | 13 | for key in keyinput: 14 | # ❺ 방향키에 따른 오프셋 15 | dx, dy = moves[key] 16 | # ❻ 게임 맵의 크기를 벗어나지 않는지 확인 17 | if is_in_bounds(x, y, dx, dy): 18 | x += dx 19 | y += dy 20 | 21 | # ❼ 캐릭터의 위치를 반환합니다. 22 | return [x, y] 23 | -------------------------------------------------------------------------------- /solution/59.py: -------------------------------------------------------------------------------- 1 | import functools 2 | 3 | def compare(a, b): 4 | # ➊ 각 수를 문자열로 바꾼 뒤, 조합하여 비교하여 더 큰 수를 반환합니다. 5 | # 예. a=3, b=30 -> t1='330', t2='303' -> int(t1) > int(t2) -> 1 반환 6 | t1 = str(a) + str(b) 7 | t2 = str(b) + str(a) 8 | # t1이 크다면 1, t2가 크다면 -1, 같으면 0 9 | return (int(t1) > int(t2)) - (int(t1) < int(t2)) 10 | 11 | def solution(numbers): 12 | # ➋ reverse = True를 이용해 내림차순으로 정렬합니다. 13 | sorted_nums = sorted( 14 | numbers, key=functools.cmp_to_key(compare), reverse=True 15 | ) 16 | # ➌ 각 정렬된 수를 문자열로 이어붙인 뒤, int로 변환한 값을 문자열로 다시 변환하여 반환합니다. 17 | answer = "".join(str(x) for x in sorted_nums) 18 | return "0" if int(answer) == 0 else answer 19 | -------------------------------------------------------------------------------- /errorcode/import_missing_module.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: ModuleNotFoundError: No module named 'missing_module' 7 | # 의미: 임포트하려는 모듈이 설치되지 않았거나 존재하지 않을 때 발생합니다. 8 | 9 | # 에러 발생 코드 10 | import missing_module 11 | 12 | # 해결 방법: 13 | # 모듈이 설치되어 있는지 확인하고, 필요한 경우 모듈을 설치하여 오류를 방지할 수 있습니다. 14 | # 예: 15 | # pip install missing_module (터미널에서 실행) 16 | # 또는 존재하는 다른 모듈을 임포트합니다. 17 | -------------------------------------------------------------------------------- /solution/06.py: -------------------------------------------------------------------------------- 1 | def solution(N, stages): 2 | # ➊ 스테이지별 도전자 수를 구함 3 | challenger = [0] * (N + 2) 4 | for stage in stages: 5 | challenger[stage] += 1 6 | 7 | # ➋ 스테이지별 실패한 사용자 수를 계산 8 | fails = { } 9 | total = len(stages) 10 | 11 | # ➌ 각 스테이지를 순회하며, 실패율을 계산 12 | for i in range(1, N + 1): 13 | if challenger[i] == 0 : # ➍ 도전한 사람이 없는 경우, 실패율은 0 14 | fails[i] = 0 15 | else: 16 | fails[i] = challenger[i] / total # ➎ 실패율을 구함 17 | total -= challenger[i] # ➏ 다음 스테이지 실패율을 구하기 위해 현재 스테이지의 인원을 뺌 18 | 19 | # ➐ 실패율이 높은 스테이지부터 내림차순으로 정렬 20 | result = sorted(fails, key=lambda x : fails[x], reverse=True) 21 | 22 | return result 23 | -------------------------------------------------------------------------------- /errorcode/attribute_error.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: AttributeError: 'list' object has no attribute 'size' 7 | # 의미: 객체에 없는 속성이나 메서드를 호출하려고 할 때 발생하는 에러입니다. 8 | 9 | # 에러 발생 코드 10 | my_list = [1, 2, 3] 11 | print(my_list.size()) 12 | 13 | # 해결 방법: 14 | # 올바른 메서드나 속성 이름을 사용하거나, 해당 객체 타입에 적합한 메서드/속성을 사용합니다. 15 | # 예: 16 | # print(len(my_list)) # 리스트의 길이를 얻으려면 len 함수를 사용합니다. 17 | -------------------------------------------------------------------------------- /errorcode/invalid_syntax.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: SyntaxError: invalid syntax 7 | # 의미: 코드에 문법 오류가 있을 때 발생하는 에러입니다. 이는 변수명 오타, 괄호 누락 등 다양한 요인으로 인해 발생할 수 있습니다. 8 | 9 | # 에러 발생 코드 10 | for i in range(0, 10) 11 | print(i) 12 | 13 | # 해결 방법: 14 | # 코드를 검토하고 문법 오류를 수정합니다. 예를 들어, 위의 경우에는 for 문 뒤에 콜론(:)이 누락되었습니다. 15 | # 예: 16 | # for i in range(0, 10): 17 | # print(i) 18 | -------------------------------------------------------------------------------- /errorcode/pop-from_empty_list.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: IndexError: pop from empty list 7 | # 의미: 비어 있는 리스트에서 요소를 pop(제거)하려고 할 때 발생합니다. 8 | 9 | # 에러 발생 코드 10 | my_list = [] 11 | my_list.pop() 12 | 13 | # 해결 방법: 14 | # 리스트가 비어 있지 않은지 확인하여 오류를 방지할 수 있습니다. 15 | # 예: 16 | # if my_list: 17 | # my_list.pop() 18 | # else: 19 | # print("Cannot pop from an empty list") 20 | -------------------------------------------------------------------------------- /errorcode/mutable_dict_key.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: TypeError: unhashable type: 'list' 7 | # 의미: 리스트와 같은 변경 가능한 객체를 딕셔너리의 키로 사용하려고 할 때 발생합니다. 딕셔너리 키는 해시 가능해야 하며, 리스트는 변경이 가능하므로 해시 가능하지 않습니다. 8 | 9 | # 에러 발생 코드 10 | my_dict = {[1, 2]: "value"} 11 | 12 | # 해결 방법: 13 | # 변경 불가능한 타입(예: 문자열, 튜플)을 딕셔너리 키로 사용하여 오류를 방지할 수 있습니다. 14 | # 예: 15 | # my_dict = {(1, 2): "value"} # 튜플을 키로 사용 16 | -------------------------------------------------------------------------------- /errorcode/value_error.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: ValueError: invalid literal for int() with base 10: 'ten' 7 | # 의미: 올바르지 않은 값이 주어졌을 때 발생하는 에러입니다. 8 | 9 | # 에러 발생 코드 10 | result = int('ten') 11 | 12 | # 해결 방법: 13 | # 올바른 값을 제공하거나, try-except 블록을 사용하여 오류를 처리합니다. 14 | # 예: 15 | # try: 16 | # result = int('ten') 17 | # except ValueError: 18 | # print("Invalid input") 19 | -------------------------------------------------------------------------------- /errorcode/function_argument_missing.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: TypeError: function_name() missing 1 required positional argument: 'arg' 7 | # 의미: 함수 호출 시 필요한 인자가 누락되었을 때 발생합니다. 8 | 9 | def function_name(arg): 10 | print(arg) 11 | 12 | # 에러 발생 코드 13 | function_name() 14 | 15 | # 해결 방법: 16 | # 함수 호출 시 필요한 모든 인자를 제공하여 오류를 방지할 수 있습니다. 17 | # 예: 18 | # function_name(arg="Hello") 19 | -------------------------------------------------------------------------------- /errorcode/key_error.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: KeyError: 'key' 7 | # 의미: 딕셔너리에서 존재하지 않는 키를 참조하려고 할 때 발생하는 에러입니다. 8 | 9 | # 에러 발생 코드 10 | my_dict = {'a': 1, 'b': 2} 11 | print(my_dict['c']) 12 | 13 | # 해결 방법: 14 | # 딕셔너리에 키가 있는지 확인하거나 try-except 블록을 사용하여 에러를 처리합니다. 15 | # 예: 16 | # if 'c' in my_dict: 17 | # print(my_dict['c']) 18 | # else: 19 | # print("Key not found") 20 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/remove_duplicates.py: -------------------------------------------------------------------------------- 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 | # Python에서는 set 자료형을 이용하여 쉽게 중복을 제거할 수 있으며, 8 | # 이를 다시 list로 변환하여 중복이 제거된 리스트를 얻을 수 있습니다. 9 | 10 | def remove_duplicates(arr): 11 | return list(set(arr)) 12 | 13 | # 예시 사용법 14 | arr = [1, 2, 2, 3, 3, 4] 15 | print(remove_duplicates(arr)) # 출력: [1, 2, 3, 4] (순서는 변할 수 있음) 16 | -------------------------------------------------------------------------------- /errorcode/index_out_of_range.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: IndexError: list index out of range 7 | # 의미: 리스트의 범위를 벗어나는 인덱스에 액세스하려고 할 때 발생합니다. 8 | 9 | # 에러 발생 코드 10 | my_list = [1, 2, 3] 11 | print(my_list[3]) 12 | 13 | # 해결 방법: 14 | # 리스트의 길이를 확인하고, 범위 내의 인덱스만 사용하여 오류를 방지할 수 있습니다. 15 | # 예: 16 | # if len(my_list) > 3: 17 | # print(my_list[3]) 18 | # else: 19 | # print("Index out of range") 20 | -------------------------------------------------------------------------------- /solution/70.py: -------------------------------------------------------------------------------- 1 | def solution(str1, str2): 2 | # ❶ 두 문자열의 길이를 저장 3 | m = len(str1) 4 | n = len(str2) 5 | 6 | # ❷ LCS를 저장할 테이블 초기화 7 | dp = [[0] * (n + 1) for _ in range(m + 1)] 8 | 9 | # ❸ 동적 프로그래밍을 통해 LCS 길이 계산 10 | for i in range(1, m + 1): 11 | for j in range(1, n + 1): 12 | # ❹ 현재 비교하는 문자가 같으면 13 | if str1[i - 1] == str2[j - 1]: 14 | dp[i][j] = dp[i - 1][j - 1] + 1 15 | # ❺ 현재 비교하는 문자가 같지 않으면 16 | else: 17 | dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) 18 | 19 | # ❻ LCS 길이 반환 20 | return dp[m][n] 21 | 22 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 23 | # print(solution("ABCBDAB","BDCAB")) # 반환값 : 4 24 | # print(solution("AGGTAB","GXTXAYB")) # 반환값 : 4 25 | -------------------------------------------------------------------------------- /solution/04.py: -------------------------------------------------------------------------------- 1 | def solution(answers): 2 | # ➊ 수포자들의 패턴 3 | patterns = [ 4 | [1, 2, 3, 4, 5], 5 | [2, 1, 2, 3, 2, 4, 2, 5], 6 | [3, 3, 1, 1, 2, 2, 4, 4, 5, 5] 7 | ] 8 | # ➋ 수포자들의 점수를 저장할 리스트 9 | scores = [0] * 3 10 | # ➌ 각 수포자의 패턴과 정답이 얼마나 일치하는지 확인 11 | for i, answer in enumerate(answers): 12 | for j, pattern in enumerate(patterns): 13 | if answer == pattern[i % len(pattern)]: 14 | scores[j] += 1 15 | # ➍ 가장 높은 점수 저장 16 | max_score = max(scores) 17 | # ➎ 가장 높은 점수를 가진 수포자들의 번호를 찾아서 리스트에 담음 18 | highest_scores = [ ] 19 | for i, score in enumerate(scores): 20 | if score == max_score: 21 | highest_scores.append(i + 1) 22 | return highest_scores 23 | -------------------------------------------------------------------------------- /solution/21.py: -------------------------------------------------------------------------------- 1 | 2 | def solution(want, number, discount): 3 | # ➊ want 리스트를 딕셔너리로 변환 4 | want_dict = { } 5 | for i in range(len(want)): 6 | want_dict[want[i]] = number[i] 7 | 8 | answer = 0 # ➋ 총 일수를 계산할 변수 초기화 9 | 10 | # ➌ 특정일 i에 회원가입 시 할인받을 수 있는 품목 체크 11 | for i in range(len(discount) - 9): 12 | discount_10d = { } # ➍ i일 회원가입 시 할인받는 제품 및 개수를 담을 딕셔너리 13 | 14 | # ➎ i일 회원가입 시 할인받는 제품 및 개수로 딕셔너리 구성 15 | for j in range(i, i + 10): 16 | if discount[j] in want_dict: 17 | discount_10d[discount[j]] = discount_10d.get(discount[j], 0) + 1 18 | 19 | # ➏ 할인하는 상품의 개수가 원하는 수량과 일치하면 정답 변수에 1 추가 20 | if discount_10d == want_dict: 21 | answer += 1 22 | 23 | return answer 24 | -------------------------------------------------------------------------------- /errorcode/value_error_in_list.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: ValueError: 'x' is not in list 7 | # 의미: 리스트에서 존재하지 않는 요소를 remove 메소드를 사용하여 삭제하려 할 때 발생하는 에러입니다. 8 | 9 | # 에러 발생 코드 10 | my_list = [1, 2, 3] 11 | my_list.remove('x') 12 | 13 | # 해결 방법: 14 | # 요소가 리스트에 있는지 확인하거나 try-except 블록을 사용하여 에러를 처리합니다. 15 | # 예: 16 | # if 'x' in my_list: 17 | # my_list.remove('x') 18 | # else: 19 | # print("Value not found in the list") 20 | -------------------------------------------------------------------------------- /errorcode/division_by_zero.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | #에러 메시지: ZeroDivisionError: division by zero 7 | # 의미: 숫자를 0으로 나눌 때 발생합니다. 수학적으로 0으로 나누는 것은 정의되지 않았으므로 프로그램이 이를 허용하지 않습니다. 8 | 9 | # 에러 발생 코드 10 | result = 10 / 0 11 | 12 | # 해결 방법: 13 | # 나누는 숫자(분모)가 0이 아닌지 확인하는 조건문을 사용하여 오류를 방지할 수 있습니다. 14 | # 예: 15 | # denominator = 0 16 | # if denominator != 0: 17 | # result = 10 / denominator 18 | # else: 19 | # print("Denominator cannot be zero.") 20 | -------------------------------------------------------------------------------- /solution/66.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | def solution(topping): 4 | # ❶ 결과값을 저장할 변수 초기화 5 | split_count = 0 6 | 7 | # ❷ 토핑의 개수를 세어서 딕셔너리에 저장 8 | topping_counter = Counter(topping) 9 | 10 | # ❸ 절반에 속한 토핑의 종류를 저장할 집합 11 | half_topping_set = set() 12 | 13 | # ❹ 롤케이크를 하나씩 절반에 넣으면서 확인 14 | for t in topping: 15 | # ❺ 절반에 토핑을 추가하고, 해당 토핑의 전체 개수를 줄임 16 | half_topping_set.add(t) 17 | topping_counter[t] -= 1 18 | 19 | # ❻ 토핑의 전체 개수가 0이면 딕셔너리에서 제거 20 | if topping_counter[t] == 0: 21 | topping_counter.pop(t) 22 | 23 | # ❼ 토핑의 종류의 수가 같다면 24 | if len(half_topping_set) == len(topping_counter): 25 | split_count += 1 26 | 27 | # ❽ 공평하게 나눌 수 있는 방법의 수 반환 28 | return split_count 29 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/combination_generation.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 조합 생성 알고리즘은 주어진 리스트에서 n개의 원소를 선택하는 모든 가능한 조합을 생성하는 알고리즘입니다. 7 | # itertools 모듈의 combinations 함수를 이용하여 리스트에서 n개의 원소를 선택하는 모든 조합을 생성할 수 있습니다. 8 | 9 | from itertools import combinations 10 | 11 | def generate_combinations(arr, n): 12 | return list(combinations(arr, n)) 13 | 14 | # 예시 사용법 15 | arr = [1, 2, 3] 16 | print(generate_combinations(arr, 2)) # 출력: [(1, 2), (1, 3), (2, 3)] 17 | -------------------------------------------------------------------------------- /solution/71.py: -------------------------------------------------------------------------------- 1 | # 답안 코드는 lis라고 되어있는데, 다른 문제와 통일하기 위해 lis로 구현했습니다. lis로 구현하신 경우 Test 코드에서도 lis로 이름을 바꿔주셔야 실행 됩니다. 2 | 3 | def solution(nums): 4 | n = len(nums) 5 | 6 | # ❶ dp[i]는 nums[i]를 마지막으로 하는 LIS의 길이를 저장하는 배열입니다. 7 | dp = [1] * n 8 | 9 | for i in range(1, n): 10 | for j in range(i): 11 | # ❷ nums[i]와 nums[j]를 비교하여, nums[i]가 더 큰 경우에만 처리합니다. 12 | if nums[i] > nums[j]: 13 | # ❸ nums[i]를 이용하여 만든 부분 수열의 길이와 14 | # nums[j]를 이용하여 만든 부분 수열의 길이 + 1 중 최댓값을 저장합니다. 15 | dp[i] = max(dp[i], dp[j] + 1) 16 | 17 | # ❹ dp 배열에서 최댓값을 찾아 최장 증가 부분 수열의 길이를 반환합니다. 18 | return max(dp) 19 | 20 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 21 | # print(solution([1, 4, 2, 3, 1, 5, 7, 3])) # 반환값 : 5 22 | # print(solution([3, 2, 1])) # 반환값 : 1 23 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/permutation_generation.py: -------------------------------------------------------------------------------- 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 | # itertools 모듈의 permutations 함수를 이용하여 리스트의 모든 순열을 생성할 수 있습니다. 8 | 9 | from itertools import permutations 10 | 11 | def generate_permutations(arr): 12 | return list(permutations(arr)) 13 | 14 | # 예시 사용법 15 | arr = [1, 2, 3] 16 | print(generate_permutations(arr)) # 출력: [(1, 2, 3), (1, 3, 2), (2, 1, 3), (2, 3, 1), (3, 1, 2), (3, 2, 1)] 17 | -------------------------------------------------------------------------------- /errorcode/missing_dict_key.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: KeyError: 'missing_key' 7 | # 의미: 사전에서 존재하지 않는 키를 사용하여 값을 검색하려고 할 때 발생합니다. 8 | 9 | # 에러 발생 코드 10 | my_dict = {"key1": "value1", "key2": "value2"} 11 | print(my_dict["missing_key"]) 12 | 13 | # 해결 방법: 14 | # 사전에 키가 있는지 확인하는 'in' 연산자를 사용하여 오류를 방지할 수 있습니다. 15 | # 예: 16 | # if "missing_key" in my_dict: 17 | # print(my_dict["missing_key"]) 18 | # else: 19 | # print("Key not found in the dictionary") 20 | -------------------------------------------------------------------------------- /solution/55.py: -------------------------------------------------------------------------------- 1 | def solution(arr1, arr2): 2 | merged = [] # 정렬된 배열을 저장할 리스트 생성 3 | i, j = 0, 0 # 두 배열의 인덱스 초기화 4 | 5 | # 두 배열을 순회하면서 정렬된 배열을 생성 6 | while i < len(arr1) and j < len(arr2): 7 | if arr1[i] <= arr2[j]: 8 | merged.append(arr1[i]) 9 | i += 1 10 | else: 11 | merged.append(arr2[j]) 12 | j += 1 13 | 14 | # arr1이나 arr2 중 남아있는 원소들을 정렬된 배열 뒤에 추가 15 | while i < len(arr1): 16 | merged.append(arr1[i]) 17 | i += 1 18 | while j < len(arr2): 19 | merged.append(arr2[j]) 20 | j += 1 21 | 22 | return merged 23 | 24 | 25 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 26 | # print(solution([1, 3, 5], [2, 4, 6])) # 반환값 : [1, 2, 3, 4, 5, 6] 27 | # print(solution([1, 2, 3], [4, 5, 6])) # 반환값 : [1, 2, 3, 4, 5, 6] 28 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/merge_list_to_dictionary.py: -------------------------------------------------------------------------------- 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 | # Python에서는 dict 함수와 zip 함수를 이용하여 두 리스트를 딕셔너리로 병합할 수 있습니다. 8 | # 주의할 점은 두 리스트의 길이가 동일해야 합니다. 9 | 10 | def merge_list_to_dictionary(keys, values): 11 | return dict(zip(keys, values)) 12 | 13 | # 예시 사용법 14 | keys = ["a", "b", "c"] 15 | values = [1, 2, 3] 16 | print(merge_list_to_dictionary(keys, values)) # 출력: {'a': 1, 'b': 2, 'c': 3} 17 | -------------------------------------------------------------------------------- /solution/78.py: -------------------------------------------------------------------------------- 1 | def solution(board): 2 | # ➊ 주어진 2차원 보드의 행과 열의 개수를 변수에 저장합니다. 3 | ROW, COL = len(board), len(board[0]) 4 | 5 | # ➋ 각 행과 열을 순회하며 최적의 정사각형을 찾습니다. 6 | for i in range(1, ROW): 7 | for j in range(1, COL): 8 | # ➌ 현재 위치의 값이 1인 경우를 확인합니다. 9 | if board[i][j] == 1: 10 | # ➍ 현재 위치에서 위, 왼쪽, 대각선 왼쪽 위의 값들을 가져옵니다. 11 | up, left, up_left = ( 12 | board[i - 1][j], 13 | board[i][j - 1], 14 | board[i - 1][j - 1], 15 | ) 16 | 17 | # ➎ 현재 위치의 값을 이전 위치들의 값들 중 가장 작은 값에 1을 더한 값으로 업데이트합니다. 18 | board[i][j] = min(up, left, up_left) + 1 19 | 20 | # ➏ 보드에서 가장 큰 값(최대 정사각형의 한 변의 길이)을 찾습니다. 21 | max_val = max(max(row) for row in board) 22 | 23 | # ➐ 최대 정사각형의 넓이를 반환합니다. 24 | return max_val**2 25 | -------------------------------------------------------------------------------- /solution/29.py: -------------------------------------------------------------------------------- 1 | def solution(enroll, referral, seller, amount): 2 | # ➊ parent 딕셔너리 key는 enroll의 노드, value는 referral의 노드로 구성됨 3 | parent = dict(zip(enroll, referral)) 4 | 5 | # ➋ total 딕셔너리 생성 및 초기화 6 | total = {name: 0 for name in enroll} 7 | 8 | # ➌ seller 리스트와 amount 리스트를 이용하여 이익 분배 9 | for i in range(len(seller)): 10 | # ➍ 판매자가 판매한 총 금액 계산 11 | money = amount[i] * 100 12 | cur_name = seller[i] 13 | # ➎ 판매자부터 차례대로 상위 노드로 이동하며 이익 분배 14 | while money > 0 and cur_name != "-": 15 | # ➏ 현재 판매자가 받을 금액 계산(10%를 제외한 금액) 16 | total[cur_name] += money - money // 10 17 | cur_name = parent[cur_name] 18 | # ➐ 10%를 제외한 금액 계산 19 | money //= 10 20 | 21 | # ➑ enroll 리스트의 모든 노드에 대해 해당하는 이익을 리스트로 반환 22 | return [total[name] for name in enroll] 23 | -------------------------------------------------------------------------------- /solution/49.py: -------------------------------------------------------------------------------- 1 | # 백트래킹을 위한 DFS 2 | def dfs(cur_k, cnt, dungeons, visited): 3 | answer_max = cnt 4 | for i in range(len(dungeons)): 5 | # ➊ 현재 피로도(cur_k)가 i번째 던전의 최소 필요 피로도보다 크거나 같고, 6 | # i번째 던전을 방문한 적이 없다면 7 | if cur_k >= dungeons[i][0] and visited[i] == 0: 8 | visited[i] = 1 # i번째 던전을 방문 처리 9 | # ➋ 현재까지의 최대 탐험 가능 던전 수와 10 | # i번째 던전에서 이동할 수 있는 최대 탐험 가능 던전 수 중 큰 값을 선택하여 업데이트 11 | answer_max = max( 12 | answer_max, dfs(cur_k - dungeons[i][1], cnt + 1, dungeons, visited) 13 | ) 14 | visited[i] = 0 15 | return answer_max 16 | 17 | # 최대 탐험 가능 던전 수를 계산하는 함수 18 | def solution(k, dungeons): 19 | visited = [0] * len(dungeons) # ➌ 던전 방문 여부를 저장할 지역 배열 20 | answer_max = dfs(k, 0, dungeons, visited) # ➍ DFS 함수 호출 21 | return answer_max 22 | -------------------------------------------------------------------------------- /solution/23.py: -------------------------------------------------------------------------------- 1 | def solution(genres, plays): 2 | answer = [ ] 3 | genres_dict = { } 4 | play_dict = { } 5 | 6 | # ➊ 장르별 총 재생 횟수와 각 곡의 재생 횟수를 저장 7 | for i in range(len(genres)): 8 | genre = genres[i] 9 | play = plays[i] 10 | if genre not in genres_dict: 11 | genres_dict[genre] = [ ] 12 | play_dict[genre] = 0 13 | genres_dict[genre].append((i, play)) 14 | play_dict[genre] += play 15 | 16 | # ➋ 총 재생 횟수가 많은 장르순으로 정렬 17 | sorted_genres = sorted(play_dict.items( ) , key=lambda x: x[1], reverse=True) 18 | 19 | # ➌ 각 장르 내에서 노래를 재생 횟수 순으로 정렬해 최대 2곡까지 선택 20 | for genre, _ in sorted_genres: 21 | sorted_songs = sorted(genres_dict[genre], key=lambda x: (-x[1], x[0])) 22 | answer.extend([idx for idx, _ in sorted_songs[:2]]) 23 | 24 | return answer 25 | -------------------------------------------------------------------------------- /solution/25.py: -------------------------------------------------------------------------------- 1 | from itertools import combinations 2 | from collections import Counter 3 | 4 | def solution(orders, course): 5 | answer = [ ] 6 | 7 | for c in course: # ➊ 각 코스 요리 길이에 대해 8 | menu = [ ] 9 | for order in orders: # 모든 주문에 대해 10 | comb = combinations( 11 | sorted(order), c 12 | ) # ➋ 조합(combination)을 이용해 가능한 메뉴 구성을 모두 구함 13 | menu += comb 14 | 15 | counter = Counter(menu) # ➌ 각 메뉴 구성이 몇 번 주문되었는지 세어줌 16 | if ( 17 | len(counter) != 0 and max(counter.values( ) ) != 1 18 | ): # ➍ 가장 많이 주문된 구성이 1번 이상 주문된 경우 19 | for m, cnt in counter.items( ) : 20 | if cnt == max(counter.values( ) ): # ➎ 가장 많이 주문된 구성을 찾아서 21 | answer.append("".join(m)) # ➏ 정답 리스트에 추가 22 | 23 | return sorted(answer) # ➐ 오름차순 정렬 후 반환 24 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/string_to_number_conversion.py: -------------------------------------------------------------------------------- 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 | # Python에서는 int() 함수를 사용하여 문자열을 정수로, float() 함수를 사용하여 문자열을 실수로 변환할 수 있습니다. 8 | 9 | def string_to_number(s): 10 | try: 11 | return int(s) 12 | except ValueError: 13 | try: 14 | return float(s) 15 | except ValueError: 16 | return "변환 불가" 17 | 18 | # 예시 사용법 19 | print(string_to_number("123")) # 출력: 123 20 | -------------------------------------------------------------------------------- /errorcode/recursion_limit_exceed.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 에러 메시지: RecursionError: maximum recursion depth exceeded 7 | # 의미: 재귀 함수 호출이 너무 깊어져 Python의 최대 재귀 깊이 제한을 초과할 때 발생합니다. 8 | 9 | # 에러 발생 코드 10 | def recursive_function(n): 11 | return recursive_function(n+1) 12 | 13 | recursive_function(0) 14 | 15 | # 해결 방법: 16 | # 재귀 함수에 종료 조건을 추가하여 오류를 방지할 수 있습니다. 17 | # 예: 18 | # def recursive_function(n): 19 | # if n == 100: # 종료 조건 20 | # return n 21 | # return recursive_function(n+1) 22 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/time_measurement.py: -------------------------------------------------------------------------------- 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 | # Python의 time 모듈을 사용하여 특정 코드 블록 또는 함수의 실행 시간을 측정할 수 있습니다. 8 | 9 | import time 10 | 11 | def measure_time(func, *args): 12 | start_time = time.time() 13 | func(*args) 14 | end_time = time.time() 15 | return end_time - start_time 16 | 17 | # 예시 사용법 18 | def sample_function(): 19 | for _ in range(1000000): 20 | pass 21 | 22 | print(measure_time(sample_function)) # 출력: 실행 시간(초) 23 | -------------------------------------------------------------------------------- /solution/10.py: -------------------------------------------------------------------------------- 1 | def solution(s): 2 | answer = 0 3 | n = len(s) 4 | for i in range(n): 5 | stack = [ ] 6 | for j in range(n): 7 | # ➊ 괄호 문자열을 회전시키면서 참조 8 | c = s[(i + j) % n] 9 | if c == "(" or c == "[" or c == "{": # ➋ 열린 괄호는 푸시 10 | stack.append(c) 11 | else: 12 | if not stack: # ➌ 짝이 맞지 않는 경우 13 | break 14 | 15 | # ➍ 닫힌 괄호는 스택의 top과 짝이 맞는지 비교 16 | if c == ")" and stack[-1] == "(": 17 | stack.pop( ) 18 | elif c == "]" and stack[-1] == "[": 19 | stack.pop( ) 20 | elif c == "}" and stack[-1] == "{": 21 | stack.pop( ) 22 | else: 23 | break 24 | else: # ➎ for문이 break에 의해 끝나지 않고 끝까지 수행된 경우 25 | if not stack: 26 | answer += 1 27 | return answer 28 | -------------------------------------------------------------------------------- /solution/47.py: -------------------------------------------------------------------------------- 1 | def solution(N): 2 | results = [] # ➊ 조합 결과를 담을 리스트 3 | 4 | def backtrack(sum, selected_nums, start): 5 | if sum == 10: # ❷ 합이 10이 되면 결과 리스트에 추가 6 | results.append(selected_nums) 7 | return 8 | 9 | for i in range(start, N + 1): # ❸ 다음에 선택할 수 있는 숫자들을 하나씩 선택하면서 10 | if sum + i <= 10: # ❹ 선택한 숫자의 합이 10보다 작거나 같으면 11 | backtrack( 12 | sum + i, selected_nums + [i], i + 1 13 | ) # ❺ 백트래킹 함수를 재귀적으로 호출합니다. 14 | 15 | backtrack(0, [], 1) # ❻ 백트래킹 함수 호출 16 | return results # ❼ 조합 결과 반환 17 | 18 | 19 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 20 | # print(solution(5)) # 반환값 : [[1, 2, 3, 4], [1, 4, 5], [2, 3, 5]] 21 | # print(solution(2)) # 반환값 : [] 22 | # print(solution(7)) # 반환값 : [[1, 2, 3, 4], [1, 2, 7], [1, 3, 6], [1, 4, 5], [2, 3, 5], [3, 7], [4, 6]] 23 | -------------------------------------------------------------------------------- /solution/46.py: -------------------------------------------------------------------------------- 1 | def solution(n, wires): 2 | # ➊ 그래프 생성 3 | graph = [[] for _ in range(n + 1)] 4 | for a, b in wires: 5 | graph[a].append(b) 6 | graph[b].append(a) 7 | 8 | # ➋ 깊이 우선 탐색 함수 9 | def dfs(node, parent): 10 | cnt = 1 11 | for child in graph[node]: # ➌ 현재 노드의 자식 노드들에 방문 12 | if child != parent: # ➍ 부모 노드가 아닌 경우에만 탐색 13 | cnt += dfs(child, node) 14 | return cnt 15 | 16 | min_diff = float("inf") 17 | for a, b in wires: 18 | # ➎ 간선 제거 19 | graph[a].remove(b) 20 | graph[b].remove(a) 21 | 22 | # ➏ 각 전력망 송전탑 개수 계산 23 | cnt_a = dfs(a, b) 24 | cnt_b = n - cnt_a 25 | 26 | # ➐ 최소값 갱신 27 | min_diff = min(min_diff, abs(cnt_a - cnt_b)) 28 | 29 | # ➑ 간선 복원 30 | graph[a].append(b) 31 | graph[b].append(a) 32 | 33 | return min_diff 34 | -------------------------------------------------------------------------------- /solution/18.py: -------------------------------------------------------------------------------- 1 | def count_sort(arr, k): 2 | # ➊ 해시 테이블 생성 및 초기화 3 | hashtable = [0] * (k + 1) 4 | 5 | for num in arr: 6 | # ➋ 현재 원소의 값이 k 이하인 때에만 처리 7 | if num <= k: 8 | # ➌ 현재 원소의 값을 인덱스로 해 해당 인덱스의 해시 테이블 값을 1로 설정 9 | hashtable[num] = 1 10 | return hashtable 11 | 12 | def solution(arr, target): 13 | hashtable = count_sort(arr, target) 14 | 15 | for num in arr: 16 | complement = target - num 17 | # ➍ target에서 현재 원소를 뺀 값이 해시 테이블에 있는지 확인 18 | if ( 19 | complement != num 20 | and complement >= 0 21 | and complement <= target 22 | and hashtable[complement] == 1 23 | ): 24 | return True 25 | return False 26 | 27 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 28 | # print(solution([1, 2, 3, 4, 8], 6)) # 반환값 : True 29 | # print(solution([2, 3, 5, 9], 10)) # 반환값 : False 30 | -------------------------------------------------------------------------------- /solution/07.py: -------------------------------------------------------------------------------- 1 | def is_valid_move(nx, ny) : # ➊ 좌표를 벗어나는지 체크하는 함수 2 | return 0 <= nx < 11 and 0 <= ny < 11 3 | 4 | def update_location(x, y, dir) : # ➋ 명령어를 통해 다음 좌표를 결정 5 | if dir == 'U': 6 | nx, ny = x, y + 1 7 | elif dir == 'D': 8 | nx, ny = x, y - 1 9 | elif dir == 'L': 10 | nx, ny = x - 1, y 11 | elif dir == 'R': 12 | nx, ny = x + 1, y 13 | return nx, ny 14 | 15 | def solution(dirs): 16 | x, y = 5, 5 17 | ans = set( ) # ➌ 겹치는 좌표는 1개로 처리하기 위함 18 | for dir in dirs : # ➍ 주어진 명령어로 움직이면서 좌표 저장 19 | nx, ny = update_location(x, y, dir) 20 | if not is_valid_move(nx, ny) : # ➎ 벗어난 좌표는 인정하지 않음 21 | continue 22 | # ➏ A에서 B로 간 경우 B에서 A도 추가해야 함(총 경로의 개수는 방향성이 없음) 23 | ans.add((x, y, nx, ny)) 24 | ans.add((nx, ny, x, y)) 25 | x, y = nx, ny # ➐ 좌표를 이동했으므로 업데이트 26 | return len(ans)/2 27 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/prime_number_detection.py: -------------------------------------------------------------------------------- 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 | # 소수는 1과 자기 자신 이외에 어떠한 수로도 나누어 떨어지지 않는 1보다 큰 양의 정수를 의미합니다. 8 | # 이 알고리즘은 2부터 (입력받은 숫자의 제곱근 + 1)까지의 숫자로 나누어 볼 때, 9 | # 한 번이라도 나누어 떨어지면 소수가 아니며, 모두 나누어 떨어지지 않으면 소수입니다. 10 | 11 | def is_prime(num): 12 | if num < 2: 13 | return False 14 | for i in range(2, int(num ** 0.5) + 1): 15 | if num % i == 0: 16 | return False 17 | return True 18 | 19 | # 예시 사용법 20 | print(is_prime(7)) # 출력: True 21 | -------------------------------------------------------------------------------- /solution/19.py: -------------------------------------------------------------------------------- 1 | # ➊ polynomial hash를 구현한 부분 2 | def polynomial_hash(str): 3 | p = 31 # 소수 4 | m = 1_000_000_007 # 버킷 크기 5 | hash_value = 0 6 | for char in str: 7 | hash_value = (hash_value * p + ord(char)) % m 8 | return hash_value 9 | 10 | def solution(string_list, query_list): 11 | # ➋ string_list의 각 문자열에 대해 다항 해시값을 계산 12 | hash_list = [polynomial_hash(str) for str in string_list] 13 | 14 | # ➌ query_list의 각 문자열이 string_list에 있는지 확인 15 | result = [ ] 16 | for query in query_list: 17 | query_hash = polynomial_hash(query) 18 | if query_hash in hash_list: 19 | result.append(True) 20 | else: 21 | result.append(False) 22 | return result 23 | 24 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 25 | # print(solution(["apple", "banana", "cherry"], ["banana", "kiwi", "melon", "apple"] )) # 반환값 : [True, False, False, True] 26 | -------------------------------------------------------------------------------- /solution/13.py: -------------------------------------------------------------------------------- 1 | def solution(board, moves): 2 | # ➊ 각 열에 대한 스택을 생성합니다. 3 | lanes = [[ ] for _ in range(len(board[0]))] 4 | 5 | # ➋ board를 역순으로 탐색하며, 각 열의 인형을 lanes에 추가합니다. 6 | for i in range(len(board) - 1, -1, -1): 7 | for j in range(len(board[0])): 8 | if board[i][j]: 9 | lanes[j].append(board[i][j]) 10 | 11 | # ➌ 인형을 담을 bucket을 생성합니다. 12 | bucket = [ ] 13 | 14 | # ➍ 사라진 인형의 총 개수를 저장할 변수를 초기화합니다. 15 | answer = 0 16 | 17 | # ➎ moves를 순회하며, 각 열에서 인형을 뽑아 bucket에 추가합니다. 18 | for m in moves: 19 | if lanes[m - 1]: # 해당 열에 인형이 있는 경우 20 | doll = lanes[m - 1].pop( ) 21 | 22 | if bucket and bucket[-1] == doll: # ➏ 바구니에 인형이 있고, 가장 위에 있는 인형과 같은 경우 23 | bucket.pop( ) 24 | answer += 2 25 | else: # ➐ 바구니에 인형이 없거나, 가장 위에 있는 인형과 다른 경우 26 | bucket.append(doll) 27 | 28 | return answer 29 | -------------------------------------------------------------------------------- /reference/early_return.py: -------------------------------------------------------------------------------- 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 | # Early return은 조건에 따라 함수에서 빠르게 반환하여 불필요한 실행을 방지하는 코드 패턴입니다. 8 | # 이는 함수의 로직을 더욱 명확하게 만들고, 중첩된 조건문을 줄일 수 있습니다. 9 | 10 | def find_item(items, target): 11 | for item in items: 12 | if item == target: 13 | return f"Item '{target}' found!" 14 | # 만약 target 아이템을 찾지 못했다면, 이 문장이 실행됩니다. 15 | return f"Item '{target}' not found" 16 | 17 | # 예시 18 | items_list = ["apple", "banana", "cherry"] 19 | print(find_item(items_list, "banana")) # 출력: "Item 'banana' found!" 20 | print(find_item(items_list, "grape")) # 출력: "Item 'grape' not found" 21 | -------------------------------------------------------------------------------- /solution/44.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | def solution(N, road, K): 4 | # ➊ 각 노드에 연결된 간선들을 저장할 리스트 5 | graph = [[] for _ in range(N + 1)] 6 | # ➋ 출발점에서 각 노드까지의 최단 거리를 저장할 리스트 7 | distances = [float("inf")] * (N + 1) 8 | distances[1] = 0 # 출발점은 0으로 초기화 9 | 10 | # ➌ 그래프 구성 11 | for a, b, cost in road: 12 | graph[a].append((b, cost)) 13 | graph[b].append((a, cost)) 14 | 15 | # ➍ 다익스트라 알고리즘 시작 16 | heap = [] 17 | heapq.heappush(heap, (0, 1)) # ➎ 출발점을 heap에 추가 18 | while heap: 19 | dist, node = heapq.heappop(heap) 20 | 21 | # ➏ 인접한 노드들의 최단 거리를 갱신하고 heap에 추가 22 | for next_node, next_dist in graph[node]: 23 | cost = dist + next_dist 24 | if cost < distances[next_node]: 25 | distances[next_node] = cost 26 | heapq.heappush(heap, (cost, next_node)) 27 | 28 | # ➐ distances 리스트에서 K 이하인 값의 개수를 구하여 반환 29 | return sum(1 for dist in distances if dist <= K) 30 | -------------------------------------------------------------------------------- /solution/50.py: -------------------------------------------------------------------------------- 1 | # ➊ 퀸이 서로 공격할 수 없는 위치에 놓이는 경우의 수를 구하는 함수 2 | def getAns(n, y, width, diagonal1, diagonal2): 3 | ans = 0 4 | # ➋ 모든 행에 대해서 퀸의 위치가 결정되었을 경우 5 | if y == n: 6 | # ➌ 해결 가능한 경우의 수를 1 증가시킴 7 | ans += 1 8 | else: 9 | # ➍ 현재 행에서 퀸이 놓일 수 있는 모든 위치를 시도 10 | for i in range(n): 11 | # ➎ 해당 위치에 이미 퀸이 있는 경우, 대각선 상에 퀸이 있는 경우 스킵 12 | if width[i] or diagonal1[i + y] or diagonal2[i - y + n]: 13 | continue 14 | # ➏ 해당 위치에 퀸을 놓음 15 | width[i] = diagonal1[i + y] = diagonal2[i - y + n] = True 16 | # ➐ 다음 행으로 이동하여 재귀적으로 해결 가능한 경우의 수 찾기 17 | ans += getAns(n, y + 1, width, diagonal1, diagonal2) 18 | # ➑ 해당 위치에 놓인 퀸을 제거함 19 | width[i] = diagonal1[i + y] = diagonal2[i - y + n] = False 20 | return ans 21 | 22 | def solution(n): 23 | # ➒ getAns 함수 호출하여 해결 가능한 경우의 수 찾기 24 | ans = getAns(n, 0, [False] * n, [False] * (n * 2), [False] * (n * 2)) 25 | return ans 26 | -------------------------------------------------------------------------------- /reference/composition_fuction.py: -------------------------------------------------------------------------------- 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 | # 함수의 합성(Composition of functions)은 하나의 함수의 출력이 또 다른 함수의 입력으로 사용되는 것입니다. 8 | # 이를 통해 여러 함수를 결합하여 더 복잡한 기능을 수행할 수 있습니다. 9 | # Python에서는 이러한 함수 합성을 쉽게 구현할 수 있습니다. 10 | 11 | # 먼저, 두 개의 간단한 함수를 정의해봅시다. 12 | def double(x): 13 | return x * 2 14 | 15 | def increment(x): 16 | return x + 1 17 | 18 | # 이제, 이 두 함수를 합성하는 새로운 함수를 정의할 수 있습니다. 19 | def composition_function(x): 20 | return increment(double(x)) # double 함수의 출력이 increment 함수의 입력으로 사용됩니다. 21 | 22 | # 함수 호출 예제 23 | result = composition_function(5) # 먼저 5를 2배로 만든 후, 1을 더합니다. 따라서 결과는 11입니다. 24 | print(result) # 출력: 11 25 | -------------------------------------------------------------------------------- /solution/24.py: -------------------------------------------------------------------------------- 1 | def solution(id_list, report, k): 2 | reported_user = { } # 신고당한 유저 - 신고 유저 집합을 저장할 딕셔너리 3 | count = { } # 처리 결과 메일을 받은 유저 - 받은 횟수를 저장할 딕셔너리 4 | # ➊ 신고 기록 순회 5 | for r in report: 6 | user_id, reported_id = r.split( ) 7 | if reported_id not in reported_user: # ➋ 신고당한 기록이 없다면 8 | reported_user[reported_id] = set( ) 9 | reported_user[reported_id].add(user_id) # ➌ 신고한 사람의 아이디를 집합에 담아 딕셔너리에 연결 10 | for reported_id, user_id_lst in reported_user.items( ) : 11 | if len(user_id_lst) >= k: # ➍ 정지 기준에 만족하는지 확인 12 | for uid in user_id_lst: # ➎ 딕셔너리를 순회하며 count 계산 13 | if uid not in count: 14 | count[uid] = 1 15 | else: 16 | count[uid] += 1 17 | answer = [ ] 18 | for i in range(len(id_list)): # ➏ 각 아이디별 메일을 받은 횟수를 순서대로 정리 19 | if id_list[i] not in count: 20 | answer.append(0) 21 | else: 22 | answer.append(count[id_list[i]]) 23 | return answer 24 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/binary_search.py: -------------------------------------------------------------------------------- 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(log n)의 시간 복잡도를 가지며, 리스트가 정렬된 상태에서만 사용할 수 있습니다. 10 | 11 | def binary_search(arr, x): 12 | left, right = 0, len(arr) - 1 13 | while left <= right: 14 | mid = (left + right) // 2 15 | if arr[mid] == x: 16 | return mid 17 | elif arr[mid] < x: 18 | left = mid + 1 19 | else: 20 | right = mid - 1 21 | return -1 22 | 23 | # 예시 사용법 24 | arr = [1, 2, 3, 4, 5] 25 | print(binary_search(arr, 3)) # 출력: 2 26 | -------------------------------------------------------------------------------- /solution/38.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | def solution(graph, start): 4 | # ❶ 그래프를 인접 리스트로 변환 5 | adj_list = defaultdict(list) 6 | for u, v in graph: 7 | adj_list[u].append(v) 8 | 9 | # ❷ DFS 탐색 함수 10 | def dfs(node, visited, result): 11 | visited.add(node) # ❸ 현재 노드를 방문한 노드들의 집합에 추가 12 | result.append(node) # ❹ 현재 노드를 결과 리스트에 추가 13 | for neighbor in adj_list.get(node, []): # ❺ 현재 노드와 인접한 노드순회 14 | if neighbor not in visited: # ❻ 아직 방문하지 않은 노드라면 15 | dfs(neighbor, visited, result) 16 | 17 | # DFS를 순회한 결과를 반환 18 | visited = set() 19 | result = [] 20 | dfs(start, visited, result) # ❼ 시작 노드에서 깊이 우선 탐색 시작 21 | return result # ❽ DFS 탐색 결과 반환 22 | 23 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 24 | # print(solution([['A', 'B'], ['B', 'C'], ['C', 'D'], ['D', 'E']], 'A')) # 반환값 : ['A', 'B', 'C', 'D', 'E'] 25 | # print(solution([['A', 'B'], ['A', 'C'], ['B', 'D'], ['B', 'E'], ['C', 'F'], ['E', 'F']], 'A')) # 반환값 : ['A', 'B', 'D', 'E', 'F', 'C'] 26 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/deque.py: -------------------------------------------------------------------------------- 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 | from collections import deque 8 | 9 | # 데크 객체 생성 10 | deq = deque() 11 | 12 | # append(item): 데크의 오른쪽 끝에 item을 추가합니다. 13 | # 반환값: 없음 14 | # 시간 복잡도: O(1) 15 | deq.append(1) # 현재 데크: deque([1]) 16 | print(deq) # 출력: deque([1]) 17 | 18 | # appendleft(item): 데크의 왼쪽 끝에 item을 추가합니다. 19 | # 반환값: 없음 20 | # 시간 복잡도: O(1) 21 | deq.appendleft(0) # 현재 데크: deque([0, 1]) 22 | print(deq) # 출력: deque([0, 1]) 23 | 24 | # popleft(): 데크의 왼쪽 끝 요소를 제거하고 그 요소를 반환합니다. 25 | # 반환값: 제거된 요소 26 | # 시간 복잡도: O(1) 27 | deq.popleft() # 현재 데크: deque([1]) 28 | print(deq) # 출력: deque([1]) 29 | 30 | # deq[K]: 데크의 K번째 요소를 반환합니다. 31 | # 반환값: K번째 요소 32 | # 시간 복잡도: O(1) 33 | print(deq[0]) # 출력: 1 34 | -------------------------------------------------------------------------------- /solution/61.py: -------------------------------------------------------------------------------- 1 | from heapq import heappush, heappop 2 | 3 | def solution(land, height): 4 | answer = 0 5 | n = len(land) 6 | # ➊ 주변 노드 탐색을 위한 di, dj 7 | di = [-1, 0, 1, 0] 8 | dj = [0, 1, 0, -1] 9 | visited = [[False] * n for _ in range(n)] 10 | # ➋ 시작 노드 추가 11 | q = [] 12 | 13 | heappush(q, [0, 0, 0]) # [비용, i, j] 14 | 15 | # ➌ BFS + 우선 순위 큐로 다음 노드 관리 16 | while q: 17 | cost, i, j = heappop(q) 18 | # ➍ 아직 방문하지 않은 경로만 탐색 19 | if not visited[i][j]: 20 | visited[i][j] = True 21 | # ➎ 현재까지 비용을 합산 22 | answer += cost 23 | for d in range(4): 24 | ni, nj = i + di[d], j + dj[d] 25 | # ➏ 유효한 인덱스일 경우 26 | if 0 <= ni < n and 0 <= nj < n: 27 | temp_cost = abs(land[i][j] - land[ni][nj]) 28 | # ➐ 입력으로 주어진 height보다 높이차가 큰 경우 29 | if temp_cost > height: 30 | new_cost = temp_cost 31 | else: 32 | new_cost = 0 33 | # ➑ 다음 경로를 푸시 34 | heappush(q, [new_cost, ni, nj]) 35 | 36 | return answer 37 | -------------------------------------------------------------------------------- /solution/52.py: -------------------------------------------------------------------------------- 1 | from itertools import permutations 2 | 3 | def solution(n, weak, dist): 4 | # ➊ 주어진 weak 지점들을 선형으로 만들기 위해 weak 리스트에 마지막 지점 + n을 추가 5 | length = len(weak) 6 | for i in range(length): 7 | weak.append(weak[i] + n) 8 | 9 | # ➋ 투입할 수 있는 친구들의 수에 1을 더한 값을 초기값으로 설정 10 | answer = len(dist) + 1 11 | 12 | # ➌ 모든 weak 지점을 시작점으로 설정하며 경우의 수를 탐색 13 | for i in range(length): 14 | for friends in permutations(dist, len(dist)): 15 | # ➍ friends에 들어있는 친구들을 순서대로 배치하며 투입된 친구 수(cnt) 측정 16 | cnt = 1 17 | position = weak[i] + friends[cnt - 1] 18 | # ➎ 현재 투입된 친구가 다음 weak 지점까지 갈 수 있는지 검사 19 | for j in range(i, i + length): 20 | if position < weak[j]: 21 | cnt += 1 22 | # ➏ 투입 가능한 친구의 수를 초과한 경우 탐색 중단 23 | if cnt > len(dist): 24 | break 25 | position = weak[j] + friends[cnt - 1] 26 | # ➐ 최소 친구 수를 구함 27 | answer = min(answer, cnt) 28 | 29 | # ➑ 모든 경우의 수를 탐색한 결과가 투입 가능한 친구 수를 초과하는 경우, -1 반환 30 | return answer if answer <= len(dist) else -1 31 | -------------------------------------------------------------------------------- /mistake/zero_division_demo.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 실수 예: 0으로 나누기 7 | # result = 10 / 0 # ZeroDivisionError: division by zero 8 | 9 | # 파이썬에서 숫자를 0으로 나누려고 하면 ZeroDivisionError가 발생합니다. 10 | 11 | # 실수 예: 변수를 사용하여 나누기를 수행하되, 변수 값이 0인 경우 12 | denominator = 0 13 | # if denominator is not 0: 14 | # result = 10 / denominator # 이 줄도 ZeroDivisionError를 발생시킵니다. 15 | 16 | # 올바른 사용법: 나눗셈을 수행하기 전에 분모가 0인지 확인 17 | if denominator != 0: 18 | result = 10 / denominator 19 | print(result) 20 | else: 21 | print("Cannot divide by zero!") 22 | 23 | # 특히 복잡한 계산이나 사용자 입력을 처리할 때는 이러한 오류가 발생할 수 있으므로 주의가 필요합니다. 24 | # 사용자 입력을 받아서 나눗셈을 수행하는 경우: 25 | 26 | # user_input = float(input("Enter a number to divide 10 by: ")) 27 | # if user_input != 0: 28 | # print(10 / user_input) 29 | # else: 30 | # print("Cannot divide by zero!") 31 | -------------------------------------------------------------------------------- /solution/51.py: -------------------------------------------------------------------------------- 1 | from itertools import combinations_with_replacement 2 | from collections import Counter 3 | 4 | def solution(n, info): 5 | maxdiff, max_comb = 0, {} 6 | 7 | # ➊ 주어진 조합에서 각각의 점수 계산 8 | def calculate_score(combi): 9 | score1, score2 = 0, 0 10 | for i in range(1, 11): 11 | if info[10 - i] < combi.count(i): 12 | score1 += i 13 | elif info[10 - i] > 0: 14 | score2 += i 15 | return score1, score2 16 | 17 | # ➋ 최대 차이와 조합 저장 18 | def calculate_diff(diff, cnt): 19 | nonlocal maxdiff, max_comb 20 | if diff > maxdiff: 21 | max_comb = cnt 22 | maxdiff = diff 23 | 24 | # ➌ 가능한 라이언의 과녁점수 조합의 모든 경우에 대해서 체크 25 | for combi in combinations_with_replacement(range(11), n): 26 | cnt = Counter(combi) 27 | score1, score2 = calculate_score(combi) 28 | diff = score1 - score2 29 | calculate_diff(diff, cnt) 30 | 31 | # ➍ 최대 차이가 0 이상인 경우, 조합 반환 32 | if maxdiff > 0: 33 | answer = [0] * 11 34 | for n in max_comb: 35 | answer[10 - n] = max_comb[n] 36 | return answer 37 | else: # ➎ 최대 차이가 0인 경우, -1 반환 38 | return [-1] 39 | -------------------------------------------------------------------------------- /reference/mutable_immutable.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서, 객체는 뮤터블(mutable) 또는 이뮤터블(immutable) 두 가지 유형으로 나뉩니다. 8 | # 뮤터블 객체는 객체가 생성된 후에도 그 상태를 변경할 수 있습니다. (예: 리스트, 딕셔너리) 9 | # 이뮤터블 객체는 객체가 생성된 후에 그 상태를 변경할 수 없습니다. (예: 정수, 문자열, 튜플) 10 | 11 | # 이뮤터블 예시: 문자열 12 | immutable_example = "Hello, World!" 13 | # immutable_example[0] = 'h' # 이 줄은 에러를 일으킵니다, 문자열은 변경할 수 없습니다. 14 | 15 | # 뮤터블 예시: 리스트 16 | mutable_example = [1, 2, 3, 4] 17 | mutable_example[0] = 0 # 리스트는 변경할 수 있습니다, 따라서 이 줄은 에러를 일으키지 않습니다. 18 | print(mutable_example) # 출력: [0, 2, 3, 4] 19 | 20 | # 튜플 (이뮤터블) 와 리스트 (뮤터블)의 비교 21 | tuple_example = (1, 2, 3) # 튜플은 이뮤터블 객체입니다. 22 | # tuple_example[0] = 0 # 이 줄은 에러를 일으킵니다, 튜플은 변경할 수 없습니다. 23 | 24 | list_example = [1, 2, 3] # 리스트는 뮤터블 객체입니다. 25 | list_example[0] = 0 # 이 줄은 에러를 일으키지 않습니다, 리스트는 변경할 수 있습니다. 26 | print(list_example) # 출력: [0, 2, 3] 27 | -------------------------------------------------------------------------------- /reference/range.py: -------------------------------------------------------------------------------- 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 | # 파이썬의 "range" 함수는 연속된 숫자의 시퀀스를 생성하는 데 사용됩니다. 8 | # 이 함수는 주로 for 루프와 함께 사용되며, 세 가지 다른 형태의 인자를 가질 수 있습니다: 9 | # 1. range(stop): 0부터 'stop - 1'까지의 숫자 시퀀스를 생성합니다. 10 | # 2. range(start, stop): 'start'부터 'stop - 1'까지의 숫자 시퀀스를 생성합니다. 11 | # 3. range(start, stop, step): 'start'부터 'stop - 1'까지의 숫자 시퀀스를 생성하되, 'step' 간격으로 숫자를 생성합니다. 12 | 13 | # 1. range(stop) 형태의 사용 예: 14 | # 아래 코드는 0부터 4까지의 숫자를 출력합니다. 15 | for i in range(5): 16 | print(i) # 출력: 0, 1, 2, 3, 4 17 | 18 | print("---------") 19 | 20 | # 2. range(start, stop) 형태의 사용 예: 21 | # 아래 코드는 5부터 9까지의 숫자를 출력합니다. 22 | for i in range(5, 10): 23 | print(i) # 출력: 5, 6, 7, 8, 9 24 | 25 | print("---------") 26 | 27 | # 3. range(start, stop, step) 형태의 사용 예: 28 | # 아래 코드는 0부터 9까지의 숫자 중, 2 간격으로 숫자를 출력합니다. 29 | for i in range(0, 10, 2): 30 | print(i) # 출력: 0, 2, 4, 6, 8 31 | -------------------------------------------------------------------------------- /mistake/power_methods_comparison.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | import math # math 모듈 사용 7 | 8 | # 1. ** 연산자 9 | # **는 파이썬의 거듭제곱 연산자입니다. 가장 직관적이며 일반적으로 사용됩니다. 10 | result1 = 2 ** 3 11 | print(result1) # 8 12 | 13 | # 2. pow 함수 14 | # pow는 내장 함수로써 2개 혹은 3개의 인자를 받습니다. 15 | result2 = pow(2, 3) # 2의 3승 16 | print(result2) # 8 17 | 18 | # pow 함수의 세 번째 인자는 모듈로 연산에 사용됩니다. 19 | result3 = pow(2, 3, 3) # (2의 3승) % 3 20 | print(result3) # 2 21 | 22 | # 3. math.pow 함수 23 | # math.pow는 math 모듈에 있는 함수로, 항상 float 값을 반환합니다. 24 | result4 = math.pow(2, 3) 25 | print(result4) # 8.0 26 | 27 | # 실수 예: 반환 값의 타입을 고려하지 않고 정수 연산을 수행하려고 할 때 28 | # int_result = math.pow(2, 3) + 1 # 결과는 float 값이 됩니다. 29 | # 올바른 방법: float 값을 int로 변환하여 사용 30 | int_result = int(math.pow(2, 3)) + 1 31 | print(int_result) # 9 32 | 33 | # **와 pow는 거의 동일한 연산을 수행하지만, 모듈로 연산이 필요한 경우나 float 반환 값이 필요한 경우에 따라 적절한 함수나 연산자를 선택해야 합니다. 34 | -------------------------------------------------------------------------------- /solution/14.py: -------------------------------------------------------------------------------- 1 | def solution(n, k, cmd): 2 | # ➊ 삭제된 행의 인덱스를 저장하는 리스트 3 | deleted = [ ] 4 | 5 | # ➋ 링크드 리스트에서 각 행 위아래의 행의 인덱스를 저장하는 리스트 6 | up = [i - 1 for i in range(n + 2)] 7 | 8 | down = [i + 1 for i in range(n + 1)] 9 | 10 | # ➌ 현재 위치를 나타내는 인덱스 11 | k += 1 12 | 13 | # ➍ 주어진 명령어(cmd) 리스트를 하나씩 처리 14 | for cmd_i in cmd: 15 | # ➎ 현재 위치를 삭제하고 그다음 위치로 이동 16 | if cmd_i.startswith("C"): 17 | deleted.append(k) 18 | up[down[k]] = up[k] 19 | down[up[k]] = down[k] 20 | k = up[k] if n < down[k] else down[k] 21 | 22 | # ➏ 가장 최근에 삭제된 행을 복원 23 | elif cmd_i.startswith("Z"): 24 | restore = deleted.pop( ) 25 | down[up[restore]] = restore 26 | up[down[restore]] = restore 27 | 28 | # ➐ U 또는 D를 사용해 현재 위치를 위아래로 이동 29 | else: 30 | action, num = cmd_i.split( ) 31 | if action == "U": 32 | for _ in range(int(num)): 33 | k = up[k] 34 | else: 35 | for _ in range(int(num)): 36 | k = down[k] 37 | 38 | # ➑ 삭제된 행의 위치에 'X'를, 그렇지 않은 행의 위치에 'O'를 포함하는 문자열 반환 39 | answer = ["O"] * n 40 | for i in deleted: 41 | answer[i - 1] = "X" 42 | return "".join(answer) 43 | -------------------------------------------------------------------------------- /mistake/none_return_tutorial.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 파이썬에서 return 문장이 없는 함수 정의 7 | def no_return_function(): 8 | print("This function doesn't have a return statement.") 9 | 10 | # 함수를 호출 11 | result = no_return_function() 12 | print(result) # None이 출력됩니다. 13 | 14 | # 파이썬에서 함수가 명시적으로 값을 반환하지 않으면, 기본적으로 None을 반환합니다. 15 | 16 | # 실수 예: 반환 값이 있는 것처럼 함수를 사용하려고 할 때 17 | def add(a, b): 18 | result = a + b 19 | # 여기서 return을 깜빡하고 쓰지 않았습니다. 20 | 21 | sum_result = add(5, 3) 22 | # print(sum_result + 2) 23 | # 위의 코드는 TypeError를 발생시킵니다. 왜냐하면 sum_result는 None이기 때문입니다. 24 | 25 | # 올바른 사용법: 함수에서 값을 반환하려면 return 문을 사용해야 합니다. 26 | def correct_add(a, b): 27 | return a + b 28 | 29 | correct_sum_result = correct_add(5, 3) 30 | print(correct_sum_result + 2) # 올바르게 10이 출력됩니다. 31 | 32 | # 때로는 함수가 None을 반환하는 것이 의도된 것일 수 있습니다. 33 | # 그러나 함수의 반환 값을 사용하려고 할 때는 항상 반환 값이 None인지 아닌지 확인하는 것이 좋습니다. 34 | -------------------------------------------------------------------------------- /solution/31.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def solution(info, edges): 4 | # ➊ 트리 구축 함수 5 | def build_tree(info, edges): 6 | tree = [[] for _ in range(len(info))] 7 | for edge in edges: 8 | tree[edge[0]].append(edge[1]) 9 | return tree 10 | 11 | tree = build_tree(info, edges) # ➋ 트리 생성 12 | max_sheep = 0 # ➌ 최대 양의 수를 저장할 변수 초기화 13 | 14 | # ➍ BFS를 위한 큐 생성 및 초기 상태 설정 15 | # (현재 위치, 양의 수, 늑대의 수, 방문한 노드 집합) 16 | q = deque([(0, 1,0, set())]) 17 | 18 | # BFS 시작 19 | while q: 20 | # ➎ 큐에서 상태 가져오기 21 | current, sheep_count, wolf_count, visited = q.popleft() 22 | # ➏ 최대 양의 수 업데이트 23 | max_sheep = max(max_sheep, sheep_count) 24 | # ➐ 방문한 노드 집합에 현재 노드의 이웃 노드 추가 25 | visited.update(tree[current]) 26 | 27 | # ➑ 인접한 노드들에 대해 탐색 28 | for next_node in visited: 29 | if info[next_node]: # ➒ 늑대일 경우 30 | if sheep_count != wolf_count + 1: 31 | q.append( 32 | (next_node, sheep_count, wolf_count + 1, visited - {next_node}) 33 | ) 34 | else: # ➓ 양일 경우 35 | q.append( 36 | (next_node, sheep_count + 1, wolf_count, visited - {next_node}) 37 | ) 38 | return max_sheep 39 | -------------------------------------------------------------------------------- /reference/for_loop.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 'for' 문은 시퀀스(리스트, 튜플, 문자열 등)의 항목들을 순차적으로 반복하여 처리하는 데 사용됩니다. 8 | # 'for' 문은 'for 변수 in 시퀀스' 형식으로 작성되며, '변수'는 시퀀스의 각 항목을 참조하는 데 사용됩니다. 9 | 10 | # 'and'와 'or'는 논리 연산자로, 여러 조건을 조합하는데 사용됩니다. 11 | # 'and' 연산자: 모든 조건이 참이어야 전체가 참입니다 (&&와 동일). 12 | # 'or' 연산자: 조건 중 하나 이상이 참이면 전체가 참입니다 (||와 동일). 13 | 14 | # 'for' 문 예제: 15 | fruits = ["apple", "banana", "cherry"] 16 | 17 | for fruit in fruits: 18 | print(fruit) 19 | 20 | # 'and'와 'or' 연산자를 사용한 'for' 문 예제: 21 | numbers = [1, 2, 3, 4, 5] 22 | 23 | for number in numbers: 24 | if number >= 2 and number <= 4: 25 | print(f"The number {number} is between 2 and 4") 26 | elif number < 2 or number > 4: 27 | print(f"The number {number} is outside the range of 2 and 4") 28 | 29 | # 이 코드는 'for' 문의 기본 사용법과 'and', 'or' 논리 연산자의 사용법을 보여줍니다. 30 | # 'and', 'or' 논리 연산자를 사용하여 'if' 문 내에서 여러 조건을 조합할 수 있습니다. 31 | -------------------------------------------------------------------------------- /study_guide.md: -------------------------------------------------------------------------------- 1 | # 스터디 생성/참여 안내 2 | 3 | 스터디를 시작하고 싶지만 사람을 어떻게 모아야 할지 걱정되시나요? 걱정 마세요! 스터디를 개설하면 자동 노출 됩니다. 4 | 5 | ## 스터디 그룹 가입하기 6 | [스터디그룹링크](https://www.linkedin.com/groups/14606078/) 7 | 8 | ## 스터디 홍보 채널 9 | - [카카오 오픈채팅방 (820명 개발자 참여)](https://open.kakao.com/o/gX0WnTCf) 10 | - [디스코드 (620명)](https://discord.gg/jUCqgExumm) 11 | - [네이버 카페 (1200명)](https://cafe.naver.com/dremdeveloper) 12 | 13 | ## 네이버 카페 질문 게시판 14 | - [질문 게시판 바로가기](https://cafe.naver.com/dremdeveloper) : 질문을 올려주시면 직접 답변을 드립니다. 15 | 16 | ## 스터디 추천 주제 17 | - 프로그래머스 / 백준 스터디 18 | - 취업/면접 준비 스터디 19 | - 공부 인증 20 | - 코딩 테스트 합격자 되기 시리즈 1독 스터디 21 | 22 | ## 자료 및 링크 23 | - [코딩 테스트 합격자 되기 - 무료 강의](https://inf.run/H9yxm) 24 | - [디스코드 가이드](https://github.com/dremdeveloper/codingtest_python/blob/main/discord.md) 25 | - [프로그래머스 정답코드 & 코테 필수 예제 (파이썬)](https://github.com/dremdeveloper/codingtest_python) 26 | - [프로그래머스 정답코드 & 코테 필수 예제 (C++)](https://github.com/dremdeveloper/codingtest_cpp) 27 | - [코딩 테스트 무료 손노트](https://cafe.naver.com/dremdeveloper/1107) 28 | - [기존 코딩 테스트 합격자 되기 스터디 내용 (각 쓰레드 참조)](https://discord.gg/KwYMvQWH5T) 29 | 30 | ## 도움이 필요하신가요? 31 | - **이메일**: ultrasuperrok@gmail.com 32 | - **링크드인**: [링크](https://www.linkedin.com/in/ultrasuperrok) 33 | 34 | 스터디 생성을 두려워하지 마세요. 당신도 할 수 있습니다! 35 | -------------------------------------------------------------------------------- /reference/variable.py: -------------------------------------------------------------------------------- 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 | # 변수(Variable)는 프로그래밍에서 데이터를 저장하는 메모리의 이름이 할당된 공간입니다. 파이썬에서는 다양한 유형의 데이터를 저장할 수 있으며, 8 | # 변수 이름은 그 데이터를 참조하는데 사용됩니다. 9 | # 변수를 선언하려면, 이름을 선택하고 등호(=) 기호를 사용하여 값을 할당합니다. 10 | 11 | # 예제 1: 정수형 변수 12 | # 여기서 'age'는 변수 이름이고, 20은 그 변수에 할당된 값입니다. 13 | age = 20 14 | print(age) # 이 코드는 변수 'age'의 값을 출력합니다. 15 | 16 | # 예제 2: 문자열 변수 17 | # 여기서 'name'은 변수 이름이고, "John"은 그 변수에 할당된 값입니다. 18 | name = "John" 19 | print(name) # 이 코드는 변수 'name'의 값을 출력합니다. 20 | 21 | # 예제 3: 부동소수점 변수 22 | # 여기서 'height'는 변수 이름이고, 5.9는 그 변수에 할당된 값입니다. 23 | height = 5.9 24 | print(height) # 이 코드는 변수 'height'의 값을 출력합니다. 25 | 26 | # 예제 4: 불리언 변수 27 | # 여기서 'is_student'는 변수 이름이고, True는 그 변수에 할당된 값입니다. 28 | is_student = True 29 | print(is_student) # 이 코드는 변수 'is_student'의 값을 출력합니다. 30 | 31 | # 변수 이름은 언더스코어(_) 또는 알파벳으로 시작해야하며, 숫자로 시작할 수 없습니다. 32 | # 또한, 변수 이름은 공백을 포함할 수 없으며, 파이썬의 키워드(예: if, else, for 등)를 사용할 수 없습니다. 33 | -------------------------------------------------------------------------------- /solution/39.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict, deque 2 | 3 | def solution(graph, start): 4 | # 그래프를 인접 리스트로 변환 5 | adj_list = defaultdict(list) 6 | for u, v in graph: 7 | adj_list[u].append(v) 8 | 9 | # BFS 탐색 함수 10 | def bfs(start): 11 | visited = set() # ❶ 방문한 노드를 저장할 셋 12 | 13 | # ❷ 탐색시 맨 처음 방문할 노드 푸시 하고 방문처리 14 | queue = deque([start]) 15 | visited.add(start) 16 | result.append(start) 17 | 18 | # ❸ 큐가 비어있지 않은 동안 반복 19 | while queue: 20 | node = queue.popleft() # ❹ 큐에 있는 원소 중 가장 먼저 푸시된 원소 팝 21 | for neighbor in adj_list.get(node, []): #❺ 인접한 이웃 노드들에 대해서 22 | if neighbor not in visited: # ❻ 방문되지 않은 이웃 노드인 경우 23 | # ❼ 이웃노드를 방문 처리함 24 | queue.append(neighbor) 25 | visited.add(neighbor) 26 | result.append(neighbor) 27 | 28 | result = [] 29 | bfs(start) # ❽ 시작 노드부터 BFS 탐색 수행 30 | return result 31 | 32 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 33 | # 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] 34 | # print(solution([(0, 1), (1, 2), (2, 3), (3, 4), (4, 5), (5, 0)],1)) # 반환값 : [1, 2, 3, 4, 5, 0] 35 | 36 | -------------------------------------------------------------------------------- /performance/append_vs_plus_performance.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # append() 메서드와 + 연산자의 동작 및 시간 복잡도에 대한 설명: 7 | # 1. append() 메서드: 리스트의 끝에 새 요소를 추가하는 연산으로, 시간 복잡도는 O(1)이며, 상수 시간이 걸립니다. 8 | # 리스트의 크기와 무관하게 일정한 시간이 소요됩니다. 9 | # 2. + 연산자: 두 리스트를 합치는 연산으로, 시간 복잡도는 O(n)입니다. 리스트의 크기에 비례하여 시간이 걸리며, 10 | # 반복문 안에서 사용할 경우 각 반복마다 새 리스트를 생성해야 하므로 시간 소요가 큽니다. 11 | import time 12 | 13 | num_elements = 10000 14 | 15 | # append() 사용 16 | start_time = time.time() 17 | lst_append = [] 18 | for i in range(num_elements): 19 | lst_append.append(i) 20 | append_time = time.time() - start_time 21 | 22 | # + 연산자 사용 23 | start_time = time.time() 24 | lst_plus = [] 25 | for i in range(num_elements): 26 | lst_plus = lst_plus + [i] 27 | plus_time = time.time() - start_time 28 | 29 | print(f"Using append() took: {append_time:.6f} seconds")# 0.002196초(환경마다 다를 수 있음) 30 | print(f"Using + operator took: {plus_time:.6f} seconds")# 0.297017초(환경마다 다를 수 있음) 31 | -------------------------------------------------------------------------------- /solution/72.py: -------------------------------------------------------------------------------- 1 | def solution(arr): 2 | n = len(arr[0]) # ❶ 입력 배열의 열의 개수를 저장합니다. 3 | dp = [[0] * n for _ in range(4)] # ❷ dp 배열을 초기화합니다. 4행 n열의 2차원 배열입니다. 4 | 5 | # 각 열에서 선택 가능한 4가지 조약돌 배치 패턴에 대해 첫 번째 열의 가중치를 초기화합니다. 6 | # ❸ 0: 상단, 1: 중앙, 2: 하단, 3: 상단과 하단 7 | dp[0][0] = arr[0][0] 8 | dp[1][0] = arr[1][0] 9 | dp[2][0] = arr[2][0] 10 | dp[3][0] = arr[0][0] + arr[2][0] 11 | 12 | # ❹ 두 번째 열부터 마지막 열까지 각 열에서 선택 가능한 4가지 조약돌 배치 패턴에 대해 최대 가중치를 계산합니다. 13 | for i in range(1, n): 14 | # 패턴 0이 선택된 경우, 이전은 패턴 {1, 2} 가능 15 | dp[0][i] = arr[0][i] + max(dp[1][i - 1], dp[2][i - 1]) 16 | # 패턴 1이 선택된 경우, 이전은 패턴 {0, 2, 3|가능 17 | dp[1][i] = arr[1][i] + max(dp[0][i - 1], dp[2][i - 1], dp[3][i - 1]) 18 | # 패턴 2가 선택된 경우, 이전은 패턴 {0, 1}이 가능 19 | dp[2][i] = arr[2][i] + max(dp[0][i - 1], dp[1][i - 1]) 20 | # 패턴 3이 선택된 경우, 이전은 패턴{1}이 가능 21 | dp[3][i] = arr[0][i] + arr[2][i] + dp[1][i - 1] 22 | 23 | # ❺ 마지막 열에서 선택 가능한 4가지 조약돌 배치 패턴 중 최대 가중치를 반환합니다. 24 | return max(dp[0][-1], dp[1][-1], dp[2][-1], dp[3][-1]) 25 | 26 | 27 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 28 | # print(solution([[1, 3, 3, 2], [2, 1, 4, 1], [1, 5, 2, 3]])) # 반환값 : 19 29 | # print(solution([[1, 7, 13, 2, 6], [2, -4, 2, 5, 4], [5, 3, 5, -3, 1]])) # 반환값 : 32 30 | -------------------------------------------------------------------------------- /solution/62.py: -------------------------------------------------------------------------------- 1 | def solution(arr, n): 2 | # ❶ 2차원 배열을 인자로 받고, 90도 회전시키는 함수 3 | def rotate_90(arr): 4 | # ❷ 배열의 크기를 저장 5 | n = len(arr) 6 | 7 | # ❸ 배열의 크기와 동일한 2차원 배열 생성(초기값은 0) 8 | rotated_arr = [[0] * n for _ in range(n)] 9 | 10 | # ❹ 배열을 90도회전 11 | for i in range(n): 12 | for j in range(n): 13 | rotated_arr[j][n - i - 1] = arr[i][j] 14 | 15 | # ❺ 90도로 회전한 배열 반환 16 | return rotated_arr 17 | 18 | # ❻ 원본배열 arr을 복사 19 | rotated_arr = arr.copy() 20 | 21 | # ❼ 90도 회전 함수 호출 22 | for _ in range(n): 23 | rotated_arr = rotate_90(rotated_arr) 24 | 25 | return rotated_arr 26 | 27 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 28 | ''' 29 | print(solution( 30 | [ 31 | [1, 2, 3, 4], 32 | [5, 6, 7, 8], 33 | [9, 10, 11, 12], 34 | [13, 14, 15, 16] 35 | ], 1)) 36 | ''' 37 | 38 | ''' 39 | 반환값 : 40 | [ 41 | [13, 9, 5, 1], 42 | [14, 10, 6, 2], 43 | [15, 11, 7, 3], 44 | [16, 12, 8, 4] 45 | ] 46 | ''' 47 | 48 | ''' 49 | print(solution( 50 | [ 51 | [1, 2, 3, 4], 52 | [5, 6, 7, 8], 53 | [9, 10, 11, 12], 54 | [13, 14,15,16] 55 | ], 2)) 56 | ''' 57 | 58 | ''' 59 | 반환값 : 60 | [ 61 | [16, 15, 14, 13], 62 | [12, 11, 10, 9], 63 | [8, 7, 6, 5], 64 | [4, 3, 2, 1] 65 | ] 66 | ''' 67 | -------------------------------------------------------------------------------- /reference/counter.py: -------------------------------------------------------------------------------- 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 | from collections import Counter 8 | 9 | # Counter(iterable) 10 | # iterable 객체(예: 문자열, 리스트, 튜플 등)를 받아, 각 요소의 출현 횟수를 계산하여 Counter 객체를 생성 11 | # 시간 복잡도: O(n), 여기서 n은 iterable의 길이 12 | iterable_example = 'abracadabra' 13 | counter_obj = Counter(iterable_example) 14 | print(counter_obj) 15 | # 출력값: Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}) 16 | 17 | # Counter.most_common(num) 18 | # Counter 객체에서 가장 빈번하게 발생하는 num 개의 요소와 그 개수를 리스트로 반환 19 | # num이 지정되지 않거나 None이면 모든 요소를 반환 20 | # 시간 복잡도: O(n log n), 여기서 n은 Counter 객체의 원수 개수 21 | most_common_elements = counter_obj.most_common(2) 22 | print(most_common_elements) 23 | # 출력값: [('a', 5), ('b', 2)] 24 | 25 | # Counter.elements() 26 | # Counter 객체에서 요소들을 횟수에 따라 반복하는 이터레이터를 반환. 27 | # 시간 복잡도: O(n), 여기서 n은 elements의 총 개수. 28 | elements_iterator = counter_obj.elements() 29 | print(list(elements_iterator)) 30 | # 출력값: ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'r', 'r', 'c', 'd'] 31 | -------------------------------------------------------------------------------- /mistake/index_error_demo.py: -------------------------------------------------------------------------------- 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 | my_list = [10, 20, 30, 40, 50] 8 | 9 | # 실수 예: 리스트의 길이를 넘는 인덱스에 접근하려고 할 때 10 | # print(my_list[5]) # IndexError: list index out of range 11 | 12 | # 파이썬에서 리스트의 인덱스는 0부터 시작하므로 my_list[5]는 유효하지 않습니다. 13 | 14 | # 실수 예: 음수 인덱스를 사용하되 범위를 벗어나는 경우 15 | # print(my_list[-6]) # IndexError: list index out of range 16 | 17 | # 파이썬에서 음수 인덱스는 리스트의 끝에서부터 시작하여 역순으로 원소에 접근합니다. 18 | # -1은 마지막 원소, -2는 끝에서 두 번째 원소를 가리킵니다. 그러나 -6은 범위를 벗어납니다. 19 | 20 | # 올바른 사용법: 인덱스의 유효성을 확인한 후 접근 21 | index_to_access = 4 22 | if 0 <= index_to_access < len(my_list): 23 | print(my_list[index_to_access]) # 올바르게 50을 출력합니다. 24 | 25 | # 음수 인덱스 사용 시 올바른 사용법: 26 | negative_index = -2 27 | if -len(my_list) <= negative_index < 0: 28 | print(my_list[negative_index]) # 올바르게 40을 출력합니다. 29 | 30 | # 문자열에서도 마찬가지로 인덱스 범위를 벗어나면 에러가 발생합니다. 31 | # string_example = "hello" 32 | # print(string_example[10]) # IndexError: string index out of range 33 | -------------------------------------------------------------------------------- /mistake/sorting_methods_comparison.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # array.sort() vs sorted(array) 7 | 8 | # 1. 문법과 개념 설명 9 | # - array.sort()는 리스트 자체를 정렬하며 리턴값이 None입니다. 10 | # 즉, 원본 리스트가 변경됩니다. 11 | # - sorted(array)는 원본 리스트를 변경하지 않고, 새로운 정렬된 리스트를 반환합니다. 12 | 13 | # 초기 리스트 14 | numbers = [3, 1, 2, 4] 15 | 16 | # 2. 어떻게 실수할 수 있는지 17 | 18 | # 잘못된 사용법: array.sort()의 반환값을 다른 변수에 할당하려는 경우 19 | sorted_nums = numbers.sort() 20 | print(sorted_nums) # None이 출력됩니다. 이는 array.sort()가 반환하는 값이 None이기 때문입니다. 21 | 22 | # 올바른 사용법 23 | numbers.sort() # 원본 리스트 자체를 정렬합니다. 24 | print(numbers) # [1, 2, 3, 4]가 출력됩니다. 25 | 26 | # 3. 올바른 사용법 27 | 28 | # sorted 함수를 사용하여 새로운 리스트에 정렬된 결과를 할당 29 | correct_sorted_nums = sorted(numbers) 30 | print(correct_sorted_nums) # [1, 2, 3, 4]가 출력됩니다. 원본 리스트는 변경되지 않습니다. 31 | 32 | # 추가 정보: sorted()는 리스트뿐만 아니라 어떤 iterable 객체도 받아 정렬된 리스트를 반환합니다. 33 | string = "dcba" 34 | sorted_string = sorted(string) 35 | print(sorted_string) # ['a', 'b', 'c', 'd']가 출력됩니다. 36 | -------------------------------------------------------------------------------- /reference/guard_clauses.py: -------------------------------------------------------------------------------- 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 | # "guard clauses"는 특정 조건이 충족되지 않을 때 함수나 루프를 조기에 종료하는 코드 패턴입니다. 8 | # 이 패턴은 중첩을 줄이고 코드의 가독성을 높이기 위해 사용됩니다. 9 | # 일반적으로 "guard clauses"는 함수의 시작 부분에 위치하며, 특정 조건이 충족되지 않을 때 10 | # 함수를 조기에 종료(early exit)하는 방법을 제공합니다. 11 | 12 | def process_data(data): 13 | # data가 리스트가 아니라면, 함수를 조기에 종료한다. 14 | if not isinstance(data, list): 15 | return "Invalid data type" 16 | 17 | # data가 비어 있지 않다면, 처리를 계속한다. 18 | if not data: 19 | return "Data cannot be empty" 20 | 21 | # data를 처리하고 결과를 반환한다. 22 | result = [item * 2 for item in data] 23 | return result 24 | 25 | # 예제 사용법 26 | data_input = [1, 2, 3, 4, 5] 27 | print(process_data(data_input)) # 출력: [2, 4, 6, 8, 10] (정상적인 처리) 28 | 29 | invalid_input = "test" 30 | print(process_data(invalid_input)) # 출력: "Invalid data type" (데이터 타입이 잘못됨) 31 | 32 | empty_input = [] 33 | print(process_data(empty_input)) # 출력: "Data cannot be empty" (데이터가 비어 있음) 34 | -------------------------------------------------------------------------------- /solution/40-2.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | def solution(graph, start): 4 | distances = {node: float("inf") for node in graph} # 모든 노드의 거리 값을 무한대로 초기화 5 | distances[start] = 0 # 시작 노드의 거리 값은 0으로 초기화 6 | queue = [] 7 | heapq.heappush(queue, [distances[start], start]) # 시작 노드를 큐에 삽입 8 | paths = {start: [start]} # 시작 노드의 경로를 초기화 9 | visited = set() # 방문한 노드를 저장할 집합 10 | 11 | while queue: 12 | current_distance, current_node = heapq.heappop(queue) 13 | if current_node in visited: # 이미 방문한 노드는 무시 14 | continue 15 | visited.add(current_node) # 현재 노드를 방문한 노드 집합에 추가 16 | 17 | for adjacent_node, weight in graph[current_node].items(): 18 | distance = current_distance + weight 19 | if distance < distances[adjacent_node]: 20 | distances[adjacent_node] = distance 21 | paths[adjacent_node] = paths[current_node] + [adjacent_node] 22 | heapq.heappush(queue, [distance, adjacent_node]) 23 | 24 | sorted_paths = {node: paths[node] for node in sorted(paths)} 25 | 26 | return [distances, sorted_paths] 27 | 28 | # TEST 코드 29 | print(solution({ 'A': {'B': 9, 'C': 3}, 'B': {'A': 5}, 'C': {'B': 1} }, 'A')) 30 | print(solution({'A': {'B': 1}, 'B': {'C': 5}, 'C': {'D': 1}, 'D': {}}, 'A')) 31 | -------------------------------------------------------------------------------- /reference/while_loop.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 'while'문은 조건이 참(True)인 동안 반복적으로 코드 블록을 실행합니다. 8 | # 'while'문의 구조는 'while 조건:'과 같으며, 조건이 참인 경우 'while' 블록 내의 코드가 계속 실행됩니다. 9 | 10 | # 'and'와 'or'는 논리 연산자로, 여러 조건을 조합하는데 사용됩니다. 11 | # 'and' 연산자: 모든 조건이 참이어야 전체가 참입니다 (&&와 동일). 12 | # 'or' 연산자: 조건 중 하나 이상이 참이면 전체가 참입니다 (||와 동일). 13 | 14 | # 'while'문 예제: 15 | count = 0 16 | 17 | while count < 5: 18 | print(f"Count is: {count}") 19 | count += 1 # count 변수를 1씩 증가시킵니다. 20 | 21 | # 'and'와 'or' 연산자를 사용한 'while'문 예제: 22 | value = 0 23 | 24 | while value < 10: 25 | if value >= 3 and value <= 6: 26 | print(f"The value {value} is between 3 and 6") 27 | elif value < 3 or value > 6: 28 | print(f"The value {value} is outside the range of 3 and 6") 29 | value += 1 # value 변수를 1씩 증가시킵니다. 30 | 31 | # 이 코드는 'while'문의 기본 사용법과 'and', 'or' 논리 연산자의 사용법을 보여줍니다. 32 | # 'while'문을 사용하여 조건이 참인 동안 코드 블록을 반복적으로 실행할 수 있으며, 33 | # 'and', 'or' 논리 연산자를 사용하여 여러 조건을 조합할 수 있습니다. 34 | -------------------------------------------------------------------------------- /solution/41.py: -------------------------------------------------------------------------------- 1 | def solution(graph, source): 2 | # ➊ 그래프의 노드 수 3 | num_vertices = len(graph) 4 | 5 | # ➋ 거리 배열 초기화 6 | distance = [float("inf")] * num_vertices 7 | distance[source] = 0 8 | 9 | # ➌ 직전 경로 배열 초기화 10 | predecessor = [None] * num_vertices 11 | 12 | # ➍ 간선 수 만큼 반복하여 최단 경로 갱신 13 | for temp in range(num_vertices - 1): 14 | for u in range(num_vertices): 15 | for v, weight in graph[u]: 16 | # ➎ 현재 노드 u를 거쳐서 노드 v로 가는 경로의 거리가 기존에 저장된 노드 v까지의 거리보다 짧은 경우 17 | if distance[u] + weight < distance[v]: 18 | # ➏ 최단 거리를 갱신해줍니다. 19 | distance[v] = distance[u] + weight 20 | # ➐ 직전 경로를 업데이트합니다. 21 | predecessor[v] = u 22 | 23 | # ➑ 음의 가중치 순회 체크 24 | for u in range(num_vertices): 25 | for v, weight in graph[u]: 26 | # ➒ 현재 노드 u를 거쳐서 노드 v로 가는 경로의 거리가 기존에 저장된 노드 v까지의 거리보다 짧은 경우 27 | if distance[u] + weight < distance[v]: 28 | # ❿ 음의 가중치 순회가 발견되었으므로 [-1]을 반환합니다. 29 | return [-1] 30 | return [distance, predecessor] 31 | 32 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 33 | # print(solution([[(1, 4), (2, 3), (4, -6 )], [(3, 5)], [(1, 2)], [(0, 7), (2, 4)],[(2, 2)]],0)) #반환갑 : [[0, -2, -4, 3, -6], [None, 2, 4, 1, 0]] 34 | # print(solution([[(1, 5), (2, -1)], [(2, 2)], [(3, -2)], [(0, 2), (1, 6)]],0)) # 반환값 : [-1] 35 | -------------------------------------------------------------------------------- /reference/if_statement.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 'if'문은 조건이 참(True)인지 거짓(False)인지를 검사하는데 사용됩니다. 8 | # 조건이 참인 경우 'if' 블록 내의 코드가 실행되고, 그렇지 않으면 실행되지 않습니다. 9 | # 또한, 'elif'와 'else'를 사용하여 더 많은 조건을 추가할 수 있습니다. 10 | 11 | # 'and'와 'or'는 논리 연산자로, 여러 조건을 조합하는데 사용됩니다. 12 | # 'and' 연산자: 모든 조건이 참이어야 전체가 참입니다 (&&와 동일). 13 | # 'or' 연산자: 조건 중 하나 이상이 참이면 전체가 참입니다 (||와 동일). 14 | 15 | # 예제 코드: 16 | age = 18 17 | has_license = True 18 | 19 | # 'if-elif-else' 구조 사용 예 20 | if age >= 18 and has_license: 21 | print("You are allowed to drive") 22 | elif age >= 18 and not has_license: 23 | print("You are not allowed to drive without a license") 24 | else: 25 | print("You are not allowed to drive") 26 | 27 | # 'or' 연산자 사용 예 28 | is_weekend = True 29 | has_holiday = False 30 | 31 | if is_weekend or has_holiday: 32 | print("You can relax today") 33 | else: 34 | print("You have to work today") 35 | 36 | # 이 코드는 'if' 문의 기본적인 사용법과 'and', 'or' 논리 연산자의 사용법을 보여줍니다. 37 | # 여러 조건을 조합하여 복잡한 조건문을 만들 수 있습니다. 38 | -------------------------------------------------------------------------------- /reference/variable_type.py: -------------------------------------------------------------------------------- 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 | # 1. 정수(Integer): 정수는 양수, 음수 및 0을 포함한 숫자를 나타냅니다. 10 | # 파이썬에서 정수형 변수를 선언할 때는 아래와 같이 합니다. 11 | age = 25 12 | print(age) # 출력: 25 13 | print(type(age)) # 출력: 14 | 15 | # 2. 부동소수점(Floating point): 부동소수점은 소수점이 있는 숫자를 나타냅니다. 16 | # 파이썬에서 부동소수점 변수를 선언할 때는 아래와 같이 합니다. 17 | height = 5.9 18 | print(height) # 출력: 5.9 19 | print(type(height)) # 출력: 20 | 21 | # 3. 문자열(String): 문자열은 한 개 이상의 문자를 나타냅니다. 22 | # 파이썬에서 문자열 변수를 선언할 때는 아래와 같이 합니다. 23 | name = "John" 24 | print(name) # 출력: John 25 | print(type(name)) # 출력: 26 | 27 | # 4. 불리언(Boolean): 불리언은 참(True) 또는 거짓(False) 두 가지 값 중 하나를 나타냅니다. 28 | # 파이썬에서 불리언 변수를 선언할 때는 아래와 같이 합니다. 29 | is_student = True 30 | print(is_student) # 출력: True 31 | print(type(is_student)) # 출력: 32 | 33 | # 이렇게 서로 다른 타입의 변수들을 선언하고 사용할 수 있습니다. 34 | # `type` 함수는 변수의 타입을 확인하는 데 사용됩니다. -------------------------------------------------------------------------------- /reference/in.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 "in" 연산자는 주로 시퀀스(리스트, 튜플, 문자열 등)에 어떤 요소가 포함되어 있는지 검사할 때 사용됩니다. 8 | # 또한 "in" 연산자는 반복문에서도 사용되며, 이 경우 시퀀스의 각 요소를 순회합니다. 9 | # "in" 연산자의 사용은 코드를 간결하고 읽기 쉽게 만들어 줍니다. 10 | 11 | # 예시 1: 리스트에서 "in" 연산자 사용 12 | my_list = [1, 2, 3, 4, 5] 13 | print(3 in my_list) # 출력: True (3이 리스트에 있으므로) 14 | print(6 in my_list) # 출력: False (6이 리스트에 없으므로) 15 | 16 | # 예시 2: 문자열에서 "in" 연산자 사용 17 | my_string = "Hello, Python!" 18 | print('Python' in my_string) # 출력: True ('Python'이 문자열에 포함되어 있으므로) 19 | print('Java' in my_string) # 출력: False ('Java'는 문자열에 포함되어 있지 않으므로) 20 | 21 | # 예시 3: 딕셔너리에서 "in" 연산자 사용 (키 검사) 22 | my_dict = {'a': 1, 'b': 2, 'c': 3} 23 | print('a' in my_dict) # 출력: True ('a'가 딕셔너리의 키 중 하나이므로) 24 | print('d' in my_dict) # 출력: False ('d'는 딕셔너리의 키 중 하나가 아니므로) 25 | 26 | # 예시 4: for 루프에서 "in" 연산자 사용 27 | for i in range(5): # 0부터 4까지의 범위에서 각 요소에 대해 28 | print(i) # 출력: 0, 1, 2, 3, 4 (한 줄에 하나씩) 29 | 30 | # "in" 연산자는 코드를 간단하고 직관적으로 만들며, 다양한 데이터 타입에서 요소의 존재를 검사할 때 유용합니다. 31 | -------------------------------------------------------------------------------- /solution/33.py: -------------------------------------------------------------------------------- 1 | def find(parents, x): 2 | # 루트 노드 찾는 함수 3 | if parents[x] == x: # 만약 x의 부모가 자기 자신이면, 즉 x가 루트 노드라면 4 | return x 5 | # 그렇지 않다면 x의 부모를 찾아서 parents[x]에 저장하고, 6 | # 그 부모 노드의 루트 노드를 찾아서 parents[x]에 저장합니다. 7 | parents[x] = find(parents, parents[x]) 8 | return parents[x] # parents[x]를 반환합니다. 9 | 10 | 11 | def union(parents, x, y): 12 | # 두 개의 집합을 합치는 함수 13 | root1 = find(parents, x) # x가 속한 집합의 루트 노드 찾기 14 | root2 = find(parents, y) # y가 속한 집합의 루트 노드 찾기 15 | 16 | parents[root2] = root1 # y가 속한 집합을 x가 속한 집합에 합침 17 | 18 | def solution(k, operations): 19 | parents = list(range(k)) # 처음에는 각 노드가 자기 자신을 부모로 가지도록 초기화 20 | n = k # 집합의 개수를 저장할 변수, 처음에는 모든 노드가 서로 다른 집합에 있으므로 k 21 | 22 | for op in operations: # operations 리스트에 있는 연산들을 하나씩 처리 23 | if op[0] == "u": # 'u' 연산이면 24 | union(parents, op[1], op[2]) # op[1]과 op[2]가 속한 집합을 합칩니다. 25 | elif op[0] == "f": # 'f' 연산이면 26 | find(parents, op[1]) # op[1]이 속한 집합의 루트 노드를 찾습니다. 27 | 28 | # 모든 노드의 루트 노드를 찾아서 집합의 개수를 계산 29 | n = len(set(find(parents, i) for i in range(k))) 30 | 31 | return n # 집합의 개수를 반환 32 | 33 | 34 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 35 | # print(solution(3,[['u', 0, 1], ['u', 1, 2], ['f', 2]])) # 반환값 : 1 36 | # print(solution(4,[['u', 0, 1], ['u', 2, 3], ['f', 0]])) # 반환값 : 2 37 | -------------------------------------------------------------------------------- /mistake/indexing_convention_tutorial.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 파이썬 리스트는 0-based 인덱싱을 사용합니다. 7 | # 즉, 첫 번째 원소의 인덱스는 0입니다. 8 | my_list = [10, 20, 30, 40, 50] 9 | 10 | # 0-based 인덱싱 사용 11 | print(my_list[0]) # 첫 번째 원소 10을 출력합니다. 12 | 13 | # 실수 예: 1-based 인덱싱을 생각하고 코드를 작성할 경우 14 | # 아래 코드는 두 번째 원소 20을 출력합니다. 15 | # print(my_list[1]) 16 | 17 | # 만약 문제가 1-based 인덱싱을 기준으로 제시된 경우, 18 | # 올바른 인덱스에 접근하기 위해서는 인덱스에서 1을 빼야 합니다. 19 | index_in_1_based = 1 20 | correct_index_in_0_based = index_in_1_based - 1 21 | print(my_list[correct_index_in_0_based]) # 올바르게 첫 번째 원소 10을 출력합니다. 22 | 23 | # 문자열도 0-based 인덱싱을 사용합니다. 24 | my_string = "hello" 25 | print(my_string[0]) # 첫 번째 문자 'h'를 출력합니다. 26 | 27 | # 실수 예: 문자열에서 1-based 인덱싱을 사용하려 할 경우 28 | # 아래 코드는 두 번째 문자 'e'를 출력합니다. 29 | # print(my_string[1]) 30 | 31 | # 마찬가지로, 문제가 1-based 인덱싱을 기준으로 제시된 경우에도 인덱스에서 1을 빼야 합니다. 32 | index_in_1_based_str = 1 33 | correct_index_in_0_based_str = index_in_1_based_str - 1 34 | print(my_string[correct_index_in_0_based_str]) # 올바르게 첫 번째 문자 'h'를 출력합니다. 35 | -------------------------------------------------------------------------------- /performance/list_vs_set_in.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 리스트에서 in 테스트: 리스트에서 'in' 연산자를 사용하여 요소가 있는지 확인하는 것은 선형 시간 복잡도를 가지며, 7 | # 즉, 시간 복잡도는 O(n)입니다. 리스트에서는 각 요소를 처음부터 순차적으로 탐색하여 검색 값이 있는지 확인합니다. 8 | # 9 | # 2. 집합에서 in 테스트: 반면에, 집합(set)에서 'in' 연산자를 사용하면, 일반적으로 상수 시간 복잡도 O(1)으로 요소를 찾을 수 있습니다. 10 | # 이는 집합이 해시 테이블 기반의 자료구조이기 때문에, 요소의 해시 값을 사용하여 빠르게 해당 요소를 찾을 수 있습니다. 11 | import time 12 | 13 | # 데이터 준비 14 | num_elements = 1000000 15 | test_value = num_elements + 1 # 이 값은 리스트와 집합에 없음. 16 | 17 | lst = list(range(num_elements)) 18 | s = set(lst) 19 | 20 | # 리스트에서 in 테스트 21 | start_time = time.time() 22 | result_list = test_value in lst 23 | end_time = time.time() 24 | list_time = end_time - start_time 25 | 26 | # 집합에서 in 테스트 27 | start_time = time.time() 28 | result_set = test_value in s 29 | end_time = time.time() 30 | set_time = end_time - start_time 31 | 32 | print(f"List membership test took: {list_time:.6f} seconds")# 0.019357초(환경마다 다를 수 있음) 33 | print(f"Set membership test took: {set_time:.6f} seconds")# 0.000003초(환경마다 다를 수 있음) 34 | -------------------------------------------------------------------------------- /mistake/operation_precedence_examples.py: -------------------------------------------------------------------------------- 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 | # 1. 문법과 개념 설명 9 | # 파이썬의 연산자는 다음과 같은 우선 순위를 갖습니다 (줄이 내려갈수록 우선순위가 낮아집니다): 10 | # - 괄호: () 11 | # - 지수: ** 12 | # - 부호: +x, -x 13 | # - 곱셈/나눗셈: *, /, %, // 14 | # - 덧셈/뺄셈: +, - 15 | 16 | # 2. 어떻게 실수할 수 있는지 17 | 18 | # 실수 예시 1: 연산 우선 순위를 간과하고 연산을 수행 19 | result = 1 + 3 * 2 # 이 연산은 1 + (3 * 2)로 해석되어, 7이 아닌 7이 됩니다. 20 | print(result) # 7이 출력됩니다. 21 | 22 | # 실수 예시 2: 복잡한 연산에서 괄호를 사용하지 않아 잘못된 결과를 얻는 경우 23 | result2 = 3 + 2 * 2 - 4 / 2 # 이 연산은 3 + (2 * 2) - (4 / 2)로 해석되어, 5가 아닌 5.0이 됩니다. 24 | print(result2) # 5.0이 출력됩니다. 25 | 26 | # 3. 올바른 사용법 27 | 28 | # 올바른 사용법 예시 1: 연산의 우선 순위를 명확하게 하기 위해 괄호 사용 29 | correct_result1 = (1 + 3) * 2 # 괄호를 사용하여 덧셈을 먼저 수행하도록 지정합니다. 30 | print(correct_result1) # 8이 출력됩니다. 31 | 32 | # 올바른 사용법 예시 2: 복잡한 연산에서 괄호를 사용하여 우선 순위를 명확하게 지정 33 | correct_result2 = (3 + 2) * (2 - 4 / 2) # 괄호를 사용하여 연산의 우선 순위를 명확하게 지정합니다. 34 | print(correct_result2) # 5.0이 출력됩니다. 35 | 36 | # 일반적인 팁: 연산의 우선 순위에 혼란이 올 경우, 괄호를 사용하여 우선 순위를 명확하게 지정하는 것이 좋습니다. 37 | -------------------------------------------------------------------------------- /solution/81.py: -------------------------------------------------------------------------------- 1 | # ❶ 각 물건의 단위 무게당 가치를 계산하여 items 리스트에 추가 2 | def calculate_unit_value(items): 3 | for item in items: 4 | item.append(item[1] / item[0]) 5 | return items 6 | 7 | # ❷ 단위 무게당 가치가 높은 순으로 물건을 정렬 8 | def sort_by_unit_value(items): 9 | items.sort(key=lambda x: x[2], reverse=True) 10 | return items 11 | 12 | 13 | def knapsack(items, weight_limit): 14 | total_value = 0 # ❸ 선택한 물건들의 총 가치를 저장하는 변수 15 | remaining_weight = weight_limit # ❹ 남은 무게 한도를 저장하는 변수 16 | 17 | # ❺ 물건을 선택합니다. 18 | for item in items: 19 | if item[0] <= remaining_weight: 20 | # ❻ 남은 무게 한도 내에서 물건을 통째로 선택 21 | total_value += item[1] 22 | remaining_weight -= item[0] 23 | else: 24 | # ❼ 남은 무게 한도가 물건의 무게보다 작으면 쪼개서 일부분만 선택 25 | fraction = remaining_weight / item[0] 26 | total_value += item[1] * fraction 27 | break # ❽ 이미 배낭의 무게 한도를 모두 사용한 경우, 28 | return total_value 29 | 30 | def solution(items, weight_limit): 31 | items = calculate_unit_value(items) 32 | items = sort_by_unit_value(items) 33 | 34 | # ❾ 배낭의 무게 한도 내에서 담을 수 있는 물건들의 최대 가치를 반환 35 | return knapsack(items, weight_limit) 36 | 37 | 38 | 39 | 40 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 41 | # print(solution([[10, 19], [7, 10], [6, 10]], 15)) # 반환값 : 273.33 42 | # print(solution([[10, 60], [20, 100], [30, 120]], 50)) # 반환값 : 240 43 | -------------------------------------------------------------------------------- /performance/string_concatenation_performance.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. += 연산자 사용: 이 부분에서는 문자열 결합을 위해 += 연산자를 사용합니다. 문자열은 변경이 불가능한 객체이므로, 7 | # 매번 += 연산을 수행할 때마다 새로운 문자열 객체가 생성되고, 이전 문자열의 내용과 새로운 문자열의 내용이 복사됩니다. 8 | # 이로 인해 이 연산은 시간 복잡도 O(n^2)를 가지게 됩니다. 9 | # 10 | # 2. join() 메서드 사용: join() 메서드는 문자열 리스트를 한 번에 결합하는 방법을 제공합니다. 11 | # 이 메서드는 내부적으로 더 효율적인 메모리 관리를 하며, 문자열을 한 번에 합치기 때문에 시간 복잡도 O(n)을 가집니다. 12 | # 따라서, 큰 문자열 리스트에서는 join() 메서드가 += 연산자보다 훨씬 빠른 성능을 보여줍니다. 13 | 14 | import time 15 | 16 | num_elements = 1000000 17 | strings = ["abcd"] * num_elements 18 | 19 | # += 연산자 사용 20 | start_time = time.time() 21 | result_str = "" 22 | for s in strings: 23 | result_str += s 24 | plus_equals_time = time.time() - start_time 25 | 26 | # join() 메서드 사용 27 | start_time = time.time() 28 | result_str = "".join(strings) 29 | join_time = time.time() - start_time 30 | 31 | print(f"Using += operator took: {plus_equals_time:.6f} seconds")# 0.514103초(환경 마다 다를 수 있음) 32 | print(f"Using join() method took: {join_time:.6f} seconds")# 0.020838초(환경 마다 다를 수 있음) 33 | -------------------------------------------------------------------------------- /reference/list_comprehension.py: -------------------------------------------------------------------------------- 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 | # "List comprehension"은 리스트를 생성하는 간결하고 효율적인 방법입니다. 8 | # 기본 구조는 [expression for item in iterable if condition] 이며, 이 구조를 사용하여 9 | # for 문과 if 문을 사용한 루프보다 더 간결하게 리스트를 생성할 수 있습니다. 10 | 11 | # 예시 1: 0부터 9까지의 숫자로 리스트 생성 12 | simple_list_comprehension = [x for x in range(10)] 13 | print(simple_list_comprehension) # 출력: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 14 | 15 | # 예시 2: 0부터 9까지의 짝수로 리스트 생성 16 | even_numbers = [x for x in range(10) if x % 2 == 0] 17 | print(even_numbers) # 출력: [0, 2, 4, 6, 8] 18 | 19 | # 예시 3: 0부터 9까지의 숫자의 제곱으로 리스트 생성 20 | squares = [x**2 for x in range(10)] 21 | print(squares) # 출력: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] 22 | 23 | # 예시 4: 두 리스트의 모든 가능한 쌍을 생성 24 | list1 = [1, 2, 3] 25 | list2 = ['a', 'b', 'c'] 26 | pairs = [(x, y) for x in list1 for y in list2] 27 | print(pairs) # 출력: [(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b'), (2, 'c'), (3, 'a'), (3, 'b'), (3, 'c')] 28 | 29 | # List comprehension은 코드를 간결하게 만들고, 코드의 가독성을 향상시킵니다. 30 | # 또한, 내부적으로 최적화되어 일반적인 for 루프보다 빠른 실행 시간을 제공합니다. 31 | -------------------------------------------------------------------------------- /solution/42.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | def solution(maps): 4 | # ➊ 이동할 수 있는 방향을 나타내는 배열 move 선언 5 | move = [[-1, 0], [0, -1], [0, 1], [1, 0]] 6 | 7 | # ➋ 맵의 크기를 저장하는 변수 선언 8 | n = len(maps) 9 | m = len(maps[0]) 10 | 11 | # ➌ 거리를 저장하는 배열 dist를 -1로 초기화 12 | dist = [[-1] * m for _ in range(n)] 13 | 14 | # ➍ bfs 함수를 선언 15 | def bfs(start): 16 | # ➎ deque를 선언, 시작 위치를 deque에 추가 17 | q = deque([start]) 18 | dist[start[0]][start[1]] = 1 19 | 20 | # ➏ deque가 빌 때까지 반복 21 | while q: 22 | here = q.popleft() 23 | 24 | # ➐ 현재 위치에서 이동할 수 있는 모든 방향 25 | for direct in move: 26 | row, column = here[0] + direct[0], here[1] + direct[1] 27 | 28 | # ➑ 이동한 위치가 범위를 벗어난 경우 다음 방향으로 넘어감 29 | if row < 0 or row >= n or column < 0 or column >= m: 30 | continue 31 | 32 | # ➒ 이동한 위치에 벽이 있는 경우 다음 방향으로 넘어 33 | if maps[row][column] == 0: 34 | continue 35 | 36 | # ➓ 이동한 위치가 처음 방문하는 경우, deque에 추가하고 거리 갱신 37 | if dist[row][column] == -1: 38 | q.append([row, column]) 39 | dist[row][column] = dist[here[0]][here[1]] + 1 40 | 41 | # 거리를 저장하는 배열 dist를 반환 42 | return dist 43 | 44 | # 시작 위치에서 bfs( ) 함수를 호출하여 거리 계산 45 | bfs([0, 0]) 46 | 47 | # 목적지까지의 거리 반환, 목적지에 도달하지 못한 경우 -1을 반환 48 | return dist[n - 1][m - 1] 49 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/dfs_recursion.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # DFS(깊이 우선 탐색)은 그래프나 트리를 탐색하는 알고리즘 중 하나로, 8 | # 루트 노드(혹은 다른 임의의 노드)에서 시작하여 마지막 노드까지 깊이를 우선하여 탐색하는 알고리즘입니다. 9 | # 재귀함수 혹은 스택을 사용하여 구현할 수 있습니다. 10 | 11 | # 2. 예시 입력 / 출력: 12 | # 입력: graph = {1: [2, 3], 2: [4, 5], 3: [], 4: [], 5: []}, start_node = 1 13 | # 출력: 1, 2, 4, 5, 3 14 | 15 | # 3. 알고리즘의 시간 복잡도: 16 | # O(V + E) (V: 정점의 개수, E: 간선의 개수) 17 | 18 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 19 | # - 경로 찾기 20 | # - 사이클 탐지 21 | # - 그래프 연결 성분 찾기 22 | 23 | 24 | def dfs(graph, start_node,visited): 25 | visited[start_node] = True 26 | print(start_node) 27 | 28 | for adj_node in graph[start_node]: # 인접한 노드 방문 29 | if not visited[adj_node]: 30 | dfs(graph,adj_node,visited) 31 | 32 | 33 | # 그래프를 인접 리스트로 표현 34 | graph = { 35 | 1: [2, 3], 36 | 2: [4, 5], 37 | 3: [], 38 | 4: [], 39 | 5: [] 40 | } 41 | 42 | visited = [False] * (len(graph) + 1) 43 | # DFS 알고리즘 실행 44 | dfs(graph, 1,visited) # 1 2 4 5 3 45 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/stack.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 자료구조 개념: 7 | # 스택(Stack)은 선입후출(FILO, First In Last Out) 원칙에 따라 작동하는 자료구조입니다. 8 | # 새로운 요소는 스택의 상단에 추가되고, 상단의 요소만이 삭제될 수 있습니다. 9 | 10 | # 2. 예시 입력 / 출력: 11 | # 입력: [1, 2, 3, 4] 12 | # 출력: [1, 2, 3] (4를 pop한 결과) 13 | 14 | # 3. 자료구조의 시간 복잡도: 15 | # - Push: O(1) 16 | # - Pop: O(1) 17 | # - Top: O(1) 18 | 19 | # 4. 해당 자료구조로 풀 수 있는 문제 예시: 20 | # - 괄호 짝 맞추기 21 | # - 브라우저 뒤로 가기 기능 22 | # - 트리의 깊이 우선 탐색(DFS) 23 | 24 | # 5. 상세과정: 25 | # - 스택 생성: 리스트를 초기화하여 스택으로 사용 26 | # - Push: 리스트의 append 메소드를 사용하여 요소를 스택의 맨 위에 추가 27 | # - Pop: 리스트의 pop 메소드를 사용하여 스택의 맨 위 요소를 삭제하고 반환 28 | # - Top: 리스트의 마지막 요소를 참조하여 스택의 맨 위 요소를 확인 29 | 30 | # 스택 생성 31 | stack = [] 32 | 33 | # Push 연산: 요소를 스택의 맨 위에 추가 34 | stack.append(1) 35 | stack.append(2) 36 | stack.append(3) 37 | stack.append(4) 38 | print(stack) # 출력: [1, 2, 3, 4] 39 | 40 | # Top 연산: 스택의 맨 위 요소 확인 41 | print(stack[-1]) # 출력: 4 42 | 43 | # Pop 연산: 스택의 맨 위 요소 삭제 및 반환 44 | stack.pop() 45 | print(stack) # 출력: [1, 2, 3] 46 | -------------------------------------------------------------------------------- /performance/for_loop_vs_list_comprehension.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. for 루프 사용: 이 부분에서는 for 루프를 사용하여 각 숫자의 제곱을 계산하고, 이를 squared_numbers 리스트에 하나씩 추가합니다. 7 | # 이 과정에서 반복문을 통해 반복적인 메서드 호출이 발생하며, 일반적으로 시간 복잡도는 O(n)입니다. 8 | # 9 | # 2. list comprehension 사용: list comprehension은 for 루프를 사용하는 것보다 더 빠른 방법으로 리스트를 생성할 수 있습니다. 10 | # 이는 내부적으로 최적화가 더 잘 되어 있어 연산이 더 빠르게 진행되기 때문입니다. 11 | # 이 방법 역시 시간 복잡도는 O(n)이지만, 상수 시간 요소가 for 루프보다 작아 성능이 더 좋습니다. 12 | import time 13 | 14 | num_elements = 10000000 15 | 16 | # for 루프 사용 17 | start_time = time.time() 18 | squared_numbers = [] 19 | for i in range(num_elements): 20 | squared_numbers.append(i * i) 21 | for_loop_time = time.time() - start_time 22 | 23 | # list comprehension 사용 24 | start_time = time.time() 25 | squared_numbers_comprehension = [i * i for i in range(num_elements)] 26 | list_comprehension_time = time.time() - start_time 27 | 28 | print(f"Using for loop took: {for_loop_time:.6f} seconds") # 1.347505초(환경마다 다를 수 있음) 29 | print(f"Using list comprehension took: {list_comprehension_time:.6f} seconds") # 0.536171초(환경마다 다를 수 있음) 30 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/fibonacci_recursion_memoization.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # 피보나치 수열은 첫 번째와 두 번째 항이 1이고, 그 이후의 항은 직전의 두 항의 합인 수열입니다. 8 | # 이 알고리즘은 메모이제이션을 사용하여 이전에 계산한 값을 저장하고 재사용함으로써, 중복 계산을 방지하는 피보나치 재귀 알고리즘입니다. 9 | 10 | # 2. 예시 입력 / 출력: 11 | # 입력: 5 12 | # 출력: 5 (피보나치 수열의 5번째 항은 5입니다) 13 | 14 | # 3. 알고리즘의 시간 복잡도: 15 | # 이 알고리즘의 시간 복잡도는 O(n)입니다. 메모이제이션 덕분에 각 n에 대해 계산은 한 번만 이루어집니다. 16 | 17 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 18 | # - n 번째 피보나치 수 찾기 19 | # - 피보나치 수열을 사용하여 다양한 수학적 문제 해결 20 | 21 | # 5. 상세 과정: 22 | # - n이 0이나 1인 경우, n을 반환합니다. (기저 사례) 23 | # - n이 메모 딕셔너리에 이미 키로 존재하면, 해당 값을 반환합니다. 24 | # - 그렇지 않으면, fibonacci(n-1)과 fibonacci(n-2)를 재귀적으로 호출하여 두 결과를 합칩니다. 그리고 이 값을 메모 딕셔너리에 저장한 후 반환합니다. 25 | def fibonacci(n, memo={}): 26 | if n <= 1: 27 | return n 28 | 29 | # 이미 계산된 값이면 메모에서 반환 30 | if n in memo: 31 | return memo[n] 32 | 33 | # 새로운 값 계산 후 메모에 저장 34 | memo[n] = fibonacci(n-1, memo) + fibonacci(n-2, memo) 35 | return memo[n] 36 | 37 | # 예제: 38 | print(fibonacci(5)) # 출력: 5 39 | -------------------------------------------------------------------------------- /mistake/binary_search_mistake.py: -------------------------------------------------------------------------------- 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 | sorted_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 8 | 9 | # 실수 예: 잘못 짠 이분 탐색 10 | def incorrect_binary_search(arr, target): 11 | low = 0 12 | high = len(arr) - 1 13 | 14 | while low <= high: 15 | mid = (low + high) // 2 16 | if arr[mid] == target: 17 | return mid 18 | elif arr[mid] < target: 19 | low = mid # 여기서 mid + 1이 되어야 합니다. 20 | else: 21 | high = mid # 여기서 mid - 1이 되어야 합니다. 22 | 23 | return -1 24 | 25 | # 위의 코드는 잘못된 업데이트 방식 때문에 무한 루프에 빠질 수 있습니다. 26 | 27 | # 올바른 사용법: 이분 탐색 28 | def binary_search(arr, target): 29 | low = 0 30 | high = len(arr) - 1 31 | 32 | while low <= high: 33 | mid = (low + high) // 2 34 | if arr[mid] == target: 35 | return mid 36 | elif arr[mid] < target: 37 | low = mid + 1 # 올바르게 범위를 조정 38 | else: 39 | high = mid - 1 # 올바르게 범위를 조정 40 | 41 | return -1 42 | 43 | print(binary_search(sorted_list, 5)) # 올바르게 4를 출력 44 | -------------------------------------------------------------------------------- /reference/zip.py: -------------------------------------------------------------------------------- 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 | # 파이썬의 "zip" 함수는 여러 개의 이터러블(iterable) 객체 (예: 리스트, 튜플)의 요소들을 "포장"하여, 8 | # 한 번에 하나씩 각 이터러블의 동일한 인덱스에 있는 요소들을 튜플로 그룹화하여 반환합니다. 9 | # 이는 여러 이터러블의 데이터를 동시에 순회할 수 있게 해줍니다. 10 | # zip 함수의 반환 값은 zip 객체이며, 이는 반복자이므로 리스트 또는 튜플로 변환하여 내용을 확인할 수 있습니다. 11 | 12 | # 예시 1: 두 리스트를 zip 함수로 묶기 13 | list1 = [1, 2, 3, 4] 14 | list2 = ['a', 'b', 'c', 'd'] 15 | zipped = zip(list1, list2) 16 | # zip 객체를 리스트로 변환하여 출력 17 | print(list(zipped)) # 출력: [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')] 18 | 19 | # 예시 2: 세 리스트를 zip 함수로 묶기 20 | list3 = ['apple', 'banana', 'cherry', 'date'] 21 | zipped = zip(list1, list2, list3) 22 | # zip 객체를 리스트로 변환하여 출력 23 | print(list(zipped)) # 출력: [(1, 'a', 'apple'), (2, 'b', 'banana'), (3, 'c', 'cherry'), (4, 'd', 'date')] 24 | 25 | # 예시 3: zip 함수와 for 루프 함께 사용 26 | # 아래의 코드는 zip 함수를 이용하여 두 리스트의 요소를 동시에 순회하는 예입니다. 27 | for num, letter in zip(list1, list2): 28 | print(f"{num} is paired with '{letter}'") # 각 숫자와 문자가 페어로 출력됩니다. 29 | 30 | # 참고: zip 함수는 가장 짧은 길이의 이터러블이 완료되면 중지됩니다. 31 | # 따라서 이터러블의 길이가 다르면, zip 함수는 가장 짧은 이터러블의 길이에 맞춰서 그룹을 생성합니다. 32 | -------------------------------------------------------------------------------- /performance/list_vs_deque_pop_performance.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 리스트에서 pop(0) 사용: 리스트에서 pop(0) 메서드를 사용하면 리스트의 첫 번째 요소를 제거하고, 7 | # 나머지 요소들을 한 칸씩 앞으로 이동합니다. 이 때문에 이 연산의 시간 복잡도는 O(n)입니다. 8 | # 여기서 n은 리스트의 길이입니다. 반복적으로 pop(0)을 호출하면 전체 시간 복잡도는 O(n^2)가 됩니다. 9 | # 10 | # 2. deque에서 popleft() 사용: deque 자료구조에서 popleft() 메서드를 사용하면, 첫 번째 요소를 상수 시간에 제거할 수 있습니다. 11 | # 이 메서드의 시간 복잡도는 O(1)입니다. 따라서, 반복적으로 popleft()를 호출하면 전체 시간 복잡도는 O(n)이 됩니다. 12 | 13 | import time 14 | from collections import deque 15 | 16 | num_elements = 100000 17 | 18 | # 리스트에서 pop(0) 사용 19 | lst = list(range(num_elements)) 20 | start_time = time.time() 21 | while lst: 22 | lst.pop(0) 23 | list_pop_time = time.time() - start_time 24 | 25 | # deque에서 popleft() 사용 26 | dq = deque(range(num_elements)) 27 | start_time = time.time() 28 | while dq: 29 | dq.popleft() 30 | deque_popleft_time = time.time() - start_time 31 | 32 | print(f"Using list's pop(0) took: {list_pop_time:.6f} seconds")# 1.152777초(환경마다 다를 수 있음) 33 | print(f"Using deque's popleft() took: {deque_popleft_time:.6f} seconds")# 0.019073초(환경마다 다를 수 있음) 34 | -------------------------------------------------------------------------------- /reference/def.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 "def" 키워드는 함수를 정의할 때 사용됩니다. 8 | # 함수는 특정 작업을 수행하는 코드 블록입니다. 9 | # 함수는 인자를 받을 수도 있고, 결과를 반환할 수도 있습니다. 10 | 11 | # 1. 인자가 없고 반환 값도 없는 함수: 12 | def greet(): 13 | print("Hello!") 14 | 15 | # 함수 호출: greet() 16 | # 출력: Hello! 17 | 18 | # 2. 인자가 있는 함수: 19 | def greet_person(name): 20 | print(f"Hello, {name}!") 21 | 22 | # 함수 호출: greet_person("John") 23 | # 출력: Hello, John! 24 | 25 | # 3. 기본 인자가 있는 함수: 26 | # 기본 인자는, 인자가 전달되지 않은 경우 사용되는 기본 값을 설정합니다. 27 | def greet_with_default(name="Guest"): 28 | print(f"Hello, {name}!") 29 | 30 | # 함수 호출: greet_with_default() 31 | # 출력: Hello, Guest! 32 | 33 | # 4. 반환 값이 있는 함수: 34 | # "return" 키워드를 사용하여 함수의 결과를 반환할 수 있습니다. 35 | def add_numbers(a, b): 36 | return a + b 37 | 38 | # 함수 호출: add_numbers(1, 2) 39 | # 반환 값: 3 40 | 41 | # 이제 각 함수를 호출해보며 그 결과를 확인해봅시다! 42 | greet() 43 | greet_person("John") 44 | greet_with_default() 45 | result = add_numbers(1, 2) 46 | print(f"Result of addition: {result}") 47 | 48 | # 위 코드에서는 다양한 유형의 함수를 "def" 키워드를 사용하여 정의했습니다. 49 | # 함수의 인자와 반환 값에 대한 개념도 설명했습니다. 50 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/tree_array.py: -------------------------------------------------------------------------------- 1 | # 트리를 배열로 구현하는 예시: 2 | 3 | # 트리는 일반적으로 노드와 간선으로 구성되며, 노드는 부모-자식 관계를 가집니다. 4 | # 배열로 트리를 구현할 때, 인덱스를 활용해 부모 노드와 자식 노드 간의 관계를 표현합니다. 5 | # 예를 들어, 인덱스 i의 노드의 왼쪽 자식 노드는 2*i, 오른쪽 자식 노드는 2*i + 1로 표현할 수 있습니다. 6 | # 이 방법은 O(1)의 시간 복잡도를 가지며, 부모 노드와 자식 노드 간의 관계를 빠르게 파악할 수 있습니다. 7 | # 그러나 모든 노드가 채워져 있지 않다면 메모리가 낭비될 수 있습니다. 8 | 9 | # 도식화: 10 | # 예를 들어, 다음과 같은 트리를 생각해 봅시다. 11 | # 1 12 | # / \ 13 | # 2 3 14 | # / \ / \ 15 | # 4 5 6 7 16 | # 이 트리를 배열로 표현하면 다음과 같습니다. 17 | # [None, 1, 2, 3, 4, 5, 6, 7] 18 | # (None은 트리의 루트가 1번 인덱스에 위치하도록 하기 위한 dummy 데이터입니다.) 19 | 20 | # 트리를 배열로 표현 21 | tree = [None, 1, 2, 3, 4, 5, 6, 7] 22 | 23 | def get_left_child_idx(idx): 24 | return 2 * idx 25 | 26 | def get_right_child_idx(idx): 27 | return 2 * idx + 1 28 | 29 | # 루트 노드의 값 출력 30 | print("Root node:", tree[1]) 31 | 32 | # 루트 노드의 왼쪽 자식 노드 값 출력 33 | left_idx = get_left_child_idx(1) 34 | print("Left child of root node:", tree[left_idx]) 35 | 36 | # 루트 노드의 오른쪽 자식 노드 값 출력 37 | right_idx = get_right_child_idx(1) 38 | print("Right child of root node:", tree[right_idx]) 39 | 40 | # 특정 노드 (예: 인덱스 3)의 왼쪽과 오른쪽 자식 노드 값 출력 41 | node_idx = 3 42 | print(f"Node at index {node_idx}:", tree[node_idx]) 43 | print(f"Left child of node at index {node_idx}:", tree[get_left_child_idx(node_idx)]) 44 | print(f"Right child of node at index {node_idx}:", tree[get_right_child_idx(node_idx)]) 45 | -------------------------------------------------------------------------------- /performance/list_vs_heapq.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. list 사용: 리스트에 요소를 추가한 후에 매번 정렬을 수행합니다. 7 | # 이 경우, append 연산은 O(1)의 시간 복잡도를 가지지만, sort() 메서드는 O(n log n)의 시간 복잡도를 가집니다. 8 | # 따라서 전체 작업의 시간 복잡도는 O(n^2 log n)이 됩니다. 9 | # 2. heapq 사용: heapq는 이진 힙 자료구조를 사용하여 요소를 추가할 때마다 힙 속성을 유지합니다. 10 | # heappush 연산은 O(log n)의 시간 복잡도를 가집니다. 11 | # 따라서 전체 작업의 시간 복잡도는 O(n log n)이 됩니다. 12 | import heapq 13 | import time 14 | import random 15 | 16 | num_elements = 10000 17 | lst = [] 18 | heap = [] 19 | 20 | # 일반 리스트 사용 21 | start_time = time.time() 22 | for _ in range(num_elements): 23 | val = random.randint(1, num_elements) 24 | lst.append(val) 25 | lst.sort() 26 | list_time = time.time() - start_time 27 | 28 | # heapq 사용 29 | start_time = time.time() 30 | for _ in range(num_elements): 31 | val = random.randint(1, num_elements) 32 | heapq.heappush(heap, val) 33 | heap_time = time.time() - start_time 34 | 35 | print(f"Insertion & sort in list took: {list_time:.6f} seconds")# 0.757835초(환경마다 달라질수 있음) 36 | print(f"Insertion using heapq took: {heap_time:.6f} seconds")# 0.022424초(환경마다 달라질수 있음) 37 | -------------------------------------------------------------------------------- /mistake/list_in_del_usage.py: -------------------------------------------------------------------------------- 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 | my_list = [10, 20, 30, 40, 50] 8 | 9 | # 1. in 연산자 10 | # `in` 연산자는 리스트에 특정 요소가 있는지 확인하는데 사용됩니다. 11 | 12 | if 20 in my_list: 13 | print("20 is in the list!") # 출력: 20 is in the list! 14 | 15 | # 2. del 문 16 | # `del`은 리스트의 특정 위치에 있는 요소를 삭제하는 데 사용됩니다. 17 | 18 | del my_list[1] # 인덱스 1의 요소 (20)를 삭제 19 | print(my_list) # 출력: [10, 30, 40, 50] 20 | 21 | # 실수 예: 잘못된 인덱스로 접근 22 | # del my_list[10] # IndexError: list assignment index out of range 23 | 24 | # 올바른 사용법: 삭제 전에 인덱스의 유효성 확인 25 | index_to_delete = 10 26 | if 0 <= index_to_delete < len(my_list): 27 | del my_list[index_to_delete] 28 | 29 | # 실수 예: `in` 연산자의 효율성 30 | # 큰 리스트에서 `in` 연산자를 사용하는 것은 비효율적일 수 있습니다. 31 | # 이는 `in` 연산자가 리스트 전체를 순회하면서 요소를 찾기 때문입니다. 32 | large_list = list(range(1, 1000000)) 33 | # if 999999 in large_list: # 이 연산은 리스트의 크기에 따라 시간이 오래 걸릴 수 있습니다. 34 | 35 | # 올바른 사용법: 가능한 경우, 집합(set)과 같은 더 효율적인 자료구조를 사용 36 | large_set = set(range(1, 1000000)) 37 | if 999999 in large_set: # 집합에서의 멤버십 테스트는 평균적으로 더 빠릅니다. 38 | print("999999 is in the set!") # 출력: 999999 is in the set! 39 | -------------------------------------------------------------------------------- /solution/64.py: -------------------------------------------------------------------------------- 1 | def solution(n): 2 | # ❶ n 크기의 2차원 배열 생성 3 | snail_array = [[0] * n for _ in range(n)] 4 | 5 | num = 1 # ❷ 달팽이 수열의 시작 숫자 6 | 7 | # ❸ 행과 열의 시작과 끝 인덱스를 설정 8 | start_row, end_row = 0, n - 1 9 | start_col, end_col = 0, n - 1 10 | 11 | while start_row <= end_row and start_col <= end_col: 12 | # ❹ 첫 번째 행 채우기 13 | for i in range(start_col, end_col + 1): 14 | snail_array[start_row][i] = num 15 | num += 1 16 | start_row += 1 17 | 18 | # ❺ 마지막 열 채우기 19 | for i in range(start_row, end_row + 1): 20 | snail_array[i][end_col] = num 21 | num += 1 22 | end_col -= 1 23 | 24 | # ❻ 마지막 행 채우기 25 | if start_row <= end_row: 26 | for i in range(end_col, start_col - 1, -1): 27 | snail_array[end_row][i] = num 28 | num += 1 29 | end_row -= 1 30 | 31 | # ❼ 첫 번째 열 채우기 32 | if start_col <= end_col: 33 | for i in range(end_row, start_row - 1, -1): 34 | snail_array[i][start_col] = num 35 | num += 1 36 | start_col += 1 37 | 38 | return snail_array 39 | 40 | 41 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 42 | # print(solution(3)) 43 | 44 | ''' 45 | 반환값 : 46 | [ 47 | [1, 2, 3], 48 | [8, 9, 4], 49 | [7, 6, 5] 50 | ] 51 | ''' 52 | 53 | # print(solution(4)) 54 | 55 | ''' 56 | 반환값 : 57 | [ 58 | [1, 2, 3, 4], 59 | [12, 13, 14, 5], 60 | [11, 16, 15, 6], 61 | [10, 9, 8, 7] 62 | ] 63 | ''' 64 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/priority_queue.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # 우선순위 큐는 각 원소가 우선순위를 가진 데이터의 집합에서, 8 | # 우선순위가 가장 높은 원소를 가장 먼저 삭제하는 자료구조입니다. 9 | # Python의 heapq 모듈은 최소 힙을 제공하여 우선순위 큐를 구현할 수 있습니다. 10 | 11 | # 2. 예시 입력 / 출력: 12 | # 입력: [(1, 'Task 1'), (3, 'Task 3'), (2, 'Task 2')] 13 | # 출력: 'Task 1', 'Task 2', 'Task 3' 14 | 15 | # 3. 알고리즘의 시간 복잡도: 16 | # - 삽입: O(log n) 17 | # - 삭제(최소 원소 추출): O(log n) 18 | 19 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 20 | # - 작업 스케줄링 21 | # - 네트워크 트래픽 제어 22 | # - 데이터 스트림의 중간 값 찾기 23 | import heapq 24 | 25 | # 우선순위 큐(최소 힙) 초기화 26 | priority_queue = [] 27 | 28 | # 원소 삽입 29 | heapq.heappush(priority_queue, (1, 'Task 1')) 30 | heapq.heappush(priority_queue, (3, 'Task 3')) 31 | heapq.heappush(priority_queue, (2, 'Task 2')) 32 | 33 | # 큐의 모든 원소 출력 (힙 트리의 형태로 저장되어 있음) 34 | print(priority_queue) # 출력: [(1, 'Task 1'), (3, 'Task 3'), (2, 'Task 2')] 35 | 36 | # 최소 원소 삭제 및 반환 37 | print(heapq.heappop(priority_queue)) # 출력: (1, 'Task 1') 38 | print(heapq.heappop(priority_queue)) # 출력: (2, 'Task 2') 39 | print(heapq.heappop(priority_queue)) # 출력: (3, 'Task 3') 40 | -------------------------------------------------------------------------------- /reference/insertionsort.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 삽입 정렬(Insertion Sort)의 개념: 7 | # - 삽입 정렬은 배열의 각 원소를 이미 정렬된 부분에 적절한 위치에 삽입하는 방식으로 동작합니다. 8 | # - 이 과정을 배열의 모든 원소에 대해 반복하여 전체 배열을 정렬합니다. 9 | 10 | # 시간 복잡도: 11 | # - 최선의 경우: O(n) 12 | # - 평균 및 최악의 경우: O(n^2) 13 | 14 | # 삽입 정렬 과정 도식화: 15 | # e.g., arr = [5, 3, 8, 4, 2] 16 | # |-> i=1, key=3: [5, 5, 8, 4, 2] -> [3, 5, 8, 4, 2] 17 | # |-> i=2, key=8: (변경 없음) -> [3, 5, 8, 4, 2] 18 | # |-> i=3, key=4: [3, 5, 8, 8, 2] -> [3, 5, 5, 8, 2] -> [3, 4, 5, 8, 2] 19 | # |-> i=4, key=2: [3, 4, 5, 8, 8] -> [3, 4, 5, 5, 8] -> [3, 4, 4, 5, 8] -> [3, 3, 4, 5, 8] -> [2, 3, 4, 5, 8] 20 | 21 | def insertion_sort(arr): 22 | # 삽입 정렬의 기본 아이디어는 각 원소를 이미 정렬된 부분 배열에 올바른 위치에 '삽입'하는 것입니다. 23 | for i in range(1, len(arr)): 24 | key = arr[i] 25 | j = i - 1 26 | 27 | # 현재 원소(key)를 정렬된 부분 배열에 적절한 위치에 삽입하는 과정 28 | while j >= 0 and key < arr[j]: 29 | arr[j + 1] = arr[j] 30 | j -= 1 31 | 32 | # 적절한 위치에 key 값을 삽입 33 | arr[j + 1] = key 34 | 35 | return arr 36 | 37 | arr = [5, 3, 8, 4, 2] 38 | sorted_arr = insertion_sort(arr) 39 | print(sorted_arr) 40 | -------------------------------------------------------------------------------- /reference/map_reduce.py: -------------------------------------------------------------------------------- 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 | # "map"과 "reduce" 함수는 iterable 객체를 효율적으로 처리할 수 있는 파이썬의 내장 함수입니다. 8 | 9 | from functools import reduce 10 | 11 | # 1. map 함수: 12 | # map 함수는 각 요소에 함수를 적용한 결과를 반환하는 반복자를 생성합니다. 13 | # 기본 구조는 "map(function, iterable)" 입니다. 14 | 15 | # map 함수 사용 예: 16 | numbers = [1, 2, 3, 4, 5] 17 | 18 | # lambda 함수를 사용하여 각 요소를 제곱하고, map 객체를 반환합니다. 19 | # 이 때, lambda 함수가 리스트 numbers의 각 요소에 대해 한 번씩 호출됩니다. 20 | squared_numbers = map(lambda x: x**2, numbers) 21 | 22 | # map 객체를 리스트로 변환하여 결과를 확인합니다. 23 | # 여기에서 map 객체를 리스트로 변환하는 과정에서 실제로 lambda 함수가 호출되며, 각 요소를 제곱합니다. 24 | print(list(squared_numbers)) # 출력: [1, 4, 9, 16, 25] 25 | 26 | 27 | # 2. reduce 함수: 28 | # reduce 함수는 iterable의 요소들을 차례대로 함수에 적용하면서 결과를 누적하여 최종 결과를 반환합니다. 29 | # 기본 구조는 "reduce(function, iterable)" 입니다. 30 | 31 | # reduce 함수 사용 예: 32 | # reduce 함수를 사용하여 numbers 리스트의 모든 요소의 합계를 계산합니다. 33 | # 이 과정에서 lambda 함수가 첫 번째와 두 번째 요소를 더하고, 그 결과를 다음 요소와 더하는 과정을 반복하여 최종 결과를 반환합니다. 34 | sum_of_numbers = reduce(lambda x, y: x + y, numbers) 35 | 36 | # 최종 결과를 출력합니다. 37 | print(sum_of_numbers) # 출력: 15 38 | 39 | # 이렇게 map과 reduce 함수를 사용하면 복잡한 연산을 단순하고 효율적으로 수행할 수 있습니다. 40 | -------------------------------------------------------------------------------- /solution/37.py: -------------------------------------------------------------------------------- 1 | def find(parent, i): 2 | # ➊ 'i'가 속한 집합의 루트 노드 찾기 3 | if parent[i] == i: 4 | return i 5 | # ➋ 경로 압축: 'i'의 부모를 직접 루트로 설정 6 | parent[i] = find(parent, parent[i]) 7 | return parent[i] 8 | 9 | def union(parent, rank, x, y): 10 | # ➌ 랭크를 기준으로 두 집합을 합치기 11 | xroot = find(parent, x) 12 | yroot = find(parent, y) 13 | 14 | if rank[xroot] < rank[yroot]: 15 | # ➍ 작은 랭크의 트리를 큰 랭크의 트리 아래에 연결 16 | parent[xroot] = yroot 17 | elif rank[xroot] > rank[yroot]: 18 | parent[yroot] = xroot 19 | else: 20 | # ➎ 랭크가 같은 경우, 한 트리를 다른 트리에 붙이고 랭크 증가 21 | parent[yroot] = xroot 22 | rank[xroot] += 1 23 | 24 | def solution(n, costs): 25 | # ➏ 비용을 기준으로 간선을 오름차순 정렬 26 | costs.sort(key=lambda x: x[2]) 27 | 28 | # ➐ 각 노드의 부모를 추적하는 parent 배열 생성 29 | parent = [i for i in range(n)] 30 | # ➑ 각 노드의 트리의 랭크를 추적하는 rank 배열 생성 31 | rank = [0] * n 32 | 33 | min_cost = 0 # 최소 신장 트리의 총 비용 34 | edges = 0 # 최소 신장 트리에 포함된 간선의 개수 35 | 36 | for edge in costs: 37 | if edges == n - 1: 38 | # ➒ n - 1개의 간선이 포함된 경우 중단(최소 신장 트리의 속성) 39 | break 40 | 41 | # ➓ 현재 간선의 두 노드가 속한 집합의 루트 찾기 42 | x = find(parent, edge[0]) 43 | y = find(parent, edge[1]) 44 | 45 | if x != y: 46 | # ⓫ 두 노드가 서로 다른 집합에 속하는 경우, 집합 합치기 47 | union(parent, rank, x, y) 48 | # 현재 간선의 비용을 최소 비용에 추가 49 | min_cost += edge[2] 50 | # ⓬ 포함된 간선의 개수 증가 51 | edges += 1 52 | 53 | return min_cost 54 | -------------------------------------------------------------------------------- /reference/try_except.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 try-except 블록은 프로그램 실행 중 발생할 수 있는 에러를 처리하기 위해 사용됩니다. 8 | # 'try' 블록 내에서 코드를 실행하다가 에러가 발생하면, 'except' 블록이 실행되며 프로그램이 중단되지 않습니다. 9 | # 이러한 방식으로, 프로그래머는 에러를 예측하고 적절히 대응할 수 있습니다. 10 | 11 | # 기본 사용 방법은 다음과 같습니다: 12 | # try: 13 | # # 에러가 발생할 가능성이 있는 코드 14 | # except <에러 종류>: 15 | # # 에러 발생 시 실행될 코드 16 | 17 | # 아래 예제에서, 우리는 0으로 나누는 에러(ZeroDivisionError)와 18 | # 존재하지 않는 리스트의 인덱스를 참조하는 에러(IndexError)를 처리합니다. 19 | 20 | try: 21 | # 0으로 나누기 시도 (ZeroDivisionError 발생) 22 | result = 10 / 0 23 | except ZeroDivisionError: 24 | # ZeroDivisionError 발생 시 이 블록이 실행됩니다. 25 | result = None 26 | print("Error: Cannot divide by zero") 27 | 28 | # result 변수가 None이므로, 에러가 발생했음을 알 수 있습니다. 29 | print(f"Result of division: {result}") 30 | 31 | # 리스트 인덱스 에러 처리 예제 32 | try: 33 | # 리스트 선언 34 | my_list = [1, 2, 3] 35 | # 존재하지 않는 인덱스 참조 시도 (IndexError 발생) 36 | value = my_list[10] 37 | except IndexError: 38 | # IndexError 발생 시 이 블록이 실행됩니다. 39 | value = None 40 | print("Error: Index out of range") 41 | 42 | # value 변수가 None이므로, 에러가 발생했음을 알 수 있습니다. 43 | print(f"Value from list: {value}") 44 | -------------------------------------------------------------------------------- /solution/63.py: -------------------------------------------------------------------------------- 1 | def multiply_matrices(matrix1, matrix2): 2 | # ❶ 결과 행렬을 0으로 초기화합니다. 3 | result = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] 4 | 5 | # ❷ 행렬 곱셈을 수행합니다. 6 | for i in range(3): 7 | for j in range(3): 8 | for k in range(3): 9 | result[i][j] += matrix1[i][k] * matrix2[k][j] 10 | 11 | return result 12 | 13 | def transpose_matrix(matrix): 14 | # ❸ 결과 행렬을 0으로 초기화합니다. 15 | result = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] 16 | 17 | # 전치 행렬을 계산합니다. 18 | for i in range(3): 19 | for j in range(3): 20 | result[j][i] = matrix[i][j] 21 | 22 | return result 23 | 24 | def solution(matrix1, matrix2): 25 | # 주어진 두 행렬을 곱합니다. 26 | multiplied = multiply_matrices(matrix1, matrix2) 27 | 28 | # 곱셈 결과의 전치 행렬을 계산합니다. 29 | transposed = transpose_matrix(multiplied) 30 | return transposed 31 | 32 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 33 | ''' 34 | print(solution( 35 | [ 36 | [1, 2, 3], 37 | [4, 5, 6], 38 | [7, 8, 9] 39 | ], 40 | 41 | [ 42 | [9, 8, 7], 43 | [6, 5, 4], 44 | [3, 2, 1] 45 | ])) 46 | ''' 47 | 48 | ''' 49 | 반환값 : 50 | [ 51 | [30, 84, 138], 52 | [24, 69, 114], 53 | [18, 54, 90] 54 | ] 55 | ''' 56 | 57 | ''' 58 | print(solution( 59 | [ 60 | [2, 4, 6], 61 | [1, 3, 5], 62 | [7, 8, 9] 63 | ], 64 | 65 | [ 66 | [9, 1, 2], 67 | [4, 5, 6], 68 | [7, 3, 8] 69 | ])) 70 | ''' 71 | 72 | ''' 73 | 반환값 : 74 | [ 75 | [76, 56, 158], 76 | [40, 31, 74], 77 | [76, 60, 134] 78 | ] 79 | ''' 80 | -------------------------------------------------------------------------------- /mistake/range_function_usage.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # range 함수의 기본적인 문법: 7 | # range([start], stop, [step]) 8 | # start: 시작 값 (생략 가능, 기본값은 0) 9 | # stop: 종료 값 (필수, 생성되는 숫자는 이 값 바로 전까지) 10 | # step: 간격 (생략 가능, 기본값은 1) 11 | 12 | # 0부터 4까지의 숫자를 생성합니다. 13 | for i in range(5): 14 | print(i) # 0, 1, 2, 3, 4를 순서대로 출력합니다. 15 | 16 | # 2부터 8까지 2 간격으로 숫자를 생성합니다. 17 | for i in range(2, 9, 2): 18 | print(i) # 2, 4, 6, 8을 순서대로 출력합니다. 19 | 20 | # 실수 예: stop 값을 포함하여 숫자를 생성하려고 할 때 21 | # 아래의 코드는 5를 출력하지 않습니다. 22 | # for i in range(1, 5): 23 | # print(i) 24 | 25 | # 올바른 방법: stop 값을 포함하여 숫자를 생성하려면 26 | # stop 값에 1을 더합니다. 27 | for i in range(1, 6): # 1부터 5까지 출력합니다. 28 | print(i) 29 | 30 | # 실수 예: step 값이 0인 경우 31 | # 아래의 코드는 무한 루프에 빠질 위험이 있습니다. 32 | # for i in range(1, 5, 0): 33 | # print(i) 34 | 35 | # 올바른 방법: step 값은 0이 아닌 다른 값을 사용합니다. 36 | for i in range(1, 5, 1): 37 | print(i) # 1, 2, 3, 4를 순서대로 출력합니다. 38 | 39 | # 실수 예: start 값이 stop 값보다 크고, step이 양수인 경우 40 | # 아래의 코드는 아무 것도 출력하지 않습니다. 41 | # for i in range(5, 1): 42 | # print(i) 43 | 44 | # 올바른 방법: start 값이 stop 값보다 클 경우, step을 음수로 설정하여 역순으로 숫자를 생성합니다. 45 | for i in range(5, 1, -1): 46 | print(i) # 5, 4, 3, 2를 순서대로 출력합니다. 47 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/dictionary.py: -------------------------------------------------------------------------------- 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 | # dic.get(key) 8 | # 딕셔너리 dic에서 주어진 key에 해당하는 값을 반환합니다. 9 | # key가 딕셔너리에 없으면 None을 반환합니다. 10 | # 시간 복잡도: O(1) 11 | dic = {'a': 1, 'b': 2, 'c': 3} 12 | value = dic.get('a') 13 | print(value) # 출력값: 1 14 | value = dic.get('d') 15 | print(value) # 출력값: None 16 | 17 | # dic[key] 18 | # 딕셔너리 dic에서 주어진 key에 해당하는 값을 반환합니다. 19 | # key가 딕셔너리에 없으면 KeyError를 발생시킵니다. 20 | # 시간 복잡도: O(1) 21 | try: 22 | value = dic['b'] 23 | print(value) # 출력값: 2 24 | value = dic['d'] 25 | print(value) # 출력값: (이 줄은 실행되지 않습니다; KeyError 발생) 26 | except KeyError as e: 27 | print(e) # 출력값: 'd' 28 | 29 | # dic.pop(key) 30 | # 딕셔너리 dic에서 주어진 key에 해당하는 항목을 제거하고 그 값을 반환합니다. 31 | # key가 딕셔너리에 없으면 KeyError를 발생시킵니다. 32 | # 시간 복잡도: O(1) 33 | try: 34 | value = dic.pop('c') 35 | print(value) # 출력값: 3 36 | value = dic.pop('d') 37 | print(value) # 출력값: (이 줄은 실행되지 않습니다; KeyError 발생) 38 | except KeyError as e: 39 | print(e) # 출력값: 'd' 40 | 41 | # key in dic 42 | # 주어진 key가 딕셔너리 dic에 있는지를 검사합니다. 43 | # 시간 복잡도: O(1) 44 | key_presence = 'a' in dic 45 | print(key_presence) # 출력값: True 46 | key_presence = 'd' in dic 47 | print(key_presence) # 출력값: False 48 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/LCS_DP.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # LCS(Longest Common Subsequence) 알고리즘은 두 문자열에서 가장 긴 공통 부분 문자열을 찾는 알고리즘입니다. 8 | # 동적 계획법(DP)를 사용하여 문제를 해결합니다. 9 | 10 | # 2. 예시 입력 / 출력: 11 | # 입력: "ABCBDAB", "BDCAB" 12 | # 출력: "BCAB" (가장 긴 공통 부분 문자열) 13 | 14 | # 3. 알고리즘의 시간 복잡도: 15 | # O(m*n), 여기서 m과 n은 각각 두 문자열의 길이입니다. 16 | 17 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 18 | # - DNA 서열 정렬 19 | # - 텍스트 비교 및 유사도 측정 20 | 21 | # 5. 상세과정: 22 | # - DP 테이블을 생성하여, 각 (i, j) 위치에 문자열1의 i번째까지의 문자와 문자열2의 j번째까지의 문자의 LCS 길이를 저장합니다. 23 | # - DP[i][j]의 값은 다음과 같이 계산됩니다: 24 | # - 문자열1의 i번째 문자와 문자열2의 j번째 문자가 같다면, DP[i][j] = DP[i-1][j-1] + 1 25 | # - 다르다면, DP[i][j] = max(DP[i-1][j], DP[i][j-1]) 26 | 27 | def LCS(X, Y): 28 | # DP 테이블 초기화 29 | dp = [[0] * (len(Y) + 1) for _ in range(len(X) + 1)] 30 | 31 | # DP 테이블 채우기 32 | for i in range(1, len(X) + 1): 33 | for j in range(1, len(Y) + 1): 34 | if X[i - 1] == Y[j - 1]: 35 | dp[i][j] = dp[i - 1][j - 1] + 1 36 | else: 37 | dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) 38 | 39 | return dp[len(X)][len(Y)] 40 | 41 | # 예시 코드 실행 42 | X = "ABCBDAB" 43 | Y = "BDCAB" 44 | print(LCS(X, Y)) # 출력: 4 45 | 46 | -------------------------------------------------------------------------------- /mistake/for_else_tutorial.py: -------------------------------------------------------------------------------- 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 | numbers = [1, 3, 5, 7, 9] 9 | target_number = 4 10 | 11 | for number in numbers: 12 | if number == target_number: 13 | print(f"Found {target_number}!") 14 | break 15 | else: 16 | # for 루프가 중간에 break 되지 않고 완전히 실행되면 else 블록이 실행됩니다. 17 | print(f"{target_number} was not found in the list.") 18 | 19 | # 위의 코드에서는 4가 리스트에 없으므로 "4 was not found in the list."가 출력됩니다. 20 | 21 | # 실수 예: else 블록을 for 루프가 항상 실행되는 마지막 부분으로 잘못 이해하는 경우 22 | # 다음과 같은 잘못된 코드를 작성할 수 있습니다. 23 | 24 | # target_number = 5 25 | 26 | # for number in numbers: 27 | # if number == target_number: 28 | # print(f"Found {target_number}!") 29 | # else: 30 | # # 이 else 블록은 for 루프의 각 반복마다 실행됩니다. 31 | # print(f"{target_number} was not found in the list.") 32 | 33 | # 위의 코드는 5 이외의 모든 숫자에 대해 "5 was not found in the list."를 출력합니다. 34 | 35 | # 올바른 사용법: for-else를 사용하여 리스트에서 특정 숫자를 찾고 결과를 출력합니다. 36 | 37 | target_number = 7 38 | 39 | for number in numbers: 40 | if number == target_number: 41 | print(f"Found {target_number}!") 42 | break 43 | else: 44 | print(f"{target_number} was not found in the list.") 45 | 46 | # 위의 코드에서는 7이 리스트에 있으므로 "Found 7!"이 출력됩니다. 47 | -------------------------------------------------------------------------------- /solution/26.py: -------------------------------------------------------------------------------- 1 | def preorder(nodes, idx): 2 | # idx가 노드 리스트의 길이보다 작을 때 3 | if idx < len(nodes): 4 | # 루트 노드를 출력한 다음, 왼쪽 서브 트리와 오른쪽 서브 트리를 재귀 호출하여 출력 순서대로 이어붙임 5 | ret = str(nodes[idx]) + " " 6 | ret += preorder(nodes, idx * 2 + 1) 7 | ret += preorder(nodes, idx * 2 + 2) 8 | return ret 9 | # idx >= len(nodes)일 때는 빈 문자열 반환 10 | else: 11 | return "" 12 | 13 | def inorder(nodes, idx): 14 | # idx가 노드 리스트의 길이보다 작을 때 15 | if idx < len(nodes): 16 | # 왼쪽 서브 트리를 먼저 재귀 호출하여 출력 순서대로 이어붙임 17 | ret = inorder(nodes, idx * 2 + 1) 18 | # 루트 노드를 출력한 다음, 오른쪽 서브 트리를 재귀 호출하여 출력 순서대로 이어붙임 19 | ret += str(nodes[idx]) + " " 20 | ret += inorder(nodes, idx * 2 + 2) 21 | return ret 22 | # idx >= len(nodes)일 때는 빈 문자열 반환 23 | else: 24 | return "" 25 | 26 | def postorder(nodes, idx): 27 | # idx가 노드 리스트의 길이보다 작을 때 28 | if idx < len(nodes): 29 | # 왼쪽 서브 트리와 오른쪽 서브 트리를 재귀 호출하여 출력 순서대로 이어붙임 30 | ret = postorder(nodes, idx * 2 + 1) 31 | ret += postorder(nodes, idx * 2 + 2) 32 | # 루트 노드를 출력함 33 | ret += str(nodes[idx]) + " " 34 | return ret 35 | # idx >= len(nodes)일 때는 빈 문자열 반환 36 | else: 37 | return "" 38 | 39 | def solution(nodes): 40 | # 전위 순회, 중위 순회, 후위 순회 결과 계산 41 | # 노드 리스트와 루트 노드의 인덱스를 매개변수로 각각 호출 42 | return [ 43 | preorder(nodes,0)[:-1], # 마지막 공백 제거 44 | inorder(nodes,0)[:-1], # 마지막 공백 제거 45 | postorder(nodes,0)[:-1], # 마지막 공백 제거 46 | ] 47 | 48 | 49 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 50 | # print(solution([1, 2, 3, 4, 5, 6, 7])) # 반환값 : ["1 2 4 5 3 6 7", "4 2 5 1 6 3 7", "4 5 2 6 7 3 1"] 51 | -------------------------------------------------------------------------------- /solution/30.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | # ➊ 이동 가능한 좌표인지 판단하는 함수 4 | def is_valid_move(ny, nx, n, m, maps): 5 | return 0 <= ny < n and 0 <= nx < m and maps[ny][nx] != "X" 6 | 7 | # ➋ 방문한 적이 없으면 큐에 넣고 방문 여부 표시 8 | def append_to_queue(ny, nx, k, time, visited, q): 9 | if not visited[ny][nx][k]: 10 | visited[ny][nx][k] = True 11 | q.append((ny, nx, k, time + 1)) 12 | 13 | def solution(maps): 14 | n, m = len(maps), len(maps[0]) 15 | visited = [[[False for _ in range(2)] for _ in range(m)] for _ in range(n)] 16 | # ➌ 위, 아래, 왼쪽, 오른쪽 이동 방향 17 | dy = [-1, 1, 0, 0] 18 | dx = [0, 0, -1, 1] 19 | q = deque( ) 20 | end_y, end_x = -1, -1 21 | 22 | # ➍ 시작점과 도착점을 찾아 큐에 넣고 방문 여부를 표시 23 | for i in range(n): 24 | for j in range(m): 25 | if maps[i][j] == "S": 26 | q.append((i, j, 0, 0)) # 시작점 27 | visited[i][j][0] = True 28 | if maps[i][j] == "E": 29 | end_y, end_x = i, j # 도착점 30 | 31 | while q: 32 | y, x, k, time = q.popleft( ) # ➎ 큐에서 좌표와 이동 횟수를 꺼냄 33 | 34 | # ➏ 도착점에 도달하면 결과 반환 35 | if y == end_y and x == end_x and k == 1: 36 | return time 37 | 38 | # ➐ 네 방향으로 이동 39 | for i in range(4): 40 | ny, nx = y + dy[i], x + dx[i] 41 | # ➏ 이동 가능한 좌표인 때에만 큐에 넣음 42 | if not is_valid_move(ny, nx, n, m, maps): 43 | continue 44 | 45 | # ➑ 다음 이동 지점이 물인 경우 46 | if maps[ny][nx] == "L": 47 | append_to_queue(ny, nx, 1, time, visited, q) 48 | # ➒ 다음 이동 지점이 물이 아닌 경우 49 | else: 50 | append_to_queue(ny, nx, k, time, visited, q) 51 | 52 | # ➓ 도착점에 도달하지 못한 경우 53 | return -1 54 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/tree_adjacentlist.py: -------------------------------------------------------------------------------- 1 | """ 2 | 트리를 인접 리스트로 구현하는 예시입니다. 3 | 4 | 인접 리스트(adjacency list)는 그래프의 각 정점에 인접한(즉, 직접 연결된) 정점의 리스트를 저장하여 그래프를 표현하는 방식입니다. 인접 리스트의 기본 개념은 각 노드 i의 모든 이웃을 리스트로 관리하는 것입니다. 5 | 6 | 트리도 사이클이 없는 그래프의 한 형태이므로, 인접 리스트로 구현이 가능합니다. 트리는 일반적으로 부모 노드와 자식 노드 간의 관계를 가지며, 이를 인접 리스트로 표현할 때는 각 노드를 키로하고, 그 노드의 자식들을 값으로 가지는 리스트로 표현합니다. 7 | 8 | 도식화: 9 | 예를 들어, 다음과 같은 트리를 생각해 봅시다. 10 | 1 11 | / \ 12 | 2 3 13 | / \ 14 | 4 5 15 | 16 | 이 트리를 인접 리스트로 표현하면 다음과 같습니다. 17 | { 18 | 1: [2, 3], 19 | 2: [4, 5], 20 | 3: [], 21 | 4: [], 22 | 5: [] 23 | } 24 | 25 | 여기서 1이라는 키에는 [2, 3]이라는 값이 연결되어 있습니다. 이는 노드 1이 노드 2와 3과 연결되어 있음을 나타냅니다. 비슷하게, 노드 2는 노드 4와 5와 연결되어 있습니다. 26 | 27 | 시간 복잡도: 28 | - 노드를 찾는 작업: O(1) 29 | - 노드의 인접 리스트를 순회하는 작업: O(deg(v)) [deg(v)는 노드 v의 차수(degree)] 30 | 31 | 즉, 트리를 순회하는 총 시간 복잡도는 O(N)이며, N은 트리의 노드 수입니다. 모든 노드를 정확히 한 번씩 방문하기 때문입니다. 32 | """ 33 | 34 | # 트리를 인접 리스트로 표현 35 | tree = { 36 | 1: [2, 3], 37 | 2: [4, 5], 38 | 3: [], 39 | 4: [], 40 | 5: [] 41 | } 42 | 43 | def print_tree(t, root): 44 | """ 45 | 주어진 루트에서 시작하여 트리를 출력합니다. 46 | """ 47 | print(root, end=' ') 48 | for child in t[root]: 49 | print_tree(t, child) 50 | 51 | print("Tree traversal:") 52 | print_tree(tree, 1) # 1 2 4 5 3 53 | 54 | """ 55 | 위 함수에서 트리를 순회하는 방식은 깊이 우선 탐색(DFS)과 유사합니다. 56 | 루트 노드에서 시작해서 자식 노드로 재귀적으로 이동하면서 값을 출력합니다. 57 | """ 58 | -------------------------------------------------------------------------------- /mistake/variable_scope_tutorial.py.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 전역 변수 (global variable): 프로그램의 모든 부분에서 접근 가능한 변수 7 | global_variable = "I'm a global variable" 8 | 9 | def function_example(): 10 | # 지역 변수 (local variable): 함수 내에서만 접근 가능한 변수 11 | local_variable = "I'm a local variable" 12 | 13 | # 전역 변수를 함수 내에서 사용하려면 global 키워드를 사용해야 합니다. 14 | global global_variable 15 | print(global_variable) # 올바른 방법으로 전역 변수를 출력합니다. 16 | 17 | # 실수 예: 지역 변수와 전역 변수의 이름이 같을 경우 18 | # 아래의 코드는 새로운 지역 변수를 만들고, 전역 변수는 변경되지 않습니다. 19 | global_variable = "I'm a changed local variable" 20 | print(global_variable) # "I'm a changed local variable"을 출력합니다. 21 | 22 | function_example() 23 | 24 | # 여전히 원래의 값인 "I'm a global variable"을 출력합니다. 25 | # 왜냐하면 위의 함수 내에서는 지역 변수만 변경되었기 때문입니다. 26 | print(global_variable) 27 | 28 | # 올바른 방법으로 전역 변수를 변경하려면: 29 | def change_global_variable(): 30 | global global_variable # 전역 변수를 사용하겠다는 것을 명시적으로 선언합니다. 31 | global_variable = "I'm a changed global variable" 32 | 33 | change_global_variable() 34 | print(global_variable) # "I'm a changed global variable"을 출력합니다. 35 | 36 | # 실수 예: 지역 변수를 함수 외부에서 사용하려고 할 때 37 | # 아래 코드는 에러를 발생시킵니다. 왜냐하면 local_variable은 function_example 함수 내의 지역 변수이기 때문입니다. 38 | # print(local_variable) 39 | 40 | # 올바른 방법은 해당 지역 변수를 함수 내에서만 사용하거나, 필요한 경우 전역 변수로 변경하는 것입니다. 41 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/LIS_DP.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # LIS(Longest Increasing Subsequence) 알고리즘은 주어진 배열에서 가장 긴 증가하는 부분 수열의 길이를 찾는 알고리즘이다. 8 | # 동적 프로그래밍 방법을 사용하여 이전에 계산한 부분 문제의 결과를 저장하고 재사용함으로써 효율적으로 문제를 해결한다. 9 | 10 | # 2. 예시 입력 / 출력: 11 | # 입력: [10, 22, 9, 33, 21, 50, 41, 60] 12 | # 출력: 5 (해당 수열에서 LIS의 길이) 13 | 14 | # 3. 알고리즘의 시간 복잡도: 15 | # 이 알고리즘의 시간 복잡도는 O(n^2)이다. 16 | 17 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 18 | # - 주어진 배열에서 최장 증가 부분 수열의 길이를 찾는 문제 19 | # - 시퀀스 정렬 문제에서 최적 부분 구조 찾기 등 20 | 21 | # 5. 상세 과정: 22 | # - DP 배열을 모두 1로 초기화한다 (각 요소 자체가 길이 1의 LIS를 형성). 23 | # - 배열의 각 요소에 대해, 그 이전의 모든 요소들과 비교하여 증가하는 부분 수열을 찾고, DP 배열을 업데이트한다. 24 | # - DP 배열의 최대값을 찾아 그것이 최장 증가 부분 수열의 길이가 된다. 25 | 26 | def lis(arr): 27 | n = len(arr) 28 | 29 | # DP 배열 초기화: 모든 요소가 자기 자신만을 포함하는 길이 1의 LIS를 형성한다. 30 | dp = [1] * n 31 | 32 | # DP 배열이 의미하는 바: dp[i]는 arr[i]를 마지막으로 하는 LIS의 길이를 나타낸다. 33 | 34 | # 배열의 각 요소에 대해 35 | for i in range(1, n): 36 | for j in range(i): 37 | # 증가하는 부분 수열을 찾으면 DP 배열 업데이트 38 | if arr[i] > arr[j] and dp[i] < dp[j] + 1: 39 | dp[i] = dp[j] + 1 40 | 41 | # DP 배열의 최대값을 찾아 반환 42 | return max(dp) 43 | 44 | # 예제: 45 | input_arr = [10, 22, 9, 33, 21, 50, 41, 60] 46 | print(lis(input_arr)) # 출력: 5 47 | -------------------------------------------------------------------------------- /reference/lambda.py: -------------------------------------------------------------------------------- 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 | # 파이썬에서 'lambda'는 익명 함수를 생성하는 데 사용되는 키워드입니다. 8 | # 'lambda' 함수는 일반 함수(def)와 같지만, 이름 없이 정의되며, 한 줄로 표현됩니다. 9 | # 기본 구조는 다음과 같습니다: lambda arguments: expression 10 | # 'lambda' 함수는 다양한 케이스에서 사용될 수 있으며, 일회성의 간단한 함수나 다른 함수의 인자로 전달될 수 있습니다. 11 | 12 | # 1. 기본적인 lambda 함수: 13 | add = lambda x, y: x + y 14 | # 사용 예: 15 | print(add(1, 2)) # 출력: 3 16 | 17 | # 2. 리스트의 sort 메서드에서 key 인자로 사용: 18 | # lambda 함수를 사용하여 리스트의 각 요소에 대한 정렬 키를 지정할 수 있습니다. 19 | my_list = [(1, 2), (3, 1), (5, 0), (4, 5)] 20 | my_list.sort(key=lambda x: x[1]) 21 | # 사용 예: 22 | print(my_list) # 출력: [(5, 0), (3, 1), (1, 2), (4, 5)] 23 | 24 | # 3. filter 함수에서 사용: 25 | # lambda 함수를 사용하여 iterable에서 특정 조건을 만족하는 요소만 필터링할 수 있습니다. 26 | nums = [0, 1, 2, 3, 4, 5] 27 | even_nums = filter(lambda x: x % 2 == 0, nums) 28 | # 사용 예: 29 | print(list(even_nums)) # 출력: [0, 2, 4] 30 | 31 | # 4. map 함수에서 사용: 32 | # lambda 함수를 사용하여 iterable의 모든 요소에 함수를 적용할 수 있습니다. 33 | nums = [0, 1, 2, 3, 4, 5] 34 | squares = map(lambda x: x ** 2, nums) 35 | # 사용 예: 36 | print(list(squares)) # 출력: [0, 1, 4, 9, 16, 25] 37 | 38 | # 5. reduce 함수에서 사용: 39 | # lambda 함수를 사용하여 iterable의 모든 요소를 단일 값으로 줄일 수 있습니다. 40 | from functools import reduce 41 | nums = [1, 2, 3, 4, 5] 42 | sum_of_nums = reduce(lambda x, y: x + y, nums) 43 | # 사용 예: 44 | print(sum_of_nums) # 출력: 15 45 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/eratosthenes_sieve.py: -------------------------------------------------------------------------------- 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 | # 예: 2부터 시작하여 2의 배수를 제거, 다음 최소값인 3의 배수를 제거, 10 | # 이후 5의 배수, 7의 배수를 차례대로 제거... (n의 제곱근까지) 11 | 12 | # 시간 복잡도: 13 | # 에라토스테네스의 체의 시간 복잡도는 O(n log log n)으로, 14 | # n 이하의 모든 소수를 효율적으로 찾을 수 있습니다. 15 | 16 | # 도식화: 17 | # e.g., n = 30, current = 2: 18 | # 시작: [F, F, T, T, T, T, T, T, T, T, T, T, T, T, ...] 19 | # 2의 배수 제거: [F, F, T, T, F, T, F, T, F, T, F, T, F, ...] 20 | # 21 | # e.g., n = 30, current = 3: 22 | # 시작: [F, F, T, T, F, T, F, T, F, T, F, T, F, ...] 23 | # 3의 배수 제거: [F, F, T, T, F, F, F, T, F, T, F, F, F, ...] 24 | # 25 | # 위와 같은 방식으로 모든 소수의 배수를 제거 26 | 27 | def eratosthenes_sieve(n): 28 | # 초기 설정: 0과 1은 소수가 아니므로 False, 나머지는 모두 True로 설정 29 | sieve = [False, False] + [True for _ in range(2, n + 1)] 30 | primes = [] 31 | 32 | for current in range(2, int(n**0.5) + 1): 33 | if sieve[current]: # current가 소수인 경우 34 | for multiple in range(current * 2, n + 1, current): 35 | sieve[multiple] = False 36 | 37 | 38 | 39 | for i in range(current + 1, n + 1): 40 | if sieve[i]: 41 | primes.append(i) 42 | 43 | return primes 44 | 45 | n = 30 46 | print(eratosthenes_sieve(n)) 47 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/fibonacci_recursion.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # 피보나치 수열은 첫 번째와 두 번째 항이 1이고, 그 이후의 항은 직전의 두 항의 합인 수열입니다. 8 | # 이 함수는 재귀적 방법으로 피보나치 수열의 n 번째 항을 계산합니다. 9 | 10 | # 2. 예시 입력 / 출력: 11 | # 입력: 5 12 | # 출력: 5 (피보나치 수열의 5번째 항은 5입니다) 13 | 14 | # 3. 알고리즘의 시간 복잡도: 15 | # 이 알고리즘의 시간 복잡도는 O(2^n)입니다. 이는 각 호출이 두 개의 새로운 호출을 생성하기 때문에 호출 횟수가 exponential하게 증가합니다. 16 | 17 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 18 | # - n 번째 피보나치 수 찾기 19 | # - 피보나치 수열을 사용하여 복잡한 수학적 문제 해결 20 | 21 | # 5. 상세 과정: 22 | # - n이 0이나 1인 경우, n을 반환합니다. (기저 사례) 23 | # - 그렇지 않으면, fibonacci(n-1)과 fibonacci(n-2)를 재귀적으로 호출하여 두 결과를 합칩니다. 24 | 25 | # 호출 구조는 다음과 같습니다 (n=5의 경우): 26 | # 27 | # fibonacci(5) 28 | # ├─ fibonacci(4) 29 | # │ ├─ fibonacci(3) 30 | # │ │ ├─ fibonacci(2) 31 | # │ │ │ ├─ fibonacci(1) 32 | # │ │ │ └─ fibonacci(0) 33 | # │ │ └─ fibonacci(1) 34 | # │ └─ fibonacci(2) 35 | # │ ├─ fibonacci(1) 36 | # │ └─ fibonacci(0) 37 | # └─ fibonacci(3) 38 | # ├─ fibonacci(2) 39 | # │ ├─ fibonacci(1) 40 | # │ └─ fibonacci(0) 41 | # └─ fibonacci(1) 42 | 43 | def fibonacci(n): 44 | if n <= 1: 45 | return n 46 | else: 47 | return fibonacci(n-1) + fibonacci(n-2) 48 | 49 | # 예제: 50 | print(fibonacci(5)) # 출력: 5 51 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/set.py: -------------------------------------------------------------------------------- 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 | # 집합 s 생성 8 | s = set() 9 | 10 | # s.add(item): 집합 s에 요소 item을 추가합니다. 11 | # 반환값: 없음 12 | # 시간 복잡도: O(1) 13 | s.add(1) # 현재 집합: {1} 14 | print(s) # 출력: {1} 15 | 16 | # s.remove(item): 집합 s에서 요소 item을 제거합니다. item이 s에 없을 경우 KeyError를 발생시킵니다. 17 | # 반환값: 없음 18 | # 시간 복잡도: O(1) 19 | s.remove(1) # 현재 집합: {} 20 | print(s) # 출력: set() 21 | 22 | # s.discard(item): 집합 s에서 요소 item을 제거합니다. item이 s에 없어도 에러가 발생하지 않습니다. 23 | # 반환값: 없음 24 | # 시간 복잡도: O(1) 25 | s.discard(1) # 현재 집합: {} (아무 변화 없음) 26 | print(s) # 출력: set() 27 | 28 | # 집합 s와 s2 생성 및 초기화 29 | s = {1, 2, 3} 30 | s2 = {3, 4, 5} 31 | 32 | # s.union(s2): 집합 s와 s2의 합집합을 반환합니다. 33 | # 반환값: 합집합 34 | # 시간 복잡도: O(len(s) + len(s2)) 35 | print(s.union(s2)) # 출력: {1, 2, 3, 4, 5} 36 | 37 | # s.intersection(s2): 집합 s와 s2의 교집합을 반환합니다. 38 | # 반환값: 교집합 39 | # 시간 복잡도: O(min(len(s), len(s2))) 40 | print(s.intersection(s2)) # 출력: {3} 41 | 42 | # s.difference(s2): 집합 s에서 s2의 요소를 제거한 차집합을 반환합니다. 43 | # 반환값: 차집합 44 | # 시간 복잡도: O(len(s)) 45 | print(s.difference(s2)) # 출력: {1, 2} 46 | 47 | # set(list): 리스트를 집합으로 변환합니다. 48 | # 반환값: 집합 49 | # 시간 복잡도: O(len(list)) 50 | print(set([6, 7, 8])) # 출력: {8,6,7}, {6,7,8} 등 으로 나타남, 집합은 순서를 보장하지 않으므로 순서 달라질수 있음 51 | 52 | # item in s: 집합 s에 item이 포함되어 있는지 확인합니다. 53 | # 반환값: bool (True 또는 False) 54 | # 시간 복잡도: O(1) 55 | print(1 in s) # 출력: True 56 | -------------------------------------------------------------------------------- /reference/countsort.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 계수 정렬(Counting Sort)은 정수 배열을 정렬하는 비교 없는 알고리즘입니다. 7 | # 시간 복잡도: O(n + k) (n은 배열의 크기, k는 최댓값과 최솟값의 차이) 8 | # 계수 정렬은 입력 데이터의 분포가 정해져 있을 때 매우 효율적입니다. 9 | 10 | # 계수 정렬의 동작 과정: 11 | # 1. 입력 배열을 순회하며 각 숫자의 개수를 센다. 12 | # 2. 개수를 기반으로 숫자를 정렬된 위치에 배치한다. 13 | # 3. 정렬된 결과를 반환한다. 14 | 15 | # 예시: 16 | # 입력 배열: [4, 2, 2, 8, 3, 3, 1] 17 | # 최댓값: 8 18 | # count 배열: [0, 1, 2, 2, 1, 0, 0, 0, 1] (각 숫자의 개수) 19 | 20 | # count 배열은 입력 배열의 숫자를 카운트한 결과를 저장합니다. 21 | # 인덱스는 숫자를 나타내며, 값은 해당 숫자가 몇 번 등장했는지를 나타냅니다. 22 | 23 | # 각 인덱스별로 숫자와 그 숫자의 개수를 나타내는 도식화: 24 | # 0: 0번 등장 25 | # 1: 1번 등장 26 | # 2: 2번 등장 27 | # 3: 2번 등장 28 | # 4: 1번 등장 29 | # 5: 0번 등장 30 | # 6: 0번 등장 31 | # 7: 0번 등장 32 | # 8: 1번 등장 33 | 34 | # 정렬된 결과 배열은 count 배열의 인덱스에 따라 해당 숫자를 순서대로 배치합니다. 35 | # 0, 1, 2, 2, 3, 3, 4, 8 순서대로 나열됩니다. 36 | 37 | def counting_sort(arr): 38 | # 입력 배열에서 최댓값을 찾아서 count 배열의 크기를 설정합니다. 39 | max_val = max(arr) 40 | count = [0] * (max_val + 1) 41 | 42 | # 입력 배열의 각 원소를 센다. 43 | for num in arr: 44 | count[num] += 1 45 | 46 | # 정렬된 결과를 담을 배열을 초기화합니다. 47 | sorted_arr = [] 48 | 49 | # count 배열을 기반으로 정렬된 배열을 생성합니다. 50 | for i in range(len(count)): 51 | sorted_arr.extend([i] * count[i]) 52 | 53 | return sorted_arr 54 | 55 | arr = [4, 2, 2, 8, 3, 3, 1] 56 | sorted_arr = counting_sort(arr) 57 | print(sorted_arr) 58 | -------------------------------------------------------------------------------- /solution/40.py: -------------------------------------------------------------------------------- 1 | import heapq 2 | 3 | def solution(graph, start): 4 | distances = {node: float("inf") for node in graph} # ❶ 모든 노드의 거리 값을 무한대로 초기화 5 | distances[start] = 0 # ❷ 시작 노드의 거리 값은 0으로 초기화 6 | queue = [] 7 | heapq.heappush(queue, [distances[start], start]) # ❸ 시작 노드를 큐에 삽입 8 | paths = {start: [start]} # ❹ 시작 노드의 경로를 초기화 9 | 10 | while queue: 11 | # ❺ 현재 가장 거리 값이 작은 노드를 가져옴 12 | current_distance, current_node = heapq.heappop(queue) 13 | # ❻ 만약 현재 노드의 거리 값이 큐에서 가져온 거리 값보다 크면, 해당 노드는 이미 처리한 것이므로 무시 14 | if distances[current_node] < current_distance: 15 | continue 16 | 17 | # ❼ 현재 노드와 인접한 노드들의 거리 값을 계산하여 업데이트 18 | for adjacent_node, weight in graph[current_node].items(): 19 | distance = current_distance + weight 20 | # ❽ 현재 계산한 거리 값이 기존 거리 값보다 작으면 최소 비용 및 최단 경로 업데이트 21 | if distance < distances[adjacent_node]: 22 | distances[adjacent_node] = distance # 최소 비용 업데이트 23 | paths[adjacent_node] = paths[current_node] + [adjacent_node] # 최단 경로 업데이트 24 | 25 | # ➒ 최소 경로가 갱신된 노드를 비용과 함께 큐에 푸시 26 | heapq.heappush(queue, [distance, adjacent_node]) 27 | 28 | # ➓ paths 딕셔너리를 노드 번호에 따라 오름차순 정렬하여 반환 29 | sorted_paths = {node: paths[node] for node in sorted(paths)} 30 | 31 | return [distances, sorted_paths] 32 | 33 | 34 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 35 | # print(solution({ 'A': {'B': 9, 'C': 3}, 'B': {'A': 5}, 'C': {'B': 1} },'A')) # 반환값 :[{'A': 0, 'B': 4, 'C': 3}, {'A': ['A'], 'B': ['A', 'C', 'B'], 'C': ['A', 'C']}] 36 | # print(solution({'A': {'B': 1},'B': {'C': 5},'C': {'D': 1},'D': { } }, 'A')) # 반환값 :[{'A': 0, 'B': 1, 'C': 6, 'D': 7}, {'A': ['A'], 'B': ['A', 'B'], 'C': ['A', 'B', 'C'], 'D': ['A', 'B', 'C', 'D']}] 37 | 38 | -------------------------------------------------------------------------------- /solution/45.py: -------------------------------------------------------------------------------- 1 | def solution(board): 2 | # ➊ 주어진 좌표가 보드의 범위 내에 있는지 확인 3 | def is_valid(x, y): 4 | return 0 <= x < N and 0 <= y < N 5 | 6 | # ➋ 주어진 좌표가 차단되었거나 이동할 수 없는지 확인 7 | def is_blocked(x, y): 8 | return (x, y) == (0, 0) or not is_valid(x, y) or board[x][y] == 1 9 | 10 | # ➌ 이전 방향과 현재 방향에 따라 비용을 계산 11 | def calculate_cost(direction, prev_direction, cost): 12 | if prev_direction == -1 or (prev_direction - direction) % 2 == 0: 13 | return cost + 100 14 | else: 15 | return cost + 600 16 | 17 | # ➍ 주어진 좌표와 방향이 아직 방문하지 않았거나 새 비용이 더 작은 경우 18 | def isShouldUpdate(x, y, direction, new_cost): 19 | return visited[x][y][direction] == 0 or visited[x][y][direction] > new_cost 20 | 21 | queue = [(0, 0, -1, 0)] 22 | N = len(board) 23 | directions = [(0, -1), (-1, 0), (0, 1), (1, 0)] 24 | visited = [[[0 for _ in range(4)] for _ in range(N)] for _ in range(N)] 25 | answer = float("inf") 26 | 27 | # ➎ 큐가 빌 때까지 반복 28 | while queue: 29 | x, y, prev_direction, cost = queue.pop(0) 30 | 31 | # ➏ 가능한 모든 방향에 대해 반복 32 | for direction, (dx, dy) in enumerate(directions): 33 | new_x, new_y = x + dx, y + dy 34 | 35 | # ➐ 이동할 수 없는 좌표는 건너뛰기 36 | if is_blocked(new_x, new_y): 37 | continue 38 | 39 | new_cost = calculate_cost(direction, prev_direction, cost) 40 | 41 | # ➑ 도착지에 도달한 경우 최소 비용 업데이트 42 | if (new_x, new_y) == (N - 1, N - 1): 43 | answer = min(answer, new_cost) 44 | # ➒ 좌표와 방향이 아직 방문하지 않았거나 새 비용이 더 작은 경우 큐에 추가 45 | elif isShouldUpdate(new_x, new_y, direction, new_cost): 46 | queue.append((new_x, new_y, direction, new_cost)) 47 | visited[new_x][new_y][direction] = new_cost 48 | 49 | return answer 50 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/dfs_stack.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # DFS(깊이 우선 탐색)은 그래프나 트리를 탐색하는 알고리즘 중 하나로, 8 | # 루트 노드(혹은 다른 임의의 노드)에서 시작하여 마지막 노드까지 깊이를 우선하여 탐색하는 알고리즘입니다. 9 | # 스택을 사용하여 구현할 수 있으며, 아래 코드는 스택을 사용한 방법으로 DFS를 구현한 예입니다. 10 | 11 | # 2. 예시 입력 / 출력: 12 | # 입력: graph = {1: [2, 3], 2: [4, 5], 3: [], 4: [], 5: []}, start_node = 1 13 | # 출력: 1 3 2 5 4 14 | 15 | # 3. 알고리즘의 시간 복잡도: 16 | # O(V + E) (V: 정점의 개수, E: 간선의 개수) 17 | 18 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 19 | # - 경로 찾기 20 | # - 사이클 탐지 21 | # - 그래프 연결 성분 찾기 22 | 23 | 24 | def dfs(graph, start_node): 25 | visited = [False] * (len(graph) + 1) 26 | stack = [start_node] 27 | 28 | while stack: 29 | node = stack.pop() 30 | 31 | if not visited[node] : 32 | visited[node] = True; 33 | print(node) 34 | for adj_node in graph[node]: # 인접한 노드 방문 35 | if not visited[adj_node]: 36 | stack.append(adj_node) 37 | 38 | 39 | # 그래프를 인접 리스트로 표현 40 | graph = { 41 | 1: [2, 3], 42 | 2: [4, 5], 43 | 3: [], 44 | 4: [], 45 | 5: [] 46 | } 47 | 48 | # DFS 알고리즘 실행 49 | dfs(graph, 1) # 1 3 2 5 4 50 | 51 | 52 | 53 | # 그래프를 인접 리스트로 표현 54 | graph = { 55 | 1: [2, 3], 56 | 2: [4, 5], 57 | 3: [], 58 | 4: [], 59 | 5: [] 60 | } 61 | 62 | # DFS 알고리즘 실행 63 | dfs(graph, 1) # 1 3 2 5 4 64 | -------------------------------------------------------------------------------- /community.md: -------------------------------------------------------------------------------- 1 | # 📚 코딩 테스트 합격자 되기 2 | 3 | ![image](https://github.com/dremdeveloper/codingtest_python/assets/131899974/b31384f5-594a-4f39-9d35-ac8f49317c35) 4 | 5 | 6 | ## 🎮스터디 모집 / 정보공유 / 책 추천 7 | 직접 스터디원을 모집하거나 정보를 공유하실 수도 있고, 편하게 참여만 하셔도 됩니다.
8 | [링크](https://docs.google.com/spreadsheets/d/1-p4O5G75vnG6jyxnkY5zamydzgro_68Z21NU5Eumxfc/edit?usp=sharing) 9 | 10 | 11 | ## 📝 정오표 및 오탈자 제보 12 | 13 | - 최신의 정정사항이나 업데이트를 확인하려면 여기를 클릭하세요! 14 |
👉 [**파이썬 편 정오표**](https://github.com/dremdeveloper/codingtest_python/blob/main/%EC%A0%95%EC%98%A4%ED%91%9C.md) 15 |
👉 [**오탈자 제보(C++/파이썬)**](https://forms.gle/xqnz13aaHgdBbhtDA) 16 | 17 | 18 | ## 🎥책 소개 및 영상 강의 19 | | 제목 | 링크 | 20 | |---------|------| 21 | | 프로그래머스 특강 | [Link](https://youtu.be/9HNCr_fxtlc?si=hL5NYmHMV4j56AIt) | 22 | | 책 소개| [Link](https://youtu.be/CLXFgptB81M) | 23 | | 코딩 테스트 합격자 되기 강의(C++편이지만 개념강의 이므로 다 들으셔도 됩니다.)| [Link](https://inf.run/H9yxm) | 24 | 25 | 26 | 27 | ## 🛒 책 구매 28 | 29 | | 책 제목 | 링크 | 30 | | --- | --- | 31 | | C++ 편 | [구매](https://www.yes24.com/Product/Goods/123272392) | 32 | | 파이썬 편 | [구매](https://www.yes24.com/Product/Goods/123272392) [미리보기](https://wikidocs.net/book/13314) | 33 | | 자바 편 | [구매](https://product.kyobobook.co.kr/detail/S000212576322) [미리보기](https://wikidocs.net/book/14549) | 34 | 35 | 36 | ## 💬 커뮤니티 참여 37 | | 항목 | 설명 | 링크 | 38 | | --- | --- | --- | 39 | | 오픈 카톡방 | - 독자 여러분과 실시간으로 소통할 수 있는 공간입니다.
- 개발 관련 얘기 및 상담을 자유롭게 진행할 수 있습니다. | [링크](https://open.kakao.com/o/gX0WnTCf) | 40 | | 네이버 카페 | 많은 알고리즘 자료가 있습니다. | [링크](https://cafe.naver.com/dremdeveloper) | 41 | 42 | 43 | 44 | ## 🚘 깃허브 45 | | 책 제목 | 링크 | 46 | | --- | --- | 47 | | 파이썬 편 | [링크](https://github.com/dremdeveloper/codingtest_python) | 48 | | C++ 편 | [링크](https://github.com/dremdeveloper/codingtest_cpp) | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/list.py: -------------------------------------------------------------------------------- 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 | lst = [1, 2, 3, 4] 8 | 9 | # append(item): 리스트의 끝에 item을 추가합니다. 반환값은 없습니다. 10 | # 시간 복잡도: O(1) (상수 시간) 11 | lst.append(5) 12 | print(lst) # 출력: [1, 2, 3, 4, 5] 13 | 14 | # insert(idx, item): idx 위치에 item을 추가합니다. 반환값은 없습니다. 15 | # 시간 복잡도: O(n) (n: 리스트의 길이) 16 | lst.insert(2, 6) 17 | print(lst) # 출력: [1, 2, 6, 3, 4, 5] 18 | 19 | # pop(): 리스트의 마지막 요소를 제거하고 반환합니다. 20 | # 시간 복잡도: O(1) (상수 시간) 21 | print(lst.pop()) # 출력: 5 22 | print(lst) # 출력: [1, 2, 6, 3, 4] 23 | 24 | # pop(0): 리스트의 첫 번째 요소를 제거하고 반환합니다. 25 | # 시간 복잡도: O(n) (n: 리스트의 길이) 26 | print(lst.pop(0)) # 출력: 1 27 | print(lst) # 출력: [2, 6, 3, 4] 28 | 29 | # remove(item): 리스트에서 item을 찾아 제거합니다. 반환값은 없습니다. 30 | # 시간 복잡도: O(n) (n: 리스트의 길이) 31 | lst.remove(6) 32 | print(lst) # 출력: [2, 3, 4] 33 | 34 | # extend(s): 리스트에 s의 모든 요소를 추가합니다. 반환값은 없습니다. 35 | # 시간 복잡도: O(k) (k: 추가하는 리스트 s의 길이) 36 | lst.extend([7, 8]) 37 | print(lst) # 출력: [2, 3, 4, 7, 8] 38 | 39 | # lst[K]: 리스트의 K 위치의 요소에 접근합니다. 40 | # 시간 복잡도: O(1) (상수 시간) 41 | print(lst[2]) # 출력: 4 42 | 43 | # lst1 + lst2: 두 리스트를 결합하여 새 리스트를 생성하고 반환합니다. 44 | # 시간 복잡도: O(n+m) (n: lst1의 길이, m: lst2의 길이) 45 | print([1, 2, 3] + [4, 5, 6]) # 출력: [1, 2, 3, 4, 5, 6] 46 | 47 | # list(set): 집합을 리스트로 변환하여 중복을 제거합니다. 순서는 보장되지 않습니다. 48 | # 시간 복잡도: O(n) (n: 리스트/집합의 길이) 49 | print(list(set([1, 2, 2, 3, 3, 4]))) # 출력 : [1,2,3,4] 50 | 51 | # item in lst: 리스트에 item이 있는지 확인합니다. 52 | # 시간 복잡도: O(n) (n: 리스트의 길이) 53 | print(3 in lst) # 출력: True 54 | -------------------------------------------------------------------------------- /reference/string.py: -------------------------------------------------------------------------------- 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 | # str1 + str2: 두 문자열 str1과 str2를 연결합니다. 8 | # 반환값: 새로운 문자열 9 | # 시간 복잡도: O(n + m), n과 m은 각각 str1과 str2의 길이입니다. 10 | str1 = "Hello" 11 | str2 = " World" 12 | result = str1 + str2 13 | print(result) # 출력: "Hello World" 14 | 15 | # delimiter.join(list_of_strings): delimiter 문자열을 사용하여 list_of_strings의 모든 문자열을 연결합니다. 16 | # 반환값: 새로운 문자열 17 | # 시간 복잡도: O(n), n은 list_of_strings의 모든 문자열 길이의 합입니다. 18 | delimiter = " | " 19 | list_of_strings = ["apple", "banana", "cherry"] 20 | result = delimiter.join(list_of_strings) 21 | print(result) # 출력: "apple | banana | cherry" 22 | 23 | # str.replace(old, new): 문자열 str에서 old 부분 문자열을 new 부분 문자열로 교체합니다. 24 | # 반환값: 새로운 문자열 25 | # 시간 복잡도: O(n), n은 str의 길이입니다. 26 | str3 = "Hello, World!" 27 | result = str3.replace("World", "Python") 28 | print(result) # 출력: "Hello, Python!" 29 | 30 | # str.split(sep): 문자열 str을 sep 문자열을 기준으로 나눕니다. 31 | # 반환값: 문자열 리스트 32 | # 시간 복잡도: O(n), n은 str의 길이입니다. 33 | str4 = "apple,banana,cherry" 34 | result = str4.split(",") 35 | print(result) # 출력: ['apple', 'banana', 'cherry'] 36 | 37 | # str.startswith(prefix): 문자열 str이 prefix로 시작하는지 확인합니다. 38 | # 반환값: bool (True 또는 False) 39 | # 시간 복잡도: O(k), k는 prefix의 길이입니다. 40 | str5 = "Hello, World!" 41 | result = str5.startswith("Hello") 42 | print(result) # 출력: True 43 | 44 | # str.endswith(suffix): 문자열 str이 suffix로 끝나는지 확인합니다. 45 | # 반환값: bool (True 또는 False) 46 | # 시간 복잡도: O(k), k는 suffix의 길이입니다. 47 | result = str5.endswith("World!") 48 | print(result) # 출력: True 49 | -------------------------------------------------------------------------------- /Coding_Test_Success_Guide.md: -------------------------------------------------------------------------------- 1 | # 코딩테스트 합격자 되기 - 챕터별 요약 및 기타공부자료 2 | 3 | **저자**: 박경록 4 | ![image](https://github.com/dremdeveloper/codingtest_python/assets/131899974/422c5885-20ad-4938-9fdb-ec127989b6f1) 5 | 6 | 7 | ## 챕터 8 | 9 | | 챕터 | 링크 | 10 | |---------|------| 11 | | 03 알고리즘의 효율 분석 | [Link](https://cafe.naver.com/dremdeveloper/994) | 12 | | 04 코딩 테스트 필수 문법 | [Link](https://cafe.naver.com/dremdeveloper/995) | 13 | | 05 배열 | [Link](https://cafe.naver.com/dremdeveloper/1007) | 14 | | 06 스택 | [Link](https://cafe.naver.com/dremdeveloper/1011) | 15 | | 07 큐 | [Link](https://cafe.naver.com/dremdeveloper/1015) | 16 | | 08 해시 | [Link](https://cafe.naver.com/dremdeveloper/1040) | 17 | | 09 트리 | [Link](https://cafe.naver.com/dremdeveloper/1042) | 18 | | 10 집합 | [Link](https://cafe.naver.com/dremdeveloper/1044) | 19 | | 11 그래프(탐색) | [Link](https://cafe.naver.com/dremdeveloper/1045) | 20 | | 11장 그래프(최소 경로) | [Link](https://cafe.naver.com/dremdeveloper/1046) | 21 | | 12장 백트래킹 | [Link](https://cafe.naver.com/dremdeveloper/1048) | 22 | | 13장 정렬 | [Link](https://cafe.naver.com/dremdeveloper/1049) | 23 | | 14장 시뮬레이션 | [Link](https://cafe.naver.com/dremdeveloper/1050) | 24 | | 15장 동적 계획법 | [Link](https://cafe.naver.com/dremdeveloper/1051) | 25 | | 16장 그리디 | [Link](https://cafe.naver.com/dremdeveloper/1052) | 26 | 27 | ## GPT를 활용한 알고리즘 공부 28 | 29 | | 챕터 | 링크 | 30 | |---------|------| 31 | | 재귀함수 | [Link](https://cafe.naver.com/dremdeveloper/1053) | 32 | | 최단경로 알고리즘 | [Link](https://cafe.naver.com/dremdeveloper/1054) | 33 | 34 | 35 | ## 공부자료 36 | | 제목 | 링크 | 37 | |---------|------| 38 | | 저자 깃허브 | [Link](https://github.com/dremdeveloper) | 39 | | 책 무료보기 | [Link](https://wikidocs.net/book/13314) | 40 | | 공부자료 정리 | [Link](https://github.com/dremdeveloper/codingtest_python/blob/main/community.md) | 41 | | 저자 카톡방 |[Link](https://open.kakao.com/o/gX0WnTCf) | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/heapq.py: -------------------------------------------------------------------------------- 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 | import heapq 8 | 9 | # 초기 리스트 정의. 현재 힙 속성을 만족하지 않음 10 | # 힙 속성: 부모 노드가 자식 노드보다 항상 작은 이진 트리 11 | lst = [4, 15, 7, 3, 2, 8] 12 | print("초기 리스트: ", lst) #출력값 : [4, 15, 7, 3, 2, 8] 13 | # 현재 트리: 14 | # 4 15 | # / \ 16 | # 15 7 17 | # / \ / 18 | # 3 2 8 19 | 20 | # heapq.heapify(iterable): 리스트를 in-place로 힙 속성을 만족하도록 변환, 반환값은 None 21 | # 시간 복잡도: O(N) 22 | heapq.heapify(lst) 23 | print("heapify(lst) 후 리스트: ", lst) #출력값 : [2, 3, 7, 4, 15, 8] 24 | # 변환된 트리: 25 | # 2 26 | # / \ 27 | # 3 7 28 | # / \ / 29 | # 4 15 8 30 | 31 | # heapq.heappush(heap, elem): 힙에 원소를 추가 32 | # 시간 복잡도: O(log N) 33 | heapq.heappush(lst, 1) 34 | print("heappush(lst, 1) 후 리스트: ", lst) #출력값 : [1, 3, 2, 4, 15, 8, 7] 35 | 36 | # heapq.heappop(heap): 힙에서 가장 작은 원소를 제거하고 그 원소를 반환 37 | # 시간 복잡도: O(log N) 38 | print("heappop(lst) 출력: ", heapq.heappop(lst)) #출력값 : 1 39 | print("heappop(lst) 후 리스트: ", lst) #출력값 : [2, 3, 7, 4, 15, 8] 40 | 41 | # ... (여기에 추가 메서드 및 설명을 넣어주세요) 42 | 43 | # heappushpop(heap, ele): 힙 heap에 요소 ele를 푸시하고, 힙에서 가장 작은 요소를 팝하고 반환 44 | # 시간 복잡도: O(log N) 45 | print("heappushpop(lst, 0) 실행 결과:", heapq.heappushpop(lst, 0)) #출력값 : 0 46 | print("heappushpop(lst, 0) 후 리스트:", lst) #출력값 : [2, 3, 7, 4, 15, 8] 47 | 48 | # heapreplace(heap, ele): 힙에서 가장 작은 요소를 팝하고, 요소 ele를 푸시 49 | # 시간 복잡도: O(log N) 50 | print("heapreplace(lst, 0) 실행 결과:", heapq.heapreplace(lst, 0)) #출력값 : 2 51 | print("heapreplace(lst, 0) 후 리스트:", lst) #출력값 : [0, 3, 7, 4, 15, 8] 52 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/bfs.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # BFS(너비 우선 탐색)는 그래프나 트리를 탐색하는 알고리즘 중 하나로, 8 | # 루트 노드(혹은 다른 임의의 노드)에서 시작하여 인접한 노드들을 먼저 탐색하는 알고리즘입니다. 9 | # 큐(Queue)를 사용하여 구현할 수 있으며, 아래 코드는 큐를 사용한 방법으로 BFS를 구현한 예입니다. 10 | 11 | # 2. 예시 입력 / 출력: 12 | # 입력: graph = {1: [2, 3], 2: [4, 5], 3: [], 4: [], 5: []}, start_node = 1 13 | # 출력: [1, 2, 3, 4, 5] 14 | 15 | # 3. 알고리즘의 시간 복잡도: 16 | # O(V + E) (V: 정점의 개수, E: 간선의 개수) 17 | 18 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 19 | # - 최단 경로 찾기 20 | # - 그래프의 연결성분 찾기 21 | 22 | # 5. BFS 상세 과정: 23 | # - 시작 노드(1)를 큐에 넣고, 방문 처리를 한다. 24 | # - 큐에서 노드를 하나 꺼낸다(노드 1). 25 | # - 해당 노드의 인접 노드 중 방문하지 않은 노드들(노드 2와 3)을 큐에 넣고 방문 처리를 한다. 26 | # - 큐에서 노드를 하나 꺼낸다(노드 2). 27 | # - 노드 2의 인접 노드 중 방문하지 않은 노드들(노드 4와 5)을 큐에 넣고 방문 처리를 한다. 28 | # - 위 과정을 큐가 빌 때까지 반복한다. 29 | 30 | from collections import deque 31 | 32 | def bfs(graph, start_node): 33 | visited = [False] * (len(graph) + 1) 34 | queue = deque([start_node]) 35 | visited[start_node] = True # 시작노드 방문 처리 36 | 37 | 38 | while queue: 39 | node = queue.popleft() 40 | print(node) # 방문 노드 출력 41 | for adj_node in graph[node]: # 인접한 노드 방문 42 | if not visited[adj_node]: 43 | queue.append(adj_node) 44 | visited[adj_node] = True 45 | 46 | # 그래프를 인접 리스트로 표현 47 | graph = { 48 | 1: [2, 3], 49 | 2: [4, 5], 50 | 3: [], 51 | 4: [], 52 | 5: [] 53 | } 54 | 55 | # BFS 알고리즘 실행 56 | bfs(graph, 1) # 1, 2, 3, 4, 5 57 | 58 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/bellmanford.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 벨만-포드 알고리즘(Bellman-Ford Algorithm) 예제 코드 7 | # 1. 알고리즘의 개념: 8 | # 벨만-포드 알고리즘은 그래프에서 주어진 시작 노드로부터 다른 모든 노드까지의 최단 경로를 찾는 알고리즘이다. 9 | # 음수 가중치를 가진 간선도 처리할 수 있으나, 음수 사이클이 있는 경우에는 알고리즘이 작동하지 않는다. 10 | 11 | # 2. 예시 입력 / 출력: 12 | # 입력: 그래프의 노드 개수 V, 간선 정보 edges, 시작 노드 src 13 | # 출력: 시작 노드로부터 각 노드까지의 최단 거리가 담긴 배열 14 | 15 | # 3. 알고리즘의 시간 복잡도: 16 | # O(V*E), 여기서 V는 노드의 수이고, E는 간선의 수이다. 17 | 18 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 19 | # - 그래프에서 단일 출발점 최단 경로 문제 20 | # - 음수 가중치가 있는 그래프에서의 최단 경로 문제 (단, 음수 사이클이 없어야 함) 21 | 22 | def bellman_ford(V, edges, src): 23 | # 시작 노드에서 다른 모든 노드까지의 최단 거리를 담을 리스트 초기화 24 | distance = [float('inf')] * V 25 | distance[src] = 0 26 | 27 | # 모든 간선에 대해 V-1번 반복하여 최단 거리를 갱신 28 | for _ in range(V-1): 29 | for u, v, w in edges: 30 | if distance[u] != float('inf') and distance[u] + w < distance[v]: 31 | distance[v] = distance[u] + w 32 | 33 | # 음수 사이클 체크: 한 번 더 반복하여 거리가 갱신되면 음수 사이클이 존재함 34 | for u, v, w in edges: 35 | if distance[u] != float('inf') and distance[u] + w < distance[v]: 36 | print("그래프에 음수 사이클이 존재합니다.") 37 | return None 38 | 39 | return distance 40 | 41 | # 간선 정보 (u, v, w) - u에서 v로 가는 가중치 w의 간선 42 | edges = [(0, 1, 1), (1, 2, 3), (0, 2, 4), (1, 3, 2), (2, 3, -1)] 43 | 44 | # 노드의 개수와 시작 노드 설정 45 | V = 4 46 | src = 0 47 | 48 | # 벨만-포드 알고리즘 실행 및 결과 출력 49 | result = bellman_ford(V, edges, src) 50 | if result: 51 | print("노드로부터의 최단 거리:", result) 52 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/union_find.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # Union-Find는 Disjoint Set을 표현할 때 사용하는 알고리즘으로, 두 특성 - union과 find를 기반으로 합니다. 8 | # - Union: 두 개의 집합을 하나의 집합으로 합칩니다. 9 | # - Find: 주어진 원소가 어떤 집합에 포함되어 있는지 찾습니다. 10 | # 랭크 기반과 경로 압축 기술을 사용하여 알고리즘의 시간 복잡도를 개선합니다. 11 | 12 | # 2. 예시 입력 / 출력: 13 | # 입력: unions = [(1, 2), (2, 3), (4, 5)] 14 | # 출력: find(3) -> 1, find(4) -> 4 15 | 16 | # 3. 알고리즘의 시간 복잡도: 17 | # - Union: O(α(n)) (α(n)은 아커만 함수의 역함수, 거의 상수 시간에 가깝습니다) 18 | # - Find: O(α(n)) 19 | 20 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 21 | # - 그래프에서 사이클 판별 22 | # - 네트워크 연결성 확인 23 | 24 | # 5. 상세과정: 25 | # - 랭크 기반: 각 노드의 랭크(트리의 높이)를 유지하면서, 랭크가 높은 트리 아래에 랭크가 낮은 트리를 합칩니다. 26 | # - 경로 압축: Find 연산 시, 노드에서 루트 노드까지의 경로를 플래튼화하여 이후 연산의 속도를 높입니다. 27 | 28 | # 각 노드의 부모 노드 정보 29 | parent = [i for i in range(6)] 30 | # 각 노드의 랭크 (트리의 높이) 31 | rank = [0] * 6 32 | 33 | def find(x): 34 | # 경로 압축 기법: 루트 노드를 찾으면서, 경로상의 노드들의 부모 노드를 루트 노드로 갱신 35 | if parent[x] != x: 36 | parent[x] = find(parent[x]) 37 | return parent[x] 38 | 39 | def union(x, y): 40 | root_x = find(x) 41 | root_y = find(y) 42 | 43 | # 랭크 기반 합치기: 랭크가 더 높은 트리에 랭크가 낮은 트리를 합침 44 | if root_x != root_y: 45 | if rank[root_x] > rank[root_y]: 46 | parent[root_y] = root_x 47 | else: 48 | parent[root_x] = root_y 49 | if rank[root_x] == rank[root_y]: 50 | rank[root_y] += 1 51 | 52 | # 예시 코드 실행 53 | union(1, 2) 54 | union(2, 3) 55 | union(4, 5) 56 | 57 | print(find(3)) # 출력: 1 58 | print(find(4)) # 출력: 4 59 | 60 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/dijkstra.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 알고리즘의 개념: 7 | # 다익스트라 알고리즘은 그래프에서 한 노드로부터 다른 모든 노드까지의 최단 경로를 찾는 알고리즘이다. 8 | # 이 알고리즘은 음수 가중치를 가진 간선을 허용하지 않는다. 9 | 10 | # 2. 예시 입력 / 출력: 11 | # 입력: 그래프의 노드 개수 V, 간선 정보 edges, 시작 노드 src 12 | # 출력: 시작 노드로부터 각 노드까지의 최단 거리가 담긴 배열 13 | 14 | # 3. 알고리즘의 시간 복잡도: 15 | # O((V+E)logV), 여기서 V는 노드의 수, E는 간선의 수 16 | 17 | # 4. 해당 알고리즘으로 풀 수 있는 문제 예시: 18 | # - 한 지점에서 다른 지점까지의 최단 경로 찾기 19 | # - 네트워크 라우팅 알고리즘 20 | 21 | from heapq import heappush, heappop 22 | 23 | def dijkstra(V, edges, src): 24 | # 시작 노드에서 다른 모든 노드까지의 최단 거리를 담을 리스트 초기화 25 | distance = [float('inf')] * V 26 | distance[src] = 0 27 | 28 | # 그래프를 인접 리스트 형태로 변환 29 | graph = [[] for _ in range(V)] 30 | for u, v, w in edges: 31 | graph[u].append((v, w)) 32 | 33 | # 우선순위 큐를 사용하여 현재 노드까지의 거리를 관리 34 | pq = [(0, src)] 35 | while pq: 36 | dist, node = heappop(pq) 37 | 38 | # 이미 처리된 노드는 무시 39 | if dist > distance[node]: 40 | continue 41 | 42 | # 현재 노드와 인접한 노드들의 거리 갱신 43 | for neighbor, weight in graph[node]: 44 | if dist + weight < distance[neighbor]: 45 | distance[neighbor] = dist + weight 46 | heappush(pq, (distance[neighbor], neighbor)) 47 | 48 | return distance 49 | 50 | # 간선 정보: (u, v, w) - u에서 v로 가는 가중치 w의 간선 51 | edges = [(0, 1, 1), (1, 2, 3), (0, 2, 4), (1, 3, 2), (2, 3, -1)] 52 | 53 | # 노드의 개수와 시작 노드 설정 54 | V = 4 55 | src = 0 56 | 57 | # 다익스트라 알고리즘 실행 및 결과 출력 58 | result = dijkstra(V, edges, src) 59 | if result: 60 | print("노드로부터의 최단 거리:", result) 61 | -------------------------------------------------------------------------------- /solution/53.py: -------------------------------------------------------------------------------- 1 | def solution(board, aloc, bloc): 2 | # ➊ 게임판의 행과 열의 개수를 저장합니다. 3 | ROW, COL = len(board), len(board[0]) 4 | # ➋ 이동할 수 있는 방향을 저장합니다. 상, 우, 하, 좌 순서로 저장되어 있습니다. 5 | DR, DC = [-1, 0, 1, 0], [0, 1, 0, -1] 6 | 7 | # ➌ 주어진 위치가 유효한 위치인지 확인하는 함수입니다. 8 | def is_valid_pos(r, c): 9 | return 0 <= r < ROW and 0 <= c < COL 10 | 11 | # ➍ 재귀적으로 호출되는 함수입니다. 12 | def recursive_func(alpha_pos, beta_pos, visited, step): 13 | # ➎ 현재 플레이어의 위치와 이동 가능한지 여부, 14 | # 상대 플레이어가 이긴 경우를 저장하는 변수들입니다. 15 | r, c = alpha_pos if step % 2 == 0 else beta_pos 16 | can_move = False 17 | is_opponent_winner = True 18 | # ➏ 이긴 경우와 지는 경우를 저장하는 리스트입니다. 19 | win_steps, lose_steps = [], [] 20 | 21 | # ➐ 현재 위치에서 이동할 수 있는 모든 방향으로 이동해봅니다. 22 | for i in range(4): 23 | nr, nc = r + DR[i], c + DC[i] 24 | # ➑ 이동할 수 있는 위치인 경우 25 | if is_valid_pos(nr, nc) and (nr, nc) not in visited and board[nr][nc]: 26 | can_move = True 27 | # ➒ 두 플레이어의 위치가 같으면 A 플레이어가 이긴 것이므로 True와 step + 1을 반환합니다. 28 | if alpha_pos == beta_pos: 29 | return True, step + 1 30 | 31 | # ➓ 재귀적으로 호출하여 이긴 여부와 남은 턴수를 가져옵니다. 32 | win, steps_left = ( 33 | recursive_func([nr, nc], beta_pos, visited | {(r, c)}, step + 1) 34 | if step % 2 == 0 35 | else recursive_func( 36 | alpha_pos, [nr, nc], visited | {(r, c)}, step + 1 37 | ) 38 | ) 39 | # ⓫ 상대 플레이어가 이긴 경우만 True로 유지합니다. 40 | is_opponent_winner &= win 41 | # ⓬ 이긴 경우와 지는 경우를 저장합니다. 42 | (win_steps if win else lose_steps).append(steps_left) 43 | 44 | # ⓭ 이동할 수 있는 위치가 없는 경우 45 | if not can_move: 46 | return False, step 47 | # ⓮ 상대 플레이어가 이긴 경우 48 | if is_opponent_winner: 49 | return False, max(win_steps) 50 | # ⓯ 현재 플레이어가 이긴 경우 51 | return True, min(lose_steps) 52 | 53 | # ⓰ A 플레이어가 이길 때까지 걸리는 최소 턴 수를 반환합니다. 54 | _, steps = recursive_func(aloc, bloc, set(), 0) 55 | return steps 56 | -------------------------------------------------------------------------------- /Algorithm_with_DataStructure/queue.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 1. 자료구조 개념: 7 | # 스택은 데이터의 삽입과 삭제가 한 쪽 끝에서만 일어나는 선형 자료구조이다. 8 | # 이러한 특성 때문에 Last In First Out (LIFO) 자료구조라고도 불린다. 9 | # 여기서는 deque라는 Python 라이브러리를 사용하여 스택을 구현하였다. 10 | 11 | # 2. 예시 입력 / 출력: 12 | # 입력: [1, 2, 3, 4, 5] (순차적으로 스택에 push) 13 | # 출력: 5 4 3 2 1 (순차적으로 스택에서 pop) 14 | 15 | # 3. 자료구조의 시간 복잡도: 16 | # 스택의 주요 연산인 push와 pop 모두 O(1)의 시간 복잡도를 가진다. 17 | # 이는 각 연산이 상수 시간에 수행됨을 의미한다. 18 | 19 | # 4. 해당 자료구조로 풀 수 있는 문제 예시: 20 | # - 괄호 짝 맞추기 문제 21 | # - 브라우저의 뒤로 가기 기능 구현 22 | # - 깊이 우선 탐색 (DFS) 등 23 | 24 | # 5. 상세 과정: 25 | # - 먼저 deque 라이브러리를 사용하여 스택 객체를 초기화한다. 26 | # - append() 메서드를 사용하여 요소를 스택에 삽입한다. 27 | # - pop() 메서드를 사용하여 스택의 맨 위 요소를 제거하고 반환한다. 28 | # 1. 자료구조 개념: 29 | # 큐는 데이터의 삽입이 한 쪽 끝에서 이루어지고 삭제는 반대 쪽 끝에서 이루어지는 선형 자료구조이다. 30 | # 이러한 특성 때문에 First In First Out (FIFO) 자료구조라고도 불린다. 31 | # 여기서는 deque라는 Python 라이브러리를 사용하여 큐를 구현하였다. 32 | 33 | # 2. 예시 입력 / 출력: 34 | # 입력: [1, 2, 3, 4, 5] (순차적으로 큐에 enqueue) 35 | # 출력: 1 2 3 4 5 (순차적으로 큐에서 dequeue) 36 | 37 | # 3. 자료구조의 시간 복잡도: 38 | # 큐의 주요 연산인 enqueue와 dequeue 모두 O(1)의 시간 복잡도를 가진다. 39 | # 이는 각 연산이 상수 시간에 수행됨을 의미한다. 40 | 41 | # 4. 해당 자료구조로 풀 수 있는 문제 예시: 42 | # - 너비 우선 탐색 (BFS) 구현 43 | # - 대기열 (Waiting Line) 문제 해결 44 | # - CPU 스케줄링 등 45 | 46 | # 5. 상세 과정: 47 | # - 먼저 deque 라이브러리를 사용하여 큐 객체를 초기화한다. 48 | # - append() 메서드를 사용하여 요소를 큐에 삽입한다. 49 | # - popleft() 메서드를 사용하여 큐의 맨 앞 요소를 제거하고 반환한다. 50 | from collections import deque 51 | 52 | # 큐 객체 초기화 53 | queue = deque() 54 | 55 | # 요소들을 큐에 삽입 (enqueue) 56 | queue.append(1) 57 | queue.append(2) 58 | queue.append(3) 59 | queue.append(4) 60 | queue.append(5) 61 | 62 | # 큐에서 요소들을 제거 (dequeue)하면서 출력 63 | while queue: 64 | print(queue.popleft()) # 출력: 1, 2, 3, 4, 5 (FIFO 순서) 65 | 66 | -------------------------------------------------------------------------------- /solution/27.py: -------------------------------------------------------------------------------- 1 | # ➊ 노드 클래스 정의 2 | class Node: 3 | # ➋ 노드 클래스 생성자 4 | def __init__(self, key): 5 | self.left = None 6 | self.right = None 7 | self.val = key 8 | 9 | # ➌ 이진 탐색 트리 클래스 10 | class BST: 11 | # ➍ 초기에 아무 노드도 없는 상태 12 | def __init__(self): 13 | self.root = None 14 | # ➎ 루트 노드부터 시작해서 이진 탐색 트리 규칙에 맞는 위치에 새 노드 삽입 15 | def insert(self, key): 16 | # 루트 노드가 없는 경우 새로운 노드를 루트 노드로 추가 17 | if not self.root: 18 | self.root = Node(key) 19 | else: 20 | curr = self.root 21 | while True: 22 | # 삽입하려는 값이 현재 노드의 값보다 작은 경우 왼쪽 자식 노드로 이동 23 | if key < curr.val: 24 | if curr.left: 25 | curr = curr.left 26 | else: 27 | # 현재 노드의 왼쪽 자식 노드가 없는 경우 새로운 노드 추가 28 | curr.left = Node(key) 29 | break 30 | else: 31 | # 삽입하려는 값이 현재 노드의 값보다 큰 경우 오른쪽 자식 노드로 이동 32 | if curr.right: 33 | curr = curr.right 34 | else: 35 | # 현재 노드의 오른쪽 자식 노드가 없는 경우 새로운 노드 추가 36 | curr.right = Node(key) 37 | break 38 | # ➏ 이진 탐색 규칙에 따라 특정값이 있는지 확인(루트 노드부터 시작) 39 | def search(self, key): 40 | curr = self.root 41 | # 현재 노드가 존재하고, 찾으려는 값과 현재 노드의 값이 같지 않은 경우 반복 42 | while curr and curr.val != key: 43 | # 찾으려는 값이 현재 노드의 값보다 작은 경우 왼쪽 자식 노드로 이동 44 | if key < curr.val: 45 | curr = curr.left 46 | else: 47 | # 찾으려는 값이 현재 노드의 값보다 큰 경우 오른쪽 자식 노드로 이동 48 | curr = curr.right 49 | return curr 50 | # ➐ lst에 있는 데이터를 활용해서 이진 탐색 트리 생성, search_lst 원소 탐색 51 | def solution(lst, search_lst): 52 | bst = BST() 53 | # 리스트의 각 요소를 이용하여 이진 탐색 트리 생성 54 | for key in lst: 55 | bst.insert(key) 56 | result = [] 57 | # 검색 리스트의 각 요소를 이진 탐색 트리에서 검색하고, 검색 결과를 리스트에 추가 58 | for search_val in search_lst: 59 | if bst.search(search_val): 60 | result.append(True) 61 | else: 62 | result.append(False) 63 | return result 64 | 65 | 66 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 67 | # print(solution([5, 3, 8, 4, 2, 1, 7, 10], [1, 2, 5, 6])) # [True, True, True, False] 68 | # print(solution([1, 3, 5, 7, 9], [2, 4, 6, 8, 10])) # [False, False, False, False, False] 69 | -------------------------------------------------------------------------------- /reference/permutation_direct.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 순열(permutations)은 리스트 내 원소들을 모든 가능한 순서대로 배열하는 것을 의미합니다. 7 | # 예를 들어, [1, 2, 3]의 순열은 [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]와 같이 2개씩 묶어서 모든 순서 조합을 생성합니다. 8 | # 시간 복잡도: O(nPn) = n! (모든 순열을 생성하므로) 9 | # 이 코드는 재귀적으로 순열을 생성하고 그 결과를 리스트에 저장합니다. 10 | 11 | # 현재 원소를 선택하여 순열 생성, lst=[1,2,3]인 경우 12 | # e.g., lst = [1, 2, 3], r = 2 13 | # |-> 1을 선택: 14 | # | | 15 | # | |-> 2를 선택: (1, 2) 생성 16 | # | | 17 | # | |-> 3를 선택: (1, 3) 생성 18 | # | 19 | # |-> 2을 선택: 20 | # | | 21 | # | |-> 1를 선택: (2, 1) 생성 22 | # | | 23 | # | |-> 3를 선택: (2, 3) 생성 24 | # | 25 | # |-> 3을 선택: 26 | # | 27 | # |-> 1를 선택: (3, 1) 생성 28 | # | 29 | # |-> 2를 선택: (3, 2) 생성 30 | 31 | def permutations(lst, r): 32 | result = [] # 최종 순열 결과를 담을 리스트 33 | 34 | def generate_permutation(chosen, remain): 35 | """ 36 | chosen: 지금까지 선택한 원소 리스트 37 | remain: 남은 원소 리스트 38 | """ 39 | # 원하는 r개의 원소를 모두 선택한 경우, 결과에 추가 40 | if len(chosen) == r: 41 | result.append(chosen[:]) # 선택한 원소 리스트를 결과에 추가 (복사하여 추가) 42 | return 43 | 44 | for i in range(len(remain)): 45 | # 현재 원소를 선택한 경우를 시뮬레이션하며 재귀 호출 46 | chosen.append(remain[i]) # 현재 원소를 chosen에 추가 47 | remaining_elements = remain[:i] + remain[i + 1:] # remain에서 현재 원소를 제외 48 | generate_permutation(chosen, remaining_elements) 49 | chosen.pop() # 현재 원소를 다시 chosen에서 제거하여 다음 시뮬레이션을 위해 돌아감 50 | 51 | generate_permutation([], lst) # 초기 호출 52 | 53 | return result 54 | 55 | lst = [1, 2, 3] 56 | r = 2 57 | print(permutations(lst, r)) 58 | 59 | -------------------------------------------------------------------------------- /reference/combination_direct.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 조합(combinations)은 주어진 리스트 내에서 특정 개수 r의 원소를 선택하는 모든 가능한 조합을 생성합니다. 7 | # 예를 들어, [1, 2, 3]에서 2개의 원소를 선택하는 경우: [(1, 2), (1, 3), (2, 3)] 8 | # 시간 복잡도: O(nCr) = n! / (r! * (n-r)!) (모든 조합을 생성하므로) 9 | # 이 코드는 재귀적으로 조합을 생성하고 그 결과를 리스트에 저장합니다. 10 | 11 | # lst=[1,2,3]인 경우, 아래 주석과 맞춰서 보면 됩니다. 12 | # 현재 원소를 선택하는 경우 13 | # e.g., lst = [1, 2, 3], r = 2 14 | # |-> 1을 선택: 15 | # | | 16 | # | |-> 2를 선택: (1, 2) 완성 17 | 18 | # 현재 원소를 선택하지 않는 경우 19 | # e.g., lst = [1, 2, 3], r = 2 20 | # | | 21 | # | |-> 2를 선택 X: 22 | # | | 23 | # | |-> 3를 선택: (1, 3) 완성 24 | 25 | #초기 호출 26 | # e.g., lst = [1, 2, 3], r = 2 27 | # |-> 1을 선택 X: 28 | # | 29 | # |-> 2를 선택: 30 | # | | 31 | # | |-> 3를 선택: (2, 3) 완성 32 | 33 | 34 | def combinations(lst, r): 35 | result = [] # 최종 조합 결과를 담을 리스트 36 | 37 | def generate_combination(chosen, remain, n): 38 | """ 39 | chosen: 지금까지 선택한 원소 리스트 40 | remain: 남은 원소 리스트 41 | n: 더 필요한 원소의 수 42 | """ 43 | 44 | # 원하는 r개의 원소를 모두 선택한 경우, 결과에 추가 45 | if n == 0: 46 | result.append(chosen[:]) # 선택한 원소 리스트를 결과에 추가 (복사하여 추가) 47 | return 48 | 49 | # 남은 원소가 없거나, 더 이상 원소를 선택할 수 없는 경우 종료 50 | if not remain or len(remain) < n: 51 | return 52 | 53 | # 현재 원소를 선택하는 경우 54 | chosen.append(remain[0]) # 현재 원소를 chosen에 추가 55 | generate_combination(chosen, remain[1:], n-1) # 다음 원소를 선택하기 위해 재귀 호출 56 | chosen.pop() # 현재 원소를 다시 chosen에서 제거하여 다음 시뮬레이션을 위해 돌아감 57 | 58 | # 현재 원소를 선택하지 않는 경우 59 | generate_combination(chosen, remain[1:], n) # 다음 원소를 선택하기 위해 재귀 호출 60 | 61 | # 초기 호출 62 | generate_combination([], lst, r) 63 | 64 | return result 65 | 66 | lst = [1, 2, 3] 67 | r = 2 68 | print(combinations(lst, r)) 69 | -------------------------------------------------------------------------------- /solution/32.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | # ➊ Node 클래스 정의 4 | class Node: 5 | def __init__(self, info, num, left=None, right=None): 6 | self.info = info # 노드의 좌표 정보 저장 7 | self.left = left # 노드의 왼쪽 자식 노드 8 | self.right = right # 노드의 오른쪽 자식 노드 9 | self.num = num # 노드의 번호 10 | 11 | # ➋ 왼쪽 자식 노드가 있는지 확인하는 함수 12 | def has_left(self): 13 | return self.left is not None 14 | 15 | # ➌ 오른쪽 자식 노드가 있는지 확인하는 함수 16 | def has_right(self): 17 | return self.right is not None 18 | 19 | # ➍ 이진 트리 생성 함수 20 | def make_BT(nodeinfo): 21 | nodes = [i for i in range(1, len(nodeinfo) + 1)] # ➎ 노드의 번호 리스트 생성 22 | nodes.sort(key=lambda x: (nodeinfo[x - 1][1], -nodeinfo[x - 1][0]), reverse=True) 23 | root = None 24 | for i in range(len(nodes)): 25 | if root is None: 26 | root = Node(nodeinfo[nodes[0] - 1], nodes[0]) 27 | else: 28 | parent = root 29 | node = Node(nodeinfo[nodes[i] - 1], nodes[i]) 30 | while True: 31 | # ➏ 부모 노드의 x좌표가 더 크면 왼쪽으로 32 | if node.info[0] < parent.info[0]: 33 | if parent.has_left(): 34 | parent = parent.left 35 | continue 36 | parent.left = node 37 | break 38 | # ➐ 부모 노드의 x좌표가 더 작거나 같으면 오른쪽으로 39 | else: 40 | if parent.has_right(): 41 | parent = parent.right 42 | continue 43 | parent.right = node 44 | break 45 | return root 46 | 47 | # ➑ 전위 순회 함수 48 | def pre_order(root, answer): 49 | stack = [root] 50 | while stack: 51 | node = stack.pop() 52 | if node is None: 53 | continue 54 | answer[0].append(node.num) 55 | stack.append(node.right) 56 | stack.append(node.left) 57 | 58 | # ➒ 후위 순회 함수 59 | def post_order(root, answer): 60 | stack = [(root, False)] 61 | while stack: 62 | node, visited = stack.pop() 63 | if node is None: 64 | continue 65 | if visited: 66 | answer[1].append(node.num) 67 | else: 68 | stack.append((node, True)) 69 | stack.append((node.right, False)) 70 | stack.append((node.left, False)) 71 | 72 | # ➓ 주어진 좌표 정보를 이용하여 이진 트리를 생성하고, 전위 순회와 후위 순회한 결과를 반환하는 함수 73 | def solution(nodeinfo): 74 | answer = [[], []] # 결과를 저장할 리스트 초기화 75 | root = make_BT(nodeinfo) # 이진 트리 생성 76 | pre_order(root, answer) # 전위 순회 77 | post_order(root, answer) # 후위 순회 78 | return answer # 결과 반환 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 코딩 테스트 합격자 되기(파이썬 편)-판매 시작 2 | | 서점 | 구매링크 | 3 | | ---------- | ---------------------------------------------- | 4 | | 무료 미리보기(~179p) | https://wikidocs.net/book/13314 | 5 | |교보문고 |https://bit.ly/3MlKPPN| 6 | |알라딘 |https://bit.ly/47bm7ti| 7 | |예스|https://www.yes24.com/Product/Goods/123272392| 8 | |정오표|[https://docs.google.com/spreadsheets/d/1BPAmoaDmn-RRBjk8O468M_v3WnI46UaX0N_0vs0pZCk/edit#gid=0](https://github.com/dremdeveloper/codingtest_python/blob/main/%EC%A0%95%EC%98%A4%ED%91%9C.md)| 9 | 10 | 11 | 12 | ![image](https://github.com/dremdeveloper/codingtest_python/assets/131899974/d7e70dc0-cd77-44b8-a68a-71475540b3b7) 13 | 14 | 15 | # 진행중인 이벤트 16 | | Event | 세부내용 |기간 | 17 | | ---------- | ---------------------------------------------- |---------------------------------------------- | 18 | |코딩테스트 스터디 |[참여방법 및 스터디 세부사항](https://cafe.naver.com/dremdeveloper/948) | 상시 | 19 | 20 | 21 | 22 | # 코딩테스트 소통공간(저자가 직접운영) 23 | | Title | Description | 24 | | ---------- | ---------------------------------------------- | 25 | |카카오톡 오픈채팅 |[클릭](https://open.kakao.com/o/gX0WnTCf) | 26 | 27 | ![image](https://github.com/dremdeveloper/codingtest_python/assets/131899974/ba74f116-ddb6-4cb4-956e-147d35e10336) 28 | 29 | # 연락처 30 | - 해당 코드들에 대해 문의사항이 있거나, 연락이 필요한 경우 아래 참조 31 | 32 | | Title | Description | 33 | | ---------- | ---------------------------------------------- | 34 | |Cafe |http://cafe.naver.com/dremdeveloper | 35 | |Business Mail |ultrasuperrok@gmail.com | 36 | |Codingtest Java |https://github.com/dremdeveloper/codingtest_java | 37 | |Codingtest CPP |https://github.com/dremdeveloper/codingtest_cpp | 38 | # 폴더 구조 39 | - 깃 허브의 폴더 구조에 대한 설명 40 | 41 | | Title | Description | 42 | | ---------- | ---------------------------------------------- | 43 | | errorcode | 구현시 자주 발생하는 에러메시지 | 44 | | mistake | 구현시 자주 실수할수 있는 사항 | 45 | | performance | 비슷한 동작을 하는데 시간복잡도가 다른 경우에 대한 시간비교 | 46 | | reference | 코딩테스트에서 많이 사용하는 문법 | 47 | | solution | 책에 있는 문제에 대한 해설 | 48 | | Algorithm_with_DataStructure | 코딩테스트에 등장하는 알고리즘과 자료구조 | 49 | 50 | -------------------------------------------------------------------------------- /mistake/ReadMe.md: -------------------------------------------------------------------------------- 1 | # 파이썬 코딩 실수 예시들 2 | 3 | 이 문서는 파이썬 프로그래밍에서 흔히 발생할 수 있는 실수와 그 예시를 제공합니다. 각 스크립트는 특정한 코딩 실수를 보여주며, 이에 대한 설명은 아래 표에서 확인할 수 있습니다. 4 | 5 | | 파일 이름 | 설명 | 6 | |--------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 7 | | [`binary_search_mistake.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/binary_search_mistake.py) | 이진 검색 알고리즘 구현 중 흔히 발생할 수 있는 실수 예시입니다. | 8 | | [`for_else_tutorial.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/for_else_tutorial.py) | `for-else` 구조의 사용 방법과 이를 잘못 이해하면 발생할 수 있는 실수를 설명합니다. | 9 | | [`index_error_demo.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/index_error_demo.py) | 리스트에서 인덱스 오류가 어떻게 발생하는지를 보여주는 예시입니다. | 10 | | [`indexing_convention_tutorial.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/indexing_convention_tutorial.py) | 파이썬의 인덱싱 규칙과 관련된 실수 가능성을 보여줍니다. | 11 | | [`list_in_del_usage.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/list_in_del_usage.py) | `del` 키워드와 리스트의 `in` 연산자 사용 시 발생할 수 있는 실수를 설명합니다. | 12 | | [`none_return_tutorial.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/none_return_tutorial.py) | 함수에서 `None`을 반환하는 방법과 관련된 실수를 설명합니다. | 13 | | [`operation_precedence_examples.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/operation_precedence_examples.py) | 연산자 우선순위와 관련된 흔한 실수 예를 제공합니다. | 14 | | [`power_methods_comparison.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/power_methods_comparison.py) | 제곱을 계산하는 다양한 방법과 이에 대한 잠재적 실수를 비교합니다. | 15 | | [`range_function_usage.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/range_function_usage.py) | `range()` 함수의 사용법과 이를 잘못 사용할 때 발생할 수 있는 실수를 설명합니다. | 16 | | [`sorting_methods_comparison.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/sorting_methods_comparison.py) | 다양한 정렬 방법과 이들 간의 성능 차이에 대한 실수 가능성을 비교합니다. | 17 | | [`variable_scope_tutorial.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/variable_scope_tutorial.py) | 변수의 범위(scope)와 관련된 실수를 설명합니다. | 18 | | [`zero_division_demo.py`](https://github.com/dremdeveloper/codingtest_python/blob/main/mistake/zero_division_demo.py) | 0으로 나누기 오류와 이를 방지하는 방법을 보여줍니다. | 19 | 20 | 각 파일의 설명은 해당 파일의 주석을 기반으로 작성되었습니다. 자세한 내용은 각 파일의 주석을 참조해주세요. 21 | -------------------------------------------------------------------------------- /reference/mergesort_recursive.py: -------------------------------------------------------------------------------- 1 | ############################################################# 2 | # | cafe | http://cafe.naver.com/dremdelover | 3 | # | Q&A | https://open.kakao.com/o/gX0WnTCf | 4 | # | business | ultrasuperrok@gmail.com | 5 | ############################################################# 6 | # 머지 정렬(Merge Sort)의 개념: 7 | # - 머지 정렬은 분할 정복(divide and conquer) 전략을 사용하는 정렬 알고리즘입니다. 8 | # - 배열을 절반으로 계속해서 분할하다가 길이가 1이 되면, 이를 기준으로 다시 합치면서 정렬합니다. 9 | # - 두 부분 배열을 합치는 과정(merge)에서 정렬이 이루어집니다. 10 | # - 머지 정렬은 안정적인 정렬로, 순서가 같은 원소들의 상대적 순서가 정렬 후에도 유지됩니다. 11 | 12 | # 시간 복잡도: 13 | # - 머지 정렬의 시간 복잡도는 O(n log n)입니다. 14 | # - 배열을 절반씩 분할하는 데 log n의 시간이 걸리고, 각 분할마다 n의 연산이 필요하므로 n log n이 됩니다. 15 | 16 | # 예시: arr = [38, 27, 43, 3, 9, 82, 10] 17 | # 머지 정렬 과정 도식화: 18 | # 1. 원래 배열을 절반씩 분할 19 | # arr -> [38, 27, 43, 3] and [9, 82, 10] 20 | # 21 | # 2. 각각의 배열을 다시 절반씩 분할 (재귀적으로 반복) 22 | # [38, 27, 43, 3] -> [38, 27] and [43, 3] 23 | # [9, 82, 10] -> [9] and [82, 10] 24 | # 25 | # 3. 분할된 배열들을 정렬하면서 병합 26 | # [38, 27] -> 27, 38 27 | # [43, 3] -> 3, 43 28 | # [82, 10] -> 10, 82 29 | # 30 | # 4. 다시 이전 단계의 정렬된 배열들을 병합 31 | # [27, 38] and [3, 43] -> 3, 27, 38, 43 32 | # [9] and [10, 82] -> 9, 10, 82 33 | # 34 | # 5. 최종적으로 병합하여 완전히 정렬된 배열을 얻음 35 | # [3, 27, 38, 43] and [9, 10, 82] -> 3, 9, 10, 27, 38, 43, 82 36 | 37 | # 병합 정렬 함수 38 | def merge_sort(arr): 39 | # 재귀 종료 조건: 리스트의 길이가 1 이하면 이미 정렬된 것으로 간주하고 반환합니다. 40 | if len(arr) <= 1: 41 | return arr 42 | 43 | # 리스트를 중간 지점에서 분할합니다. 44 | mid = len(arr) // 2 45 | left = merge_sort(arr[:mid]) # 왼쪽 부분 리스트를 재귀적으로 정렬합니다. 46 | right = merge_sort(arr[mid:]) # 오른쪽 부분 리스트를 재귀적으로 정렬합니다. 47 | 48 | # 두 부분 리스트를 병합합니다. 49 | return merge(left, right) 50 | 51 | # 병합 함수 52 | def merge(left, right): 53 | result = [] # 병합된 결과를 저장할 리스트를 초기화합니다. 54 | i = j = 0 # 왼쪽과 오른쪽 부분 리스트를 가리키는 인덱스를 초기화합니다. 55 | 56 | # 두 부분 리스트를 비교하면서 작은 값을 결과 리스트에 추가합니다. 57 | while i < len(left) and j < len(right): 58 | if left[i] < right[j]: 59 | result.append(left[i]) 60 | i += 1 61 | else: 62 | result.append(right[j]) 63 | j += 1 64 | 65 | # 남은 원소들을 결과 리스트에 추가합니다. 66 | while i < len(left): 67 | result.append(left[i]) 68 | i += 1 69 | 70 | while j < len(right): 71 | result.append(right[j]) 72 | j += 1 73 | 74 | return result 75 | 76 | # 주어진 리스트를 정렬합니다. 77 | arr = [38, 27, 43, 3, 9, 82, 10] 78 | sorted_arr = merge_sort(arr) 79 | 80 | # 정렬된 결과를 출력합니다. 81 | print(sorted_arr) 82 | -------------------------------------------------------------------------------- /performance/ReadMe.md: -------------------------------------------------------------------------------- 1 | # 제대로 알고 구현하기 2 | 코딩테스트 문제를 분석하고 실제 알고리즘을 구현할 때, 여러가지 난관이 부딪힐 수 있습니다. 가장 많은 분들이 공부하다가 어려움을 느끼시는 경우는 크게 두 가지일 것입니다.

첫 번째는 문제를 이해하고 알맞은 알고리즘을 적용했는데도 시간초과가 발생하는 경우 입니다. 결국엔 해결하지 못하고 정답코드를 봤는데도 본인이 구현한 코드와 별 다를게 없어보입니다. 이 경우 대부분 원인은 알고리즘 구현을 위해 사용한 파이썬에서 제공한 함수들이, 생각보다 많은 연산을 하는 경우 입니다. 본인이 직접 구현하지 않고 이미 제공하는 함수 들을 그냥 바로 쓰기 때문에 제대로 공부하지 않으면 놓치기 쉬운 부분 입니다. 따라서 파이썬에서 제공하는 함수들의 시간복잡도를 제대로 파악하는 것이 중요 합니다. 3 |

두 번째는 문법적 오류가 발생한 경우 입니다. 한 번에 에러없이 구현하면 좋겠지만 대 부분의 경우 디버깅 과정을 거쳐서 구현을 하게 됩니다. 따라서 문법적 오류가 발생할 때 출력되는 에러메시지의 의미를 명확히 파악하는것이 중요합니다. 4 |

본 장에서는, 먼저 코딩테스트에서 자주 사용되는 파이썬 함수들의 시간 복잡도를 알아본 다음 자주 발생하는 오류메시지 및 이를 조치하는 방법에 대해 설명하겠습니다. 5 | 6 | 7 | # 파이썬 함수의 시간 복잡도 8 | ## 리스트 9 | 배열 기반의 구조로, 인덱스를 활용한 접근 및 맨 끝부분에서 추가및 제거가 빠릅니다. 하지만 원소의 중간에서 삽입/삭제 하거나 왼소의 맨 처음에 삽입하는 경우에는 상당히 비효율적입니다. 아래 list는 임의 변수이름 입니다. 아래 표에서 lst는 리스트 타입의 변수 입니다. 10 | 11 | 12 | | 메서드 | 동작 | 시간복잡도| 13 | | ---------- | ---------------------------------------------- |------------------------------ | 14 | | lst.append(item) | item을 lst의 맨 끝에 추가 | O(1) | 15 | | lst.insert(idx,item) | item을 lst의 idx 위치에 삽입
(그 이후 원소들은 한칸씩 밀림) | O(N),N은 lst의 길이 | 16 | | lst.pop() | lst의 마지막 원소 제거 후, 해당 원소 반환 | O(1) | 17 | | lst.pop(0) | lst의 첫 번째 원소 제거 후 해당 원소 반환
(모든 원소가 앞으로 한 칸씩 이동)| O(N),N은 lst의 길이 | 18 | | lst.remove(item) | lst에서 item과 일치하는 첫번째 원소 찾아서 제거 | O(N),N은 lst의 길이 | 19 | | lst.extend(s) | lst모든 원소들을 현재 리스트의 끝에 추가 | O(N),N은 lst의 길이 | 20 | | lst[K] | lst의 k번째 인덱스에 있는 요소를 반환합니다. | O(1) | 21 | | lst1 + lst2 | lst1와 lst2의 원소들을 하나의 리스트를 결합하고, 해당 리스트를 반환 | O(N+M), N은 lst1의 길이이고, M은 lst2의 길이 | 22 | | list(set) | set을 list로 변환 후 반환 | O(N), N은 set의 길이 | 23 | | item in lst | lst에 K가 있는지 확인 한후, True 혹은 False 반환 | O(N) N은 lst의 길이 | 24 | 25 | ## 덱 26 | 덱은 내부적으로 이중 연결 리스트로 구현되어 있습니다. 양쪽 끝에서 추가 및 제거 작업이 매우 빠릅니다. 삽입/삭제 연산 모두 시간복잡도 O(1) 입니다. 하지만 리스트와 마찬가지로 중간에서 삽입/삭제는 느립니다. 인덱스를 활용해서 접근할 수는 있지만, 인덱스 접근 연산은 덱의 원소개수가 N개일때, 시간복잡도가 O(N)이므로 리스트에 비해 느립니다. 아래 표에서 deq는 덱 타입의 변수 입니다. 27 | 28 | | 메서드 | 동작 | 시간복잡도| 29 | | ---------- | ---------------------------------------------- |------------------------------ | 30 | | deq.append(item) | item을 deq의 오른쪽 끝에 추가 |O(1) | 31 | | deq.appendleft(item) | item을 deq의 왼쪽 끝에 추가 |O(1) | 32 | | deq.popleft() | deq의 오른쪽 끝에 있는 원소를 제거하고, 그 원소를 반환 |O(1) | 33 | | deq[K] | deq의 K번째 위치에 있는 원소를 반환 |O(N), N은 deq의 길이 | 34 | 35 | 36 | <작업중> 37 | -------------------------------------------------------------------------------- /errorcode/ReadMe.md: -------------------------------------------------------------------------------- 1 | # Error Code 설명 2 | 3 | | 파일 이름 | 설명 | 4 | |-----------|------| 5 | | [attribute_error.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/attribute_error.py) | 객체에 없는 속성이나 메서드를 호출하려고 할 때 발생하는 에러에 대한 예시입니다. | 6 | | [division_by_zero.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/division_by_zero.py) | 숫자를 0으로 나눌 때 발생하는 에러를 설명합니다. | 7 | | [function_argument_missing.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/function_argument_missing.py) | 함수 호출 시 필요한 인자가 누락되었을 때 발생하는 에러 예시입니다. | 8 | | [import_missing_module.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/import_missing_module.py) | 임포트하려는 모듈이 설치되지 않았거나 존재하지 않을 때 발생하는 에러를 보여줍니다. | 9 | | [indentation_error.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/indentation_error.py) | 코드에 들여쓰기 오류가 있을 때 나타나는 에러를 설명합니다. | 10 | | [index_out_of_range.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/index_out_of_range.py) | 리스트의 범위를 벗어나는 인덱스에 액세스하려고 할 때 발생하는 에러 예시입니다. | 11 | | [invalid_syntax.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/invalid_syntax.py) | 코드에 문법 오류가 있을 때 발생하는 에러를 설명합니다. | 12 | | [key_error.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/key_error.py) | 딕셔너리에서 존재하지 않는 키를 참조하려고 할 때 발생하는 에러에 대한 예시입니다. | 13 | | [missing_dict_key.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/missing_dict_key.py) | 사전에서 존재하지 않는 키를 사용하여 값을 검색하려고 할 때 발생하는 에러를 보여줍니다. | 14 | | [mutable_dict_key.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/mutable_dict_key.py) | 리스트와 같은 변경 가능한 객체를 딕셔너리의 키로 사용하려고 할 때 발생하는 에러를 설명합니다. | 15 | | [name_error.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/name_error.py) | 정의되지 않은 변수를 참조하려고 할 때 발생하는 에러에 대한 예시입니다. | 16 | | [pop-from-empty-list.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/pop-from-empty-list.py) | 빈 리스트에서 요소를 pop하려고 할 때 발생하는 에러를 설명합니다. | 17 | | [recursion_limit_exceed.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/recursion_limit_exceed.py) | 재귀 함수 호출이 너무 깊어져 Python의 최대 재귀 깊이 제한을 초과할 때 발생하는 에러를 보여줍니다. | 18 | | [string_number_addtion.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/string_number_addtion.py) | 문자열과 숫자는 서로 더할 수 없으며, 이렇게 시도할 때 발생하는 에러를 설명합니다. | 19 | | [type_error.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/type_error.py) | 두 개의 서로 다른 타입의 데이터를 연산하려고 할 때 발생하는 에러에 대한 예시입니다. | 20 | | [value_error.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/value_error.py) | 올바르지 않은 값이 주어졌을 때 발생하는 에러를 설명합니다. | 21 | | [value_error_in_list.py](https://github.com/dremdeveloper/codingtest_python/blob/main/errorcode/value_error_in_list.py) | 리스트에서 존재하지 않는 요소를 remove 메소드를 사용하여 삭제하려 할 때 발생하는 에러를 보여줍니다. | 22 | -------------------------------------------------------------------------------- /discord.md: -------------------------------------------------------------------------------- 1 | 2 | # Discord 음성채널 설명서 3 | 4 | ## 목차 5 | 1. 음성채널이란? 6 | 2. Discord 가입 및 설정 7 | 3. 음성채널에 접속하기 8 | 4. 음성채널에서 할 수 있는 일 9 | 5. **모각코란?** 10 | 6. 문제 해결 11 | 12 | --- 13 | 14 | 디스코드를 이미 어느정도 아시는 분은 **5. 모각코란**로 바로 가주시면 됩니다. 15 | 16 | ## 1. 음성채널이란? 17 | 18 | | 설명 | 19 | | --- | 20 | | 음성채널은 Discord에서 사용자들이 실시간으로 음성을 통해 소통할 수 있는 공간입니다. 텍스트 채팅과 달리, 음성채널에서는 마이크를 사용하여 대화를 나눌 수 있으며, 동시에 여러 사람이 참여할 수 있습니다. | 21 | 22 | ## 2. Discord 가입 및 설정 23 | 24 | 음성채널에 참석하려면 먼저 Discord에 가입해야 합니다. 아래의 테이블은 가입 및 설정에 필요한 단계를 설명합니다: 25 | 26 | | 단계 | 설명 | 27 | | --- | --- | 28 | | **1. Discord 가입** | [Discord 웹사이트](https://discord.com/)에 접속하여 무료로 계정을 생성합니다. 이메일 주소를 입력하고 비밀번호를 설정하면 가입이 완료됩니다. | 29 | | **2. 앱 다운로드 (선택 사항)** | Discord는 웹브라우저에서도 사용할 수 있지만, 데스크탑 또는 모바일 앱을 다운로드하여 사용하는 것이 더 편리할 수 있습니다.
- [Windows/Mac 다운로드](https://discord.com/download)
- [iOS/Android 앱스토어](https://discord.com/download)에서 다운로드 | 30 | | **3. 서버 참여** | 서버 초대 링크를 통해 원하는 서버에 참여합니다. 초대 링크를 클릭하면 자동으로 서버에 가입됩니다. | 31 | 32 | ## 3. 음성채널에 접속하기 33 | 34 | | 단계 | 설명 | 35 | | --- | --- | 36 | | **1. 채널 선택** | Discord 서버의 좌측 패널에서 원하는 음성채널을 클릭합니다. | 37 | | **2. 음성 연결** | 음성채널에 자동으로 연결되며, 마이크와 스피커를 통해 대화가 가능합니다. | 38 | | **3. 나가기** | 음성채널에서 나가려면 좌측 하단의 `전화 끊기` 아이콘을 클릭합니다. | 39 | 40 | 41 | 42 | 43 | 44 | ## 4. 음성채널에서 할 수 있는 일 45 | 46 | 음성채널에서 할 수 있는 주요 작업을 아래 테이블에서 설명합니다: 47 | 48 | | 작업 | 설명 | 49 | | --- | --- | 50 | | **마이크 음소거/해제** | 마이크 아이콘을 클릭하여 자신을 음소거하거나 음소거 해제할 수 있습니다. | 51 | | **사용자 볼륨 조절** | 채널 내 다른 사용자의 볼륨을 개별적으로 조정할 수 있습니다. | 52 | | **화면 공유** | 화면 아이콘을 클릭하여 자신의 화면을 공유할 수 있습니다.
- **화면 공유 시작**: 음성채널에 접속한 후, 하단의 `화면` 아이콘을 클릭합니다.
- **공유할 화면 선택**: 전체 화면 또는 특정 응용 프로그램 창을 선택하여 공유할 수 있습니다.
- **화면 공유 종료**: 화면 공유를 중지하려면 `화면 공유 중지` 버튼을 클릭합니다. | 53 | | **채팅으로 커뮤니케이션** | 음성채널에 있는 동안 텍스트 채팅을 통해서도 자유롭게 소통할 수 있습니다. | 54 | | **채널 간 이동** | 다른 음성채널로 손쉽게 이동할 수 있습니다. | 55 | 56 | 57 | ## 5. 모각코란? 58 | 59 | 모각코는 오후 10시 쯔음 사람들이 많이 모입니다. 60 | 61 | | 항목 | 설명 | 62 | | --- | --- | 63 | | **모각코 정의** | "모두 각자 코딩"의 약어로, Discord 음성채널에 모여 각자 공부하거나 코딩하는 활동을 말합니다. | 64 | | **모각코 참여 방법** | 음성채널에 접속하여 각자 공부나 코딩을 진행하면 됩니다. 혼자 공부하는 것보다 여러 사람과 함께 모여서 공부하면 더 집중할 수 있고, 동기부여가 될 수 있습니다. **모각코에 참여** 하려면 먼저 [디스코드 채널]([https://discord.gg/jUCqgExumm](https://discord.gg/MFgKD4NSAn)에 1회 가입 후, [모각코 음성 채널](https://discord.gg/4b4CFhd62C)에 입장해야 합니다. | 65 | | **화면 공유 선택** | 자신의 코딩 또는 공부 내용을 다른 사람들과 공유하고 싶다면, 화면 공유 기능을 사용할 수 있습니다. 하지만 화면 공유는 선택 사항이며, 강제는 아닙니다. | 66 | | **자유로운 소통** | 필요에 따라 텍스트 채팅이나 음성으로 다른 참여자와 소통할 수 있지만, 이 역시 자유롭게 선택할 수 있습니다. | 67 | | **목적** | 함께 모여서 각자 집중하는 시간을 가지는 것이 목적이므로, 부담 없이 참여할 수 있습니다. | 68 | 69 | **채널 입장 화면** 70 | ![image](https://github.com/user-attachments/assets/3c96aa0a-c02e-43f3-abcf-ddf42ca8a11d) 71 | 72 | 73 | **영상 공유 화면(필수 아님)** 74 | ![image](https://github.com/user-attachments/assets/3c3c2d0d-ad5f-4668-8f2c-b1a1d291d7da) 75 | 76 | 77 | 78 | ## 6. 문제 해결 79 | 80 | | 문제 | 해결 방법 | 81 | | --- | --- | 82 | | **마이크 작동 안 함** | 마이크 설정이 올바르게 되어 있는지 확인하고, Discord의 음성 설정에서 마이크 입력 장치를 확인하세요. | 83 | | **소리가 들리지 않음** | 스피커 또는 헤드폰 연결을 확인하고, Discord 음성 설정에서 출력 장치를 확인하세요. | 84 | | **지연/끊김 현상** | 인터넷 연결 상태를 확인하고, Discord 서버의 위치를 변경하여 해결할 수 있습니다. | 85 | | **권한 문제** | 서버 관리자에게 문의하여 적절한 권한을 부여받으세요. | 86 | 87 | --- 88 | 89 | 이 설명서가 Discord 음성채널과 모각코 활동에 도움이 되길 바랍니다. 궁금한 점이 있으면 언제든지 질문하세요! 90 | -------------------------------------------------------------------------------- /solution/48.py: -------------------------------------------------------------------------------- 1 | def solution(board): 2 | def is_valid(num, row, col): 3 | # ❶ 현재 위치에 num이 들어갈 수 있는지 검사 4 | return not (in_row(num, row) or in_col(num, col) or in_box(num, row, col)) 5 | 6 | def in_row(num, row): 7 | # ❷ 해당 행에 num이 있는지 확인 8 | return num in board[row] 9 | 10 | def in_col(num, col): 11 | # ❸ 해당 열에 num이 있는지 확인하는 함수 12 | return num in (board[i][col] for i in range(9)) 13 | 14 | def in_box(num, row, col): 15 | # ❹ 현재 위치의 3x3 박스에 num이 있는지 확인 16 | box_row = (row // 3) * 3 17 | box_col = (col // 3) * 3 18 | for i in range(box_row, box_row + 3): 19 | for j in range(box_col, box_col + 3): 20 | if board[i][j] == num: 21 | return True 22 | return False 23 | 24 | def find_empty_position(): 25 | # ❺ 스도쿠 보드에서 비어 있는 위치 반환 26 | for i in range(9): 27 | for j in range(9): 28 | if board[i][j] == 0: 29 | return i, j 30 | return None 31 | 32 | def find_solution(): 33 | # ❻ 비어 있는 위치에 가능한 숫자를 넣어가며 스도쿠 해결 34 | empty_pos = find_empty_position() 35 | # ❼ 빈 칸이 없으면 스도쿠가 해결된 것으로 간주 36 | if not empty_pos: 37 | return True 38 | row, col = empty_pos 39 | for num in range(1, 10): 40 | if is_valid(num, row, col): 41 | board[row][col] = num 42 | if find_solution(): # ❽ 다음 빈 칸으로 재귀적으로 탐색 43 | return True 44 | board[row][col] = 0 # ❾ 가능한 숫자가 없으면 원래의 0으로 되돌림 45 | return False 46 | 47 | find_solution() 48 | return board 49 | 50 | 51 | # TEST 코드 입니다. 주석을 풀고 실행시켜보세요 52 | ''' 53 | print(solution( 54 | [ 55 | [5, 3, 0, 0, 7, 0, 0, 0, 0], 56 | [6, 0, 0, 1, 9, 5, 0, 0, 0], 57 | [0, 9, 8, 0, 0, 0, 0, 6, 0], 58 | [8, 0, 0, 0, 6, 0, 0, 0, 3], 59 | [4, 0, 0, 8, 0, 3, 0, 0, 1], 60 | [7, 0, 0, 0, 2, 0, 0, 0, 6], 61 | [0, 6, 0, 0, 0, 0, 2, 8, 0], 62 | [0, 0, 0, 4, 1, 9, 0, 0, 5], 63 | [0, 0, 0, 0, 8, 0, 0, 7, 9], 64 | ]) 65 | ) 66 | ''' 67 | 68 | ''' 69 | 반환값 : 70 | [ 71 | [5, 3, 4, 6, 7, 8, 9, 1, 2], 72 | [6, 7, 2, 1, 9, 5, 3, 4, 8], 73 | [1, 9, 8, 3, 4, 2, 5, 6, 7], 74 | [8, 5, 9, 7, 6, 1, 4, 2, 3], 75 | [4, 2, 6, 8, 5, 3, 7, 9, 1], 76 | [7, 1, 3, 9, 2, 4, 8, 5, 6], 77 | [9, 6, 1, 5, 3, 7, 2, 8, 4], 78 | [2, 8, 7, 4, 1, 9, 6, 3, 5], 79 | [3, 4, 5, 2, 8, 6, 1, 7, 9], 80 | ] 81 | ''' 82 | 83 | 84 | ''' 85 | print(solution( 86 | [ 87 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 88 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 89 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 90 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 91 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 92 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 93 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 94 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 95 | [0, 0, 0, 0, 0, 0, 0, 0, 0], 96 | ]) 97 | ) 98 | ''' 99 | 100 | 101 | ''' 102 | 반환값 : 103 | [ 104 | [1, 2, 3, 4, 5, 6, 7, 8, 9], 105 | [4, 5, 6, 7, 8, 9, 1, 2, 3], 106 | [7, 8, 9, 1, 2, 3, 4, 5, 6], 107 | [2, 3, 4, 5, 6, 7, 8, 9, 1], 108 | [5, 6, 7, 8, 9, 1, 2, 3, 4], 109 | [8, 9, 1, 2, 3, 4, 5, 6, 7], 110 | [3, 4, 5, 6, 7, 8, 9, 1, 2], 111 | [6, 7, 8, 9, 1, 2, 3, 4, 5], 112 | [9, 1, 2, 3, 4, 5, 6, 7, 8], 113 | ] 114 | ''' 115 | 116 | 117 | 118 | 119 | 120 | --------------------------------------------------------------------------------