2024-10-27 21:00:00 (5문제)
2024-10-13 21:00:00 (5문제)
양과 늑대
코드 제출 (4등) 문제 바로가기이현석
2024-10-20 12:08:39이 코드는 DFS 알고리즘을 사용하여 트리 구조에서 최대 양의 수를 찾는다. 각 노드는 양 또는 늑대를 나타내며, 늑대 수가 양 수 이상이 되면 탐색을 중단한다. 자식 노드들을 리스트로 저장하고, 현재 노드에서 갈 수 있는 모든 경로를 탐색한다. 재귀적으로 DFS를 수행하며 각 경로에서 얻을 수 있는 최대 양의 수를 계산한다. 마지막으로 가능한 모든 경로 중 최대 양의 수를 반환한다. 개선 방안: 1. 메모이제이션 도입: (current, sheep, wolf) 상태 캐싱으로 중복 계산 방지 2. 비트마스킹 사용: next_steps를 집합 대신 비트마스크로 표현하여 메모리 및 연산 최적화 3. 늑대/양 수 미리 계산: DFS 전에 각 서브트리의 늑대/양 수를 계산하여 가지치기 효율 향상 4. 반복적 DFS: 재귀 대신 스택 사용으로 콜 스택 오버플로우 방지 및 성능 개선 5. 휴리스틱 도입: 양이 많은 경로를 우선 탐색하여 최적해를 빠르게 찾을 가능성 증가
def solution(animal, paths): children = [[] for _ in range(len(animal))] for parent, child in paths: children[parent].append(child) def dfs(current, sheep, wolf, next_steps): if animal[current] == 0: sheep += 1 else: wolf += 1 if wolf >= sheep: return sheep new_steps = next_steps + children[current] new_steps.remove(current) max_sheep = sheep for step in new_steps: max_sheep = max(max_sheep, dfs(step, sheep, wolf, new_steps)) return max_sheep return dfs(0, 0, 0, [0])주병규
2024-10-13 14:30:17이 코드는 트리 구조를 탐색하며 최대 양의 수를 찾는 BFS 알고리즘을 사용합니다. 트리를 구성하고 큐를 이용해 노드를 탐색합니다. 각 노드에서 양과 늑대의 수를 갱신하고, 늑대가 양보다 많아지면 해당 경로를 중단합니다. 방문한 노드는 표시하고, 최대 양의 수를 지속적으로 갱신합니다. 루트 노드로 돌아가는 경우도 고려하여 최적의 결과를 찾습니다. 개선 가능한 부분: 1. 집합(set)을 사용하여 방문 가능한 노드를 추적하면 더 효율적일 수 있습니다. 리스트 복사 대신 집합 연산으로 시간 복잡도 개선 가능. 2. 비트마스킹을 활용하여 상태를 표현하면 메모리 사용량과 연산 속도를 개선할 수 있습니다. 비트 연산이 리스트 조작보다 빠름. 3. DFS로 알고리즘을 변경하면 스택 메모리를 활용해 더 효율적일 수 있습니다. 재귀 호출로 구현 시 코드가 간결해지고 실행 속도 향상 가능. 4. 가지치기(pruning)를 더 적극적으로 수행하여 불필요한 탐색을 줄일 수 있습니다. 현재 최대값을 넘을 수 없는 경로는 조기에 중단. 5. 동적 프로그래밍을 적용하여 중복 계산을 줄일 수 있습니다. 이미 계산한 상태를 메모이제이션하여 재사용 가능.
from collections import deque def solution(info, edges): n = len(info) tree = [[] for _ in range(n)] for parent, child in edges: tree[parent].append(child) queue = deque([(0, 0, 0, info[:])]) answer = 1 while queue: node, sheep, wolf, infoCopy = queue.pop() value = infoCopy[node] infoCopy[node] = 2 if value == 1: wolf += 1 elif value == 0: sheep += 1 queue.append((0,sheep,wolf,infoCopy[:])) if wolf >= sheep: continue if answer < sheep: answer = sheep for child in tree[node]: queue.append((child, sheep, wolf, infoCopy[:])) return answer배수훈
2024-10-08 09:40:32이 코드는 DFS와 백트래킹을 사용하여 트리 구조에서 양과 늑대의 최대 수를 찾는 알고리즘입니다. 방문 여부를 추적하고, 양의 수가 늑대보다 많을 때만 탐색을 계속합니다. 각 노드를 방문할 때마다 양이나 늑대의 수를 증가시키고, 모든 가능한 경로를 탐색합니다. 결과는 set에 저장되며, 최종적으로 최대값을 반환합니다. 이 방식은 모든 가능한 경우를 고려하여 정확한 결과를 얻습니다. 개선 방안: 1. set 대신 단일 변수로 최대값 추적 (메모리 사용 감소, 약간의 속도 향상) 2. 불필요한 재귀 호출 제거 (늑대가 더 많아지는 경우 즉시 반환) 3. 엣지 리스트를 인접 리스트로 변환 (검색 속도 향상) 4. 양의 최대 수에 도달하면 조기 종료 (불필요한 탐색 방지) 5. 비트마스킹을 사용하여 방문 상태 관리 (메모리 사용 감소, 연산 속도 향상)
def solution(info, edges): result = set() visit = [False for _ in info] def dfs(sheeps, wolfs): if sheeps > wolfs: result.add(sheeps) else: return for s, e in edges: if visit[s] and not visit[e]: visit[e] = True if info[e] == 0: dfs(sheeps + 1, wolfs) else: dfs(sheeps, wolfs + 1) visit[e] = False visit[0] = True dfs(1, 0) return max(result)사라지는 발판
코드 제출 (2등) 문제 바로가기주병규
2024-10-13 14:31:23이 코드는 BFS와 재귀를 사용한 백트래킹 알고리즘을 구현했습니다. 두 플레이어의 이동을 시뮬레이션하며 모든 가능한 경로를 탐색합니다. get_next_positions 함수로 다음 이동 가능 위치를 찾고, search 함수에서 재귀적으로 게임을 진행합니다. 각 턴마다 이동 후 보드 상태를 변경하고 백트래킹합니다. 승리 조건을 확인하고 최적의 이동 횟수를 계산합니다. solution 함수에서 최종 결과를 반환합니다. 개선 방안: 1. 메모이제이션 도입: (aloc, bloc, turn) 상태를 캐시하여 중복 계산 방지 2. 비트마스킹으로 보드 상태 표현: 메모리 사용량 감소 및 연산 속도 향상 3. 알파-베타 가지치기 적용: 불필요한 탐색 줄여 실행 시간 단축 4. 반복적 깊이 증가(IDA*) 알고리즘 사용: 메모리 효율성 개선 및 최적해 빠르게 탐색 5. 휴리스틱 함수 도입: 탐색 순서 최적화로 실행 시간 단축
from collections import deque # 현재 위치에서 다음으로 이동할 수 있는 위치들을 반환하는 함수 def get_next_positions(board, loc): dRow, dCol = [0, 0, 1, -1], [1, -1, 0, 0] next_positions = [] for d in range(4): nr, nc = loc[0] + dRow[d], loc[1] + dCol[d] if nr < 0 or nc < 0 or nr >= len(board) or nc >= len(board[0]): continue elif board[nr][nc] == 0: continue next_positions.append((nr, nc)) return next_positions # 재귀적으로 게임을 탐색하여 승리/패배 여부와 이동 횟수를 계산하는 함수 def search(board, aloc, bloc, turn): if turn % 2 == 0: # A의 턴 next_positions = get_next_positions(board, aloc) else: # B의 턴 next_positions = get_next_positions(board, bloc) # 현재 턴의 캐릭터가 더 이상 이동할 수 없으면 상대가 승리함 if not next_positions: return turn % 2 != 0, turn # (A가 승리하면 True, B가 승리하면 False), 현재까지의 이동 횟수 반환 # A와 B가 같은 위치에 있으면 현재 턴의 캐릭터가 승리함 if aloc == bloc: return turn % 2 == 0, turn + 1 win, lose = [], [] if turn % 2 == 0: # A의 턴 board[aloc[0]][aloc[1]] = 0 # A가 이동한 위치를 0으로 처리 for nr, nc in next_positions: is_a_win, cnt = search(board, [nr, nc], bloc, turn + 1) if is_a_win: win.append(cnt) # A가 이기는 경우 else: lose.append(cnt) # A가 지는 경우 board[aloc[0]][aloc[1]] = 1 # 백트래킹을 위해 위치 복구 else: # B의 턴 board[bloc[0]][bloc[1]] = 0 # B가 이동한 위치를 0으로 처리 for nr, nc in next_positions: is_a_win, cnt = search(board, aloc, [nr, nc], turn + 1) if not is_a_win: win.append(cnt) # B가 이기는 경우 else: lose.append(cnt) # B가 지는 경우 board[bloc[0]][bloc[1]] = 1 # 백트래킹을 위해 위치 복구 # 승리하는 경우가 있으면 가장 빨리 승리할 수 있는 경로를 선택 if win: return turn % 2 == 0, min(win) # 승리하는 사람과 그 중 가장 빠른 승리 else: # 패배할 수밖에 없다면 최대한 오래 버팀 return turn % 2 != 0, max(lose) # 패배하는 가장 긴 경로 반환 # 최종적으로 승리/패배 여부와 이동 횟수 반환 def solution(board, aloc, bloc): winner, answer = search(board, aloc, bloc, 0) return answer외톨이 알파벳
코드 제출 (4등) 문제 바로가기이현석
2024-10-19 18:09:01이 코드는 문자열 처리 알고리즘을 사용하여 '외로운 문자'를 찾습니다. 입력 문자열을 순회하며 이전 문자와 다르고 이미 본 문자를 'lonely' 집합에 추가합니다. 'seen' 집합으로 이미 본 문자를 기록합니다. 마지막으로 'lonely' 집합을 정렬하여 결과를 반환합니다. 시간 복잡도는 O(n log n)입니다. 개선 사항: 1. 정렬 대신 우선순위 큐 사용: 더 빠른 삽입 및 추출 가능 2. 문자열 대신 리스트 사용: 문자열 연산이 느림 3. 집합 대신 배열 사용: 알파벳만 처리한다면 더 빠름 4. 미리 할당된 배열로 'seen' 대체: 메모리 접근 속도 향상 5. 입력이 크다면 병렬 처리 고려: 대규모 입력 처리 속도 향상
def solution(input_string): lonely = set() prev = '' seen = set() for i in range(len(input_string)): if input_string[i] != prev and input_string[i] in seen: lonely.add(input_string[i]) seen.add(input_string[i]) prev = input_string[i] answer = ''.join(sorted(lonely)) return answer if answer else "N"주병규
2024-10-13 14:30:44이 코드는 문자열에서 고립된 문자를 찾는 알고리즘을 구현합니다. 입력 문자열을 순회하며 연속되지 않은 문자를 식별합니다. 두 개의 집합(set)을 사용하여 문자를 추적합니다. 마지막 문자를 별도로 처리합니다. 정렬된 고립 문자들을 결과로 반환합니다. 빈 결과일 경우 "N"을 반환합니다. 개선 가능한 점: 1. Counter 클래스 사용으로 코드 간소화 가능 (이유: 더 pythonic하고 가독성 향상) 2. 문자열 대신 리스트 사용으로 성능 향상 (이유: 문자열 연산은 비용이 큼) 3. 정렬 대신 우선순위 큐 사용 고려 (이유: 대규모 데이터에서 더 효율적) 4. 입력 문자열 길이가 1인 경우 조기 반환 (이유: 불필요한 처리 방지) 5. 집합 대신 비트마스크 사용 고려 (이유: 메모리 사용량 감소 및 연산 속도 향상)
def solution(input_string): answer = '' alphabetSet = set() aloneSet = set() before = input_string[0] for idx in range(1, len(input_string)): if before != input_string[idx]: if before in alphabetSet: aloneSet.add(before) else: alphabetSet.add(before) before = input_string[idx] if before in alphabetSet: aloneSet.add(before) else: alphabetSet.add(before) answer = "".join(sorted(list(aloneSet))) return answer if len(answer)>0 else "N"배수훈
2024-10-08 11:00:58이 코드는 문자열 처리와 해시맵을 사용하는 알고리즘입니다. 입력 문자열을 순회하며 연속된 문자 그룹을 찾습니다. defaultdict를 사용하여 각 문자의 그룹 등장 횟수를 세고, 2회 이상 등장한 문자를 결과에 포함시킵니다. 결과를 정렬하고 문자열로 반환합니다. 빈 결과일 경우 'N'을 반환합니다. 개선 방안: 1. 문자열 순회를 한 번만 하도록 최적화 (현재 코드는 두 번 순회). 이유: 시간 복잡도 개선 2. 정렬 대신 우선순위 큐 사용. 이유: 더 빠른 삽입 및 정렬 가능 3. join 대신 리스트 컴프리헨션으로 문자열 생성. 이유: 메모리 사용 감소 4. 입력이 ASCII 문자로 제한된다면 defaultdict 대신 길이 128의 리스트 사용. 이유: 해시 연산 제거로 속도 향상 5. groupby 함수 활용하여 코드 간소화. 이유: 가독성 향상 및 내장 함수의 최적화 이점
from collections import defaultdict def solution(input_string): instr = input_string acnt = defaultdict(int) p = 0 ch = instr[p] cnt = 0 while p < len(instr): if instr[p] == ch: cnt += 1 p += 1 continue acnt[ch] += 1 ch = instr[p] p += 1 cnt = 1 acnt[ch] += 1 result = [] for ch in acnt: if acnt[ch] > 1: result.append(ch) result.sort() result = "".join(result) return 'N' if len(result) == 0 else result체육대회
코드 제출 (4등) 문제 바로가기이현석
2024-10-19 21:38:471. 완전 탐색 알고리즘을 사용하여 모든 가능한 학생 배치를 확인합니다. 2. itertools의 permutations 함수로 학생 인덱스의 순열을 생성합니다. 3. 각 순열에 대해 학생들의 능력 합계를 계산합니다. 4. 최대 합계를 갱신하며 모든 경우의 수를 탐색합니다. 5. 최종적으로 가장 높은 합계를 반환합니다. 6. 시간 복잡도는 O(n! * m)으로, n은 학생 수, m은 종목 수입니다. 7. 완전 탐색 방식으로 모든 경우의 수를 고려하여 정확한 결과를 얻습니다. 개선 사항: 1. DP를 활용하여 중복 계산을 줄일 수 있습니다. 부분 문제의 결과를 저장하고 재사용하면 시간을 단축할 수 있습니다. 2. 그리디 알고리즘을 적용하여 각 종목마다 가장 능력이 높은 학생을 선택하는 방식으로 근사해를 빠르게 구할 수 있습니다. 3. 비트마스킹을 사용하여 학생 선택 상태를 효율적으로 관리하고 중복을 제거할 수 있습니다. 4. 휴리스틱 알고리즘을 도입하여 모든 경우를 탐색하지 않고 최적해에 가까운 결과를 빠르게 찾을 수 있습니다. 5. 병렬 처리를 통해 여러 순열을 동시에 계산하여 실행 시간을 단축할 수 있습니다.
from itertools import permutations def solution(ability): max_sum = 0 for perm in permutations(range(len(ability)), len(ability[0])): sum_value = 0 for event, student in enumerate(perm): sum_value += ability[student][event] max_sum = max(max_sum, sum_value) return max_sum주병규
2024-10-13 14:31:41이 코드는 BFS 알고리즘을 사용하여 최적의 인원 배치를 찾습니다. 큐를 사용하여 모든 가능한 조합을 탐색합니다. 각 단계에서 이벤트와 사람을 매칭시키고, 능력치를 누적합니다. 모든 이벤트가 끝나면 최대 능력치를 갱신합니다. 마지막으로 최대 능력치를 반환합니다. 개선 방안: 1. 비트마스킹으로 사람 선택 상태 표현 (메모리 효율성 증가) 2. 힙큐 사용하여 유망한 경로 먼저 탐색 (pruning 효과) 3. DP로 접근하여 중복 계산 제거 (시간 복잡도 개선) 4. 그리디 알고리즘으로 근사해 빠르게 구하기 (대규모 데이터셋에 유용) 5. 병렬 처리로 탐색 속도 향상 (멀티코어 활용)
from collections import deque def solution(ability): answer = 0 queue = deque([(0,0,[0]*len(ability))]) eventLen = len(ability[0]) peopleLen = len(ability) while queue: idx, cnt, people = queue.pop() if eventLen == idx: answer = max(answer,cnt) continue for i in range(peopleLen): if people[i] == 0 : queue.append((idx+1,cnt+ability[i][idx],people[:i]+[1]+people[i+1:])) return answer배수훈
2024-10-08 11:24:32이 코드는 백트래킹 알고리즘을 사용하여 최적의 능력 배치를 찾습니다. 깊이 우선 탐색(DFS)을 통해 모든 가능한 조합을 탐색합니다. 재귀 함수를 사용하여 각 종목에 선수를 배정합니다. 전역 변수 result를 사용하여 최대 점수를 추적합니다. use 배열로 선수의 사용 여부를 관리합니다. 모든 종목에 선수가 배정되면 현재 점수와 최대 점수를 비교하여 갱신합니다. 개선 방안: 1. 전역 변수 대신 nonlocal 키워드 사용: 함수 범위 내에서 변수 관리가 더 효율적입니다. 2. 비트마스킹으로 선수 사용 여부 관리: 메모리 사용량 감소 및 연산 속도 향상을 기대할 수 있습니다. 3. 가지치기(Pruning) 추가: 현재까지의 점수가 이미 최대 점수보다 작으면 탐색 중단하여 불필요한 연산을 줄일 수 있습니다. 4. 동적 계획법(DP) 적용: 중복 계산을 피하고 시간 복잡도를 개선할 수 있습니다. 5. 그리디 알고리즘으로 접근: 각 종목별로 최고 점수를 가진 선수를 선택하는 방식으로 근사해를 빠르게 구할 수 있습니다.
result = 0 def solution(ability): n = len(ability) m = len(ability[0]) use = [-1 for _ in range(n)] def find(depth, cur): global result if depth == m: result = max(result, cur) return for i, s in enumerate(ability): if use[i] >= 0: continue use[i] = depth find(depth + 1, cur + s[depth]) use[i] = -1 find(0, 0) return result유전법칙
코드 제출 (3등) 문제 바로가기주병규
2024-10-13 14:31:55이 코드는 유전적 특성을 시뮬레이션하는 알고리즘을 구현했습니다. 쿼리별로 세대와 번호를 입력받아 유전형질을 결정합니다. 4진법 변환을 이용해 부모로부터 자식으로의 유전 경로를 추적합니다. 재귀 대신 반복문을 사용해 깊이를 계산합니다. 경로를 역순으로 탐색하여 최종 유전형질을 결정합니다. 마지막으로 모든 쿼리 결과를 리스트로 반환합니다. 개선 방안: 1. 캐싱 도입: 중복 계산 방지 (메모이제이션) 2. 비트 연산 활용: 4진법 계산 최적화 3. 리스트 컴프리헨션: 코드 간소화 및 속도 향상 4. 입력 유효성 검사: 예외 처리로 안정성 향상 5. 상수 시간 알고리즘 고려: 패턴 분석으로 O(1) 접근 가능성 검토
def solution(queries): answer = [] def find(depth,number): path = [] depthCnt = depth while depthCnt>1: depthCnt-=1 path.append(number%4) number = number//4 for num in reversed(path): if num == 0: return "RR" elif num ==3: return "rr" return "Rr" for query in queries: generation,number = query answer.append(find(generation,number-1)) # re = [] # for query in [[4,i] for i in range(1,65)]: # generation,number = query # re.append(find(generation,number-1)) return answer배수훈
2024-10-08 14:19:59이 코드는 재귀적 접근법을 사용하여 유전자 패턴을 결정합니다. 주요 알고리즘은 재귀와 분할 정복입니다. 각 세대에서 부모의 유전자를 찾아 자식의 유전자를 결정합니다. 'Rr' 유전자를 가진 부모의 경우, 자식의 유전자는 미리 정의된 패턴에 따라 결정됩니다. 재귀 호출을 통해 1세대까지 거슬러 올라가 유전자를 결정합니다. 결과적으로 주어진 쿼리에 대한 유전자 패턴을 리스트로 반환합니다. 개선 방안: 1. 메모이제이션 도입: 중복 계산 방지, 시간 복잡도 개선 2. 반복문으로 변경: 재귀 대신 반복문 사용, 스택 오버플로우 방지 및 성능 향상 3. 비트 연산 활용: 유전자 표현을 비트로 변환하여 연산 속도 향상 4. 룩업 테이블 사용: 자주 사용되는 결과를 미리 계산하여 저장, 접근 시간 단축 5. 병렬 처리 고려: 여러 쿼리를 동시에 처리하여 전체 실행 시간 단축
case = ('RR','Rr','Rr','rr') def get_gene(pose): n, p = pose if n == 1: return 'Rr' mother_gene = get_gene((n - 1, (p - 1) // 4 + 1)) result = "" if mother_gene == 'Rr': result = case[p % 4 - 1] else: result = mother_gene return result def solution(queries): return [get_gene(q) for q in queries]
2024-10-06 21:00:00 (7문제)
신고 결과 받기
코드 제출 (5등) 문제 바로가기주병규
2024-10-06 21:02:04이 코드는 딕셔너리와 집합을 사용하는 해시 기반 알고리즘을 구현했습니다. 신고 내역을 처리하고 신고 횟수를 계산하여 결과를 반환합니다. 시간 복잡도는 O(N)이며, N은 report의 길이입니다. 개선 가능한 부분: 1. Counter 사용: collections.Counter로 신고 횟수를 더 효율적으로 계산 가능 (이유: 내장 함수가 최적화되어 있음) 2. defaultdict 활용: 초기화 로직 간소화 가능 (이유: 키 존재 여부 확인 불필요) 3. list comprehension 사용: 마지막 루프를 간결하게 작성 가능 (이유: 파이썬 내부적으로 최적화됨) 4. set으로 report 중복 제거: 입력 데이터 전처리로 중복 보고 제거 (이유: 불필요한 처리 감소) 5. generator 표현식 사용: 메모리 사용량 감소 가능 (이유: 대용량 데이터 처리 시 유리)
def solution(id_list, report, k): reportDic = {} for reGet in report: sender, getter = reGet.split() if getter not in reportDic: reportDic[getter] = set() reportDic[getter].add(sender) senderDic={} for name in id_list: senderDic[name]=0 answer = [] for reported in reportDic: senders = list(reportDic[reported]) if len(senders)>=k: for sender in senders: senderDic[sender] +=1 for sender in senderDic: answer.append(senderDic[sender]) return answer이현석
2024-10-06 06:21:48이 코드는 해시맵과 집합을 사용하여 신고 시스템을 구현합니다. 중복 신고를 제거하고, 사용자별 신고자 목록을 만듭니다. 정지된 사용자를 찾고, 신고자에게 보낼 메일 수를 계산합니다. 최종적으로 각 사용자가 받을 메일 수를 반환합니다. 개선 사항: 1. 리스트 컴프리헨션 대신 제너레이터 표현식 사용 (메모리 효율) 2. banned 리스트 대신 set 사용 (검색 속도 향상) 3. mail_count를 defaultdict로 변경 (키 존재 여부 확인 불필요) 4. 반복문 최적화: 한 번의 순회로 banned와 mail_count 계산 5. 입력 크기가 작다면 numpy 사용 고려 (벡터화 연산으로 속도 향상)
def solution(id_list, report, k): report = set(report) reports = {user: [] for user in id_list} for r in report: a, b = r.split() reports[b].append(a) banned = [user for user in id_list if len(reports[user]) >= k] mail_count = {user: 0 for user in id_list} for user in banned: for reporter in reports[user]: mail_count[reporter] += 1 return [mail_count[user] for user in id_list]이석민
2024-10-06 06:13:39이 코드는 해시 테이블(딕셔너리)과 집합을 사용하여 신고 시스템을 구현합니다. 주요 단계는 다음과 같습니다: 1. 신고 데이터를 파싱하고 중복 제거 2. 사용자별 신고한 목록과 신고받은 목록 생성 3. 정지 기준을 충족하는 사용자 식별 4. 각 사용자가 신고한 정지된 사용자 수 계산 개선 사항: 1. 튜플 대신 리스트 컴프리헨션 사용 (메모리 효율) 2. dict.setdefault() 메서드로 코드 간소화 (가독성 향상) 3. any() 함수로 필터링 최적화 (성능 향상) 4. 불필요한 변수 제거 및 인라인 처리 (메모리 사용 감소) 5. Counter 클래스 활용하여 카운팅 간소화 (코드 간결성)
def solution(id_list, report, k): report = tuple(map(lambda s: s.split(), report)) # ((from, to),) report_user = dict() report_table = dict() for (f, t) in report: if f not in report_table: report_table[f] = set() if t not in report_user: report_user[t] = set() if t in report_table[f]: continue report_table[f].add(t) report_user[t].add(f) ban_users = tuple(map(lambda v: v[0], filter(lambda v: len(v[1]) >= k , report_user.items()))) answer = list() for uid in id_list: if uid not in report_table.keys(): answer.append(0) continue answer.append(len(tuple(filter(lambda t: t in ban_users, report_table[uid])))) return answer배수훈
2024-10-04 00:34:56요약: 1. 해시맵을 사용한 카운팅 알고리즘 2. 사용자별 신고 목록과 신고 횟수를 기록 3. 중복 신고를 제거하고 유효한 신고만 카운트 4. 정지 기준(k)을 넘은 사용자를 확인 5. 각 사용자가 받을 처리 결과 메일 수를 계산 6. 입력 순서대로 결과를 반환 7. 시간 복잡도: O(N), 여기서 N은 report의 길이 개선 가능성: 1. set 대신 frozenset 사용: 불변성으로 약간의 성능 향상 가능 2. list comprehension 대신 제너레이터 표현식 사용: 메모리 사용 감소 3. 입력 검증 추가: 잘못된 입력 처리로 안정성 향상 4. defaultdict 대신 일반 dict와 get() 메서드 사용: 약간의 성능 향상 5. 병렬 처리 고려: 대용량 데이터 처리 시 처리 속도 향상 가능
from collections import defaultdict def solution(id_list, report, k): user_report = defaultdict(set) report_cnt = defaultdict(int) for r_str in report: id, r_id = r_str.split(" ") if r_id not in user_report[id]: user_report[id].add(r_id) report_cnt[r_id] += 1 result = defaultdict(int) for id in id_list: for r_id in user_report[id]: if report_cnt[r_id] >= k: result[id] += 1 return [result[id] for id in id_list]k진수에서 소수 개수 구하기
코드 제출 (5등) 문제 바로가기주병규
2024-10-06 21:02:16이 코드는 진법 변환과 소수 판별을 사용하는 알고리즘입니다. 주어진 숫자를 k진법으로 변환한 후, 0을 기준으로 분리하여 소수를 찾습니다. 정규표현식으로 0을 제거하고, 에라토스테네스의 체 원리를 이용해 소수를 판별합니다. 스택이나 큐는 사용되지 않았으며, 간단한 반복문과 조건문으로 구현되었습니다. 소수 판별 함수는 제곱근까지만 확인하여 효율성을 높였습니다. 개선 가능한 점: 1. 정규표현식 대신 문자열 분할 사용 (더 빠름, re 모듈 임포트 불필요) 2. 소수 판별 시 2와 3의 배수 먼저 확인 (불필요한 반복 줄임) 3. 에라토스테네스의 체 구현으로 소수 판별 최적화 (여러 수 판별 시 효율적) 4. 진법 변환 시 문자열 연산 대신 리스트 사용 후 join (대규모 입력 시 효율적) 5. 소수 캐싱으로 중복 계산 방지 (메모리 사용량 증가, 실행 시간 감소)
import re def solution(n, k): answer = 0 num = "" while n > 0: num = str(n % k) + num n = n // k numList = [] for value in re.split(r"0+", num): if value != "1" and value != "": numList.append(int(value)) def isPrim(num): for i in range(2, int(num**0.5) + 1): if num%i == 0 : return False return True for num in numList: if isPrim(num): answer += 1 return answer이현석
2024-10-06 11:05:50이 코드는 주어진 숫자를 k진수로 변환한 후 소수를 찾는 알고리즘을 구현합니다. 에라토스테네스의 체와 유사한 방식으로 소수를 판별합니다. 변환된 수를 '0'을 기준으로 분할하여 각 부분을 정수로 변환합니다. 각 정수에 대해 소수 여부를 확인하고 소수의 개수를 세어 반환합니다. 이 알고리즘은 브루트포스 방식으로 소수를 판별하며, 문자열 처리와 정수 변환을 사용합니다. 개선 사항: 1. numpy 대신 내장 함수 사용 (문제 규칙 위반) 2. is_prime 함수에서 6k±1 최적화 적용 (소수 판별 속도 향상) 3. 에라토스테네스의 체 알고리즘 사용 (대량의 소수 판별 시 효율적) 4. 문자열 분할 대신 정수 연산으로 구현 (메모리 사용 감소) 5. 캐싱을 통한 반복 계산 방지 (중복 소수 판별 회피)
import numpy as np def is_prime(num): if num < 2: return False for i in range(2, int(num**0.5)+1): if num % i == 0: return False return True def solution(n, k): converted = np.base_repr(n, base=k) numbers = converted.split('0') count = 0 for num_str in numbers: if num_str == '': continue num = int(num_str) if is_prime(num): count += 1 return count이석민
2024-10-06 06:36:06이 코드는 에라토스테네스의 체와 기수 변환을 사용하는 알고리즘입니다. 주어진 수를 k진법으로 변환한 후, 0으로 구분된 부분 문자열들 중 소수의 개수를 세는 방식입니다. 에라토스테네스의 체를 통해 소수 판별을 최적화했습니다. 전역 변수를 사용해 에라토스테네스의 체를 한 번만 생성합니다. 기수 변환은 나머지 연산을 이용해 구현했습니다. 마지막으로, 변환된 수를 0으로 split하여 각 부분이 소수인지 확인합니다. 개선 가능한 부분: 1. 에라토스테네스의 체 대신 밀러-라빈 소수 판별법 사용 (큰 수 처리에 효과적) 2. 문자열 대신 정수 배열로 처리하여 메모리 사용 줄이기 (큰 수 처리 시 유리) 3. radix 함수에서 join 대신 문자열 직접 구성 (미세한 속도 향상) 4. is_prime 함수에서 작은 소수들에 대해 직접 체크 (초기 판별 속도 향상) 5. eratos 배열을 비트 배열로 구현하여 메모리 사용량 줄이기 (대규모 데이터 처리 시 유리)
def radix(n, k): result = [] while n > 0: n, m = divmod(n, k) result.append(m) return ''.join(map(str, result[::-1])) eratos = None def is_prime(n, max_stop): if n <= 1: return False global eratos if eratos is None: eratos = [False] * max_stop for i in range(2, max_stop): if eratos[i]: continue pos = i + i while pos < max_stop: eratos[pos] = True pos += i return eratos[n] is not True def solution(n, k): n = radix(n, k) stop = int(10_000_000) cnt = 0 for v in n.split('0'): if len(v) == 0: continue if is_prime(int(v), stop): cnt += 1 return cnt배수훈
2024-10-04 01:11:37이 코드는 진법 변환과 소수 판별을 사용하는 알고리즘을 구현했습니다. 주어진 숫자를 k진법으로 변환한 후, 0을 기준으로 분리하여 각 부분이 소수인지 확인합니다. 소수 판별은 제곱근까지만 나누어 확인하는 방식을 사용했습니다. 전체적으로 수학적 접근과 문자열 처리를 결합한 구현 문제 해결 방식을 보여줍니다. 개선 가능한 점: 1. 에라토스테네스의 체 사용: 소수 판별을 더 빠르게 할 수 있습니다. 2. 비트 연산 활용: 진법 변환 시 비트 연산으로 속도 향상 가능합니다. 3. 문자열 대신 리스트 사용: 문자열 연산보다 리스트 연산이 더 빠릅니다. 4. 소수 캐싱: 이미 확인한 소수를 저장하여 재사용할 수 있습니다. 5. 인라인 함수 사용: 소수 판별 함수를 별도로 만들어 코드 가독성 개선 가능합니다.
import math def solution(n, k): num = n c_num = "" while num > 0: if num < k: c_num += str(num) break c_num += str(num % k) num //= k nums = c_num[::-1].split("0") # max_num = int(str(k - 1) * len(max(nums))) # che = [True for i in range(max_num + 1)] # for i in range(2, int(math.sqrt(max_num)) + 1): # if che[i]: # for j in range(i + i, max_num + 1, i): # che[j] = False result = 0 for i in nums: if len(i) == 0: continue a = int(i) if a <= 1: continue flag = True for j in range(2, int(math.sqrt(a)) + 1): if a % j == 0: flag = False break if flag: result += 1 return result주차 요금 계산
코드 제출 (4등) 문제 바로가기주병규
2024-10-06 21:02:25이 코드는 주차 요금 계산 알고리즘을 구현합니다. 딕셔너리를 사용하여 차량별 입출차 기록과 주차 시간을 관리합니다. 문자열 파싱과 시간 계산을 통해 각 차량의 총 주차 시간을 구합니다. 마지막으로 요금 규칙을 적용하여 최종 요금을 계산합니다. 이 알고리즘은 해시 테이블(딕셔너리)을 주로 사용하며, 시간 복잡도는 O(n log n)입니다. 개선 방안: 1. 시간 계산을 분 단위로 통일하여 연산 간소화 (이유: 연산 횟수 감소) 2. 딕셔너리 대신 리스트와 정수 인덱싱 사용 (이유: 메모리 접근 속도 향상) 3. 정렬 대신 우선순위 큐 사용 (이유: 시간 복잡도 개선 가능) 4. 문자열 파싱을 위한 더 효율적인 방법 사용 (이유: 문자열 처리 시간 단축) 5. 반복문 최적화 및 불필요한 조건문 제거 (이유: 불필요한 연산 제거)
import math def solution(fees, records): defaultTime, defaultCharge, unitTime, unitCharge= fees carRecordDic = {} carTimeDic = {} for record in records: time,number,behavior = record.split(" ") hour,minute = [int(char) for char in time.split(":")] if behavior == "OUT": inHour,inMinute= 0,0 if len(carRecordDic.get(number,[]))>0: inHour,inMinute = carRecordDic[number].pop() time = (hour-inHour)*60+(minute-inMinute) carTimeDic[number] = carTimeDic.get(number,0) carTimeDic[number] = carTimeDic[number]+time else: carRecordDic[number] = carRecordDic.get(number,[]) carRecordDic[number].append((hour,minute)) for number in carRecordDic: if len(carRecordDic[number])>0: hour,minute = carRecordDic[number].pop() carTimeDic[number] =carTimeDic.get(number,0) carTimeDic[number]= carTimeDic[number]+(23-hour)*60+(59-minute) carNumbers = sorted(carTimeDic) answer = [] for number in carNumbers: time = carTimeDic[number]-defaultTime time = math.ceil(time/unitTime if time>0 else 0) answer.append(time*unitCharge+defaultCharge) return answer이석민
2024-10-06 11:11:14이 코드는 주차 요금 계산 알고리즘을 구현하고 있습니다. 1. 해시맵(dict)과 defaultdict를 사용하여 차량별 주차 시간과 요금을 관리합니다. 2. 시간 문자열을 분 단위로 변환하는 함수를 구현했습니다. 3. 입차와 출차 기록을 순회하며 차량별 주차 시간을 계산합니다. 4. 출차하지 않은 차량은 23:59에 출차한 것으로 처리합니다. 5. 주차 시간에 따라 요금을 계산하는 함수를 구현했습니다. 6. 차량 번호를 정렬하여 최종 요금 리스트를 반환합니다. 7. 전체적으로 해시맵을 활용한 시뮬레이션 알고리즘을 사용했습니다. 개선 가능한 부분: 1. 시간 계산을 분 단위가 아닌 초 단위로 처리하면 더 정확할 수 있습니다. 2. 차량 번호를 정수로 변환하여 처리하면 정렬 속도를 개선할 수 있습니다. 3. calculate 함수에서 나눗셈 대신 뺄셈을 사용하여 최적화할 수 있습니다. 4. 입출차 기록을 한 번의 순회로 처리하여 시간 복잡도를 개선할 수 있습니다. 5. 문자열 split 대신 인덱싱을 사용하여 파싱 속도를 향상시킬 수 있습니다.
import collections def hh_mm_to_m(s): hh, mm = map(int, s.split(':')) return mm + (hh * 60) def calculate(f, time_delta): basic_min, basic_price, unit_min, unit_price = f # print(f, time_delta) result = basic_price time_delta -= basic_min if time_delta <= 0: return result n, r = divmod(time_delta, unit_min) return result + (n * unit_price) + (unit_price if r > 0 else 0) def solution(fees, records): car_min = collections.defaultdict(int) car_nums = dict() car_price = collections.defaultdict(int) for r in records: time, num, action = r.split(' ') m = hh_mm_to_m(time) if action == 'IN': car_nums[num] = m elif action == 'OUT': time_delta = m - car_nums[num] car_min[num] += time_delta del car_nums[num] # cleanup remain for K, V in car_nums.items(): time_delta = hh_mm_to_m('23:59') - V car_min[K] += time_delta # print(car_min) for K, V in car_min.items(): car_price[K] = calculate(fees, V) return list(map(lambda k: car_price[k], sorted(car_price.keys())))배수훈
2024-10-04 02:31:54이 코드는 주차장 요금 계산 알고리즘을 구현한 것입니다. 주요 알고리즘 유형은 해시 테이블(딕셔너리)과 시간 계산입니다. 코드는 차량 입출차 기록을 처리하여 각 차량의 주차 시간을 계산하고, 이를 기반으로 요금을 산출합니다. 시간 계산을 위해 문자열 파싱과 산술 연산을 사용하며, defaultdict를 활용하여 데이터를 효율적으로 관리합니다. 마지막으로 계산된 요금을 차량 번호 순으로 정렬하여 반환합니다. 개선 방안: 1. 시간 계산 함수(calc_m)를 최적화하여 문자열 파싱 대신 정수 연산만 사용: 더 빠른 연산 가능 2. 딕셔너리 대신 배열을 사용하여 메모리 사용량 줄이기: 차량 번호가 제한적일 경우 유리 3. 정렬 대신 우선순위 큐 사용: 대규모 데이터셋에서 더 효율적일 수 있음 4. 시간 계산을 분 단위로 통일하여 불필요한 변환 줄이기: 연산 횟수 감소 5. 입력 데이터 사전 정렬로 최종 정렬 단계 제거: 전체 실행 시간 단축 가능
from collections import defaultdict import math def solution(fees, records): result = defaultdict(int) def calc_m(in_time, out_time): it = list(map(int, in_time.split(":"))) ot = list(map(int, out_time.split(":"))) it_hh, it_mm = it[0], it[1] ot_hh, ot_mm = ot[0], ot[1] m = ot_mm - it_mm h = ot_hh - it_hh m = (h * 60) + m return m time_table = dict() time_sum = defaultdict(int) for r in records: time, car_num, in_out = r.split(" ") if in_out == "IN": time_table[car_num] = time if in_out == "OUT": in_time = time_table[car_num] time_sum[car_num] += calc_m(in_time, time) del time_table[car_num] end = "23:59" for car_num in time_table.keys(): in_time = time_table[car_num] time_sum[car_num] += calc_m(in_time, end) for car_num in time_sum: m = time_sum[car_num] fee = fees[1] if m - fees[0] > 0: fee += math.ceil((m - fees[0]) / fees[2]) * fees[3] result[car_num] = fee return [result[cn] for cn in sorted(result)]양궁대회
코드 제출 (4등) 문제 바로가기배수훈
2024-10-06 21:43:49이 코드는 백트래킹 알고리즘을 사용하여 최적의 화살 배치를 찾는다. find 함수는 재귀적으로 모든 가능한 화살 배치를 생성한다. 생성된 배치들은 ans 리스트에 저장된다. 각 배치에 대해 점수를 계산하고, 가장 큰 점수 차이를 가진 배치를 찾는다. 동점인 경우 가장 낮은 점수부터 많이 맞힌 배치를 선택한다. 최종적으로 가장 좋은 배치 또는 이길 수 없는 경우 [-1]을 반환한다. 개선 방안: 1. 가지치기: 현재 점수 차이가 최대값보다 작으면 탐색 중단 (불필요한 탐색 감소) 2. 메모이제이션: 이미 계산된 상태 저장 및 재사용 (중복 계산 방지) 3. 비트마스킹: 화살 배치를 비트로 표현하여 메모리 사용량 감소 및 연산 속도 향상 4. 반복문 대신 리스트 컴프리헨션 사용: 코드 간결화 및 약간의 성능 향상 5. 점수 계산 최적화: 누적 점수 차이를 유지하여 반복 계산 감소
def solution(n, info): ans = [] def find(cur, depth, rest): if rest == 0: ans.append([c for c in cur]) return if depth == 11: tmp = [c for c in cur] tmp[10] = rest ans.append(tmp) return if info[depth] < rest: cur[depth] = info[depth] + 1 find(cur, depth + 1, rest - cur[depth]) cur[depth] = 0 find(cur, depth + 1, rest) find([0 for i in range(11)], 0, n) result = 0 resulta = [] for a in ans: sumb = 0 suma = 0 for i in range(11): if a[i] == 0 and info[i] == 0: continue s = 10 - i if a[i] > info[i]: suma += s else: sumb += s if suma > sumb: df = suma - sumb if df > result or (df == result and a[::-1] > resulta[::-1]): result = df resulta = a return [-1] if result == 0 else resulta이석민
2024-10-06 21:40:03이 코드는 백트래킹을 사용한 완전 탐색 알고리즘을 구현했습니다. 점수를 0부터 10까지 순회하며 각 점수에 대해 라이언이 이기거나 지는 두 가지 경우를 재귀적으로 탐색합니다. 모든 점수를 고려한 후, 남은 화살을 0점에 할당하고 점수 차이를 계산합니다. 최대 점수 차이를 갱신하며 최적의 화살 배치를 찾습니다. 마지막으로 여러 최적해 중 가장 낮은 점수에 더 많은 화살을 쏜 경우를 선택합니다. 개선 방안: 1. 비트마스킹으로 상태 표현: 메모리 사용량 감소, 연산 속도 향상 2. 메모이제이션 도입: 중복 계산 방지로 시간 복잡도 개선 3. 가지치기 강화: 현재까지의 점수로 최대 점수 차이를 넘을 수 없는 경우 즉시 반환 4. 반복문으로 재귀 제거: 콜 스택 오버헤드 감소 5. 정렬 대신 우선순위 큐 사용: 최적해 선택 시 시간 복잡도 개선
def solution(n, info): max_diff = 0 answer_list = [] def calculate(score, op, remain_arrow, ryan_info): nonlocal max_diff, answer_list idx = 10 - score if score > 10 or remain_arrow < 0: # Base case: All scores have been considered if remain_arrow < 0: return if remain_arrow > 0: ryan_info[10] += remain_arrow # Assign remaining arrows to 0 score ryan_score = 0 apeach_score = 0 for i in range(11): if ryan_info[i] == 0 and op[i] == 0: continue if ryan_info[i] > op[i]: ryan_score += 10 - i else: apeach_score += 10 - i diff = ryan_score - apeach_score if diff > 0: if diff > max_diff: max_diff = diff answer_list = [ryan_info.copy()] elif diff == max_diff: answer_list.append(ryan_info.copy()) if remain_arrow > 0: ryan_info[10] -= remain_arrow # Backtrack return # Option 1: Ryan tries to win this score need_to_win = op[idx] + 1 if remain_arrow >= need_to_win: ryan_info[idx] = need_to_win calculate(score + 1, op, remain_arrow - need_to_win, ryan_info) ryan_info[idx] = 0 # Backtrack # Option 2: Ryan does not win this score ryan_info[idx] = 0 calculate(score + 1, op, remain_arrow, ryan_info) ryan_info = [0] * 11 calculate(0, info, n, ryan_info) if not answer_list: return [-1] # Select the best answer according to the problem's criteria answer_list.sort(key=lambda x: x[::-1], reverse=True) return answer_list[0]주병규
2024-10-06 21:02:33이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 문제를 해결합니다. 큐를 이용해 모든 가능한 경우의 수를 탐색합니다. 각 화살의 점수를 계산하고, 라이언의 점수가 어피치보다 높을 때 최대 점수 차이를 갱신합니다. 동점 시 가장 낮은 점수를 더 많이 맞힌 경우를 선택합니다. 모든 경우를 탐색한 후 최적의 답을 반환합니다. 개선 사항: 1. 비트마스킹을 사용하여 메모리 사용량 줄이기 (리스트 대신 정수로 상태 표현) 2. 가지치기: 남은 화살로 최대 점수를 얻어도 이길 수 없는 경우 탐색 중단 3. 메모이제이션 도입: 이미 계산한 상태는 재계산하지 않도록 함 4. 더 효율적인 자료구조 사용: deque 대신 힙(heapq) 사용하여 우선순위 큐 구현 5. 점수 계산 최적화: 누적 점수 차이를 사용하여 매번 점수를 다시 계산하지 않도록 함
from collections import deque def solution(n, info): answers = [] apeachScore = 0 for idx, score in enumerate(info): if score > 0: apeachScore += 10 - idx maxScore = 0 queue = deque([(0, n, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 0, apeachScore)]) while queue: idx, remain, rionInfo, rionScore, apeachScore = queue.popleft() if idx == 10 or remain == 0: if rionScore > apeachScore: scoreDiff = rionScore - apeachScore if scoreDiff > maxScore: maxScore = scoreDiff answers = [rionInfo[:10]+[rionInfo[10]+remain]] elif scoreDiff == maxScore: answers.append(rionInfo[:10]+[rionInfo[10]+remain]) continue queue.append((idx + 1, remain, rionInfo[:], rionScore, apeachScore)) if remain > info[idx]: shoot = info[idx] + 1 newRionInfo = rionInfo[:] newRionInfo[idx] = shoot newRionScore = rionScore + (10 - idx) newApeachScore = apeachScore if info[idx] > 0: newApeachScore -= (10 - idx) queue.append((idx + 1, remain - shoot, newRionInfo, newRionScore, newApeachScore)) if not answers: return [-1] answer = [0] * 11 for an in answers: for i in range(10, -1, -1): if an[i] > answer[i]: answer = an break elif an[i] < answer[i]: break return answer양과 늑대
코드 제출 (2등) 문제 바로가기주병규
2024-10-06 22:06:02BFS 알고리즘을 사용한 트리 탐색 문제 해결 코드입니다. 덱을 이용해 노드, 양, 늑대 수, 방문 정보를 관리합니다. 각 노드를 방문하며 양과 늑대 수를 갱신하고 조건을 확인합니다. 늑대가 양 이상이면 해당 경로를 중단합니다. 모든 가능한 경로를 탐색하여 최대 양 수를 구합니다. 루트 노드로 돌아가는 경우를 고려해 전체 상태를 큐에 추가합니다. 방문한 노드는 2로 표시하여 중복 방문을 방지합니다. 개선 사항: 1. 비트마스킹으로 방문 상태 관리 (메모리 사용량 감소, 연산 속도 향상) 2. 우선순위 큐 사용하여 양이 많은 경로 먼저 탐색 (최적해 빠른 도출) 3. DP를 활용한 중복 상태 제거 (불필요한 연산 감소) 4. DFS로 알고리즘 변경 (메모리 사용량 감소, 재귀 제한에 주의) 5. 그래프 전처리로 불필요한 노드 제거 (탐색 범위 축소)
from collections import deque def solution(info, edges): n = len(info) tree = [[] for _ in range(n)] for parent, child in edges: tree[parent].append(child) queue = deque([(0, 0, 0, info[:])]) answer = 1 while queue: node, sheep, wolf, infoCopy = queue.pop() value = infoCopy[node] infoCopy[node] = 2 if value == 1: wolf += 1 elif value == 0: sheep += 1 queue.append((0,sheep,wolf,infoCopy[:])) if wolf >= sheep: continue if answer < sheep: answer = sheep for child in tree[node]: queue.append((child, sheep, wolf, infoCopy[:])) return answer파괴되지 않은 건물
코드 제출 (5등) 문제 바로가기배수훈
2024-10-07 14:43:44이 코드는 2차원 누적 합(2D Prefix Sum) 알고리즘을 사용합니다. 스킬 효과를 누적 합 배열에 적용하고, 가로와 세로 방향으로 누적 합을 계산합니다. 마지막으로 원본 보드와 누적 합을 더해 파괴되지 않은 건물 수를 세어 반환합니다. 누적 합 알고리즘으로 시간 복잡도를 O(N*M + K)로 줄였습니다. 개선 사항: 1. 리스트 컴프리헨션 대신 numpy 배열 사용 (빠른 연산, 메모리 효율) 2. 누적 합 계산을 numpy의 cumsum 함수로 대체 (벡터화된 연산으로 속도 향상) 3. 마지막 카운팅을 numpy의 sum과 boolean indexing으로 최적화 4. 입력 데이터가 크다면 멀티스레딩이나 멀티프로세싱 고려 (병렬 처리로 속도 향상) 5. 피벗 인덱스 기법 사용하여 누적 합 계산 최적화 (반복문 줄여 속도 향상)
def solution(board, skill): h = len(board) w = len(board[0]) result = [[0 for j in range(w + 1)] for i in range(h + 1)] for t, r1, c1, r2, c2, d in skill: if t == 1: d *= -1 result[r1][c1] += d result[r1][c2 + 1] += -d result[r2 + 1][c1] += -d result[r2 + 1][c2 + 1] += d for i in range(h): for j in range(w - 1): result[i][j + 1] += result[i][j] for i in range(h - 1): for j in range(w): result[i + 1][j] += result[i][j] cnt = 0 for i in range(h): for j in range(w): cnt += 1 if board[i][j] + result[i][j] > 0 else 0 return cnt이현석
2024-10-06 22:01:19이 코드는 2차원 누적합(Prefix Sum) 알고리즘을 사용합니다. 스킬 효과를 누적합 배열에 기록하고, 이를 계산하여 원본 보드에 반영합니다. 누적합 배열 초기화, 스킬 효과 기록, 가로 방향 누적합 계산, 세로 방향 누적합 계산, 원본 보드 갱신 및 결과 계산의 단계로 구성됩니다. 시간 복잡도는 O(N*M + K)이며, 여기서 N과 M은 보드의 크기, K는 스킬의 수입니다. 개선 방안: 1. NumPy 사용: 배열 연산 최적화 (표준 라이브러리 제한으로 불가능) 2. 병렬 처리: 누적합 계산에 멀티스레딩 적용 (GIL로 인해 효과 제한적) 3. 비트 연산: 양수 판별에 비트 연산 사용 (미세한 최적화) 4. 메모리 최적화: 인플레이스 연산으로 메모리 사용 줄이기 5. 알고리즘 개선: 세그먼트 트리나 펜윅 트리 고려 (구현 복잡성 증가)
def solution(board, skill): n = len(board) m = len(board[0]) prefix_sum = [[0] * (m + 1) for _ in range(n + 1)] # 누적합 배열에 스킬 반영 for ty, r1, c1, r2, c2, degree in skill: if ty == 1: # 공격일 때는 음수로 degree = -degree # 변화량을 기록 prefix_sum[r1][c1] += degree prefix_sum[r1][c2 + 1] -= degree prefix_sum[r2 + 1][c1] -= degree prefix_sum[r2 + 1][c2 + 1] += degree # 누적합 계산 for i in range(n): for j in range(1, m): prefix_sum[i][j] += prefix_sum[i][j - 1] for j in range(m): for i in range(1, n): prefix_sum[i][j] += prefix_sum[i - 1][j] # 원본 보드에 누적합 반영 answer = 0 for i in range(n): for j in range(m): board[i][j] += prefix_sum[i][j] if board[i][j] > 0: answer += 1 return answer이현석
2024-10-06 21:58:38이 코드는 2차원 배열에 대한 누적 합 연산을 수행합니다. 스킬 리스트를 순회하며 보드의 특정 영역에 대해 값을 더하거나 뺍니다. 모든 스킬 적용 후, 양수 값을 가진 셀의 수를 계산합니다. 이는 브루트 포스 접근법을 사용하며, 시간 복잡도는 O(N*M*K)입니다 (N, M은 보드 크기, K는 스킬 수). 개선 방안: 1. 2D 누적 합 기법 사용: O(N*M + K) 시간 복잡도로 개선 가능. 더 빠른 연산 가능. 2. NumPy 사용: 벡터화된 연산으로 속도 향상. 단, 표준 라이브러리 제한으로 사용 불가. 3. 리스트 컴프리헨션으로 answer 계산: 간결하고 약간 더 빠른 코드 작성 가능. 4. pypy 사용: CPython보다 빠른 실행 속도. 단, 대회 규칙에 따라 다를 수 있음. 5. 멀티스레딩/멀티프로세싱: 대규모 입력에 대해 병렬 처리로 속도 향상 가능. 구현 복잡성 증가.
def solution(board, skill): n = len(board) m = len(board[0]) for ty,r1,c1,r2,c2,degree in skill: if ty == 1: degree = -degree for i in range(r1, r2+1): for j in range(c1, c2+1): board[i][j] += degree answer = 0 for i in range(n): for j in range(m): if board[i][j] > 0: answer += 1 return answer주병규
2024-10-06 21:02:43이 코드는 누적 합(Prefix Sum) 알고리즘을 사용하여 2D 배열의 구간 업데이트를 효율적으로 처리합니다. 스킬 적용 시 효과를 누적 합 배열에 기록하고, 이를 한 번에 계산하여 원본 배열에 적용합니다. 마지막으로 0 이하가 된 셀의 수를 세어 답을 구합니다. 시간 복잡도는 O(N*M + K)로, N*M은 보드 크기, K는 스킬 수입니다. 개선 방안: 1. NumPy 사용: 대규모 배열 연산 빠름 (표준 라이브러리 제한으로 불가능) 2. 멀티스레딩: 큰 보드에서 병렬 처리로 속도 향상 가능 3. 비트 연산: 정수 연산을 비트 연산으로 대체하여 속도 개선 4. 메모리 최적화: 효과 배열을 1차원으로 압축하여 메모리 사용량 감소 5. 캐시 최적화: 데이터 접근 패턴을 캐시 친화적으로 변경하여 속도 향상
def solution(board, skill): answer = len(board) * len(board[0]) effect = [[0] * (len(board[0]) + 1) for _ in range(len(board) + 1)] for behavior in skill: skillType, r1, c1, r2, c2, degree = behavior if skillType == 1: degree = -degree effect[r1][c1] += degree effect[r1][c2 + 1] -= degree effect[r2 + 1][c1] -= degree effect[r2 + 1][c2 + 1] += degree for i in range(len(board)): for j in range(1, len(board[0])): effect[i][j] += effect[i][j - 1] for j in range(len(board[0])): for i in range(1, len(board)): effect[i][j] += effect[i - 1][j] for i in range(len(board)): for j in range(len(board[0])): board[i][j] += effect[i][j] if board[i][j] <= 0: answer -= 1 return answer이석민
2024-10-06 11:28:29이 코드는 2D 배열 순회와 누적 합 알고리즘을 사용합니다. 스킬 리스트를 순회하며 보드를 업데이트하고, 최종적으로 양수 값의 개수를 세어 반환합니다. 중첩 루프를 사용해 직사각형 영역을 업데이트하고 있습니다. 시간 복잡도는 O(N*M*K)로, N과 M은 보드의 크기, K는 스킬의 개수입니다. 이는 큰 입력에 대해 비효율적일 수 있습니다. 개선 방안: 1. 누적 합(Prefix Sum) 기법 사용: O(N*M + K) 시간 복잡도로 개선 가능. 각 스킬 적용 시 전체 보드 갱신 대신 경계만 표시. 2. 스킬 정렬 및 병합: 같은 영역에 적용되는 스킬들을 미리 계산하여 보드 갱신 횟수 감소. 3. NumPy 사용: 큰 배열 연산에 더 효율적이나, 표준 라이브러리 제한으로 사용 불가. 4. 비트 연산 활용: 작은 정수 값들의 경우 비트 연산으로 더 빠른 계산 가능. 5. 멀티스레딩: 큰 보드의 경우 병렬 처리로 성능 향상 가능하나, CPython의 GIL로 인해 제한적일 수 있음.
# 효율성: 시간초과 def solution(board, skill): for record in skill: t, r1, c1, r2, c2, degree = record pos0 = (r1, c1) pos1 = (r2, c2) for y in range(pos0[0], pos1[0] + 1): for x in range(pos0[1], pos1[1] + 1): if t == 1: board[y][x] -= degree else: board[y][x] += degree cnt = len(board) * len(board[0]) for y in range(len(board)): for x in range(len(board[0])): if board[y][x] <= 0: cnt -= 1 return cnt사라지는 발판
첫번째로 코드 제출 문제 바로가기
2024-09-29 21:00:00 (7문제)
단어변환
코드 제출 (5등) 문제 바로가기주병규
2024-09-29 06:27:01이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 주어진 단어들 사이의 최소 변환 횟수를 찾는다. 먼저 단어 간 연결 관계를 트리 구조로 만든다. 그 후 BFS를 통해 시작 단어에서 목표 단어까지의 최단 경로를 찾는다. 단어 간 차이가 한 글자일 때만 연결되며, 이를 확인하는 check 함수를 사용한다. 큐를 이용해 BFS를 구현하고, 목표 단어에 도달할 때까지의 최소 변환 횟수를 반환한다. 개선 방안: 1. set 사용: words를 set으로 변환하여 검색 및 제거 속도 향상 (O(n) → O(1)) 2. 양방향 BFS: 시작점과 끝점에서 동시에 BFS 수행하여 탐색 범위 축소 3. 비트마스킹: 단어를 비트로 표현하여 비교 연산 최적화 4. 해시 테이블: wordDic 대신 해시 테이블 사용하여 룩업 시간 단축 5. 메모이제이션: 이미 방문한 단어와 그 깊이를 저장하여 중복 계산 방지
from collections import deque def solution(begin, target, words): def check(word1,word2): #다른 알파벳이 2개 이상 있는지 확인하는 function cnt = 0 for ch1,ch2 in zip(word1,word2): if ch1!=ch2: cnt+=1 return cnt<2 wordDic = {} #word를 저장하는 Tree wordLen = len(words) queue = deque([begin]) #begin 부터 시작하여 다른 words들과 비교하였을때 다른 알파벳이 1개인 word를 자신의 자식 노드로 삼는다 while queue: word = queue.popleft() wordDic[word] = [] for word2 in words: if check(word,word2): wordDic[word].append(word2) words.remove(word2) queue.append(word2) answer = wordLen queue = deque([(begin,0)]) #bfs while queue: word,cnt = queue.popleft() children = wordDic[word] #node의 word가 target과 같은 경우 anwer에 이전 answer값과 현재 cnt값중 가장 작은 값을 저장 if word == target:answer = min(answer,cnt) if not children : continue for child in children : queue.append((child,cnt+1)) #answer이 변하지 않았을 경우 return 0 if answer == wordLen : return 0 return answer이현석
2024-09-27 09:52:23이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 단어 변환 문제를 해결합니다. 시작 단어에서 목표 단어로 변환하는 최소 단계를 찾습니다. deque를 사용하여 큐를 구현하고, 방문한 단어를 추적합니다. 각 단계에서 한 글자만 다른 단어를 찾아 큐에 추가합니다. 목표 단어를 찾으면 단계 수를 반환하고, 찾지 못하면 0을 반환합니다. 개선 사항: 1. 비트 연산을 사용하여 단어 비교 속도 향상 (비트 연산이 일반적으로 더 빠름) 2. 양방향 BFS 구현으로 탐색 공간 축소 (평균적으로 더 빠른 실행 시간) 3. 단어 목록을 사전으로 그룹화하여 검색 속도 개선 (해시 테이블 사용으로 빠른 검색) 4. 목표 단어가 words에 없을 때 즉시 반환하는 대신 먼저 확인 (불필요한 계산 방지) 5. 문자열 대신 정수로 단어 인코딩하여 메모리 사용량 감소 및 비교 속도 향상
from collections import deque def solution(begin, target, words): if target not in words: return 0 queue = deque([(begin, 0)]) visited = set([begin]) while queue: current_word, steps = queue.popleft() if current_word == target: return steps for word in words: if word not in visited and sum([c1 != c2 for c1, c2 in zip(current_word, word)]) == 1: queue.append((word, steps + 1)) visited.add(word) return 0이석민
2024-09-24 01:18:26이 코드는 BFS 알고리즘을 사용하여 단어 변환 문제를 해결합니다. 정규 표현식을 사용하여 한 글자만 다른 단어를 찾습니다. 각 단어에 대해 변환 가능한 단어 목록을 미리 계산합니다. BFS를 사용하여 시작 단어에서 목표 단어까지의 최단 경로를 찾습니다. 큐를 사용하여 BFS를 구현하고, 방문한 단어를 기록하여 중복 방문을 방지합니다. 목표 단어에 도달하면 변환 횟수를 반환하고, 도달할 수 없으면 0을 반환합니다. 개선 방안: 1. 정규 표현식 대신 문자열 비교로 변경 (정규식은 느림) 2. 단어 간 차이를 미리 계산하여 저장 (매번 계산 대신 조회) 3. 양방향 BFS 사용 (시작점과 끝점에서 동시에 탐색) 4. 비트마스크로 방문 여부 체크 (리스트 대신 비트 연산으로 고속화) 5. 휴리스틱 함수 도입하여 A* 알고리즘 적용 (BFS보다 효율적인 탐색 가능)
import re import collections def available(w, words): result = set() wlist = list(w) for idx, c in enumerate(wlist): wlist[idx] = '.' regex = re.compile('^' + ''.join(wlist) + '$') wlist[idx] = c for word in words: if regex.match(word) is None: continue if word == w: continue result.add(word) return list(result) def solution(begin, target, words): word_vector = {} for w in words + [begin]: word_vector[w] = available(w, words) queue = collections.deque() # (current, used, depth) queue.append((begin, [begin], 0)) while queue: current, used, depth = queue.popleft() if current == target: return depth for w in word_vector[current]: if w in used: continue queue.append((w, used + [w], depth + 1)) return 0배수훈
2024-09-23 16:20:14BFS 알고리즘을 사용한 단어 변환 문제 해결 코드입니다. 패턴 매칭을 위해 defaultdict를 활용하여 와일드카드 패턴을 생성합니다. BFS를 위해 deque를 사용하고, 방문 여부를 defaultdict로 관리합니다. 단어를 순회하며 한 글자씩 변경하여 다음 단계의 단어를 찾고, 목표 단어에 도달할 때까지 BFS를 수행합니다. 목표 단어에 도달하면 변환 횟수를 반환하고, 불가능한 경우 0을 반환합니다. 개선 방안: 1. 양방향 BFS 사용: 시작점과 끝점에서 동시에 BFS 수행으로 탐색 공간 축소 2. 비트마스킹 활용: 문자열 대신 비트마스크로 단어 표현하여 메모리 사용량 감소 3. A* 알고리즘 적용: 휴리스틱 함수로 목표까지의 예상 거리 활용하여 탐색 최적화 4. 전처리 최적화: 패턴 생성 시 set 대신 list 사용으로 메모리 사용량 줄이기 5. 문자열 조작 개선: 슬라이싱 대신 리스트로 변환 후 조작하여 시간 복잡도 개선
from collections import defaultdict, deque def solution(begin, target, words): pattern = defaultdict(set) for w in words: for i, ch in enumerate(w): p = w[:i] + "*" + w[i + 1:] pattern[p].add(w) queue = deque() queue.append([begin, 0]) visit = defaultdict(bool) visit[begin] = True while len(queue) > 0: node = queue.popleft(); word = node[0] cnt = node[1] if word == target: return cnt next = set() for i, ch in enumerate(word): p = word[:i] + "*" + word[i + 1:] next = next | pattern[p] for n in next: if visit[n]: continue visit[n] = True queue.append([n, cnt + 1]) return 0게임 맵 최단거리
코드 제출 (5등) 문제 바로가기주병규
2024-09-29 06:28:17이 코드는 BFS 알고리즘을 사용하여 2D 맵에서 최단 경로를 찾는다. deque를 큐로 사용하고, 방문한 위치를 set으로 관리한다. 상하좌우 이동을 리스트로 정의하고, 맵의 끝점을 미리 계산한다. BFS 루프에서 현재 위치에서 네 방향으로 이동을 시도하며, 유효한 이동인 경우 큐에 추가한다. 목표 지점에 도달하면 이동 횟수를 반환하고, 도달할 수 없으면 -1을 반환한다. 개선 사항: 1. 방문 체크를 2D 배열로 변경 (메모리 사용량 증가, 접근 속도 향상) 2. 목표 지점 도달 확인을 큐에 넣을 때 수행 (루프 횟수 감소) 3. 맵 경계 체크를 함수로 분리 (코드 가독성 향상, 약간의 성능 저하 가능) 4. movement를 전역 상수로 선언 (메모리 사용 최적화) 5. 큐에 튜플 대신 개별 요소 저장 (언패킹 연산 제거로 약간의 성능 향상)
from collections import deque def solution(maps): movement = [(0, 1), (1, 0), (-1, 0), (0, -1)] xEnd = len(maps[0]) - 1 yEnd = len(maps) - 1 queue = deque([(0, 0, 1)]) #(row값,column값,비용(cnt)) visited = set([(0, 0)]) #bfs while queue: i, j, cnt = queue.popleft() if i == yEnd and j == xEnd: return cnt for dx, dy in movement: ni, nj = i + dx, j + dy if 0 <= ni <= yEnd and 0 <= nj <= xEnd and maps[ni][nj] == 1 and (ni, nj) not in visited: visited.add((ni, nj)) queue.append((ni, nj, cnt + 1)) return -1이현석
2024-09-27 09:55:17BFS 알고리즘을 사용한 2D 그리드 탐색 코드입니다. deque를 사용하여 큐를 구현했습니다. 시작점에서 목표지점까지의 최단 거리를 계산합니다. 4방향 이동을 dx, dy 리스트로 처리합니다. 방문한 지점은 거리 값으로 갱신합니다. 목표에 도달할 수 없으면 -1을 반환합니다. 개선 사항: 1. visited 배열 사용: 메모리 사용량 증가하지만 중복 방문 방지로 시간 단축 2. 목표 도달 시 즉시 반환: 불필요한 탐색 줄여 시간 절약 3. 방향 탐색에 리스트 컴프리헨션 사용: 간결성 향상 4. 경계 체크를 함수로 분리: 코드 가독성 개선 5. input 최적화: sys.stdin.readline() 사용하여 입력 속도 향상
from collections import deque def solution(maps): answer = 0 dx , dy = [1,-1,0,0],[0,0,1,-1] def bfs(x,y): q = deque() q.append((x,y)) while q: x,y = q.popleft() for i in range(4): nx = dx[i] + x ny = dy[i] + y if nx < 0 or nx >= len(maps) or ny < 0 or ny >= len(maps[0]): continue if maps[nx][ny] == 0: continue if maps[nx][ny] == 1: maps[nx][ny] = maps[x][y] + 1 q.append((nx, ny)) return maps[len(maps)-1][len(maps[0])-1] answer = bfs(0,0) return -1 if answer == 1 else answer이석민
2024-09-24 01:31:00이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 미로 탈출 경로를 찾습니다. 2D 맵에서 시작점부터 도착점까지의 최단 거리를 계산합니다. collections.deque를 사용하여 큐를 구현하고, 방문한 위치를 set으로 관리합니다. 상하좌우 이동을 통해 가능한 경로를 탐색하며, 벽이나 맵 밖으로 나가는 경우는 무시합니다. 목표 지점에 도달하면 이동 횟수를 반환하고, 도달할 수 없으면 -1을 반환합니다. 개선 사항: 1. 시작점과 도착점을 바꾸어 BFS를 실행하면 불필요한 탐색을 줄일 수 있습니다. 목표에 빠르게 도달할 가능성이 높아집니다. 2. 2D 배열로 visited를 관리하면 set 대신 더 빠른 접근이 가능합니다. 메모리 사용량도 줄어듭니다. 3. 맵의 크기가 작다면 비트마스킹을 사용하여 visited를 관리할 수 있습니다. 메모리 사용량을 크게 줄일 수 있습니다. 4. 양방향 BFS를 사용하면 탐색 범위를 줄일 수 있습니다. 시작점과 도착점에서 동시에 BFS를 실행하여 중간에서 만나는 지점을 찾습니다. 5. A* 알고리즘을 사용하면 휴리스틱을 통해 더 효율적인 경로 탐색이 가능합니다. 목표 지점까지의 예상 거리를 고려하여 탐색 순서를 최적화합니다.
import collections def solution(maps): width = len(maps[0]) height = len(maps) available_move = ((-1, 0), (1, 0), (0, -1), (0, 1)) ## dest = (0, 0) ## start = (n - 1, m - 1) visited = set() # do not visit if there's fast way (already visited) queue = collections.deque() queue.append((width - 1, height - 1, 1)) # (x, y, depth) while queue: x, y, depth = queue.popleft() if x == 0 and y == 0: return depth if (x, y) in visited: continue if maps[y][x] == 0: continue visited.add((x, y)) for (next_x, next_y) in available_move: new_x, new_y = x + next_x, y + next_y if new_x < 0 or new_x >= width or new_y < 0 or new_y >= height: continue queue.append((new_x, new_y, depth + 1)) return -1배수훈
2024-09-23 16:30:15이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 2차원 맵에서 최단 경로를 찾습니다. deque를 사용하여 다음 방문할 위치를 관리합니다. 방문 여부를 체크하기 위해 2차원 리스트를 사용합니다. 상하좌우 이동을 위해 dx, dy 배열을 사용합니다. 시작점부터 BFS를 수행하며 목표지점에 도달하면 이동 횟수를 반환합니다. 맵 경계를 벗어나거나 이미 방문한 곳, 벽은 건너뜁니다. 목표에 도달할 수 없으면 -1을 반환합니다. 개선 사항: 1. 목표 위치를 상수로 저장하여 매번 계산하지 않도록 합니다. 반복적인 계산을 줄일 수 있습니다. 2. visit 배열 대신 set을 사용하여 방문 체크를 더 빠르게 할 수 있습니다. 메모리 사용량은 증가하지만 검색 속도가 향상됩니다. 3. 맵의 크기를 미리 계산하여 변수에 저장합니다. 반복적인 len() 호출을 줄일 수 있습니다. 4. 다음 위치 계산 시 리스트 컴프리헨션을 사용하여 코드를 간결하게 만들 수 있습니다. 가독성이 향상되고 약간의 성능 향상이 있을 수 있습니다. 5. 맵의 크기가 작다면 A* 알고리즘을 사용하여 더 빠르게 최단 경로를 찾을 수 있습니다. 휴리스틱 함수를 사용하여 탐색 효율성을 높일 수 있습니다.
from collections import deque def solution(maps): next_list = deque() visit = list(map(lambda arr: list(map(lambda num: False, arr)), maps)) dx = [1, 0, -1, 0] dy = [0, 1, 0, -1] next_list.append([0, 0, 1]) visit[0][0] = True while(len(next_list) > 0): loc = next_list.popleft() x = loc[0] y = loc[1] if (x == len(maps) - 1 and y == len(maps[0]) - 1): return loc[2] for ix, iy in zip(dx, dy): next_x = x + ix next_y = y + iy if next_x < 0 or next_x >= len(maps) or next_y < 0 or next_y >= len(maps[0]): continue if not visit[next_x][next_y] and maps[next_x][next_y] == 1: visit[next_x][next_y] = True next_list.append([next_x, next_y, loc[2] + 1]) return -1경주로 건설 (카카오)
코드 제출 (5등) 문제 바로가기이현석
2024-09-29 11:37:34이 코드는 BFS 알고리즘을 사용하여 2D 그리드에서 최소 비용 경로를 찾는다. 3차원 배열을 사용하여 각 위치와 방향에 대한 비용을 추적한다. 큐를 사용하여 BFS를 구현하고, 각 이동마다 비용을 계산한다. 방향 전환 시 추가 비용이 발생한다. 모든 가능한 경로를 탐색하고 목적지에 도달하는 최소 비용을 반환한다. 개선 사항: 1. A* 알고리즘 사용: 휴리스틱을 통해 더 효율적인 탐색 가능 2. 방문 여부 체크: 이미 방문한 상태 재방문 방지로 시간 단축 3. 우선순위 큐 사용: 최소 비용 경로 우선 탐색으로 효율성 향상 4. 목적지 도달 시 즉시 종료: 불필요한 탐색 줄여 시간 단축 5. 비트마스킹: 방향 정보 저장에 비트마스킹 사용하여 메모리 절약 이유: 1. A*는 목표까지의 추정 거리를 고려해 더 효율적으로 탐색함 2. 중복 방문 제거로 불필요한 연산 감소 3. 최소 비용 경로 우선 탐색으로 목적지에 빠르게 도달 4. 목적지 도달 후 추가 탐색 방지로 시간 절약 5. 비트마스킹으로 메모리 사용량 감소 및 연산 속도 향상
from collections import deque def solution(board): N = len(board) cost = [[[float('inf')] * 4 for _ in range(N)] for _ in range(N)] d = [(-1, 0), (1, 0), (0, -1), (0, 1)] queue = deque() for i in range(4): cost[0][0][i] = 0 queue.append((0, 0, -1, 0)) while queue: x, y, prev, current_cost = queue.popleft() for i in range(4): dx, dy = d[i] nx, ny = x + dx, y + dy if 0 <= nx < N and 0 <= ny < N and board[nx][ny] == 0: new_cost = current_cost + 100 if prev != -1 and prev != i: new_cost += 500 if new_cost < cost[nx][ny][i]: cost[nx][ny][i] = new_cost queue.append((nx, ny, i, new_cost)) return min(cost[N-1][N-1])주병규
2024-09-29 06:33:42이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 최소 비용 경로를 찾는다. 2D 보드에서 장애물을 피해 시작점에서 끝점까지 이동하는 최소 비용을 계산한다. 큐를 사용하여 BFS를 구현하고, 각 위치에 도달하는 최소 비용을 저장하는 DP 테이블을 활용한다. 네 방향으로의 이동을 고려하며, 직선 이동과 방향 전환에 따른 비용 차이를 반영한다. 시작점에서 오른쪽과 아래 방향으로의 두 가지 초기 이동을 각각 계산하여 최소값을 반환한다. 개선 방안: 1. A* 알고리즘 사용: 휴리스틱 함수로 목표까지의 거리를 추정하여 더 효율적으로 탐색 가능. 2. 비트마스킹으로 방문 상태 관리: 메모리 사용량 감소 및 접근 속도 향상. 3. Dijkstra 알고리즘 적용: 우선순위 큐를 사용하여 최소 비용 경로를 더 빠르게 찾을 수 있음. 4. 방향 전환 비용 최적화: 현재 방식은 불필요한 방향 전환을 고려할 수 있어, 이를 개선하면 성능 향상 가능. 5. 메모이제이션 강화: 중복 계산을 줄이기 위해 각 위치별 방향까지 고려한 DP 테이블 사용.
from collections import deque def solution(board): movement = [(0, 1), (1, 0), (-1, 0), (0, -1)] xEnd = len(board[0]) - 1 yEnd = len(board) - 1 #가장 작은 비용을 저장하는 map makeBoard = [[float('inf') for _ in range(xEnd+1)] for _ in range(yEnd+1)] def bfs(boardDp, queue): #queue = [(row값,column값,비용,방향)] #방향은 movement의 index값으로 나타낸다 ex)방향이 0일 경우 (0,1)으로 움직임 = 오른쪽으로 움직임 while queue: i, j, price, direction = queue.popleft() for idx, (dx, dy) in enumerate(movement): ni, nj = i + dx, j + dy if 0 <= ni <= yEnd and 0 <= nj <= xEnd and board[ni][nj] == 0: #현재 방향과 가려는 방향이 같으면 100 아니라면 600(한번 움직이고 코너를 만들어야 함으로 100+500=600) cost = 100 if direction == idx else 600 #최소 비용을 저장하는 map에 (발생한 비용+이때까지의 비용)과 원래 저장되어있던 비용중 가장 작은 비용을 저장한다 if boardDp[ni][nj] >= cost + price: boardDp[ni][nj] = cost + price queue.append((ni, nj, cost + price, idx)) return boardDp[yEnd][xEnd] #출발지점(0,0)에서 갈 수 있는 방향은 오른쪽(0,1) 또는 아래(1,0)임으로 둘을 따로 계산하여 비교해준다 return min(bfs(makeBoard, deque([(0, 0, 0, 0)])), bfs(makeBoard, deque([(0, 0, 0, 1)])))배수훈
2024-09-24 15:52:22이 코드는 BFS 알고리즘을 사용하여 2D 그리드 상의 최소 비용 경로를 찾습니다. 시작점에서 목표지점까지 네 방향으로 이동하며, 직선 이동은 100, 방향 전환은 600의 비용이 듭니다. deque를 사용하여 BFS를 구현하고, 방문 배열로 각 위치의 최소 비용을 추적합니다. 오른쪽과 아래쪽 두 방향으로 시작하는 경우를 각각 계산하여 최소값을 반환합니다. 개선 사항: 1. 우선순위 큐 사용: 비용이 낮은 경로 먼저 탐색 (다익스트라 알고리즘) 2. 방향 전환 비용 최적화: 500으로 조정 (600-100) 3. 목표 도달 시 즉시 종료: 불필요한 탐색 방지 4. 비트마스킹으로 방문 배열 최적화: 메모리 사용량 감소 5. pypy 사용: 실행 속도 향상
from collections import deque import sys def solution(board): n = len(board) d = [[-1, 0, 1, 0], [0, 1, 0, -1]] def dfs(start): visit = [[sys.maxsize for i in range(n)] for j in range(n)] visit[0][0] = 0 queue = deque() queue.append(start) while queue: x, y, cost, dir = queue.popleft() for i in range(4): nx = x + d[0][i] ny = y + d[1][i] if nx < 0 or nx >= n or ny < 0 or ny >= n: continue if board[nx][ny] == 1: continue n_cost = cost + (100 if dir == i else 600) if n_cost < visit[nx][ny]: visit[nx][ny] = n_cost queue.append([nx, ny, n_cost, i]) return visit[n - 1][n - 1] return min(dfs([0, 0, 0, 1]), dfs([0, 0, 0, 2]))배수훈
2024-09-24 15:52:21이 코드는 BFS 알고리즘을 사용하여 2D 보드에서 최소 비용 경로를 찾는다. 시작점에서 도착점까지 모든 가능한 경로를 탐색하며, 각 칸의 최소 비용을 갱신한다. 방향 전환 시 추가 비용이 발생하며, 장애물을 피해야 한다. 두 가지 시작 방향에 대해 BFS를 실행하고 최소 비용을 반환한다. 개선 방안: 1. 우선순위 큐 사용: 비용이 낮은 경로 우선 탐색 (heapq 모듈) 2. 방문 배열 대신 딕셔너리 사용: 메모리 효율성 개선 3. 방향 전환 로직 최적화: if-else 대신 삼항 연산자 사용 4. 불필요한 방문 제거: 이미 최소 비용보다 높은 경우 큐에 추가하지 않음 5. 목적지 도달 시 즉시 종료: 불필요한 탐색 방지
from collections import deque import sys def solution(board): n = len(board) d = [[-1, 0, 1, 0], [0, 1, 0, -1]] def dfs(start): visit = [[sys.maxsize for i in range(n)] for j in range(n)] visit[0][0] = 0 queue = deque() queue.append(start) while queue: x, y, cost, dir = queue.popleft() for i in range(4): nx = x + d[0][i] ny = y + d[1][i] if nx < 0 or nx >= n or ny < 0 or ny >= n: continue if board[nx][ny] == 1: continue n_cost = cost + (100 if dir == i else 600) if n_cost < visit[nx][ny]: visit[nx][ny] = n_cost queue.append([nx, ny, n_cost, i]) return visit[n - 1][n - 1] return min(dfs([0, 0, 0, 1]), dfs([0, 0, 0, 2]))이석민
2024-09-24 03:38:22이 코드는 BFS 알고리즘을 사용하여 2D 그리드에서 최소 비용 경로를 찾는 문제를 해결합니다. 큐를 사용하여 BFS를 구현하고 있으며, 방향 전환 시 추가 비용을 고려합니다. 시작점에서 두 가지 초기 방향(오른쪽, 아래)으로 BFS를 실행하여 최소 비용을 계산합니다. 각 칸의 최소 비용을 저장하는 price_board를 사용하여 중복 방문을 방지하고 효율성을 높입니다. 마지막으로 두 방향의 결과 중 최소값을 반환합니다. 개선 가능한 점: 1. 우선순위 큐 사용: collections.deque 대신 heapq를 사용하면 더 빠를 수 있음. 비용이 낮은 경로를 먼저 탐색하므로 효율적. 2. 방문 여부 체크: 별도의 visited 배열을 사용하여 중복 방문을 줄이면 실행 시간 단축 가능. 3. 조기 종료: 목적지에 도달하면 즉시 반환하도록 수정하여 불필요한 탐색 방지. 4. 방향 전환 최적화: 이전 방향과 새 방향이 수직인 경우에만 500 추가. 같은 방향이면 비용 추가 불필요. 5. 메모이제이션: 두 번째 BFS 실행 시 이전 결과 재사용 가능. 중복 계산 방지로 시간 절약.
import collections def solution(board): # n x n, 0 -> available, 1 -> wall # start: (0, 0), end: (n - 1, n - 1) # one-way: 100, change direction cost: 500 queue = collections.deque() def BFS(queue): SIZE = len(board) price_board = [[SIZE * SIZE * 100_000_000_000] * SIZE for _ in range(SIZE)] directions = {'L': (-1, 0), 'R': (1, 0), 'U': (0, -1), 'D': (0, 1)} # price_board[0][0] = 0 while queue: x, y, cost, direction = queue.popleft() if x == SIZE - 1 and y == SIZE - 1: continue # We've reached the end for d, (dx, dy) in directions.items(): new_cost = 100 if direction is not None and direction != d: new_cost += 500 new_x, new_y = x + dx, y + dy if new_x < 0 or new_x >= SIZE or new_y < 0 or new_y >= SIZE: continue # Out of bounds if board[new_y][new_x] == 1: continue # It's a wall if price_board[new_y][new_x] < cost + new_cost: continue price_board[new_y][new_x] = cost + new_cost queue.append((new_x, new_y, cost + new_cost, d)) return price_board[SIZE - 1][SIZE - 1] queue.append((0, 0, 0, 'R')) a = BFS(queue) queue.clear() queue.append((0, 0, 0, 'D')) b = BFS(queue) queue.clear() return min(a, b)조이스틱
코드 제출 (4등) 문제 바로가기이현석
2024-09-29 11:38:54이 코드는 그리디 알고리즘을 사용하여 조이스틱 문제를 해결합니다. 각 문자를 변경하는 최소 횟수를 계산하고, 좌우 이동의 최소 거리를 찾습니다. 문자 변경과 커서 이동을 모두 고려하여 최소 조작 횟수를 구합니다. 'A'가 연속된 구간을 건너뛰는 최적의 경로를 찾아 이동 횟수를 최소화합니다. 마지막으로 문자 변경 횟수와 최소 이동 횟수를 합산하여 답을 반환합니다. 개선 가능한 점: 1. ord() 함수 호출을 줄이기 위해 문자를 정수로 미리 변환 (이유: 반복적인 함수 호출 감소) 2. 이진 탐색으로 'A'가 아닌 다음 문자 찾기 (이유: 큰 입력에서 더 효율적) 3. 투 포인터 기법으로 연속된 'A' 구간 찾기 (이유: 선형 시간 복잡도로 개선 가능) 4. 불필요한 계산 줄이기 위해 early return 추가 (이유: 특정 조건에서 빠른 종료 가능) 5. 동적 계획법으로 최적 경로 찾기 (이유: 더 복잡한 패턴에서 최적해 보장)
def solution(name): answer = 0 length = len(name) move = length - 1 for idx in range(length): answer += min(ord(name[idx]) - ord('A'), ord('Z') - ord(name[idx]) + 1) next_idx = idx + 1 while next_idx < length and name[next_idx] == 'A': next_idx += 1 distance = idx + length - next_idx + min(idx, length - next_idx) move = min(move, distance) answer += move return answer주병규
2024-09-29 06:39:47이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 주어진 이름을 만드는 최소 조작 횟수를 구합니다. 큐를 사용하여 현재 상태(인덱스, 비용, 현재 단어)를 저장하고 탐색합니다. 각 단계에서 현재 문자를 변경하는 비용을 계산하고, 왼쪽 또는 오른쪽으로 이동하는 경우를 큐에 추가합니다. 목표 단어에 도달하면 결과를 반환하고, 그렇지 않으면 계속 탐색합니다. 최악의 경우 모든 가능한 상태를 탐색하므로 시간 복잡도는 O(n^2)입니다. 개선 방안: 1. 그리디 알고리즘 사용: 최적의 이동 방향을 미리 계산하여 불필요한 탐색 제거 (시간 복잡도 개선) 2. 비트마스크 활용: 문자열 대신 비트마스크로 상태 표현 (메모리 사용량 감소 및 연산 속도 향상) 3. 투 포인터 기법: 양쪽에서 동시에 탐색하여 효율성 증가 (탐색 범위 축소) 4. 메모이제이션 도입: 중복 계산 방지 (불필요한 재계산 제거) 5. A* 알고리즘 적용: 휴리스틱 함수로 더 효율적인 탐색 유도 (탐색 방향 최적화)
from collections import deque def solution(name): answer = 0 word = "" #name의 크기에 따라 초기 word = "AAA"(크기=3) 또는 "AAAA"(크기=4) for _ in range(len(name)): word+="A" queue = deque([(0,0,word)]) #(계산하려는 index값,비용(cnt),현재 word) #BFS while queue: idx,cnt, word = queue.popleft() #up = 해당 index의 word 값을 원하는 name 값으로 변형시키기 위해 아래 또는 위래 움직이는 비용 up = abs(ord(word[idx]) - ord(name[idx])) #down = up과 반대방향으로 움직였을때 발생하는 비용 down = (26 - up) result = min(up, down)+cnt #해당 index의 word 값을 name 값으로 변경 word = word[:idx]+name[idx]+word[idx+1:] #word와 name이 같을 겨우 return if word == name: return result #커서를 오른쪽으로 이동 queue.append(((idx+1)%len(name),result+1,word)) #커서를 왼쪽으로 이동 queue.append(((idx-1)%len(name),result+1,word)) return -1배수훈
2024-09-25 09:46:38이 코드는 그리디 알고리즘을 사용하여 조이스틱 문제를 해결합니다. 먼저 각 문자를 'A'로 변경하는 최소 이동 횟수를 계산합니다. 그 다음, 좌우 이동의 최소 횟수를 찾기 위해 모든 가능한 경로를 탐색합니다. 연속된 'A'를 건너뛰는 최적의 경로를 찾아 전체 이동 횟수를 최소화합니다. 마지막으로 상하 이동과 좌우 이동의 합을 반환합니다. 개선 사항: 1. 비트 연산을 사용하여 ord() 함수 호출을 줄일 수 있습니다. 이는 연산 속도를 향상시킵니다. 2. min_dst 계산 시 불필요한 반복을 줄이기 위해 투 포인터 기법을 사용할 수 있습니다. 이는 시간 복잡도를 개선합니다. 3. 연속된 'A'를 찾는 과정에서 KMP 알고리즘을 응용할 수 있습니다. 이는 긴 문자열에서 효율적입니다. 4. 동적 프로그래밍을 사용하여 부분 문제의 결과를 저장하고 재사용할 수 있습니다. 이는 중복 계산을 줄입니다. 5. 문자열 처리 대신 정수 배열로 변환하여 작업하면 메모리 사용과 접근 속도를 개선할 수 있습니다.
def solution(name): arr = [min(abs(ord('A') - ord(i)), 26 - abs(ord('A') - ord(i))) for i in name] result = sum(arr) n = len(name) min_dst = n - 1 for i, ch in enumerate(name): j = i + 1 while j < n and name[j] == 'A': j += 1 min_dst = min(min_dst, (i * 2) + (n - j), ((n - j) * 2) + i) return result + min_dst큰 수 만들기
코드 제출 (5등) 문제 바로가기주병규
2024-09-29 06:47:33그리디 알고리즘을 사용한 코드입니다. 앞에서부터 순회하며 현재 숫자가 다음 숫자보다 작으면 제거합니다. 제거 후 이전 위치로 돌아가 다시 비교합니다. k개를 모두 제거하거나 끝까지 순회할 때까지 반복합니다. 남은 k개는 뒤에서부터 제거합니다. 마지막으로 결과를 반환합니다. 개선 방안: 1. 스택 사용: O(n) 시간 복잡도로 개선 가능. 현재 방식은 최악의 경우 O(n^2). 2. 문자열 대신 리스트 사용: 문자열 연산이 비효율적이므로 리스트로 변환 후 작업. 3. 불필요한 슬라이싱 제거: 인덱스만 조작하여 메모리 사용 줄이기. 4. 이진 탐색 활용: 제거할 위치 찾는 데 이진 탐색 사용하여 시간 단축. 5. 투 포인터 기법: 두 개의 포인터를 사용하여 비교 횟수 줄이기.
def solution(number, k): idx = 0 while idx < len(number)-1 and k!=0: #현재 자리의 숫자가 다음 자리의 숫자보다 작으면 그 숫자를 제거 if number[idx]<number[idx+1]: number = number[:idx]+number[idx+1:] k-=1 # 제거한 후, 이전 자리로 돌아가서 다시 비교 idx= idx-1 if idx-1>=0 else 0 else: idx+=1 # 제거해야 할 숫자가 남아있다면, 뒤에서 k개를 제거 # 굳이 가장 작은 숫자를 제거하지 않아도 정렬되어있음으로 뒷자리부터 제거하면된다 if k!=0: number= number[:len(number)-k] return number이석민
2024-09-28 03:21:57이 코드는 스택을 사용하는 그리디 알고리즘을 구현했습니다. 주어진 숫자 문자열에서 k개의 숫자를 제거하여 가장 큰 수를 만드는 문제를 해결합니다. 스택을 이용해 현재 숫자와 이전 숫자를 비교하며 더 작은 숫자를 제거합니다. 모든 숫자를 순회한 후, 남은 숫자들을 이어 붙여 결과를 반환합니다. 개선 가능한 점: 1. 리스트 대신 deque 사용: 스택 연산이 더 빠름 2. 문자열 직접 순회: list(number) 대신 number 직접 사용 3. join 대신 ''.join(stack)[:len(number)-k] 사용: 슬라이싱 감소 4. 조기 종료 조건 추가: k==0일 때 반복 중단 5. 입력이 내림차순일 때 최적화: 마지막 k개 문자 제거
def solution(number, k): stack = [] cntr = 0 nums = list(number) for i in nums: while len(stack) > 0 and stack[-1] < i and cntr < k: stack.pop() cntr += 1 stack.append(i) return ''.join(stack[0:len(number) - (k - cntr)])이현석
2024-09-27 10:11:19이 코드는 스택 알고리즘을 사용하여 주어진 숫자에서 k개의 숫자를 제거하여 가장 큰 수를 만드는 문제를 해결합니다. 각 숫자를 순회하며 스택의 top과 비교하여 더 큰 숫자를 유지합니다. 스택을 사용하여 효율적으로 이전 숫자들을 관리합니다. k개의 숫자를 모두 제거하거나 모든 숫자를 순회한 후, 남은 숫자들을 결합하여 결과를 반환합니다. 시간 복잡도는 O(n)이며, 공간 복잡도는 O(n)입니다. 개선 사항: 1. 입력이 내림차순일 때 더 빠르게 처리하도록 최적화 (이유: 최악의 경우 실행 시간 개선) 2. k가 0이 되면 즉시 종료하여 불필요한 반복 제거 (이유: 불필요한 연산 감소) 3. 문자열 대신 정수로 처리하여 메모리 사용량 감소 (이유: 메모리 효율성 향상) 4. 큰 수에 대해 더 효율적인 알고리즘 고려 (예: 분할 정복) (이유: 대규모 입력 처리 개선) 5. 파이썬의 deque 사용하여 pop 연산 최적화 (이유: 스택 연산 효율성 향상)
def solution(number, k): stack = [] for n in number: while stack and k > 0 and stack[-1] < n: stack.pop() k -= 1 stack.append(n) return ''.join(stack[:len(number) - k])배수훈
2024-09-25 10:16:14이 코드는 그리디 알고리즘을 사용하여 주어진 숫자 문자열에서 k개의 숫자를 제거하여 가장 큰 수를 만드는 문제를 해결합니다. 문자열을 순회하며 현재 숫자보다 다음 숫자가 더 크면 현재 숫자를 제거합니다. 제거 후 이전 위치로 돌아가 다시 비교를 수행합니다. k개의 숫자를 모두 제거하지 못한 경우 남은 개수만큼 뒤에서 제거합니다. 시간 복잡도는 O(n^2)입니다. 개선 방안: 1. 스택을 사용하여 O(n) 시간 복잡도로 개선 가능. 이유: 불필요한 반복 제거 2. 문자열 대신 리스트 사용. 이유: 문자열 슬라이싱은 비효율적 3. 뒤에서부터 순회하는 방식 고려. 이유: 특정 케이스에서 더 효율적 4. 이진 탐색을 활용한 최적화. 이유: 큰 숫자를 빠르게 찾을 수 있음 5. 숫자의 개수가 적을 경우 완전 탐색 고려. 이유: 작은 입력에서 더 빠를 수 있음
def solution(number, k): i = 0 while i < len(number) - 1 and k > 0: if number[i + 1] > number[i]: number = number[:i] + number[i + 1:] k -= 1 if i == 0: i -= 1 else: i -= 2 i += 1 if k > 0: number = number[:len(number) - k] return number구명보트
코드 제출 (5등) 문제 바로가기주병규
2024-09-29 06:48:55이 코드는 그리디 알고리즘을 사용하여 구명보트 문제를 해결합니다. 사람들의 몸무게를 정렬한 후, 양 끝에서부터 탐색하며 가장 무거운 사람과 가장 가벼운 사람을 짝지어 보트에 태웁니다. 무게 제한을 초과하면 무거운 사람만 태웁니다. 이 과정을 반복하여 필요한 보트의 수를 계산합니다. 개선 사항: 1. deque 사용: 리스트 대신 collections.deque 사용. 양 끝 접근이 O(1)로 빨라짐. 2. 이분 탐색: 가장 가벼운 사람을 찾을 때 이분 탐색 적용. 시간 복잡도 개선 가능. 3. 카운팅 정렬: 몸무게 범위가 제한적이라면 카운팅 정렬로 정렬 속도 향상. 4. 그룹화: 비슷한 몸무게끼리 그룹화하여 계산 횟수 줄이기. 5. 병렬 처리: 대규모 데이터의 경우 병렬 처리로 속도 향상 가능.
def solution(people, limit): answer = 0 people.sort() start = 0 end = len(people) - 1 while start <= end: #현재 가장 무거운 사람을 태운 뒤 현재 가장 가벼운 사람까지 태울 수 있다면 태워준다 if people[start] + people[end] <= limit: start += 1 end -= 1 answer += 1 return answer이석민
2024-09-28 10:15:43이 코드는 그리디 알고리즘을 사용하여 구명보트 문제를 해결합니다. 사람들의 무게를 정렬하고 양 끝에서 포인터를 사용하여 가장 무거운 사람과 가장 가벼운 사람을 매칭합니다. 두 사람의 무게 합이 제한을 초과하면 무거운 사람만 보트에 태웁니다. 포인터를 이동시키며 매칭 횟수를 세고, 전체 인원에서 매칭 횟수를 뺀 값을 반환합니다. 개선 사항: 1. 정렬 대신 힙을 사용하여 시간 복잡도를 개선할 수 있습니다. (O(nlogn) -> O(n)) 2. 딕셔너리를 사용하여 무게별 인원 수를 카운트하면 메모리 사용량을 줄일 수 있습니다. 3. 리스트 컴프리헨션으로 입력을 받아 초기화 시간을 단축할 수 있습니다. 4. 불필요한 변수 선언을 줄여 코드를 간소화할 수 있습니다. 5. 최적화된 입출력 처리로 대용량 데이터 처리 속도를 향상시킬 수 있습니다.
import collections import math def solution(people, limit): people.sort() ptr_a = 0 ptr_b = len(people) - 1 cnt = 0 while ptr_a < ptr_b: if people[ptr_b] + people[ptr_a] <= limit: cnt += 1 ptr_a += 1 ptr_b -= 1 return len(people) - cnt이현석
2024-09-27 09:55:40이 코드는 탐욕 알고리즘을 사용하여 구명보트 문제를 해결합니다. 덱(Deque)을 활용하여 정렬된 사람들의 무게를 관리합니다. 가장 무거운 사람과 가장 가벼운 사람을 짝지어 보트에 태우는 방식으로 진행합니다. 무게 제한을 초과하면 무거운 사람만 태웁니다. 이 과정을 모든 사람이 탈 때까지 반복합니다. 시간 복잡도는 O(nlogn)입니다. 개선 방안: 1. 정렬 대신 카운팅 정렬 사용 (O(n) 시간 복잡도) 2. 덱 대신 투 포인터 방식 사용 (메모리 사용 감소) 3. limit 체크를 while 루프 조건에 포함 (불필요한 연산 감소) 4. 리스트 컴프리헨션으로 초기 정렬 (약간의 속도 향상) 5. 함수 내 지역 변수로 limit, len(people) 저장 (반복적 접근 최소화)
from collections import deque def solution(people, limit): answer = 0 people = deque(sorted(people)) while people: start = people.pop() if len(people) > 0 and start + people[0] <= limit: people.popleft() answer += 1 return answer배수훈
2024-09-25 13:25:20이 코드는 그리디 알고리즘을 사용하여 구명보트 문제를 해결합니다. 사람들의 무게를 딕셔너리에 저장하고, 가장 무거운 사람부터 시작하여 짝을 찾습니다. 무게 제한을 초과하지 않는 선에서 가장 가벼운 사람을 함께 태웁니다. 이 과정을 모든 사람이 보트에 탈 때까지 반복합니다. 시간 복잡도는 O(n)입니다. 개선 사항: 1. 정렬된 리스트와 투 포인터 사용: O(nlogn)이지만 상수 시간이 더 빠를 수 있음 2. 비트마스킹으로 무게 표현: 메모리 사용량 감소 및 접근 속도 향상 3. 이분 탐색으로 짝 찾기: 큰 입력에서 더 효율적일 수 있음 4. 미리 계산된 누적 합 사용: 반복적인 계산 줄임 5. 병렬 처리: 대규모 데이터셋에서 성능 향상 가능
from collections import defaultdict def solution(people, limit): w = defaultdict(int) for p in people: w[p] += 1 n = len(people) l, r = 1, 240 cnt = 0 while l <= r: if w[r] == 0: r -= 1 continue w[r] -= 1 cnt += 1 m = limit - r while l <= m: if w[l] == 0: l += 1 continue w[l] -= 1 break return cnt단속카메라
코드 제출 (6등) 문제 바로가기하지웅
2024-09-29 10:13:42이 코드는 그리디 알고리즘을 사용하여 최소 카메라 수를 계산합니다. 차량 경로를 끝나는 지점 기준으로 정렬합니다. 정렬된 경로를 순회하며 카메라 위치를 갱신합니다. 새 경로의 시작점이 현재 카메라 위치보다 뒤에 있으면 새 카메라를 설치합니다. 카메라 수를 세어 반환합니다. 개선 사항: 1. 정렬 대신 우선순위 큐 사용: 더 빠른 실행 시간 2. 입력 크기가 작으면 C++ 사용: 파이썬보다 빠름 3. 끝점만 저장하는 배열로 변경: 메모리 사용량 감소 4. 입력을 미리 정렬된 상태로 받기: 정렬 과정 생략 가능 5. 비트 연산 활용: 정수형 연산이 더 빠름
def solution(routes): routes.sort(key=lambda x: x[1]) cameras = 0 end_camera = -float('inf') for i in routes: if end_camera < i[0]: end_camera = i[1] cameras += 1 return cameras주병규
2024-09-29 06:52:10이 코드는 그리디 알고리즘을 사용하여 최소 카메라 개수를 찾는다. 먼저 차량의 진출 시점을 기준으로 정렬한다. 첫 번째 차량의 진출 시점에 카메라를 설치하고, 이 시점 이전에 진입한 차량들을 모두 처리한다. 이 과정을 모든 차량이 처리될 때까지 반복한다. 시간 복잡도는 O(n log n)이다. 개선 방안: 1. 정렬 대신 우선순위 큐 사용: 힙 정렬로 O(n log n) 유지하면서 메모리 사용 감소 2. 이분 탐색으로 다음 카메라 위치 찾기: O(log n)으로 개선 가능 3. 투 포인터 기법 적용: 메모리 사용 줄이고 루프 횟수 감소 4. 입력 데이터 특성에 따라 계수 정렬 고려: 범위가 제한적이면 O(n)으로 개선 5. 병렬 처리 활용: 대규모 데이터셋에서 정렬 및 탐색 속도 향상
def solution(routes): answer = 0 idx = 0 #나가는 시점을 기준으로 sort routes.sort(key = lambda x:x[1]) while idx <len(routes): answer+=1 start, end = routes[idx] idx+=1 #만약 현재 end에 카메라를 설치하였을때 end보다 진입 시점이 빠르면 카메라에 찍힌다 while idx<len(routes) and routes[idx][0]<=end: idx+=1 return answer이석민
2024-09-28 18:25:08이 코드는 그리디 알고리즘을 사용하여 최소 카메라 설치 문제를 해결합니다. 차량 경로를 종료 지점 기준으로 정렬한 후, 첫 번째 차량의 종료 지점에 카메라를 설치합니다. 이후 각 차량의 시작점이 이전 카메라 위치보다 크면 새 카메라를 설치합니다. 카메라 수를 세어 반환합니다. 개선 사항: 1. 정렬 시 lambda 대신 itemgetter 사용 (속도 향상) 2. 리스트 컴프리헨션으로 routes 필터링 (불필요한 반복 제거) 3. 카메라 위치 업데이트 로직 최적화 (조건문 간소화) 4. 입력 크기가 작은 경우 정렬 대신 힙 사용 고려 (시간복잡도 개선) 5. 병렬 처리 도입 검토 (대규모 데이터셋에 유리) 이유: itemgetter가 lambda보다 빠름, 필터링으로 처리할 데이터 감소, 로직 단순화로 연산 감소, 힙으로 정렬 비용 절감, 병렬화로 대규모 처리 속도 향상 가능.
def solution(routes): routes.sort(key = lambda v: (v[1], v[0])) cnt = 1 camera = routes[0][1] for start, end in routes: if start > camera: camera = end cnt += 1 return cnt이현석
2024-09-27 10:05:19이 코드는 구간 스케줄링 문제를 해결하는 그리디 알고리즘을 사용합니다. 경로를 종료 시간 기준으로 정렬한 후, 겹치지 않는 최대 경로 수를 찾습니다. 시간 복잡도는 정렬로 인해 O(n log n)입니다. 카메라 설치 최소 개수를 반환합니다. 개선 가능성: 1. 리스트 컴프리헨션으로 정렬: 메모리 사용 감소 2. 튜플 언패킹 사용: 가독성 향상 3. float('-inf') 대신 -30001 사용: 문제 제약조건 활용 4. 정렬 키를 lambda 대신 itemgetter로 변경: 약간의 속도 향상 5. 입력이 이미 정렬된 경우 확인: 정렬 단계 생략 가능성 이유: 1,2,3은 미세 최적화, 4는 내장 함수가 더 빠름, 5는 불필요한 정렬 방지 가능.
def solution(routes): answer = 0 routes.sort(key = lambda x: (x[1], x[0])) min_value = float('-inf') for route in routes: if route[0] > min_value: answer += 1 min_value = route[1] return answer배수훈
2024-09-25 11:07:26이 코드는 그리디 알고리즘을 사용하여 카메라 설치 문제를 해결합니다. 경로를 종료 지점을 기준으로 정렬한 후, 겹치지 않는 구간마다 카메라를 설치합니다. 시간 복잡도는 O(n log n)입니다. 개선 사항: 1. 리스트 컴프리헨션으로 정렬: 메모리 사용 감소 2. 튜플 언패킹 활용: 가독성 향상 3. 함수형 프로그래밍 적용: 코드 간결화 4. 이진 탐색 활용: 시간 복잡도 개선 가능성 5. 세그먼트 트리 사용: 구간 쿼리 최적화 이유: 1. 메모리 효율적 2. 파이썬 특성 활용 3. 가독성 및 성능 향상 4. 특정 상황에서 시간 복잡도 개선 5. 대규모 데이터셋에서 효율적
def solution(routes): rs = sorted(routes, key = lambda r: (r[1], r[0])) cnt = 0 p = -30_001 for r in rs: if r[0] > p: cnt += 1 p = r[1] return cnt배수훈
2024-09-25 11:06:33이 코드는 그리디 알고리즘을 사용하여 차량의 경로를 감시하는 카메라 설치 문제를 해결합니다. 경로를 종료 지점 기준으로 정렬하고, 큐를 사용하여 겹치는 구간을 처리합니다. 피봇 포인트를 이용해 카메라 설치 위치를 결정하며, 겹치지 않는 새로운 구간이 나타날 때마다 카메라를 추가합니다. 마지막 구간에 대한 처리를 별도로 수행합니다. 개선 가능한 점: 1. 큐 대신 단순 변수 사용: 메모리 및 시간 절약 2. 정렬 시 lambda 대신 operator.itemgetter 사용: 약간의 성능 향상 3. 마지막 구간 처리 로직 간소화: 코드 단순화 및 가독성 향상 4. 입력 데이터가 크다면 힙 사용 고려: 메모리 효율적인 정렬 가능 5. 두 지점 간 거리가 매우 크다면 좌표 압축 기법 고려: 메모리 사용량 감소
import collections def solution(routes): rs = sorted(routes, key = lambda r: (r[1], r[0])) q = collections.deque() pivot = 0 result = 0 for r in rs: if len(q) == 0: q.append(r) pivot = r[1] continue if r[0] <= pivot: pivot = max(pivot, r[0]) else: # print(q, r) result += 1 q.clear() pivot = r[1] q.append(r) if q: if q[-1][0] <= pivot: result += 1 else: result += 2 return result
2024-09-22 21:00:00 (6문제)
키패드 누르기
코드 제출 (5등) 문제 바로가기주병규
2024-09-22 03:39:16이 코드는 키패드 누르기 문제를 해결하는 알고리즘을 구현했습니다. 주요 알고리즘 유형은 그리디(Greedy)와 시뮬레이션입니다. 각 숫자마다 왼손과 오른손의 현재 위치에서 목표 숫자까지의 거리를 계산합니다. 거리가 같으면 주손을 사용하고, 그렇지 않으면 더 가까운 손을 사용합니다. 왼손, 오른손의 현재 위치를 계속 업데이트하면서 각 숫자를 누르는 손을 결정합니다. 결과로 각 숫자를 누른 손의 순서를 문자열로 반환합니다. 개선 사항: 1. 거리 계산 함수를 별도로 만들어 코드 중복을 줄일 수 있습니다. 가독성이 향상되고 유지보수가 쉬워집니다. 2. 키패드 위치를 딕셔너리로 미리 저장하면 거리 계산이 더 간단해집니다. 복잡한 계산식 대신 좌표 차이로 거리를 구할 수 있습니다. 3. 리스트 대신 집합(set)을 사용하면 in 연산의 시간복잡도가 O(1)로 줄어듭니다. 큰 입력에서 성능 향상을 기대할 수 있습니다. 4. if-elif-else 구문을 간소화하여 코드의 가독성을 높일 수 있습니다. 조건문을 줄이면 실행 시간도 약간 개선될 수 있습니다. 5. 문자열 연결 대신 리스트에 추가 후 join을 사용하면 대규모 입력에서 더 효율적입니다. 문자열 연산은 새로운 객체를 생성하므로 메모리 사용량과 시간이 증가할 수 있습니다.
def solution(numbers, hand): leftNums = [1,4,7] #왼쪽 손가락으로 누를 수 있는 번호 rightNums = [3,6,9] #오른쪽 손가락으로 누를 수 있는 번호 leftCurrent = 10 # *번호는 10으로 rightCurrent = 12 # #번호는 12으로 answer = "" for num in numbers: if num == 0 : num = 11# 0번호는 11으로 #왼쪽손가락으로 해당 번호까지 가는데 비용 = (123,456,789를 각 1,2,3층으로 표현 하였을때 한층에 3개임으로 //3을 해준다) 층 수 + 해당 층 까지 갔을때 필요한 이동 수 leftCnt = abs(num-leftCurrent)//3+abs(num-leftCurrent)%3 rightCnt = abs(num-rightCurrent)//3+abs(num-rightCurrent)%3 isLeft = True if num in leftNums: isLeft = True elif num in rightNums: isLeft = False else: #비용이 같을 경우 어느 손잡이인가에 따라 if leftCnt == rightCnt: if hand=="left": isLeft = True else: isLeft = False elif leftCnt>rightCnt: isLeft = False else: isLeft = True #이동한 손 저장 밑 현재 위치 변화 if isLeft: leftCurrent = num answer+="L" else: rightCurrent = num answer+="R" return answer이석민
2024-09-20 18:10:41이 코드는 키패드 누르기 문제를 해결하는 알고리즘을 구현했습니다. 시뮬레이션 및 그리디 접근 방식을 사용합니다. 각 숫자에 대해 왼손과 오른손의 현재 위치를 추적하고, 맨해튼 거리를 계산하여 어느 손을 사용할지 결정합니다. 결과는 문자열로 반환됩니다. 개선 사항: 1. 딕셔너리로 키패드 위치 매핑 (상수 시간 접근 가능) 2. 거리 계산을 위한 룩업 테이블 사용 (반복적 계산 감소) 3. 리스트 컴프리헨션으로 결과 생성 (더 파이썬스러운 방식) 4. 불필요한 조건문 제거 (코드 간소화) 5. 타입 힌팅 추가 (가독성 및 디버깅 용이성 향상)
def distance(a, b): return abs(a[0] - b[0]) + abs(a[1] - b[1]) def solution(numbers, p_hand): left_pos = (3, 0) right_pos = (3, 2) result = [] for n in numbers: pos = (n - 1) // 3 hand = (n - 1) % 3 ## 0 => 왼손, 1 => 중간, 2 => 오른손 if n == 0: pos = 3 hand = 1 if hand == 2: result.append('R') right_pos = (pos, hand) elif hand == 0: result.append('L') left_pos = (pos, hand) else: left_distance = distance((pos, hand), left_pos) right_distance = distance((pos, hand), right_pos) if left_distance == right_distance: result.append(p_hand[0].upper()) if p_hand == 'right': right_pos = (pos, hand) else: left_pos = (pos, hand) elif left_distance < right_distance: result.append('L') left_pos = (pos, hand) else: result.append('R') right_pos = (pos, hand) return ''.join(result)배수훈
2024-09-19 15:52:04이 코드는 스마트폰 키패드 입력 문제를 해결하는 알고리즘입니다. 주어진 숫자 배열에 대해 왼손과 오른손 중 어느 손으로 입력할지 결정합니다. 키패드를 2차원 배열로 표현하고, 각 손가락의 위치를 좌표로 관리합니다. 숫자마다 거리를 계산하여 가까운 손을 선택하고, 거리가 같으면 주손을 사용합니다. 결과는 문자열로 반환됩니다. 이 알고리즘은 단순한 반복문과 조건문을 사용하여 구현되었습니다. 개선 가능한 점: 1. 딕셔너리를 사용하여 키패드 위치를 미리 저장하면 검색 시간을 줄일 수 있습니다. O(1) 접근이 가능해집니다. 2. calc_distance 함수 대신 튜플 연산을 사용하면 함수 호출 오버헤드를 줄일 수 있습니다. 3. 리스트 컴프리헨션을 사용하여 코드를 간결하게 만들 수 있습니다. 4. enumerate 대신 인덱스를 직접 사용하면 약간의 성능 향상을 얻을 수 있습니다. 5. 문자열 연결 대신 리스트를 사용하고 마지막에 join하면 더 효율적입니다. 문자열 연결은 매번 새로운 문자열을 생성하기 때문입니다.
def calc_distance(a, b): return abs(a[0] - b[0]) + abs(a[1] - b[1]) def solution(numbers, hand): keypad = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['*', '0', '#']] lp = [3, 0] rp = [3, 2] result = [" "] * len(numbers) for i, num in enumerate(numbers): str_num = str(num) for j in range(0, 3): if str_num == keypad[j][0]: lp[0] = j lp[1] = 0 result[i] = "L" break if str_num == keypad[j][2]: rp[0] = j rp[1] = 2 result[i] = "R" break for j in range(0, 4): if str_num == keypad[j][1]: num_point = [j, 1] a = calc_distance(num_point, lp) b = calc_distance(num_point, rp) if a > b: rp[0] = j rp[1] = 1 result[i] = "R" elif a < b: lp[0] = j lp[1] = 1 result[i] = "L" else: if hand == "right": rp[0] = j rp[1] = 1 result[i] = "R" else: lp[0] = j lp[1] = 1 result[i] = "L" break return "".join(result)이현석
2024-09-16 18:12:18이 코드는 숫자 키패드에서 손가락 움직임을 시뮬레이션하는 알고리즘을 구현합니다. 각 숫자에 대해 왼손 또는 오른손을 사용할지 결정하며, 거리 계산을 통해 가까운 손을 선택합니다. 주요 알고리즘은 그리디 접근법을 사용하며, 매 단계에서 최적의 선택을 합니다. 코드는 반복문을 사용하여 각 숫자를 순회하고, 조건문으로 손의 위치를 갱신합니다. 거리 계산은 맨해튼 거리 공식을 활용합니다. 최종적으로 각 숫자에 대한 손 선택을 문자열로 반환합니다. 개선 사항: 1. 거리 계산 함수를 별도로 만들어 코드 중복 제거 (가독성 향상) 2. 숫자와 좌표 매핑을 미리 계산하여 저장 (반복적 계산 감소) 3. 리스트 컴프리헨션으로 answer 생성 (메모리 사용 최적화) 4. 숫자를 0-11로 미리 변환하여 저장 (조건문 간소화) 5. 비트 연산을 활용한 거리 계산 최적화 (계산 속도 향상)
def solution(numbers, hand): answer = '' prev_left = 10 prev_right = 12 for number in numbers: if number == 0: number = 11 if number in [1, 4, 7]: answer += 'L' prev_left = number elif number in [3, 6, 9]: answer += 'R' prev_right = number else: left_distance = abs((prev_left - 1) // 3 - (number - 1) // 3) + abs((prev_left - 1) % 3 - (number - 1) % 3) right_distance = abs((prev_right - 1) // 3 - (number - 1) // 3) + abs((prev_right - 1) % 3 - (number - 1) % 3) if left_distance < right_distance: answer += 'L' prev_left = number elif right_distance < left_distance: answer += 'R' prev_right = number else: if hand == 'right': answer += 'R' prev_right = number else: answer += 'L' prev_left = number return answer2개 이하로 다른 비트
코드 제출 (5등) 문제 바로가기주병규
2024-09-22 03:48:04요약: 1. 비트 연산과 그리디 알고리즘 사용 2. 각 숫자에 대해 다음 큰 수 찾기 3. XOR 연산으로 비트 차이 확인 4. 차이가 2개 이하면 바로 다음 수 선택 5. 차이가 3개 이상이면 최소 비트 변경으로 조정 6. 이진수 조작으로 최적의 다음 수 계산 7. 모든 숫자에 대해 반복하여 결과 도출 개선 방안: 1. 비트 연산 최적화: 'bin().count()' 대신 비트 연산 사용 (예: n & (n - 1)) 이유: 내장 함수보다 비트 연산이 일반적으로 더 빠름 2. 루프 최적화: 'for _ in range()' 대신 비트 시프트 연산 사용 이유: 반복문보다 비트 연산이 더 효율적 3. 메모이제이션 도입: 동일한 입력에 대한 결과 저장 및 재사용 이유: 중복 계산 방지로 시간 절약 가능 4. 입력 정렬 고려: 정렬된 입력에 대해 이진 탐색 활용 가능성 검토 이유: 대규모 입력에서 효율적인 탐색 가능 5. 병렬 처리 고려: 대규모 입력에 대해 멀티스레딩 적용 가능성 검토 이유: 다중 코어 활용으로 전체 처리 시간 단축 가능
def solution(numbers): answer = [] for num in numbers: fNum = num+1 # num과 num보다 큰 fnum xor연산을 비교 후 1(둘의 비트가 다를 때) 카운트 checkCnt = bin(num^fNum).count("1") # 2개 이하일때 정답 if checkCnt<=2: answer.append(fNum) else: addNum = "" # 어차피 이진수 00...01을 더한것이기 때문에 달라진 수 = 자리올림이 된 가장 큰(가장 왼쪽) 비트 1개 + 나머지 0이된 비트의 수 ex) 00101111+00000001 = 00110000 #따라서 위 예제처럼 이전 수 와 비교하였을때 가장 왼쪽비트를 제외한 비트들이 1에서 0이 된 것 임으로 필요한 만큰 가장 작은(가장 오른쪽) 비트를 1로 바꾸어 나가면 된다 for _ in range(checkCnt-2): addNum+="1" answer.append(int(addNum,2)+fNum) return answer이석민
2024-09-20 18:44:31이 코드는 비트 조작을 사용하여 주어진 숫자보다 큰 가장 작은 숫자를 찾는 알고리즘을 구현했습니다. 주요 단계는 다음과 같습니다: 1. 숫자를 이진수로 변환 2. 가장 오른쪽 '0'을 '1'로 변경 3. 변경된 비트 오른쪽의 첫 '1'을 '0'으로 변경 4. 결과를 10진수로 변환 이 알고리즘은 비트 연산과 그리디 접근법을 사용합니다. 개선 가능한 점: 1. bin() 함수 직접 사용으로 to_binary() 함수 제거 가능 (간소화) 2. to_decimal() 대신 int(binary, 2) 사용 (더 빠름) 3. 비트 연산자 활용으로 속도 개선 가능 (예: n & -n으로 최하위 비트 찾기) 4. 전체 이진 문자열 대신 필요한 부분만 조작 (메모리 효율) 5. math.log2()로 최상위 비트 위치 빠르게 찾기 가능 (불필요한 반복 감소) 이러한 개선으로 코드 실행 시간과 메모리 사용을 줄일 수 있습니다.
import math def to_binary(n): result = [] cnt = 3 d = n while d > 0: d, m = divmod(d, 2) result.append(m) return list(reversed(result)) def to_decimal(b): result = 0 for idx, b in enumerate(reversed(b)): result += (pow(2, idx) * int(b)) return result def ans(n): #binary = to_binary(n) binary = ['0'] + list(bin(n)[2:]) # 가장 맨 뒤에 있는 0을 찾고 => 1로 설정, # 그리고 뒤에 있는 1을 0으로 설정 cur = len(binary) - 1 while cur >= 0: if binary[cur] == '0': binary[cur] = '1' for idx, b in enumerate(binary[cur + 1:], cur + 1): if b == '1': binary[idx] = '0' break return to_decimal(binary) cur -= 1 def solution(numbers): return list(map(ans, numbers))이현석
2024-09-20 17:50:43이 코드는 비트 연산과 수학적 접근을 사용하여 짝수와 홀수를 처리합니다. 짝수는 단순히 1을 더하고, 홀수는 가장 낮은 0 비트를 찾아 처리합니다. 루프를 사용해 각 숫자를 순회하며, 내부 while 루프로 홀수의 비트를 확인합니다. Math.pow 함수로 증가량을 계산하여 결과를 도출합니다. 전체적으로 간단한 구현이지만 큰 수에 대해 비효율적일 수 있습니다. 개선 방안: 1. Math.pow 대신 비트 시프트 연산(1L << (c-1)) 사용: 더 빠른 연산 가능 2. 홀수 처리 시 비트 연산으로 최하위 0 비트 찾기: ((x & -x) >> 1) 활용 3. 모든 숫자에 대해 (x & -x) >> 1을 더하는 단일 공식 적용: 조건문 제거 4. long 대신 int 사용 가능한 경우 int로 변경: 메모리 사용량 감소 5. 병렬 처리 고려: 대량의 데이터에 대해 성능 향상 가능
class Solution { public long[] solution(long[] numbers) { long[] answer = new long[numbers.length]; for (int i = 0; i < numbers.length; i++) { long x = numbers[i]; if (x % 2 == 0) { answer[i] = x + 1; } else { long temp = x; int c = 0; while (temp % 2 == 1) { temp /= 2; c++; } long increment = (long)Math.pow(2, c - 1); answer[i] = x + increment; } } return answer; } }배수훈
2024-09-19 17:25:22이 코드는 동적 프로그래밍(DP)과 비트 연산을 사용하여 주어진 숫자보다 큰 최소의 비트 차이를 가진 숫자를 찾는 알고리즘을 구현합니다. defaultdict를 사용하여 메모이제이션을 구현하고, 짝수와 홀수를 별도로 처리합니다. 홀수의 경우 이진 표현을 조작하여 결과를 얻습니다. 결과는 입력 리스트와 같은 길이의 리스트로 반환됩니다. 개선 가능한 점: 1. 비트 연산을 직접 사용하여 문자열 변환 과정을 제거 (런타임 개선) 2. 홀수 처리 로직을 최적화하여 불필요한 연산 줄이기 3. 입력 범위에 따라 미리 결과를 계산하여 저장 (시간복잡도 개선) 4. 병렬 처리를 통한 대규모 입력 처리 속도 향상 5. 입력값의 범위와 특성에 따라 다른 알고리즘 고려 (예: 이분 탐색)
from collections import defaultdict def solution(numbers): memo = defaultdict(int) memo[1] = 2 result = [0 for i in range(len(numbers))] for i, num in enumerate(numbers): if memo[num] > 0: result[i] = memo[num] continue if num % 2 == 0: memo[num] = num + 1 result[i] = memo[num] continue temp = '0' + bin(num)[2:] right_idx = temp.rfind('0') temp_list = list(temp) temp_list[right_idx] = '1' temp_list[right_idx+1] = '0' temp_str = "".join(temp_list) memo[num] = int("0b" + temp_str, 2) result[i] = memo[num] return result스킬 트리
코드 제출 (5등) 문제 바로가기주병규
2024-09-22 03:58:23이 코드는 큐(Queue)를 사용한 문자열 처리 알고리즘입니다. 선행 스킬 순서를 set으로 변환하여 빠른 검색을 가능하게 합니다. 각 스킬 트리를 순회하며 선행 스킬 순서를 확인합니다. deque를 사용하여 선행 스킬 순서를 효율적으로 관리합니다. 올바른 순서로 스킬을 습득한 경우 카운트를 증가시킵니다. 모든 스킬 트리를 검사한 후 최종 결과를 반환합니다. 시간 복잡도는 O(N*M)이며, N은 스킬 트리의 수, M은 각 스킬 트리의 평균 길이입니다. 개선 사항: 1. 문자열 대신 정수 인덱스를 사용하여 비교 속도 향상 (해시 맵 사용) 2. 스킬 트리를 미리 필터링하여 불필요한 문자 제거 3. 선행 스킬 순서를 비트마스크로 표현하여 메모리 사용량 감소 4. 투 포인터 기법을 사용하여 deque 대신 문자열 인덱스 비교 5. 다이나믹 프로그래밍을 활용하여 중복 계산 방지
from collections import deque def solution(skill, skill_trees): #선행 스킬 순서가 있는 스킬 set skillSet = set(skill) answer = 0 for skillTree in skill_trees: skillDeque = deque(skill) isPass = True for getSkill in skillTree: #선행 스킬 순서가 있는 스킬일 경우 if getSkill in skillSet: #선행 스킬중 먼저 배워야하는 스킬을 들고와 현재 스킬트리의 스킬과 일치하는지 확인(일치하지 않을 시 선행 스킬에 맞지 않음) if getSkill != skillDeque.popleft(): isPass = False break if isPass: answer += 1 return answer이석민
2024-09-20 19:02:37이 코드는 스킬 트리의 유효성을 검사하는 알고리즘을 구현했습니다. 큐와 집합 자료구조를 활용하여 스킬 순서를 확인합니다. match 함수는 각 스킬 트리의 유효성을 검사하고, solution 함수는 전체 스킬 트리에 대해 유효한 개수를 반환합니다. 알고리즘의 시간 복잡도는 O(N*M)입니다 (N: 스킬 트리 개수, M: 각 트리의 길이). 개선 가능한 부분: 1. skill을 문자열로 유지하고 인덱스로 접근하면 deque 변환 불필요 (메모리 효율) 2. set 대신 딕셔너리로 스킬 인덱스 저장하면 검색 빠름 (시간 효율) 3. match 함수를 제너레이터로 변경하여 메모리 사용 줄임 4. 불필요한 Counter 사용 대신 sum()으로 True 개수 직접 계산 (시간 효율) 5. 전체 로직을 한 번의 순회로 처리하는 방식으로 재구성 (시간 복잡도 개선)
import collections def match(skill, tree): skill = collections.deque(skill) skill_list = set(skill) for s in tree: if s in skill_list: if skill[0] == s: skill_list.remove(s) skill.popleft() else: return False return True def solution(skill, skill_trees): result = map(lambda t: match(skill, t), skill_trees) return collections.Counter(result)[True]이현석
2024-09-20 18:27:21이 코드는 문자열 처리와 정규표현식을 사용하는 알고리즘입니다. 주어진 스킬 순서와 스킬트리들을 비교하여 유효한 스킬트리의 개수를 세는 방식입니다. 각 스킬트리에서 주어진 스킬에 해당하지 않는 문자를 모두 제거합니다. 필터링된 문자열이 주어진 스킬 순서의 시작 부분과 일치하는지 확인합니다. 일치하는 경우 유효한 스킬트리로 간주하고 카운트를 증가시킵니다. 모든 스킬트리를 검사한 후 최종 카운트를 반환합니다. 이 알고리즘은 문자열 처리와 반복문을 주로 사용합니다. 개선 가능한 점: 1. replaceAll 대신 StringBuilder를 사용하여 문자열 필터링 - 더 빠른 문자열 조작 가능 2. startsWith 대신 직접 문자 비교 - 불필요한 문자열 생성 방지 3. 정규표현식 대신 HashSet 사용 - 더 빠른 문자 검색 가능 4. 스킬 순서를 역순으로 처리 - 불필요한 문자열 생성 감소 5. 병렬 처리 도입 - 대규모 데이터셋에서 성능 향상 가능
class Solution { public int solution(String skill, String[] skill_trees) { int answer = 0; for(int i = 0; i < skill_trees.length; i++) { String skillTree = skill_trees[i]; String filtered = skillTree.replaceAll("[^" + skill + "]", ""); if(skill.startsWith(filtered)) { answer++; } } return answer; } }배수훈
2024-09-20 09:38:02이 코드는 스택 알고리즘을 사용하여 주어진 스킬 순서와 스킬 트리들의 유효성을 검사합니다. 먼저 필수 스킬 집합을 생성하고, 각 스킬 트리를 순회하며 필수 스킬의 순서를 확인합니다. 불필요한 스킬은 무시하고, 필수 스킬의 순서가 맞지 않으면 해당 트리를 무효로 처리합니다. 유효한 스킬 트리의 개수를 세어 반환합니다. 개선 방안: 1. 리스트 대신 문자열로 처리: 메모리 사용 감소 2. 집합 대신 딕셔너리 사용: 룩업 시간 개선 3. 플래그 변수 제거: 불필요한 변수 사용 줄임 4. 제너레이터 표현식 활용: 메모리 효율성 향상 5. 내장 함수 all() 사용: 코드 간결화 및 최적화
def solution(skill, skill_trees): cnt = 0 ss = set(skill) for st in skill_trees: i = 0 flag = True for ch in st: if ch not in ss: continue if skill[i] != ch: flag = False break i += 1 if flag: cnt += 1 return cnt배수훈
2024-09-20 09:28:59이 코드는 정규표현식과 문자열 처리를 사용하여 스킬 트리의 유효성을 검사합니다. 주어진 스킬 순서와 스킬 트리들을 비교하여 유효한 스킬 트리의 개수를 세는 알고리즘입니다. 정규표현식으로 관련 스킬만 추출하고, 순서를 확인합니다. 각 스킬 트리에 대해 순회하면서 스킬 순서를 검증하고, 유효한 경우 카운터를 증가시킵니다. 시간 복잡도는 O(n*m)입니다 (n: 스킬 트리 개수, m: 각 스킬 트리 길이). 개선 방안: 1. 정규표현식 대신 set을 사용하여 필요한 문자만 필터링 (더 빠른 처리 가능) 2. 스킬 순서를 딕셔너리로 미리 매핑하여 검색 시간 단축 3. 제너레이터 표현식 사용으로 메모리 사용량 감소 4. any() 함수 사용으로 루프 최적화 5. 문자열 join() 메소드로 문자 필터링 최적화 이유: set 연산이 정규표현식보다 빠름, 딕셔너리 검색은 O(1), 제너레이터는 메모리 효율적, any()는 조건 만족 시 즉시 종료, join()은 효율적인 문자열 연산
import re def solution(skill, skill_trees): cnt = 0 r = re.compile(f"[{skill}]") for st in skill_trees: i = 0 flag = True for ch in r.findall(st): if skill[i] != ch: flag = False break i += 1 if flag: cnt += 1 return cnt줄서는 방법
코드 제출 (5등) 문제 바로가기주병규
2024-09-22 04:12:49이 코드는 순열을 생성하는 알고리즘을 구현했습니다. 팩토리얼 계산과 리스트 조작을 사용하여 k번째 순열을 찾습니다. 수학적 접근법으로 각 자리에 올 수 있는 숫자를 결정합니다. 리스트에서 선택된 숫자를 제거하며 순열을 구성합니다. 팩토리얼 값을 미리 계산하여 효율성을 높였습니다. 전체적으로 수학적 접근과 리스트 조작을 결합한 알고리즘입니다. 개선 방안: 1. 팩토리얼 계산을 미리 저장하여 반복 계산 방지 (메모이제이션) 2. 리스트 대신 배열 사용으로 메모리 접근 최적화 3. 불필요한 변수 제거로 메모리 사용량 감소 4. 리스트 조작 대신 인덱스 계산으로 속도 향상 5. 큰 수에 대해 모듈로 연산 추가로 오버플로우 방지
import math def solution(n, k): answer = [] # 사람들(번호) 리스트 numList = [i for i in range(1, n+1)] #남은 사람의 수 remain = n #현재 자리에 사람이 정해졌을 때 가능한 나머지 자리에 배치 할 수 있는 경우의 수 = factorial(남은사람의 수) k -= 1 #처음에 첫번째 자리가 정해졌을 때 가능한 경우의 수 factorial에서 나누어간다 current = math.factorial(n-1) while remain > 0: #원하는 k번째 방법 // current = 현재 자리에 가능한 사람의 최대 사전 순 index = k // current k %= current #정한 사람의 번호 제거 answer.append(numList.pop(index)) remain -= 1 if remain>0: current //= remain return answer이현석
2024-09-22 01:08:09이 코드는 수학적 순열을 계산하는 알고리즘을 구현했습니다. 팩토리얼 값을 미리 계산하여 저장합니다. 남은 숫자들을 리스트로 관리하며, 각 자리수마다 해당하는 숫자를 선택합니다. 선택된 숫자는 리스트에서 제거됩니다. k값을 업데이트하며 다음 자리수로 넘어갑니다. 마지막으로 계산된 순열을 반환합니다. 개선 사항: 1. ArrayList 대신 LinkedList 사용: 요소 제거가 더 빠름 2. 팩토리얼 계산에 long 대신 BigInteger 사용: 더 큰 n 값 처리 가능 3. 숫자 선택 시 이진 검색 적용: 큰 n에 대해 더 효율적 4. 팩토리얼 값을 미리 계산하지 않고 필요할 때마다 계산: 메모리 사용량 감소 5. 병렬 처리 도입: 대규모 계산 시 성능 향상 가능
import java.util.*; class Solution { public int[] solution(int n, long k) { int[] answer = new int[n]; long[] fac = new long[n]; List<Integer> numbers = new ArrayList<>(); fac[0] = 1; for (int i = 1; i < n; i++) { fac[i] = fac[i-1] * i; } for (int i = 1; i <= n; i++) { numbers.add(i); } k--; for(int i = 0; i < n; i++) { int idx = (int)(k / fac[n - i - 1]); answer[i] = numbers.get(idx); numbers.remove(idx); k %= fac[n - i - 1]; } return answer; } }이석민
2024-09-20 19:17:52이 코드는 동적 프로그래밍(DP)과 재귀를 사용하여 순열을 생성합니다. factorial 함수는 메모이제이션을 통해 팩토리얼 값을 계산합니다. recursive 함수는 순열을 재귀적으로 구성합니다. solution 함수는 주어진 n과 k에 대한 k번째 순열을 반환합니다. 이 알고리즘은 팩토리얼 계산을 최적화하고 순열을 효율적으로 생성합니다. 개선 사항: 1. itertools.permutations 사용: 더 빠르고 내장 함수임 2. 팩토리얼 계산을 미리 수행하여 저장: 반복 계산 방지 3. 리스트 대신 deque 사용: O(1) 시간 복잡도로 요소 제거 가능 4. 재귀 대신 반복문 사용: 스택 오버플로우 방지 및 성능 향상 5. 비트마스킹 기법 도입: 메모리 사용량 감소 및 연산 속도 향상
memo = {} def factorial(n): global memo if n <= 1: return 1 if n in memo: return memo[n] memo[n] = n * factorial(n - 1) return memo[n] def recursive(n, avail, k): if n == 0: return [] msn = factorial(len(avail) - 1) # most significant number idx = k // msn current = avail.pop(idx) return [current] + recursive(n - 1, avail, k % msn) def solution(n, k): available = [n for n in range(1, n + 1)] # k == 1-index, convert to 0-idx return recursive(n, available, k - 1)배수훈
2024-09-20 11:21:15이 코드는 순열 생성 알고리즘을 구현한 것으로, 팩토리얼을 이용한 조합론적 접근을 사용합니다. 먼저 n!을 계산하고, 이를 이용해 k번째 순열의 각 자리 수를 결정합니다. 리스트를 사용하여 사용 가능한 숫자를 관리하며, 각 단계에서 해당 자리에 올 숫자를 선택합니다. 선택된 숫자는 리스트에서 제거하고 결과에 추가합니다. 이 과정을 n-1번 반복한 후, 마지막 남은 숫자를 추가하여 순열을 완성합니다. 개선 사항: 1. math.factorial() 사용으로 초기 팩토리얼 계산 최적화 (이유: 내장 함수가 더 빠름) 2. itertools.permutations() 사용 고려 (이유: 더 효율적인 순열 생성 가능) 3. 리스트 대신 집합 사용하여 remove 연산 최적화 (이유: O(1) 시간 복잡도) 4. 미리 계산된 팩토리얼 값 사용 (이유: 반복적인 계산 회피) 5. 이진 검색으로 숫자 선택 과정 최적화 (이유: O(log n) 시간 복잡도로 개선)
def solution(n, k): f = 1 for i in range(1, n + 1): f *= i nums = [i for i in range(1, n + 1)] ans = [] while n > 1: f = f // n num = nums[(k - 1) // f] ans.append(num) nums.remove(num) n -= 1 k %= f ans.append(nums[-1]) return ans타깃 넘버
코드 제출 (5등) 문제 바로가기주병규
2024-09-22 04:14:06이 코드는 깊이 우선 탐색(DFS)을 사용하여 주어진 숫자들을 더하거나 빼서 목표 숫자를 만드는 모든 경우의 수를 계산합니다. 재귀 함수를 통해 각 숫자를 더하거나 빼는 두 가지 경우를 모두 탐색합니다. 목표 숫자에 도달하면 카운터를 증가시킵니다. 전역 변수 대신 nonlocal 키워드를 사용하여 내부 함수에서 외부 변수를 수정합니다. 모든 숫자를 처리한 후 최종 결과를 반환합니다. 개선 사항: 1. 동적 프로그래밍(DP)으로 변경: 중복 계산 방지로 시간 단축 가능 2. 비트마스크 사용: 모든 조합을 빠르게 생성하여 시간 복잡도 개선 3. 이진 트리 구조 활용: 효율적인 탐색으로 속도 향상 4. 메모이제이션 도입: 중간 결과 저장으로 반복 계산 회피 5. 병렬 처리 고려: 대규모 입력에 대해 멀티스레딩으로 성능 개선
def solution(numbers, target): answer = 0 def calculate(index,current): nonlocal answer if index == len(numbers): if current == target: answer +=1 return calculate(index+1,current+numbers[index]) calculate(index+1,current-numbers[index]) calculate(0,0) return answer이현석
2024-09-22 01:12:41이 코드는 DFS(깊이 우선 탐색)의 변형을 사용하여 목표 숫자를 만드는 방법의 수를 계산합니다. 각 숫자에 대해 더하기와 빼기 연산을 수행하며, 모든 가능한 조합을 생성합니다. ArrayList를 큐처럼 사용하여 각 단계의 중간 결과를 저장합니다. 마지막으로 목표 숫자와 일치하는 결과의 수를 세어 반환합니다. 개선 사항: 1. 재귀 DFS 사용: 메모리 사용 감소, 더 빠른 실행 가능성 2. 비트마스크 활용: 연산 속도 향상, 메모리 사용 감소 3. DP(동적 계획법) 적용: 중복 계산 방지, 시간 복잡도 개선 4. 이분 탐색 도입: 큰 입력값에 대해 더 효율적 5. 병렬 처리 고려: 대규모 입력에 대한 성능 향상 가능성
import java.util.*; class Solution { public int solution(int[] numbers, int target) { int answer = 0; ArrayList<Integer> q = new ArrayList<>(); q.add(0); for (int number : numbers) { ArrayList<Integer> tmp = new ArrayList<>(); for (int a : q) { tmp.add(a - number); tmp.add(a + number); } q = tmp; } for (int x : q) { if (x == target) { answer++; } } return answer; } }이석민
2024-09-20 19:27:08이 코드는 재귀 알고리즘을 사용하여 숫자 배열에서 특정 목표값을 만들 수 있는 경우의 수를 계산합니다. 각 숫자를 더하거나 빼는 모든 조합을 탐색하며, 깊이 우선 탐색(DFS) 방식으로 동작합니다. 목표값에 도달하면 전역 변수 cnt를 증가시킵니다. 재귀 호출은 numbers 배열이 비어질 때까지 계속되며, 최종적으로 cnt 값을 반환합니다. 개선 방안: 1. 메모이제이션을 활용한 동적 계획법(DP)으로 중복 계산 피하기 (시간 복잡도 개선) 2. 비트마스킹을 이용한 반복문으로 재귀 대체 (메모리 사용량 감소, 속도 향상) 3. 투 포인터 기법 적용하여 공간 복잡도 개선 (O(n) → O(1)) 4. itertools.product 사용하여 모든 조합 생성 (코드 간결화, 속도 향상) 5. 재귀 대신 스택을 이용한 반복적 DFS 구현 (콜 스택 오버플로우 방지, 대규모 입력 처리 가능)
import sys cnt = 0 sys.setrecursionlimit(50) def recursive(current, numbers, target): global cnt if len(numbers) == 0: if current == target: cnt += 1 return cur_num = numbers[0] recursive(current + cur_num, numbers[1:], target) recursive(current - cur_num, numbers[1:], target) def solution(numbers, target): global cnt recursive(0, numbers, target) return cnt배수훈
2024-09-20 11:31:31이 코드는 깊이 우선 탐색(DFS)을 사용한 완전 탐색 알고리즘을 구현하고 있습니다. 주어진 숫자 배열에서 각 숫자를 더하거나 빼서 목표 숫자를 만드는 방법의 수를 계산합니다. 재귀 함수를 사용하여 모든 가능한 조합을 탐색하며, 배열의 끝에 도달하면 현재 합계가 목표와 일치하는지 확인합니다. 최종적으로 목표를 달성하는 모든 경우의 수를 반환합니다. 개선 사항: 1. 메모이제이션을 도입하여 중복 계산 방지 (DP 활용) 2. 비트마스킹을 이용한 최적화로 연산 속도 향상 3. 목표값을 초과하는 경우 조기 종료 조건 추가 4. itertools.product를 활용한 반복문 구현으로 재귀 제거 5. 누적합을 이용한 최적화로 불필요한 연산 감소 이유: 1. 중복 계산 감소로 시간 복잡도 개선 2. 비트 연산으로 속도 향상 3. 불필요한 탐색 제거 4. 재귀 오버헤드 감소 5. 연산 횟수 감소
def bf(numbers, target, i, acc): if i == len(numbers): return 1 if acc == target else 0 return bf(numbers, target, i + 1, acc + numbers[i]) + bf(numbers, target, i + 1, acc - numbers[i]) def solution(numbers, target): return bf(numbers, target, 0, 0)여행 경로
코드 제출 (5등) 문제 바로가기주병규
2024-09-22 04:27:14이 코드는 DFS와 BFS를 혼합한 알고리즘을 사용하여 주어진 항공권으로 가능한 여행 경로를 찾습니다. Node 클래스로 그래프를 구현하고, 티켓을 알파벳 순으로 정렬합니다. deque를 사용해 BFS 방식으로 탐색하며, 각 단계에서 가능한 모든 경로를 확인합니다. 모든 티켓을 사용했을 때 경로를 반환합니다. 개선 사항: 1. 딕셔너리 대신 2D 배열로 그래프 표현 (메모리 사용 감소, 접근 속도 향상) 2. 티켓 정렬 대신 우선순위 큐 사용 (정렬 시간 절약) 3. 재귀적 DFS로 변경 (메모리 사용 감소) 4. 비트마스킹으로 방문 상태 관리 (메모리 사용 감소, 연산 속도 향상) 5. 오일러 경로 알고리즘 적용 (시간 복잡도 개선)
from collections import deque class Node: def __init__(self, name): self.name = name self.children = [] def solution(tickets): nodes = {} tickets.sort(key=lambda x: x[1]) #가능한 경로를 알파벳 순서로 정렬 for ticket in tickets: #경로 tree 구현 start, end = ticket nodes[start] = nodes.get(start, Node(start)) nodes[end] = nodes.get(end, Node(end)) nodes[start].children.append(nodes[end]) #DFS (경로,이동한 횟수, 남은 티켓들) queue = deque([(["ICN"],0,tickets)]) ticketLen = len(tickets) while queue: path,cnt,notVisited = queue.popleft() if cnt == ticketLen: return path #현재 공항에서 가능한 경로들 for node in nodes[path[-1]].children: #이동한 경로 move = [path[-1],node.name] #사용한 티켓이 아닌 경우 if move in notVisited: newVisited = notVisited.copy() newVisited.remove(move) queue.append((path+[node.name],cnt+1,newVisited)) return []이현석
2024-09-22 01:30:49이 코드는 깊이 우선 탐색(DFS)과 우선순위 큐를 사용하여 항공권 경로를 찾는 알고리즘을 구현했습니다. 해시맵을 사용하여 출발지와 도착지를 연결하고, 우선순위 큐로 알파벳 순서를 유지합니다. DFS로 모든 경로를 탐색하며, 역순으로 결과를 저장합니다. 마지막에 결과를 뒤집어 올바른 순서로 반환합니다. 알고리즘은 모든 티켓을 사용하는 유일한 경로를 찾습니다. 개선 사항: 1. ArrayList 대신 LinkedList 사용: 역순 삽입이 더 효율적 2. 재귀 대신 스택 사용: 깊은 재귀에서 스택 오버플로우 방지 3. PriorityQueue 대신 정렬된 List 사용: 메모리 사용 감소 4. 문자열 비교 최소화: 해시코드 사용으로 비교 연산 줄임 5. 백트래킹 최적화: 유효하지 않은 경로 조기 감지 및 중단
import java.util.*; class Solution { public String[] solution(String[][] tickets) { Map<String,PriorityQueue<String>> maps = new HashMap<>(); List<String> answer = new ArrayList<>(); for (String[] ticket : tickets) { maps.computeIfAbsent(ticket[0], k -> new PriorityQueue<>()).add(ticket[1]); } dfs("ICN", maps, answer); Collections.reverse(answer); return answer.toArray(new String[0]); } private void dfs(String start, Map<String,PriorityQueue<String>> maps, List<String> answer) { PriorityQueue<String> target = maps.get(start); while(target != null && !target.isEmpty()) { String next = target.poll(); dfs(next, maps, answer); } answer.add(start); } }이석민
2024-09-20 19:47:52이 코드는 DFS와 백트래킹을 사용하여 항공권 경로를 찾는 알고리즘을 구현했습니다. collections.defaultdict를 활용해 공항 간 연결 정보를 저장합니다. 재귀 함수를 통해 가능한 모든 경로를 탐색하며, 알파벳 순서로 정렬된 목적지를 우선 방문합니다. 백트래킹을 사용해 잘못된 경로를 되돌리고 다른 경로를 탐색합니다. 모든 티켓을 사용했을 때 유효한 경로를 반환합니다. 개선 방안: 1. 인접 리스트 대신 인접 행렬 사용: 빠른 접근 가능 2. 정렬 대신 우선순위 큐 사용: 효율적인 최소값 추출 3. 반복적 DFS로 변경: 재귀 오버헤드 감소 4. 방문 여부를 별도 배열로 관리: 메모리 사용 최적화 5. 티켓 수를 미리 계산하여 전달: 불필요한 매개변수 제거
import collections def recursive(cur, airport, ticket_remain): if ticket_remain == 0: return [cur] airport[cur].sort() for idx, (next_ap, visited) in enumerate(airport[cur]): if visited: continue airport[cur][idx][1] = True result = recursive(next_ap, airport, ticket_remain - 1) airport[cur][idx][1] = False if result is not None: return [cur] + result def solution(tickets): airport = collections.defaultdict(list) for (src, dst) in tickets: airport[src].append([dst, False]) # [dst, visited] ticket_remain = len(tickets) return recursive('ICN', airport, ticket_remain)배수훈
2024-09-20 13:18:49이 코드는 깊이 우선 탐색(DFS)을 사용하여 주어진 항공권으로 가능한 모든 여행 경로를 찾습니다. 재귀적으로 각 티켓을 사용하며 경로를 구성합니다. 모든 티켓을 사용한 경로를 찾으면 answer 리스트에 추가합니다. 마지막으로 알파벳 순으로 정렬하여 첫 번째 경로를 반환합니다. used 리스트로 티켓 사용 여부를 추적합니다. 백트래킹을 통해 모든 가능한 경로를 탐색합니다. 개선 방안: 1. 사전 정렬로 DFS 조기 종료: 티켓을 미리 정렬하여 첫 번째 유효 경로를 찾으면 즉시 반환. 이유: 불필요한 탐색 줄임 2. 인접 리스트 사용: 딕셔너리로 출발지별 도착지 리스트 생성. 이유: 티켓 검색 시간 단축 3. iterative deepening DFS 적용: 메모리 사용 최적화. 이유: 큰 입력에서 더 효율적 4. 비트마스크로 used 배열 대체: 메모리 사용 감소 및 연산 속도 향상. 이유: 더 빠른 비트 연산 활용 5. Hierholzer 알고리즘 고려: 오일러 경로 찾기에 최적화된 알고리즘. 이유: 특정 조건에서 더 효율적
def solution(tickets): answer = [] used = [False for _ in tickets] def dfs(path): if len(path) == len(tickets) + 1: answer.append(path) return for idx, ticket in enumerate(tickets): if ticket[0] == path[len(path) - 1] and not used[idx]: used[idx] = True dfs(path + [ticket[1]]) used[idx] = False dfs(["ICN"]) answer.sort() return answer[0]
2024-09-15 21:00:00 (4문제)
디스크 컨트롤러
코드 제출 (6등) 문제 바로가기하지웅
2024-09-15 18:12:13이 코드는 디스크 컨트롤러 스케줄링 문제를 해결하는 알고리즘을 구현했습니다. 주요 알고리즘은 우선순위 큐를 사용한 그리디 접근법입니다. 작업을 요청 시간 순으로 정렬하고, 현재 시간에 처리 가능한 작업들을 우선순위 큐에 넣습니다. 우선순위 큐에서 가장 짧은 작업을 선택하여 처리합니다. 모든 작업이 완료될 때까지 이 과정을 반복합니다. 마지막으로 평균 처리 시간을 계산하여 반환합니다. 개선 사항: 1. 리스트 대신 deque 사용: 작업 추출 시 O(1) 시간 복잡도 2. 힙 연산 최소화: 현재 시간 이전 작업만 힙에 추가 3. 시간 계산 최적화: 누적 대기 시간만 계산 4. 입력 정렬 제거: 정렬 없이 시간순으로 처리 가능 5. 힙 크기 제한: 처리 가능한 작업만 힙에 유지 이유: deque는 양끝 연산이 빠름, 불필요한 힙 연산 줄임, 계산 간소화, 정렬 비용 제거, 메모리 사용 최적화
import heapq def solution(jobs): # 요청 순서대로 정렬 jobs.sort() total, current, complete = 0, 0, 0 waiting = [] jobs_cnt = len(jobs) while complete < jobs_cnt: # 현재 시간에 있는 작업을 대기 시킴 while jobs and jobs[0][0] <= current: begin, duration = jobs.pop(0) # 작업 시작 시간, 소요 시간 heapq.heappush(waiting, (duration, begin)) # 소요 시간 기준 대기 if waiting: # 대기 중인 요청 중 가장 짧은 요청 처리 duration, begin = heapq.heappop(waiting) current += duration total += current - begin complete += 1 else: # 대기 중인 요청이 없으면 다음 요청 작업 시작 current = jobs[0][0] if jobs else current answer = total // jobs_cnt return answer이석민
2024-09-15 00:44:03이 코드는 디스크 작업 스케줄링 문제를 해결하는 우선순위 큐 기반 알고리즘을 사용합니다. 작업을 시작 시간 순으로 정렬하고 우선순위 큐를 사용하여 처리 시간이 짧은 작업부터 실행합니다. 현재 시간을 추적하며 대기 중인 작업들을 큐에 추가하고, 큐에서 가장 짧은 작업을 꺼내 처리합니다. 모든 작업이 완료될 때까지 이 과정을 반복하며, 각 작업의 대기 시간을 누적하여 평균 대기 시간을 계산합니다. 개선 방안: 1. 정렬 대신 이진 탐색으로 다음 작업 찾기 (로그 시간 복잡도) 2. 큐 대신 리스트와 heapify 사용 (더 빠른 초기화) 3. 매 반복마다 jobs_cur 갱신 대신 한 번에 처리 (연산 줄임) 4. max 함수 대신 조건문 사용 (약간의 최적화) 5. 분기 조건 최적화 (불필요한 검사 줄임)
import heapq INSERT = 1 LEN = 0 def solution(jobs): queue = [] jobs.sort() queue.append((jobs[0][1], jobs[0][0])) current_ms = 0 jobs_cur = 1 job_waittime = 0 while queue: item = heapq.heappop(queue) job_waittime += max(current_ms - item[INSERT], 0) + item[LEN] current_ms = max(current_ms + item[LEN], item[INSERT] + item[LEN]) for available_job in jobs[jobs_cur:]: if available_job[0] > current_ms: break heapq.heappush(queue, (available_job[1], available_job[0])) jobs_cur += 1 if not queue and jobs_cur < len(jobs): available_job = jobs[jobs_cur] queue.append((available_job[1], available_job[1])) jobs_cur += 1 return job_waittime // len(jobs)이현석
2024-09-11 21:24:49이 코드는 최소 작업 시간 우선 스케줄링 알고리즘을 구현합니다. 작업 목록을 정렬하고 시간을 증가시키며 가능한 작업을 처리합니다. 각 단계에서 시작 가능하고 실행 시간이 가장 짧은 작업을 선택합니다. 모든 작업이 완료될 때까지 반복하며 총 대기 시간을 계산합니다. 완료된 작업은 배열로 표시하고 평균 대기 시간을 반환합니다. 그리디 알고리즘과 시뮬레이션 기법을 사용하여 문제를 해결합니다. 시간 복잡도는 O(n^2)이며 n은 작업의 개수입니다. 개선 방안: 1. 우선순위 큐 사용: 매번 최소 작업 찾는 대신 힙으로 O(log n) 시간에 처리 가능 2. 이벤트 기반 시뮬레이션: 시간을 1씩 증가시키지 않고 다음 이벤트로 점프 3. 작업 정렬 기준 변경: 시작 시간이 아닌 (시작 시간, 실행 시간) 기준으로 정렬 4. 인덱스 대신 객체 사용: 작업 정보를 클래스로 만들어 가독성과 확장성 향상 5. 조기 종료 조건 추가: 모든 작업이 완료되면 즉시 루프 탈출하여 불필요한 반복 방지
def solution(jobs): answer = 0 jobs.sort() n = len(jobs) time = 0 total_time = 0 completed = [False] * n while not all(completed): min_task = float('inf') index = -1 for i in range(n): if not completed[i] and jobs[i][0] <= time and jobs[i][1] <= min_task: min_task = jobs[i][1] index = i if index != -1: time += jobs[index][1] total_time += time - jobs[index][0] completed[index] = True else: time += 1 return total_time // n주병규
2024-09-09 20:02:52이 코드는 작업 스케줄링 문제를 해결하는 그리디 알고리즘을 사용합니다. 작업을 종료 시간 기준으로 정렬한 후, 현재 시간에 가능한 가장 짧은 작업을 선택합니다. 작업이 없으면 다음 가능한 시간으로 이동합니다. 총 대기 시간을 계산하여 평균을 반환합니다. 개선 방안: 1. 힙 사용: 최소 힙으로 시작 시간 정렬, O(log n) 시간 복잡도로 개선 가능 2. 이중 정렬: 시작 시간과 소요 시간으로 정렬, 더 효율적인 작업 선택 가능 3. 시간 복잡도 개선: 현재 O(n^2), 힙 사용 시 O(n log n)으로 개선 4. 불필요한 슬라이싱 제거: 리스트 조작 대신 인덱스 사용, 메모리 효율 개선 5. 시간 계산 최적화: 누적 시간 사용, 반복적인 계산 감소
def solution(jobs): jobsLen = len(jobs) #끝나는 시점을 기준으로 sort #이렇게 정렬하게 되면 현재 시간을 기준으로 가장 짧은 작업부터 시작할 수 있게 된다 jobs = sorted(jobs, key=lambda x: x[1]) #총 걸린 시간 answer = 0 #현재 시간 time = 0 while jobs: notFound = True for idx, job in enumerate(jobs): #가장 짧은 작업을 가져오는데 이가 현재 시점에서 시작하는 작업인가를 확인 #맞을 시 해당 작업을 answer및 time에 추가해준다 if time >= job[0]: jobs = jobs[:idx] + jobs[idx+1:] answer += time + job[1] - job[0] time += job[1] notFound = False break #만약 어떠한 작업도 현재 시점에서는 실행할 수 없으면 가장 빠르게 실행할 수 있는 시점으로 이동한다(기다린다) if notFound and jobs: time = min(job[0] for job in jobs) return answer // jobsLen배수훈
2024-09-09 11:33:41이 코드는 최소 힙(Min Heap)과 정렬을 사용하여 디스크 컨트롤러 스케줄링 문제를 해결합니다. 작업을 도착 시간 순으로 힙에 넣고, 현재 시간에 가능한 작업 중 가장 짧은 것을 선택합니다. 전체 대기 시간을 계산하고 평균을 반환합니다. 이는 SJF(Shortest Job First) 알고리즘의 변형입니다. 개선 가능한 점: 1. 힙 대신 정렬된 리스트 사용: 작업이 적을 때 더 효율적일 수 있음 2. 우선순위 큐 사용: 현재 시간에 가능한 작업을 더 효율적으로 관리 3. 이중 우선순위 큐 도입: 도착 시간과 처리 시간 모두 고려 가능 4. 인덱스 사용하여 jobs 리스트 직접 순회: 메모리 사용 줄일 수 있음 5. 그리디 알고리즘으로 접근: 매 순간 최적의 선택을 하는 방식으로 구현 가능
import heapq def solution(jobs): hq = [] for j in jobs: heapq.heappush(hq, (j[0], j[1])) cur = 0 pt = 0 while len(hq) > 0: arr = [] while len(hq) > 0 and hq[0][0] <= cur: arr.append(heapq.heappop(hq)) if len(arr) == 0: tmp = heapq.heappop(hq) pt += tmp[1] cur = tmp[0] + tmp[1] continue arr.sort(key = lambda p: p[1]) wt = (cur - arr[0][0]) + arr[0][1] pt += wt cur = cur + arr[0][1] for i in range(1, len(arr)): heapq.heappush(hq, (arr[i][0], arr[i][1])) return pt // len(jobs)보석 쇼핑
코드 제출 (5등) 문제 바로가기이석민
2024-09-15 01:20:22이 코드는 투 포인터 알고리즘을 사용하여 모든 보석 종류를 포함하는 최소 구간을 찾습니다. 먼저 보석 종류를 파악하고, 시작과 끝 포인터를 이용해 구간을 조절합니다. 끝 포인터를 이동하며 모든 종류를 포함할 때까지 구간을 확장하고, 시작 포인터를 이동하며 최소 구간을 찾습니다. 현재 구간의 보석 정보를 딕셔너리로 관리하며, 최소 구간을 갱신합니다. 마지막으로 1-indexed로 변환하여 결과를 반환합니다. 개선 방안: 1. 집합(set)을 사용하여 보석 종류 파악: O(n) 시간 복잡도 개선 2. 딕셔너리 대신 배열 사용: 메모리 사용량 감소, 접근 속도 향상 3. 불필요한 조건 검사 제거: ptr_start <= ptr_end 조건 삭제로 연산 감소 4. 람다 함수 대신 리스트 컴프리헨션 사용: 약간의 성능 향상 5. 초기 min_distance를 sys.maxsize로 설정: 불필요한 len(gems) 호출 제거
def solution(gems): ### pre setup ### items = dict() # filling gems for name in gems: if name not in items: items[name] = 0 items_cnt = len(items) # end setup ## min_distance = len(gems) min_pos = (0, 0) #(start_pos, end_pos) ptr_start = 0 ptr_end = 0 current_el = dict() while ptr_end < len(gems): # 부족한 상황에는 다 추가 if len(current_el) < items_cnt: if gems[ptr_end] not in current_el: current_el[gems[ptr_end]] = 0 current_el[gems[ptr_end]] += 1 # 항목이 다 있는 상태. 부족해질 때 까지 앞으로 땡길것. while len(current_el) == items_cnt and ptr_start <= ptr_end: distance = ptr_end - ptr_start if distance < min_distance: min_pos = (ptr_start, ptr_end) min_distance = distance current_el[gems[ptr_start]] -= 1 if current_el[gems[ptr_start]] == 0: del current_el[gems[ptr_start]] ptr_start += 1 ptr_end += 1 return list(map(lambda v: v + 1, min_pos))이현석
2024-09-14 18:37:26이 코드는 투포인터 알고리즘을 사용하여 모든 종류의 보석을 포함하는 가장 짧은 구간을 찾습니다. 시작점과 끝점을 이동시키며 모든 보석을 포함하는 최소 구간을 탐색합니다. 딕셔너리를 사용하여 현재 구간의 보석 개수를 추적합니다. 모든 종류의 보석을 포함하면 시작점을 이동시키고, 그렇지 않으면 끝점을 이동시킵니다. 구간의 길이를 비교하여 최소 구간을 갱신합니다. 마지막으로 1-인덱스 기반으로 결과를 반환합니다. 개선 가능한 점: 1. 집합 대신 리스트 컴프리헨션으로 고유 보석 수 계산 (메모리 효율) 2. 딕셔너리 대신 카운터 객체 사용 (간결성, 속도) 3. any() 함수로 딕셔너리 값 검사 (가독성) 4. 끝점 이동 시 조건문 제거 (불필요한 검사 감소) 5. 반복문 조건 간소화 (end < num_gems 조건만으로 충분)
def solution(gems): unique_gems = set(gems) num_unique_gems = len(unique_gems) num_gems = len(gems) start = end = 0 gem_dict = {gems[0]: 1} answer = [0, num_gems - 1] while start < num_gems and end < num_gems: if len(gem_dict) == num_unique_gems: if end - start < answer[1] - answer[0]: answer = [start, end] gem_dict[gems[start]] -= 1 if gem_dict[gems[start]] == 0: del gem_dict[gems[start]] start += 1 else: end += 1 if end < num_gems: gem_dict[gems[end]] = gem_dict.get(gems[end], 0) + 1 return [answer[0] + 1, answer[1] + 1]배수훈
2024-09-10 17:21:28이 코드는 투 포인터 알고리즘을 사용하여 모든 종류의 보석을 포함하는 가장 짧은 구간을 찾는다. defaultdict를 사용하여 보석의 개수를 추적하고, 구간을 확장하거나 축소하며 최적의 결과를 갱신한다. 시작과 끝 인덱스를 조정하며 모든 보석 종류를 포함하는 최소 구간을 찾아 반환한다. 개선 가능한 부분: 1. set(gems)를 미리 계산하여 재사용: 반복적인 set 생성 방지 2. 초기 result를 [0, m]으로 설정: 불필요한 비교 연산 감소 3. 구간 길이 계산을 변수로 저장: 반복적인 계산 방지 4. 빠른 종료 조건 추가: 최소 구간 발견 시 즉시 반환 5. bisect 모듈 사용 고려: 이진 탐색으로 구간 탐색 최적화 가능
from collections import defaultdict def solution(gems): n = len(set(gems)) m = len(gems) i, j = 0, 0 jewelry_box = defaultdict(int) jewelry_box[gems[0]] += 1 result = [0, m - 1] while i <= j < m: if len(jewelry_box) == n: if result[1] - result[0] + 1 > j - i + 1: result[0], result[1] = i, j if jewelry_box[gems[i]] == 1: del jewelry_box[gems[i]] else: jewelry_box[gems[i]] -= 1 i += 1 else: j += 1 if j == m: break jewelry_box[gems[j]] += 1 result[0] += 1 result[1] += 1 return result주병규
2024-09-09 20:44:02이 코드는 투 포인터(Two Pointer) 알고리즘을 사용하여 문제를 해결합니다. 주요 단계는 다음과 같습니다: 1. 모든 보석 종류를 세트로 저장합니다. 2. 시작과 끝 포인터를 초기화합니다. 3. 끝 포인터를 증가시키며 보석을 딕셔너리에 추가합니다. 4. 모든 종류의 보석을 포함하면 시작 포인터를 이동하며 범위를 줄입니다. 5. 가장 짧은 범위를 계속 갱신합니다. 6. 모든 보석을 순회할 때까지 3-5 단계를 반복합니다. 7. 최종적으로 가장 짧은 범위를 반환합니다. 개선 가능성: 1. 집합 대신 frozenset 사용: 불변성으로 약간의 성능 향상 가능 2. 딕셔너리 대신 Counter 객체 사용: 더 효율적인 카운팅 가능 3. 리스트 컴프리헨션으로 초기 집합 생성: 약간 더 빠른 실행 가능 4. 불필요한 변수 제거: 메모리 사용 최적화 5. bisect 모듈 활용: 이진 검색으로 시작점 찾기 최적화 가능
def solution(gems): #잼들의 종류를 모아놓은 set gemList = set() for gem in gems: gemList.add(gem) #잼들의 종류의 개수 gemListLen = len(gemList) startPoint = 0 #진열대에 있는 모든 잼들의 개수 gemLen = len(gems) endPoint = gemLen #현재 살 수 있는 잼을 key로 개수를 value로 저장 check = {} start = 0 #end를 점점 키우면서 check에 값을 더해나가는데 start를 늘려 전체적인 길이를 줄일 수 있으면 줄인다 for end in range(gemLen): #check에 gem 추가 check[gems[end]] = check.get(gems[end],0)+1 #만약 현재 모든 종류의 잼을 살 수 있는 상태라면 start의 크기를 늘릴 수 있을 만큼 늘려가면서 길이를 줄인다 while len(check)==gemListLen: #길이가 더 작으면 저장 if end-start < endPoint-startPoint: startPoint,endPoint = start+1,end+1 #start부분의 잼 들고오기 num = check.get(gems[start],1) #만약 잼이 1개밖에 없다면 해당 잼을 check에서 제거 if num == 1 : del check[gems[start]] #잼이 1개 이상 있다면 그 개수를 1개 줄여준다 else: check[gems[start]]-=1 start+=1 return [startPoint,endPoint]섬 연결하기
코드 제출 (6등) 문제 바로가기하지웅
2024-09-15 17:45:28크루스칼 알고리즘을 사용한 최소 신장 트리 구현. 간선을 비용 순으로 정렬 후 순회하며 연결. 연결된 노드 집합을 유지하며 모든 노드가 연결될 때까지 반복. 시간복잡도는 O(E log E)로 간선 정렬이 지배적. 개선 방안: 1. Union-Find 자료구조 사용: 더 빠른 연결 확인 가능 2. 힙 사용: 간선 정렬 대신 최소 힙으로 O(E log E) 유지하며 메모리 효율 개선 3. 프림 알고리즘: 노드 수가 많고 간선이 적은 경우 더 효율적 4. 이진 탐색 트리: 연결 집합 대신 사용하여 탐색 및 삽입 속도 향상 5. 병렬 처리: 정렬 단계에서 멀티스레딩으로 대규모 입력 처리 속도 개선
def solution(n, costs): # 리스트 정렬(비용기준) costs.sort(key=lambda x: x[2]) connection = set([costs[0][0]]) total = 0 while len(connection) < n: for x, y, cost in costs: if x in connection and y not in connection: connection.add(y) total += cost break elif y in connection and x not in connection: connection.add(x) total += cost break return total이석민
2024-09-15 02:12:00이 코드는 크루스칼 알고리즘을 사용하여 최소 신장 트리를 구현한 것입니다. 비용을 기준으로 간선을 오름차순 정렬한 후, 사이클을 형성하지 않는 간선을 선택하여 트리를 구성합니다. Union-Find 자료구조를 사용하여 연결된 섬들을 효율적으로 관리합니다. 모든 섬이 연결될 때까지 반복하며, 최종적으로 최소 비용을 반환합니다. 개선 가능한 부분: 1. Union-Find 최적화: 경로 압축과 랭크 기반 유니온 사용 (더 빠른 연산) 2. heapq 모듈 사용: 정렬 대신 우선순위 큐 활용 (더 효율적인 간선 선택) 3. 불필요한 set 연산 제거: lands_area_rep 딕셔너리 삭제 (메모리 및 시간 절약) 4. 입력 데이터 직접 사용: costs 리스트 변환 없이 바로 사용 (전처리 시간 단축) 5. early termination: n-1개의 간선 선택 시 즉시 종료 (불필요한 반복 방지)
import heapq def solution(n, costs): # costs -> list[[land_start_idx, land_end_idx, cost(weight)]] order_by_cost_asc = sorted(list(map(lambda v: (v[2], v[0], v[1]), costs))) lands = set(map(lambda v: v[0], costs)) lands.update(set(map(lambda v: v[1], costs))) lands_area = dict() lands_area_rep = dict() for idx in lands: lands_area[idx] = idx lands_area_rep[idx] = set([idx]) ### end setup #### belong = set() cost_sum = 0 for (cost, start_idx, end_idx) in order_by_cost_asc: if lands_area[start_idx] == lands_area[end_idx]: continue cost_sum += cost merged_from = lands_area[start_idx] merged_to = lands_area[end_idx] lands_area_rep[merged_to].update(lands_area_rep[merged_from]) lands_area_rep[merged_from].update(lands_area_rep[merged_to]) for old_idx in lands_area_rep[merged_from]: lands_area[old_idx] = merged_to if len(lands_area_rep[merged_to]) == len(lands): break return cost_sum이현석
2024-09-11 21:31:43이 코드는 크루스칼 알고리즘을 사용한 최소 신장 트리(MST) 구현입니다. Union-Find 자료구조를 활용하여 사이클 검사를 효율적으로 수행합니다. 간선을 비용 순으로 정렬한 후, 가장 저렴한 간선부터 선택합니다. 선택된 간선이 사이클을 만들지 않으면 MST에 추가합니다. 총 n-1개의 간선이 선택되면 알고리즘이 종료됩니다. 시간 복잡도는 O(E log E)로, E는 간선의 수입니다. Union-Find 최적화로 거의 상수 시간에 연산이 가능합니다. 개선 방안: 1. 경로 압축을 더 적극적으로 사용하여 find 함수 최적화 2. 랭크 기반 유니온으로 트리 깊이 최소화 3. 힙을 사용하여 간선 정렬 대신 우선순위 큐 활용 4. 프림 알고리즘으로 전환하여 dense 그래프에서 성능 향상 5. 입력 크기에 따라 크루스칼과 프림 알고리즘 선택적 사용
def find(x): if parent[x] != x: parent[x] = find(parent[x]) return parent[x] def union(x, y): x = find(x) y = find(y) if x != y: parent[x] = y def solution(n, costs): costs.sort(key=lambda x: x[2]) global parent parent = list(range(n)) total_cost = 0 cnt = 0 for cost in costs: x, y, c = cost if find(x) != find(y): union(x, y) total_cost += c cnt += 1 if cnt == n - 1: break return total_cost배수훈
2024-09-11 10:57:57이 코드는 크루스칼 알고리즘을 구현한 최소 신장 트리(MST) 솔루션입니다. 간선을 비용순으로 정렬하고, 각 노드의 소속을 추적하며 사이클을 형성하지 않는 간선을 선택합니다. 선택된 간선의 비용을 누적하여 최종 MST 비용을 계산합니다. Union-Find 자료구조를 사용하지 않고 직접 구현한 점이 특징입니다. 전체적으로 그리디 알고리즘과 분리 집합의 개념을 활용합니다. 개선 사항: 1. Union-Find 자료구조 사용: 더 효율적인 집합 관리 가능 (시간복잡도 개선) 2. 정렬 기준 단순화: (e[2],)로 충분함 (불필요한 정렬 기준 제거) 3. 집합 체크 최적화: 매 반복마다 set() 생성 대신 별도 변수로 관리 (중복 연산 제거) 4. 조건문 단순화: 중복되는 로직 통합 (코드 가독성 및 유지보수성 향상) 5. 리스트 대신 배열 사용: array 모듈의 array 사용 (메모리 사용 최적화)
# from collections import defaultdict def sumMst(belong_to, first_mst_num, second_mst_num): for i, node_mst_num in enumerate(belong_to): if node_mst_num == first_mst_num: belong_to[i] = second_mst_num def solution(n, costs): costs.sort(key = lambda e: (e[2], e[1], e[2])) belong_to = [-1 for i in range(n)] result = 0 mst_num = 0 for cost in costs: check = set(belong_to) if -1 not in check and len(check) == 1: break if belong_to[cost[0]] >= 0 and belong_to[cost[0]] == belong_to[cost[1]]: continue if belong_to[cost[0]] == -1 and belong_to[cost[1]] == -1: belong_to[cost[0]] = mst_num belong_to[cost[1]] = mst_num mst_num += 1 result += cost[2] continue if belong_to[cost[0]] >= 0: if belong_to[cost[1]] == -1: belong_to[cost[1]] = belong_to[cost[0]] else: sumMst(belong_to, belong_to[cost[0]], belong_to[cost[1]]) result += cost[2] continue if belong_to[cost[1]] >= 0: if belong_to[cost[0]] == -1: belong_to[cost[0]] = belong_to[cost[1]] else: sumMst(belong_to, belong_to[cost[1]], belong_to[cost[0]]) result += cost[2] continue return result주병규
2024-09-10 18:39:14크루스칼 알고리즘, Union-Find 자료구조 1. 간선을 비용 순으로 정렬 2. Union-Find 구조로 섬들의 연결 상태 관리 3. 비용이 낮은 간선부터 연결 시도 4. 두 섬이 연결되어 있지 않으면 연결하고 비용 추가 5. 모든 섬이 연결될 때까지 반복 6. 최소 신장 트리(MST)를 구성하는 알고리즘 7. 그리디한 방식으로 최적해 도출 개선 방안: 1. Path Compression 기법 적용: find 함수 최적화로 시간 복잡도 개선 2. Union by Rank 사용: 트리의 높이를 최소화하여 find 연산 속도 향상 3. 간선 정렬에 Counting Sort 적용: 비용 범위가 작다면 더 빠른 정렬 가능 4. 이진 힙(Binary Heap) 사용: 간선 선택 과정 최적화 가능 5. Prim 알고리즘 고려: 간선이 많은 경우 더 효율적일 수 있음
def solution(n, costs): #비용의 순서로 정렬 #비용이 작은 순으로 간선을 연결하여 최소비용이 되도록 만든ㄴ다 costs = sorted(costs,key = lambda x : x[2]) #index는 child 섬 value는 parent 섬 #초기에는 자기 자신이 부모, 자식 노드 parent = [i for i in range(n)] #두 노드의 부모 노드를 찾고 만약 같은 경우 같은 tree에 존재하는 것 임으로 pass #만약 부모 노드가 다르면 서로 다른 tree에 존재하는 것 임으로 이를 한 노드를 부모노드로 저장해주어 연결시킨다 def union(x,y): xFind = find(x) yFind = find(y) if xFind == yFind: return parent[xFind] = yFind #부모 노드를 찾는 함수 def find(x): if parent[x] == x: return x return find(parent[x]) answer = 0 cnt = 0 for i in range(len(costs)): #두 노드의 부모 노드가 다를 시(두 노드가 하나의 tree로 연결되어있지 않을 시) if find(costs[i][0])!=find(costs[i][1]): #두 노드 연결 union(costs[i][0],costs[i][1]) #총 비용에 현재 간선의 비용 추가 answer+=costs[i][2] #방문한 노드의 수 +1 cnt+=1 #모든 노드를 방문했으면 바로 return if cnt == n :return return answer가사 검색
코드 제출 (5등) 문제 바로가기이현석
2024-09-15 18:07:12이 코드는 문자열 검색 알고리즘을 구현했습니다. 단어 길이별로 해시맵을 사용하여 단어들을 그룹화합니다. 각 쿼리에 대해 와일드카드 위치를 확인하고 부분 문자열 매칭을 수행합니다. 시작 또는 끝 부분 매칭을 위해 startswith()와 endswith() 메서드를 사용합니다. 전체적으로 브루트 포스 접근 방식을 취하고 있습니다. 개선 방안: 1. 트라이(Trie) 자료구조 사용: 접두사/접미사 검색 최적화 2. 이진 검색 도입: 정렬된 리스트에서 빠른 검색 가능 3. 쿼리 결과 캐싱: 중복 쿼리 처리 속도 향상 4. 병렬 처리 활용: 대량의 쿼리 동시 처리 5. 문자열 해싱: 빠른 문자열 비교를 위한 해시 값 사용
# 55점 def solution(words, queries): words_by_length = {} for word in words: length = len(word) if length not in words_by_length: words_by_length[length] = [] words_by_length[length].append(word) answer = [] for query in queries: count = 0 length = len(query) if length not in words_by_length: answer.append(0) continue if query[0] == '?': idx = query.rfind('?') + 1 sub_query = query[idx:] for word in words_by_length[length]: if word.endswith(sub_query): count += 1 else: idx = query.find('?') sub_query = query[:idx] for word in words_by_length[length]: if word.startswith(sub_query): count += 1 answer.append(count) return answer이석민
2024-09-15 17:45:07트라이 자료구조를 사용한 문자열 매칭 알고리즘입니다. 전방향 및 후방향 트라이를 구축하여 쿼리 패턴을 효율적으로 처리합니다. Node 클래스로 트라이 노드를 구현하고, push와 flush 메서드로 단어를 삽입합니다. match_cnt 메서드로 쿼리 패턴과 일치하는 단어 수를 계산합니다. defaultdict를 사용해 길이별로 트라이를 관리하고, 쿼리 패턴에 따라 적절한 트라이를 선택합니다. 시간복잡도는 트라이 구축에 O(N*L), 쿼리 처리에 O(M*L)로 효율적입니다 (N: 단어 수, M: 쿼리 수, L: 최대 단어 길이). 개선 사항: 1. Node 클래스의 children을 리스트로 변경하여 메모리 사용량 감소 (알파벳 소문자만 사용 가정) 이유: 딕셔너리보다 리스트가 메모리 효율적이며 접근 속도가 빠름 2. 트라이 구축 시 길이별로 단어를 미리 정렬하여 불필요한 트라이 생성 방지 이유: 쿼리 길이와 일치하는 단어만 처리하여 시간 및 공간 복잡도 개선 3. 와일드카드 개수에 따라 전방향/후방향 트라이 중 효율적인 것 선택 이유: 와일드카드가 적은 쪽에서 시작하면 탐색 범위가 줄어듦 4. 쿼리 결과를 캐싱하여 중복 계산 방지 이유: 동일한 쿼리가 반복될 경우 계산 시간 단축 5. 병렬 처리를 통한 성능 향상 (멀티스레딩 또는 멀티프로세싱) 이유: 대량의 쿼리를 동시에 처리하여 전체 실행 시간 단축
import collections from typing import * class Node: children = {} cnt = 0 root = None def __init__(self, root = None): self.children = dict() self.root = root def push(self, c): if c not in self.children: self.children[c] = Node(self) return self.children[c] ''' push가 완료되면 반드시 flush로 뒷정리를 해줘야 함. ''' def flush(self): root_ptr = self while root_ptr != None: root_ptr.cnt += 1 root_ptr = root_ptr.root def __str__(self): return str(self.children) def __repr__(self): return str(self.children) def match_cnt(self, str_slice): node_ptr = self for c in str_slice: if c == '?': return node_ptr.cnt if c not in node_ptr.children: return 0 node_ptr = node_ptr.children[c] return node_ptr.cnt def solution(words, queries): trie_forward = collections.defaultdict(Node) trie_backward = collections.defaultdict(Node) for w in words: l = len(w) # fill forward node_ptr = trie_forward[l] for c in w: node_ptr = node_ptr.push(c) node_ptr.flush() node_ptr = trie_backward[l] for c in reversed(w): node_ptr = node_ptr.push(c) node_ptr.flush() ans = [] for q in queries: l = len(q) res = 0 if q[0] == '?': res = trie_backward[l].match_cnt(q[::-1]) else: res = trie_forward[l].match_cnt(q) ans.append(res) return ans이석민
2024-09-15 02:27:48알고리즘: 정규표현식 매칭 요약: 1. 각 쿼리를 정규표현식 패턴으로 변환 2. 모든 단어에 대해 패턴 매칭 시도 3. 매칭되는 단어 수 계산 4. 결과 리스트에 추가 5. 모든 쿼리에 대해 반복 6. 정규표현식 사용으로 간단한 구현 7. 브루트포스 접근법 사용 개선 방안: 1. 트라이(Trie) 자료구조 사용: 검색 속도 향상 가능 2. 이분 탐색으로 길이별 단어 그룹화: 불필요한 비교 줄임 3. 쿼리 결과 캐싱: 중복 계산 방지 4. 와일드카드 위치에 따른 최적화: 접두사/접미사 별도 처리 5. 병렬 처리: 대용량 데이터셋에서 성능 향상 가능
# 100점중 55점 (시간초과). 대신 3분만에 구현완료. 시간 안될것 같으면 부분점수 라도 얻는게? import re def solution(words, queries): result = [] for q in queries: r = re.compile('^' + q.replace('?', '.') + '$') cnt = 0 for w in words: if r.match(w) is not None: cnt += 1 result.append(cnt) return result배수훈
2024-09-11 15:04:48이 코드는 이진 검색(Binary Search)을 활용한 문자열 매칭 알고리즘을 구현했습니다. 단어 길이별로 정렬된 리스트를 만들고, 쿼리의 와일드카드 위치에 따라 정방향 또는 역방향 리스트를 사용합니다. bisect 함수로 매칭되는 단어의 범위를 빠르게 찾아 결과를 계산합니다. 전처리 과정에서 정렬을 수행하고, 각 쿼리마다 이진 검색을 실행하여 효율적으로 해결합니다. 개선 방안: 1. 트라이(Trie) 자료구조 사용: 더 빠른 검색 가능 2. 쿼리 캐싱: 중복 쿼리 처리 속도 향상 3. 병렬 처리: 멀티스레딩으로 대량의 쿼리 처리 속도 개선 4. 메모리 최적화: 필요 없는 길이의 리스트 제거 5. 정규표현식 사용: 와일드카드 매칭에 더 효율적
from bisect import bisect_left, bisect_right MAX_WORD_LEN = 100_001 def solution(words, queries): asc = [[] for i in range(MAX_WORD_LEN)] rev_asc = [[] for i in range(MAX_WORD_LEN)] for w in words: n = len(w) asc[n].append(w) rev_asc[n].append(w[::-1]) for i in range(1, MAX_WORD_LEN): asc[i].sort() rev_asc[i].sort() result = [0 for i in range(len(queries))] for i, q in enumerate(queries): left, right = 0, 0 if q[0] == "?": q = q[::-1] left = bisect_left(rev_asc[len(q)], q.replace("?", "a")) right = bisect_right(rev_asc[len(q)], q.replace("?", "z")) else: left = bisect_left(asc[len(q)], q.replace("?", "a")) right = bisect_right(asc[len(q)], q.replace("?", "z")) result[i] = right - left return result주병규
2024-09-10 19:18:39이 코드는 트라이(Trie) 자료구조를 사용하여 문자열 검색 문제를 해결하는 알고리즘을 구현했습니다. 주요 특징은 다음과 같습니다: 1. 트라이 구조를 사용하여 단어를 저장하고 검색합니다. 2. 정방향과 역방향 두 개의 트라이를 만들어 효율적인 검색을 가능하게 합니다. 3. 와일드카드(?)를 처리하기 위해 모든 가능한 경로를 탐색합니다. 4. 중복 쿼리를 처리하기 위해 결과를 캐시합니다. 5. BFS 방식으로 트라이를 탐색하여 매칭되는 단어 수를 계산합니다. 6. 쿼리의 와일드카드 위치에 따라 정방향 또는 역방향 트라이를 선택합니다. 7. 각 쿼리에 대해 매칭되는 단어 수를 반환합니다. 개선 가능한 부분: 1. 와일드카드 처리 시 불필요한 탐색을 줄이기 위해 각 길이별 단어 수를 미리 계산해 둘 수 있습니다. 이유: 모든 글자가 ?인 경우 빠르게 답을 찾을 수 있습니다. 2. 트라이 노드에 해당 노드를 루트로 하는 서브트리의 단어 수를 저장하면 탐색 시간을 줄일 수 있습니다. 이유: 매번 끝까지 탐색하지 않아도 중간에 결과를 알 수 있습니다. 3. 문자열 반전 대신 두 포인터 방식으로 역방향 탐색을 구현하면 메모리 사용을 줄일 수 있습니다. 이유: 문자열 복사 비용을 절약할 수 있습니다. 4. 트라이 구조 대신 접미사 배열(Suffix Array)을 사용하면 더 빠른 검색이 가능할 수 있습니다. 이유: 특정 상황에서 트라이보다 효율적인 검색이 가능합니다. 5. 병렬 처리를 통해 여러 쿼리를 동시에 처리하면 전체 실행 시간을 줄일 수 있습니다. 이유: 멀티코어 CPU를 효율적으로 활용할 수 있습니다.
class Node: def __init__(self, data): #현재 가사 self.data = data #다음 가사 self.child = {} #가사의 끝인 경우 true self.isEnd = False def solution(words, queries): #?가 앞에 나오는 경우와 뒤에 나오는 경우 각각 reverseRoot tree와 forwardRoot를 사용하여 검색한다 #두 트리 모두 가사의 순서대로 tree를 만드는데 예를들어 frodo의 경우 f가 루트 r이 자식 노드 그 자식노드가 o가 된다 #fowardRoot는 앞에서 부터 순서대로 tree를 만든것이고 reverseRoot는 반대이다 #이를 나눈 이유는 ?가 나올때는 모든 자식 노드들을 보아야하는데 ?????o같은 경우 모든 노드들을 보아야하는데 reverseRoot를 가지고 뒤에서 부터 맞추어 나간다면 경우의 수를 확연히 줄일 수 있다 forwardRoot = Node(None) reverseRoot = Node(None) #가사를 글자 순서대로(또는 글자 순서 반대로) tree를 만들어 준다 def addChild(text,node): for char in text: if char not in node.child: node.child[char] = Node(char) node = node.child[char] node.isEnd = True for word in words: addChild(word,forwardRoot) addChild(word[::-1],reverseRoot) #tree를 가지고 가사를 찾아주는 함수 def find(text,root): nodes = [root] length = len(text) cnt = 0 for idx, char in enumerate(text): newNodes = [] for node in nodes: #?일 경우 모든 자식 노드들을 append if char == "?": #가사의 마지막인 경우 매치된 총 수에 모든 자식의 노드의 수를 더해준다 if idx == length - 1: for childNode in node.child.values(): if childNode.isEnd: cnt += 1 else: newNodes.extend(node.child.values()) #자식 노드 중 순서에 맞고 알파벳이 일치할 경우 해당 자식을 추가해준다 elif char in node.child: childNode = node.child[char] #가사의 마지막일 경우 매치된 총 수에 1을 더해준다 if idx == length - 1: if childNode.isEnd: cnt += 1 else: newNodes.append(childNode) nodes = newNodes #만약 순서와 알파벳이 맞는 자식노드가 없으면 break if not nodes: break return cnt #중복된 검색이 있을 수 있음으로 dictionary에 저장 answerDic = {} answer = [] for query in queries: if query not in answerDic: #?부터 시작할 시 reverRoot를 반대일시 forwardRoot를 사용 if query[0]=="?": answerDic[query] = find(query[::-1],reverseRoot) else: answerDic[query] = find(query,forwardRoot) answer.append(answerDic[query]) return answer
2024-09-08 21:00:00 (6문제)
A (실버2)
코드 제출 (5등) 문제 바로가기주병규
2024-09-08 15:44:43이 코드는 동적 계획법(DP)을 사용한 알고리즘입니다. 입력값을 받아 모듈러 연산을 적용하며 누적 합을 계산합니다. 각 줄의 값은 이전 줄의 합과 현재 값을 곱하여 계산됩니다. 최종 답은 각 줄의 합을 누적하여 구합니다. 모든 연산에서 모듈러 연산을 적용하여 오버플로우를 방지합니다. 시간 복잡도는 O(n)으로, 입력 크기에 비례합니다. 공간 복잡도는 O(1)로, 추가 메모리 사용이 최소화되었습니다. 코드는 간결하고 효율적으로 구현되었습니다. 개선 가능한 점: 1. 리스트 컴프리헨션 사용: 'for m in [int(x) for x in input().split()]'로 변경. 이유: 메모리 사용 감소 2. 상수 최적화: 'modNum'을 함수 외부로 이동. 이유: 반복문 내 연산 감소 3. 비트 연산 활용: 모듈러 연산을 비트 연산으로 대체. 이유: 일부 경우 더 빠른 연산 가능 4. 입력 최적화: sys.stdin.readline() 사용. 이유: 대량 입력 시 더 빠름 5. 루프 언롤링 적용: 반복문 내부 연산 展開. 이유: 일부 환경에서 성능 향상 가능
n = int(input()) answer = 0 before = 0 modNum = 1000_000_007 #현재 줄의 값의 합 = (현재 줄의 값 * (이전 줄의 값의 합+1)) % 1000000007 # ex)문제에서 cpu4에서는 6+6+3 = 3(2+2+1) = 현재줄의 값*(이전줄의 값+1) for m in list(map(int, input().split())): before = (m*(before+1))%modNum answer = (answer+before)%modNum print(answer %modNum)배수훈
2024-09-05 17:43:21이 코드는 동적 프로그래밍(DP) 접근법을 사용하여 배열의 부분 수열 합을 계산합니다. 입력받은 배열을 순회하며 이전 결과를 활용해 현재 위치까지의 부분 수열 합을 누적합니다. 모듈러 연산을 사용하여 큰 수를 처리합니다. 시간 복잡도는 O(n)입니다. 개선 방안: 1. 리스트 컴프리헨션으로 입력 받기: 더 빠른 입력 처리 가능 2. sum 대신 다른 변수명 사용: 내장 함수와 충돌 방지 3. 불필요한 형변환 제거: 마지막 출력에서 int() 제거 4. 미리 계산된 값 활용: (pre + 1) * arr[i]를 한 번만 계산 5. 비트 연산 사용: % MOD 대신 & (MOD-1) 사용 (MOD가 2의 거듭제곱일 때) 이유: 1. 더 효율적인 메모리 사용 2. 이름 충돌 방지로 오류 예방 3. 불필요한 연산 제거 4. 중복 계산 방지 5. 비트 연산이 일반적으로 더 빠름
n = int(input()) arr = list(map(int, input().split(" "))) MOD = 1000000007 sum = arr[0] % MOD pre = sum for i in range(1, n - 1): pre = ((pre + 1) * arr[i]) % MOD sum = (sum + pre) % MOD print(int(sum))이현석
2024-09-03 17:41:13이 코드는 동적 프로그래밍(DP)을 사용하여 CPU 성능 점수를 계산합니다. 입력받은 CPU 성능 값을 이용해 각 위치에서의 점수를 계산하고 누적합을 구합니다. MOD 연산을 사용하여 큰 수를 처리합니다. 시간 복잡도는 O(n)입니다. 메모리 사용량을 줄이기 위해 rolling DP를 적용할 수 있습니다. 입력을 한 번에 받아 처리하면 더 빠를 수 있습니다. 반복문 내 연산을 최적화하여 MOD 연산 횟수를 줄일 수 있습니다. 마지막 CPU는 계산에서 제외되는데, 이유가 명확하지 않아 확인이 필요합니다. sys.stdin.readline()을 사용하면 입력 처리 속도를 향상시킬 수 있습니다.
MOD = 10**9+7 n = int(input()) cpu = list(map(int, input().split())) dp = [0] * n dp[0] = cpu[0] % MOD sum = dp[0] for i in range(1, n-1): dp[i] = ((dp[i-1] + 1) * cpu[i]) % MOD sum = (sum + dp[i]) % MOD print(sum)이석민
2024-09-02 03:30:41이 코드는 역순으로 순회하며 누적 곱을 계산하는 알고리즘을 사용합니다. 입력을 받아 튜플로 저장하고, 뒤에서부터 현재 값과 이전 누적 값을 곱하여 새로운 누적 값을 계산합니다. 모듈러 연산을 사용하여 큰 수를 다룹니다. 최종 결과는 각 단계의 누적 값을 합한 것입니다. 시간 복잡도는 O(n)입니다. 개선 사항: 1. sys.stdin.readline().split()을 map(int, sys.stdin.read().split())로 변경: 한 번에 모든 입력을 읽어 처리 속도 향상 2. 리스트 컴프리헨션 대신 제너레이터 표현식 사용: 메모리 사용량 감소 3. 모듈러 연산을 비트 연산으로 최적화: 더 빠른 연산 가능 4. 루프 언롤링 적용: 반복문 오버헤드 감소 5. PyPy로 실행: JIT 컴파일러로 인한 성능 향상
import sys # n = 500_000 # multiply = [i for i in range(1, 500_001)] n = int(sys.stdin.readline()) multiply = tuple(map(int, sys.stdin.readline().split(' '))) current = 0 last = 0 result = 0 for i in range(n - 2, -1, -1): current = (current * multiply[i] + multiply[i]) % 1_000_000_007 result = (result + current) % 1_000_000_007 print(result)이석민
2024-09-02 03:04:51이 코드는 동적 프로그래밍(DP) 알고리즘을 사용합니다. 입력으로 받은 수열을 역순으로 순회하며 부분 결과를 저장합니다. 각 단계에서 이전 결과를 활용하여 새로운 값을 계산합니다. 최종 결과는 모든 계산 값의 합을 1,000,000,007로 나눈 나머지입니다. 코드는 O(n) 시간 복잡도를 가집니다. 개선 가능한 점: 1. 메모리 사용량 줄이기: 전체 배열 대신 두 개의 변수만 사용 (공간 복잡도 O(1)) 2. 입력 처리 최적화: sys.stdin.buffer.read()로 한 번에 읽기 3. 모듈로 연산 최적화: (a + b) % m = ((a % m) + (b % m)) % m 성질 활용 4. 반복문 최적화: range() 대신 while 루프 사용 5. 타입 힌팅 추가: 코드 가독성 향상 및 잠재적 버그 방지 이유: 1) 메모리 사용 감소, 2) 입력 처리 시간 단축, 3) 중간 결과 크기 제한으로 오버플로우 방지, 4) 루프 오버헤드 감소, 5) 코드 품질 향상 및 디버깅 용이성
# 30점 부분점수 import sys # n = 500_000 # multiply = [i for i in range(1, 500_001)] n = int(sys.stdin.readline()) multiply = tuple(map(int, sys.stdin.readline().split(' '))) arr = [0] * n arr[-1] = multiply[-1] result = multiply[-1] for i in range(n - 2, 0, -1): arr[i] = arr[i + 1] * multiply[i - 1] + multiply[i - 1] result = (result + arr[i]) % 1_000_000_007 print(result)B (실버3)
코드 제출 (5등) 문제 바로가기이석민
2024-09-08 20:13:05이 코드는 동적 프로그래밍(DP)과 큐를 사용하여 파도반 수열을 계산합니다. 수열의 n번째 항을 구하기 위해 이전 세 항의 합을 이용합니다. 큐를 사용하여 최근 세 항만 유지하며 메모리를 절약합니다. 입력된 테스트 케이스 수만큼 반복하여 각 n에 대한 결과를 출력합니다. 개선 방안: 1. 미리 계산된 결과를 저장하는 캐시를 도입하여 반복 계산 방지 (메모이제이션) 2. 행렬 거듭제곱을 이용한 O(log n) 시간 복잡도 알고리즘으로 변경 3. sys.stdin.readline().rstrip()을 사용하여 입력 처리 최적화 4. 큐 대신 리스트의 슬라이싱을 사용하여 연산 간소화 5. 테스트 케이스별로 함수를 호출하지 않고 한 번에 모든 결과를 계산하여 출력 이유: 캐시로 중복 계산 방지, 행렬 거듭제곱으로 시간 복잡도 개선, 입력 처리 최적화로 실행 시간 단축, 리스트 슬라이싱으로 연산 효율화, 일괄 계산으로 함수 호출 오버헤드 감소
import sys import collections def solve(n): nums = collections.deque((1, 1, 1)) current = 3 if n <= 3: nums[n - 1] while current < n: nums.append(nums.popleft() + nums[0]) current += 1 return nums[-1] T = int(sys.stdin.readline()) for _ in range(T): print(solve(int(sys.stdin.readline())))주병규
2024-09-08 15:46:42이 코드는 동적 프로그래밍(DP) 알고리즘을 사용하여 수열을 생성합니다. 입력된 테스트 케이스 수만큼 반복하며, 각 케이스에 대해 n번째 수열 값을 계산합니다. 초기 5개 값을 설정한 후, 6번째부터는 이전 값과 5번째 이전 값의 합으로 새로운 값을 생성합니다. 미리 계산된 값을 저장하여 재사용하는 메모이제이션 기법을 적용했습니다. 마지막으로, 각 테스트 케이스에 대한 결과를 출력합니다. 개선 가능한 점: 1. 최대 n값을 미리 계산하여 한 번에 수열 생성 (이유: 중복 계산 방지) 2. 리스트 대신 딕셔너리 사용 (이유: 메모리 효율성 향상) 3. 제너레이터 사용하여 메모리 사용 최적화 (이유: 대규모 입력 처리 개선) 4. 입력 받는 방식을 sys.stdin.readline()으로 변경 (이유: 입력 처리 속도 향상) 5. PyPy3로 실행 (이유: 일반적으로 CPython보다 빠른 실행 속도)
t = int(input()) nArr = [int(input()) for _ in range(t)] sieve = [0,1,1,1,2] #6번째 이후 부터는 이전 번째 값 + 5번째 이번 값 for n in nArr: for i in range(len(sieve),n+1): sieve.append(sieve[i-1]+sieve[i-5]) print(sieve[n])배수훈
2024-09-08 15:32:23이 코드는 동적 프로그래밍(DP)을 사용하여 파도반 수열을 계산합니다. 먼저 입력 개수를 받고, DP 배열을 초기화합니다. 점화식을 이용해 DP 배열을 채우고, 각 입력에 대해 결과를 출력합니다. 시간 복잡도는 O(n)입니다. 개선 방안: 1. sys.stdin.buffer.readline()을 사용하여 입력 속도 향상 (바이트 단위 읽기가 더 빠름) 2. 출력 시 f-string 대신 format() 메서드 사용 (약간 더 빠름) 3. 미리 계산된 값을 상수로 저장하여 반복 계산 제거 4. 입력값의 최대치만큼만 DP 배열 계산 (메모리 사용 최적화) 5. 큰 수의 경우 모듈러 연산 추가 (오버플로우 방지)
import sys n = int(sys.stdin.readline()) dp = [0 for i in range(100)] dp[0], dp[1], dp[2] = 1, 1, 1 for i in range(3, 100): dp[i] = dp[i - 3] + dp[i - 2] for i in range(n): x = int(sys.stdin.readline()) sys.stdout.write(f"{dp[x - 1]}\n")이현석
2024-09-08 13:38:00이 코드는 동적 프로그래밍(DP)을 사용하여 파도반 수열을 계산합니다. 초기 값을 설정한 후, 점화식 dp[i] = dp[i-1] + dp[i-5]를 사용해 나머지 값을 채웁니다. 테스트 케이스 수를 입력받고, 각 케이스마다 n을 입력받아 dp[n]을 출력합니다. 미리 계산된 값을 저장하여 반복적인 계산을 피하는 효율적인 방법입니다. 개선 방안: 1. 입력을 한 번에 받아 처리: 입출력 횟수 감소로 시간 절약 2. 리스트 컴프리헨션 사용: 더 빠른 리스트 생성 가능 3. 함수로 분리: 코드 구조화 및 재사용성 향상 4. sys.stdin.readline() 사용: 더 빠른 입력 처리 5. 필요한 만큼만 dp 배열 확장: 메모리 사용 최적화
t = int(input()) dp = [0] * 101 dp[1] = 1 dp[2] = 1 dp[3] = 1 dp[4] = 2 dp[5] = 2 dp[6] = 3 dp[7] = 4 dp[8] = 5 dp[9] = 7 dp[10] = 9 for i in range(11, 101): dp[i] = dp[i-1] + dp[i-5] for _ in range(t): n = int(input()) print(dp[n])C (골드5)
코드 제출 (5등) 문제 바로가기이현석
2024-09-08 18:00:53BFS 알고리즘을 사용하여 격자에서 가장 긴 경로와 그 경로의 시작점과 끝점의 숫자 합을 찾는 문제를 해결합니다. 각 비어있지 않은 셀에서 BFS를 시작하여 가장 먼 셀을 찾고, 그 거리와 숫자 합을 갱신합니다. 방문 배열을 사용하여 각 BFS에서 셀의 방문 여부와 거리를 기록합니다. 최종적으로 가장 긴 경로의 시작점과 끝점 숫자의 합을 출력합니다. 개선 방안: 1. 미리 0이 아닌 셀의 좌표를 리스트에 저장하여 BFS 시작점 탐색 시간 단축 (이유: 불필요한 반복 감소) 2. visited 배열 대신 set을 사용하여 메모리 사용량 감소 (이유: 희소 행렬의 경우 효율적) 3. 경로의 길이가 현재 최대 길이보다 작아지면 BFS 조기 종료 (이유: 불필요한 탐색 방지) 4. 방향 배열 dx, dy를 하나의 리스트로 합치기 (이유: 메모리 접근 횟수 감소) 5. PyPy3로 제출하여 실행 시간 단축 (이유: JIT 컴파일러로 인한 성능 향상)
from collections import deque n, m = map(int, input().split()) grid = [list(map(int, input().split())) for _ in range(n)] dx = [-1, 1, 0, 0] dy = [0, 0, 1, -1] max_len, before_max_len, max_num = 0, 0, 0 def bfs(start_x, start_y): global max_len, before_max_len, max_num visited = [[0] * m for _ in range(n)] q = deque([(start_x, start_y)]) visited[start_x][start_y] = 1 end_x, end_y = start_x, start_y while q: x, y = q.popleft() if grid[x][y] == 0: continue for i in range(4): nx, ny = x + dx[i], y + dy[i] if 0 <= nx < n and 0 <= ny < m and grid[nx][ny] != 0 and not visited[nx][ny]: visited[nx][ny] = visited[x][y] + 1 q.append((nx, ny)) end_x, end_y = nx, ny if visited[end_x][end_y] > max_len: max_len = visited[end_x][end_y] max_num = grid[start_x][start_y] + grid[end_x][end_y] before_max_len = visited[end_x][end_y] elif visited[end_x][end_y] == max_len: max_num = max(max_num, grid[start_x][start_y] + grid[end_x][end_y]) for i in range(n): for j in range(m): if grid[i][j] != 0: bfs(i, j) print(max_num)배수훈(pypy3)
2024-09-08 17:16:44이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 2차원 배열에서 특정 조건을 만족하는 최대 거리와 값을 찾는다. 입력으로 받은 2차원 배열을 순회하며 각 위치에서 BFS를 수행한다. BFS 과정에서 최대 거리와 해당 거리에서의 최대 값을 갱신한다. 모든 위치에 대해 BFS를 수행한 후 전체 최대 거리와 그때의 결과 값을 출력한다. 개선 가능한 부분: 1. 방문 배열을 매번 초기화하지 않고 전역 변수로 사용하면 시간 절약 가능 (메모리 사용량 증가) 2. BFS 대신 플로이드-워셜 알고리즘 사용 가능 (시간 복잡도 O(N^3)로 개선) 3. 불필요한 BFS 호출 줄이기 위해 값이 0인 위치는 건너뛰기 4. 큐 대신 리스트와 투 포인터 사용하여 메모리 사용량 줄이기 5. 방향 배열 d를 상수로 정의하여 매번 zip 연산 피하기
from collections import deque n, m = list(map(int, input().split(" "))) arr = [[0 for j in range(m)] for i in range(n)] for i in range(n): tmp = list(map(int, input().split(" "))) for j in range(m): arr[i][j] = tmp[j] d = list(zip([0, 1, 0, -1], [1, 0, -1, 0])) dm = 0 result = 0 queue = deque() visit = [[False for b in range(m)] for a in range(n)] for i in range(n): for j in range(m): if arr[i][j] == 0: continue queue.clear() queue.append([i, j, 0]) for a in range(n): for b in range(m): visit[a][b] = False visit[i][j] = True dis_max = 1 room_num_max = 0 while len(queue) > 0: next = queue.popleft() x = next[0] y = next[1] dis = next[2] if dis > dis_max: room_num_max = arr[x][y] dis_max = dis elif dis == dis_max: room_num_max = max(room_num_max, arr[x][y]) for dx, dy in d: nx = x + dx ny = y + dy if nx < 0 or nx >= n or ny < 0 or ny >= m: continue if arr[nx][ny] == 0 or visit[nx][ny]: continue visit[nx][ny] = True queue.append([nx, ny, dis + 1]) if (dis_max == 0): continue if dis_max > dm: dm = dis_max result = arr[i][j] + room_num_max elif dis_max == dm: result = max(result, arr[i][j] + room_num_max) print(0 if dm == 0 else result)주병규
2024-09-08 15:51:20이 코드는 BFS(너비 우선 탐색) 알고리즘을 사용하여 2D 그리드에서 가장 긴 경로를 찾는다. 모든 셀에서 BFS를 시작하여 최대 거리와 해당 경로를 찾는다. 최대 거리에 도달하는 모든 경로를 저장하고, 시작점과 끝점의 값 합이 가장 큰 경로를 선택한다. 전체 그리드를 순회하며 각 셀에서 BFS를 실행하는 브루트 포스 방식을 사용한다. 큐를 사용하여 BFS를 구현하고, 방문한 셀을 추적하기 위해 집합을 사용한다. 마지막으로, 가능한 모든 최장 경로 중에서 시작점과 끝점의 값 합이 최대인 경로를 찾아 결과를 출력한다. 개선 방안: 1. 다이나믹 프로그래밍을 사용하여 중복 계산 줄이기: 이미 계산된 경로 재사용 가능. 2. 양방향 BFS 도입: 시작점과 끝점에서 동시에 BFS 실행하여 탐색 공간 축소. 3. A* 알고리즘 사용: 휴리스틱 함수로 더 효율적인 경로 탐색 가능. 4. 그리드 전처리로 불필요한 탐색 제거: 연결된 구성요소 식별하여 탐색 범위 축소. 5. 병렬 처리 도입: 여러 시작점에서 동시에 BFS 실행하여 전체 실행 시간 단축.
from collections import deque n, m = map(int, input().split()) mapGrid = [list(map(int, input().split())) for _ in range(n)] maxVal = 0 maxResults = [] def bfs(i, j): visited = set() queue = deque([(i, j, 0)]) global maxVal,maxResults while queue: row, column, cnt = queue.popleft() # visit한 곳이거나 0이라서 갈 수 없는 곳이라면 continue if (row, column) in visited or mapGrid[row][column] == 0: continue visited.add((row, column)) #현재까지 길이 중 가장 긴 길이라면 maxVal과 maxResults를 갱신 if cnt > maxVal: maxVal = cnt maxResults = [(i,j,row, column)] #현재까지 길이가 maxVal과 같다면 maxResults에 추가 elif cnt == maxVal: maxResults.append((i,j,row, column)) if row > 0: queue.append((row - 1, column, cnt + 1)) if row < n - 1: queue.append((row + 1, column, cnt + 1)) if column > 0: queue.append((row, column - 1, cnt + 1)) if column < m - 1: queue.append((row, column + 1, cnt + 1)) #브루트 포스로 모든 경우의 수를 탐색 for i in range(n): for j in range(m): bfs(i,j) result = 0 for startI,startJ,endI,endJ in maxResults: result = max(result,mapGrid[endI][endJ] + mapGrid[startI][startJ]) print(result)이석민
2024-09-08 12:29:54이 코드는 BFS 알고리즘을 사용하여 격자에서 가장 멀리 떨어진 두 점을 찾는 문제를 해결합니다. 각 육지 지점에서 BFS를 수행하여 가장 먼 육지를 찾고, 그 거리와 두 점의 높이 합을 계산합니다. 모든 육지 지점에 대해 이 과정을 반복하여 최대 거리와 최대 높이 합을 찾습니다. 입력을 받고 결과를 출력하는 부분도 포함되어 있습니다. 개선 가능한 부분: 1. 방문 배열 대신 집합을 사용하여 메모리 사용량 줄이기 (더 빠른 검색 가능) 2. 불필요한 좌표 검사를 BFS 큐에 넣기 전에 수행하여 큐 크기 줄이기 3. 전역 방문 배열을 사용하여 각 BFS마다 새로운 배열 생성 방지 4. 미리 육지 좌표만 저장하여 불필요한 반복 줄이기 5. 다익스트라 알고리즘을 사용하여 모든 점에서의 최단 거리를 한 번에 계산 가능 이유: 메모리 사용 최적화, 불필요한 연산 제거, 전체 실행 시간 단축을 위함입니다.
import sys import collections y_len, x_len = map(int, sys.stdin.readline().split(' ')) matrix = [tuple(map(int, sys.stdin.readline().split(' '))) for _ in range(y_len)] def fartest(x, y): visited = [[0] * x_len for _ in range(y_len)] to_visit = collections.deque() if matrix[y][x] == 0: return -1, -1 to_visit.append((x, y, 0)) last = (-1, -1, -1) while to_visit: x_cur, y_cur, l = to_visit.popleft() if y_cur < 0 or y_cur >= y_len: continue if x_cur < 0 or x_cur >= x_len: continue if matrix[y_cur][x_cur] == 0: continue if visited[y_cur][x_cur] != 0: continue last = (x_cur, y_cur, l) visited[y_cur][x_cur] = 1 to_visit.append((x_cur + 1, y_cur, l + 1)) to_visit.append((x_cur - 1, y_cur, l + 1)) to_visit.append((x_cur, y_cur + 1, l + 1)) to_visit.append((x_cur, y_cur - 1, l + 1)) return last[2], matrix[y][x] + matrix[last[1]][last[0]] max_l, max_s = 0, 0 for cur_y in range(y_len): for cur_x in range(x_len): l, s = fartest(cur_x, cur_y) if l == -1: continue if max_l < l: max_l = l max_s = s elif max_l == l and max_s < s: max_s = s print(max_s)D (골드5)
코드 제출 (5등) 문제 바로가기배수훈
2024-09-08 19:32:33이 코드는 그리디 알고리즘을 사용하여 전자레인지 버튼 조작 횟수를 최소화합니다. 입력된 시간을 60초, 10초, 1초 단위로 분해하고, 5초 이상일 때 10초 버튼을 추가로 누르는 최적화를 수행합니다. 30초에서 60초 사이의 특수 케이스를 처리하며, 최종적으로 각 버튼의 누름 횟수를 계산합니다. 결과는 리스트에 저장되어 출력됩니다. 개선 사항: 1. 입력을 한 번에 받아 처리하면 I/O 시간을 줄일 수 있습니다. 2. 리스트 컴프리헨션 대신 튜플을 사용하여 메모리 사용을 줄일 수 있습니다. 3. 나눗셈 연산을 비트 연산으로 대체하여 속도를 높일 수 있습니다. 4. 조건문을 간소화하여 코드 실행 시간을 줄일 수 있습니다. 5. 미리 계산된 룩업 테이블을 사용하여 반복적인 계산을 피할 수 있습니다.
size = int(input()) for i in range(size): n = int(input()) buttons = [0 for i in range(5)] sixties, tens, ones = n // 60, (n % 60) // 10, n % 10 if ones > 5: tens += 1 ones -= 10 if tens > 3: sixties += 1 tens -= 6 if tens < 0 and ones == 5: # 30~60인데 일의 자리가 5인 경우는 빼는게 낫다. tens += 1 ones -= 10 buttons[0] = sixties buttons[1 if tens >= 0 else 2] = abs(tens) buttons[3 if ones >= 0 else 4] = abs(ones) print(*buttons)이현석
2024-09-08 19:27:33이 코드는 그리디 알고리즘을 사용하여 시간을 화폐로 변환합니다. 60분 단위로 먼저 처리하고, 남은 시간을 35분을 기준으로 나눠 처리합니다. 35분 이상일 경우 60분에서 뺀 후 10분 단위로 계산하고, 35분 미만일 경우 바로 10분 단위로 계산합니다. 각 단계에서 5분을 기준으로 올림 또는 내림 처리를 합니다. 결과는 5개의 화폐 단위로 출력됩니다. 개선 사항: 1. 미리 계산된 룩업 테이블 사용 (더 빠른 접근 가능) 2. 비트 연산으로 나눗셈과 모듈로 연산 최적화 (더 빠른 연산) 3. 문자열 조인 대신 f-string 사용 (약간 더 빠름) 4. if-else 구조를 딕셔너리로 대체 (더 간결하고 빠를 수 있음) 5. 입력을 한 번에 받아 처리 (I/O 작업 감소)
t = int(input()) for _ in range(t): n = int(input()) result = [0] * 5 x = n if x > 60: result[0] += x // 60 x %= 60 if x > 35: result[0] += 1 x = 60 - x if x % 10 > 5: result[2] += x // 10 + 1 result[3] += 10 - (x % 10) else: result[2] += x // 10 result[4] += x % 10 else: if x % 10 > 5: result[1] += x // 10 + 1 result[4] += 10 - (x % 10) else: result[1] += x // 10 result[3] += x % 10 print(" ".join(map(str, result)))이석민
2024-09-08 16:33:02이 코드는 동적 프로그래밍(DP)과 분할 정복 방식을 사용한 알고리즘입니다. 주어진 시간을 시, 10분, 1분 단위로 나누어 계산합니다. 각 단계에서 최적의 해를 찾기 위해 재귀적으로 솔루션을 호출합니다. min_state 함수를 통해 두 상태를 비교하여 최적의 상태를 선택합니다. 음수 처리를 위한 로직도 포함되어 있습니다. 마지막으로 최종 결과를 출력합니다. 개선 가능한 점: 1. 재귀 대신 반복문 사용: 스택 오버플로우 방지, 실행 속도 향상 2. 메모이제이션 도입: 중복 계산 방지로 시간 복잡도 개선 3. 비트마스킹 활용: 상태 저장 및 비교 연산 최적화 4. 그리디 알고리즘 고려: 특정 경우 더 빠른 해결 가능 5. 입력 처리 최적화: sys.stdin.readline().rstrip()으로 개행 문자 제거
import sys T = int(sys.stdin.readline()) def sum_state(a: dict[str, int]): return sum(a.values()) def min_state(a: dict[str, int], b: dict[str, int]): a_sum, b_sum = sum_state(a), sum_state(b) # print(a, b) if a_sum < b_sum: return a elif b_sum < a_sum: return b if a['ADDH'] < b['ADDH']: return a elif a['ADDH'] > b['ADDH']: return b if a['ADDT'] < b['ADDT']: return a elif a['ADDT'] > b['ADDT']: return b if a['MINT'] < b['MINT']: return a elif a['MINT'] > b['MINT']: return b if a['ADDO'] < b['ADDO']: return a elif a['ADDO'] > b['ADDO']: return b if a['MINO'] < b['MINO']: return a elif a['MINO'] > b['MINO']: return b # 아예 똑같은 경우 return a def solution(n: int): # cnt, result = 10_000_000, {'ADDH': 10_000_000, 'ADDT': 10_000_000, 'MINT': 10_000_000, 'ADDO': 10_000_000, 'MINO': 10_000_000} def solution_10(n: int, state: dict[str, int]): state_1 = dict(state) state_2 = dict(state) if abs(n) % 10 == 0: if n < 0: state_1['MINT'] = abs(n) // 10 return state_1 state_1['ADDT'] = n // 10 return state_1 if n < 0: state_1['MINT'] = abs(n) // 10 state_2['MINT'] = (abs(n) // 10) + 1 MINT_1 = (n % 10 - 10, state_1) MINT_2 = (n % 10, state_2) a = solution_1(*MINT_1) b = solution_1(*MINT_2) # print(a, b) return min_state(a, b) else: state_1['ADDT'] = n // 10 state_2['ADDT'] = (n // 10) + 1 ADDT_1 = (n % 10 , state_1) ADDT_2 = (n % 10 - 10, state_2) a = solution_1(*ADDT_1) b = solution_1(*ADDT_2) return min_state(a, b) def solution_1(n: int, state: dict[str, int]): state1 = dict(state) state2 = dict(state) if n < 0: state1['MINO'] = abs(n) return state1 state2['ADDO'] = n return state2 ADDH_1 = (n % 60, {'ADDH': n // 60, 'ADDT': 0, 'MINT': 0, 'ADDO': 0, 'MINO': 0}) ADDH_2 = (n % 60 - 60, {'ADDH': n // 60 + 1, 'ADDT': 0, 'MINT': 0, 'ADDO': 0, 'MINO': 0}) ADDH_1 = solution_10(*ADDH_1) # 108이라는 숫자가 왔을때, 60 -> +48로 갈수도 ADDH_2 = solution_10(*ADDH_2) # 108이라는 숫자가 왔을때, 120 -> -12로 갈수도 # print(ADDH_1, ADDH_2) return min_state(ADDH_1, ADDH_2) for _ in range(T): result = solution(int(sys.stdin.readline())) print(result['ADDH'], result['ADDT'], result['MINT'], result['ADDO'], result['MINO'])주병규
2024-09-08 15:59:36이 코드는 시간을 버튼 입력으로 변환하는 그리디 알고리즘을 사용합니다. 입력된 시간을 시, 10분, 1분 단위로 분해합니다. 1분 버튼이 5번 이상 필요할 경우 10분 버튼을 대신 사용합니다. 10분 버튼이 3번 이상 필요할 경우 1시간 버튼을 대신 사용합니다. 음수 시간 처리를 위해 특별한 로직을 사용합니다. 마지막으로 각 버튼의 필요 횟수를 계산하여 출력합니다. 개선 가능한 점: 1. 입력 처리를 list comprehension 대신 map()으로 변경하여 메모리 사용 줄이기 (큰 입력에 효과적) 2. button 리스트 대신 튜플 사용으로 메모리 절약 (불변성 활용) 3. 나눗셈 연산 최소화를 위해 비트 연산 사용 (60으로 나누는 대신 >> 연산자 활용) 4. 조건문 간소화 및 불필요한 연산 제거 (if-else 구조 최적화) 5. 전체 로직을 함수로 묶어 재사용성 높이고 전역 변수 사용 줄이기 (코드 구조 개선)
from collections import deque t = int(input()) nArr = [int(input()) for _ in range(t)] for n in nArr: #각 addt과 addo는 양수일때는 그대로 addt,addo 값이며 이가 음수 일때는 줄여야 한다고 판단하여 각 mint,mino값이 된다 button = [0]*5 addh = n//60 addt = (n%60)//10 addo = n%10 #addo가 5이상일시 상위 시간(10분)을 돌려줘고 addo를 10분 줄이는 것이 이득 if addo >5 : addt+=1 addo-=10 #addt가 3이상일시 상위 시간(1시간)을 돌려줘고 addt를 6분 줄이는 것이 이득 if addt >3: addh+=1 addt-=6 #addt가 음수일때(mint가 1이상일때) 우선 순위고 addt가 더 높음으로 addo를 줄이고 addt를 늘리는 것이 더 이득이다 if addt<0 and addo ==5: addt+=1 addo-=10 button[0] = addh button[2-(addt>=0)] = abs(addt) button[4-(addo>=0)] = abs(addo) print(*button)E (골드5)
코드 제출 (4등) 문제 바로가기배수훈
2024-09-08 21:02:32BFS 알고리즘을 사용하여 직사각형 모양의 문자 블록을 확인하는 코드입니다. 입력된 2차원 배열에서 각 문자 블록의 크기를 계산하고 실제 크기와 비교합니다. 큐를 사용하여 BFS 탐색을 수행하며, 방문 여부를 체크합니다. 모든 블록이 올바른 직사각형 모양이면 "dd"를, 그렇지 않으면 "BaboBabo"를 출력합니다. 개선 사항: 1. 불필요한 반복문 제거: 전체 배열을 순회하지 않고 첫 번째 미방문 셀에서 시작할 수 있습니다. 2. 방문 배열 대신 집합 사용: 메모리 사용량 감소 및 검색 속도 향상을 위해 집합을 사용할 수 있습니다. 3. 인라인 함수 사용: 좌표 유효성 검사를 위한 인라인 함수를 사용하여 코드 가독성을 높일 수 있습니다. 4. 더 효율적인 크기 계산: 실제 크기를 계산할 때 BFS 대신 DFS를 사용하여 스택 메모리를 활용할 수 있습니다. 5. early return 사용: 잘못된 블록을 발견하면 즉시 함수를 종료하여 불필요한 계산을 줄일 수 있습니다.
from collections import deque n, m = map(int, input().split(" ")) arr = [input() for i in range(n)] visit = [[False for j in range(m)] for i in range(n)] flag = False for i in range(n): if flag: break for j in range(m): if visit[i][j]: continue ch = arr[i][j] y = j while y < m and arr[i][y] == ch: y += 1 x = i while x < n and arr[x][j] == ch: x += 1 size = (i - x) * (j - y) queue = deque() queue.append([i, j]) visit[i][j] = True real_size = 1 while len(queue) > 0: next = queue.popleft() x = next[0] y = next[1] for dx, dy in zip([0, 1], [1, 0]): nx = x + dx ny = y + dy if nx >= n or ny >= m: continue if arr[nx][ny] != ch: continue if visit[nx][ny]: continue real_size += 1 queue.append([nx, ny]) visit[nx][ny] = True if size != real_size: print("BaboBabo") flag = True break if flag == False: print("dd")이석민
2024-09-08 18:05:39BFS 알고리즘을 사용하여 정사각형 모양의 문자 패턴을 확인합니다. 입력된 2차원 문자열 배열에서 각 위치를 시작점으로 BFS를 수행하며 정사각형 패턴을 검사합니다. 대각선 방향으로의 확장을 고려하여 정사각형의 경계를 결정하고, 내부 영역을 BFS로 탐색하며 동일한 문자로 구성되어 있는지 확인합니다. 모든 위치에서 정사각형 패턴이 유효하면 'dd'를, 하나라도 유효하지 않으면 'BaboBabo'를 출력합니다. 개선 사항: 1. 방문 배열을 깊은 복사하지 않고 전역 변수로 사용하여 메모리 사용량 감소 (이미 그렇게 구현됨) 2. 정사각형 경계 결정 시 이진 탐색 사용으로 시간 복잡도 개선 가능 (O(n) → O(log n)) 3. BFS 대신 DFS 사용하여 스택 메모리 활용, 재귀 제한에 주의 4. 문자열 입력 시 sys.stdin.readline().rstrip() 사용하여 개행 문자 제거 최적화 5. collections.deque 대신 리스트를 사용하여 메모리 사용량 감소 가능, 큰 입력에서는 deque가 유리
import sys import collections import copy height, width = map(int, sys.stdin.readline().split(' ')) matrix = [list(sys.stdin.readline().strip()) for _ in range(height)] visited = [[False] * width for _ in range(height)] def is_square(x, y): global matrix, visited, height, width partial_width = 0 partial_height = 0 approx_width = 0 approx_height = 0 char = matrix[y][x] for cur_x in range(x, width): if matrix[y][cur_x] != char: break approx_width = cur_x for cur_y in range(y, height): if matrix[cur_y][x] != char: break approx_height = cur_y # visited_local = copy.deepcopy(visited) to_visit = collections.deque() to_visit.append((x, y)) ## boundary check while to_visit: (cur_x, cur_y) = to_visit.popleft() # print(char, cur_x, cur_y) if cur_x < 0 or cur_x >= width: continue if cur_y < 0 or cur_y >= height: continue if matrix[cur_y][cur_x] != char: ## approx_width, height에 가기 전에 이미 다른게 막으면... 그건 중간에 뭐가 있는거니까 중지 if (y <= cur_y <= approx_height) and (x <= cur_x <= approx_width): # print(y, cur_y, approx_height, x, cur_x, approx_width) # print('t') return False continue if visited[cur_y][cur_x] == True: continue if (y <= cur_y <= approx_height) == False or (x <= cur_x <= approx_width) == False: # print(y, cur_y, approx_height, x, cur_x, approx_width) return False visited[cur_y][cur_x] = True partial_width = max(partial_width, cur_x) partial_height = max(partial_height, cur_y) to_visit.append((cur_x + 1, cur_y)) to_visit.append((cur_x - 1, cur_y)) to_visit.append((cur_x, cur_y + 1)) to_visit.append((cur_x, cur_y - 1)) # 대각선만 검사해 보는거로 (전체 검사하니 시간초과) # for cur_y in range(y, partial_height + 1): # if matrix[cur_y][x] != char: # return False # if matrix[cur_y][partial_width] != char: # return False # for cur_x in range(x, partial_width + 1): # if matrix[y][cur_x] != char: # return False # if matrix[partial_height][cur_x] != char: # return False return True for y in range(height): for x in range(width): if visited[y][x] == True: continue if is_square(x, y) == False: print('BaboBabo') exit() print('dd')주병규
2024-09-08 16:09:26이 코드는 BFS 알고리즘을 사용하여 그리드를 탐색합니다. 각 문자 영역을 찾고, 해당 영역 내에 구멍이 있는지 확인합니다. BFS로 같은 문자로 이루어진 영역을 탐색하며 최대/최소 좌표를 기록합니다. 영역 내 모든 좌표를 방문했는지 확인하여 구멍 유무를 판단합니다. 전체 그리드를 순회하며 각 미방문 좌표에서 BFS를 시작합니다. 구멍이 발견되면 "BaboBabo"를, 아니면 "dd"를 출력합니다. 개선 사항: 1. 방문 체크를 2D 배열로 변경 (set 대신): 메모리 접근 속도 향상 2. BFS 대신 DFS 사용: 재귀로 구현하면 코드 간소화 가능 3. 최대/최소 좌표 대신 전체 영역 크기만 계산: 불필요한 연산 제거 4. 방향 배열 사용: 코드 간소화 및 가독성 향상 5. 입력 받을 때 strip() 사용: 불필요한 공백 제거로 안정성 향상
from collections import deque n, m = map(int, input().split()) grid = [list(input()) for _ in range(n)] visited = set() def check(i, j): char = grid[i][j] checkVisited = set() queue = deque([(i, j)]) maxI, maxJ = i, j minI, minJ = i, j while queue: currentI, currentJ = queue.popleft() #상하좌우 중 같은 글자를 가진 곳만 visit if (currentI, currentJ) in checkVisited or char != grid[currentI][currentJ]: continue checkVisited.add((currentI, currentJ)) #방분한 곳의 좌우 끝값 maxI = max(currentI, maxI) maxJ = max(currentJ, maxJ) minI = min(currentI, minI) minJ = min(currentJ, minJ) if currentI < n - 1: queue.append((currentI + 1, currentJ)) if currentJ < m - 1: queue.append((currentI, currentJ + 1)) if currentI > 0: queue.append((currentI - 1, currentJ)) if currentJ > 0: queue.append((currentI, currentJ - 1)) visited.update(checkVisited) #방문한 곳의 좌우 끝값을 이용해 방문하지 않은 곳이 있는지 확인 for row in range(minI, maxI + 1): for column in range(minJ, maxJ + 1): if (row, column) not in checkVisited: return True return False found = False for i in range(n): for j in range(m): if (i, j) not in visited: if check(i, j): print("BaboBabo") found = True break if found: break if not found: print("dd")보너스 (골드5)
코드 제출 (3등) 문제 바로가기이석민
2024-09-08 19:54:54이 코드는 2차원 격자에서 주어진 단어를 찾는 문제를 해결하는 다이나믹 프로그래밍(DP) 알고리즘을 사용합니다. 재귀 함수와 메모이제이션을 활용하여 중복 계산을 피하고 효율성을 높입니다. 8방향 탐색을 통해 단어를 찾으며, 각 위치에서 시작하는 경우의 수를 계산합니다. 3차원 DP 테이블을 사용하여 현재 위치와 단어의 길이에 따른 결과를 저장합니다. 최종적으로 모든 시작 위치에서의 경우의 수를 합산하여 결과를 출력합니다. 개선 가능한 부분: 1. 불필요한 재귀 호출 제거: 범위 체크를 먼저 수행하여 불필요한 호출 감소 2. 방향 배열 사용: 8방향 탐색을 위한 dx, dy 배열 활용으로 코드 간소화 3. 입력 최적화: sys.stdin.readline().split()을 한 번만 호출하여 입력 처리 속도 향상 4. 메모리 사용 최적화: 3차원 리스트 대신 튜플을 키로 사용하는 딕셔너리로 변경 5. 반복문 사용: 깊이가 깊지 않은 경우 반복문으로 변경하여 재귀 오버헤드 감소
import sys import collections sys.setrecursionlimit(1000) from typing import * H, W, L = map(int, sys.stdin.readline().split(' ')) matrix = [tuple(sys.stdin.readline().rstrip()) for _ in range(H)] FIND_WORD = sys.stdin.readline() quick_path = [[dict() for _ in range(W)] for _ in range(H)] def find_len(x, y): global quick_path, matrix # def optimized_recursive(x, y, l, debug_path: List[str]): def optimized_recursive(x, y, l, debug_path: List[str] = []): if (0 <= x < W) == False or (0 <= y < H) == False: return 0 if l == L - 1 and matrix[y][x] == FIND_WORD[L - 1]: # reach to the end # print('===>', x, y) return 1 if l in quick_path[y][x]: return quick_path[y][x][l] if matrix[y][x] != FIND_WORD[l]: quick_path[y][x][l] = 0 return 0 # print(debug_path, x, y) # debug_path.append((matrix[y][x], x, y)) # way4 = optimized_recursive(x - 1, y, l + 1, debug_path) + optimized_recursive(x + 1, y, l + 1, debug_path) + optimized_recursive(x, y + 1, l + 1, debug_path) + optimized_recursive(x, y - 1, l + 1, debug_path) # cross = optimized_recursive(x - 1, y + 1, l + 1, debug_path) + optimized_recursive(x - 1, y - 1, l + 1, debug_path) + optimized_recursive(x + 1, y + 1, l + 1, debug_path) + optimized_recursive(x + 1, y - 1, l + 1, debug_path) way4 = optimized_recursive(x - 1, y, l + 1) + optimized_recursive(x + 1, y, l + 1) + optimized_recursive(x, y + 1, l + 1) + optimized_recursive(x, y - 1, l + 1) cross = optimized_recursive(x - 1, y + 1, l + 1) + optimized_recursive(x - 1, y - 1, l + 1) + optimized_recursive(x + 1, y + 1, l + 1) + optimized_recursive(x + 1, y - 1, l + 1) # debug_path.pop() quick_path[y][x][l] = way4 + cross return quick_path[y][x][l] # print(x, y) return optimized_recursive(x, y, 0) cnt = 0 for y in range(H): for x in range(W): cnt += find_len(x, y) print(cnt)주병규
2024-09-08 16:14:43이 코드는 격자에서 주어진 단어를 찾는 문제를 해결하는 동적 프로그래밍(DP) 알고리즘을 사용합니다. 격자를 순회하며 첫 글자를 찾고, 이후 각 글자에 대해 8방향으로 이전 글자를 찾아 경우의 수를 누적합니다. 2D DP 배열을 사용하여 각 위치에서 끝나는 부분 단어의 경우의 수를 저장하고, 다음 글자로 넘어갈 때마다 새로운 DP 배열을 생성합니다. 마지막 글자에 대한 모든 경우의 수를 합산하여 최종 결과를 출력합니다. 개선 방안: 1. 불필요한 격자 순회 제거: 현재 글자가 있는 위치만 저장하고 다음에 그 주변만 확인 이유: 전체 격자를 매번 순회하는 것보다 효율적 2. 비트마스킹 활용: 8방향 확인을 비트 연산으로 최적화 이유: 방향 확인 로직을 더 빠르게 처리 가능 3. 롤링 해시 적용: 단어 비교를 상수 시간에 수행 이유: 긴 단어에 대해 문자열 비교 시간 단축 4. 메모이제이션: 이미 계산된 부분 문자열의 결과를 저장하여 재사용 이유: 중복 계산 방지로 시간 절약 5. KMP 알고리즘 응용: 단어 패턴 매칭을 더 효율적으로 수행 이유: 문자열 검색 속도 향상 가능
h, w, l = map(int, input().split()) grid = [list(input()) for _ in range(h)] word = input() directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)] dp = [[0] * w for _ in range(h)] answer = 0 #첫번째 글자는 1로 시작 for i in range(h): for j in range(w): if grid[i][j] == word[0]: dp[i][j] = 1 #이전 글자의 위치를 찾아서 그 위치의 값만큼 더해준다 #이전 글자의 위치는 8방향으로 갈 수 있는 위치이며 해당 위치에 이전 글자가 있는지 확인한다 #이전 글자가 있다면 해당 위치의 값을 가져와서 현재 위치의 값을 더해준다 #이렇게 하면 해당 위치에 현재 글자가 있는 경우의 수를 구할 수 있다 for idx in range(1, len(word)): #중복된 글자가 있을 경우 해당 값이 원하는 값보다 더 증가함으로 #바로 이전의 기록만 저장해준다 next_dp = [[0] * w for _ in range(h)] answer=0 for i in range(h): for j in range(w): if grid[i][j] == word[idx]: value = 0 for di, dj in directions: ni, nj = i + di, j + dj #갈 수 있는 곳이며 해당 위치에 글자가 바로 이전의 글자라면 값을 가져온다 if 0 <= ni < h and 0 <= nj < w and grid[ni][nj] == word[idx - 1]: value += dp[ni][nj] next_dp[i][j] = value answer+=value dp = next_dp print(answer)
2024-09-01 21:00:00 (5문제)
주식 가격
코드 제출 (6등) 문제 바로가기주병규
2024-09-01 18:23:24주어진 가격 목록에서 각 가격보다 높은 가격이 나오는 날짜를 계산합니다. 이 코드는 두 개의 중첩 루프를 사용하여 모든 가격에 대해 모든 이후 가격과 비교하며, 이는 시간 복잡도가 O(N^2)입니다. 더 빠른 실행 시간을 위해 이중 루프를 단일 루프로 대체하여 각 가격에 대해 이후 가격을 스캔하는 대신 각 가격에 대해 마지막으로 더 높은 가격을 저장하고, 해당 가격이 현재 가격보다 높으면 카운터를 증가시킬 수 있습니다. 이렇게 하면 시간 복잡도가 O(N)으로 줄어듭니다. 또한 각 이터레이션에서 현재 가격이 이전 가격보다 큰지 여부를 확인하여 해당 지점 이후의 값은 더 이상 확인할 필요가 없으므로 중첩 루프의 안쪽 루프를 추가로 최적화할 수 있습니다.
def solution(prices): length = len(prices) answer = [0]*length for i in range(length): for j in range(i+1,length): answer[i] +=1 if prices[i]>prices[j]: break #떨어지는 시점 확인 (ex) i는 0일때 index가 3인 순간에 값이 이전 값 보다 작음으로 이때 까지 answer의 값을 증가시킨다) return answer하지웅
2024-09-01 17:21:14주어진 가격 목록에서 각 가격보다 나중에 더 높은 가격이 몇 개 있는지 계산하는 함수입니다. 이중 for 루프를 사용하여 모든 가격 쌍을 비교하여 계산합니다. 시간 복잡도는 O(n^2)으로, 입력 크기가 커지면 실행 시간이 급격히 증가합니다. i 번째 가격 이후의 가격 중 가장 낮은 가격을 기억하여 불필요한 비교를 줄이면 시간 복잡도를 O(n)으로 줄일 수 있습니다.
def solution(prices): answer = [0] * len(prices) for i in range(len(prices)): for j in range(i + 1, len(prices)): answer[i] += 1 if prices[j] < prices[i]: break return answer이석민
2024-08-30 00:59:39주어진 가격 목록에서 각 가격에 대해 해당 가격보다 낮은 가격이 나오는 가장 빠른 시간을 찾는 알고리즘입니다. 최소 힙을 사용하여 효율적으로 탐색을 수행합니다. 힙 데이터 구조를 사용하여 탐색 과정을 최적화했지만, 힙 데이터 구조를 대신하여 이진 트리, 해시 테이블 등 다른 자료 구조를 사용하는 것을 고려하면 더 빠른 실행 시간을 얻을 수 있습니다. 또한, 반복문 내에서 힙에서 요소를 제거하는 조건을 최적화하거나, 힙에서 요소를 제거하는 작업을 더욱 효율적으로 수행할 수 있는 자료 구조를 사용하는 것을 고려할 수 있습니다.
import heapq def solution(prices): pricelist = list() result = [0] * len(prices) for idx, p in enumerate(prices): while len(pricelist) > 0 and pricelist[0][0] < -p: price, pos = heapq.heappop(pricelist) result[pos] = idx - pos heapq.heappush(pricelist, (-p, idx)) # on remain while len(pricelist) > 0: price, pos = pricelist.pop() result[pos] = len(prices) - pos - 1 return result이현석
2024-08-27 12:19:26주어진 가격 리스트에서 각 가격보다 나중에 더 낮은 가격이 나오는 최소 시간을 찾는 알고리즘입니다. 스택을 이용하여 각 가격에 대한 다음 낮은 가격을 찾고, 이를 이용하여 최소 시간을 계산합니다. 시간 복잡도는 O(N)으로, 각 가격을 최대 두 번씩만 스택에 넣고 뺄 수 있기 때문에 효율적입니다. 더 빠른 실행 시간을 위해, 스택에 넣기 전에 현재 가격이 스택의 마지막 가격보다 작거나 같은 경우, 스택의 마지막 가격을 제거하고 현재 가격을 추가하는 방식으로 최적화할 수 있습니다. 이렇게 하면 불필요한 스택 연산을 줄일 수 있습니다. 또한, 스택에 넣기 전에 현재 가격이 스택의 마지막 가격보다 작거나 같은 경우, 스택의 마지막 가격을 제거하고 현재 가격을 추가하는 방식으로 최적화할 수 있습니다. 이렇게 하면 불필요한 스택 연산을 줄일 수 있습니다.
def solution(prices): length = len(prices) answer = [0] * length stack = [] for i in range(length): while stack and prices[stack[-1]] > prices[i]: j = stack.pop() answer[j] = i - j stack.append(i) while stack: j = stack.pop() answer[j] = length - j - 1 return answer배수훈
2024-08-26 11:32:06주어진 가격 목록에서 각 가격이 다음 낮은 가격보다 얼마나 오래 유지되는지를 계산하는 알고리즘입니다. 스택을 사용하여 이전 가격 정보를 유지하고 앞에서부터 순회하며 계산하여 결과를 역순으로 반환합니다. 현재 코드는 스택에 대한 반복적인 탐색을 사용하여 시간 복잡도가 O(N^2) 입니다. 스택을 활용한 탐색을 한 번에 수행할 수 있도록 탐색을 한 번으로 축소하여 시간 복잡도를 O(N)으로 줄일 수 있습니다. 예를 들어, 현재 탐색 중에 최솟값을 기록하고, 만약 현재 값이 최솟값보다 작으면 최솟값을 갱신하고, 현재 값이 최솟값보다 크면 현재 값과 최솟값 사이의 거리를 계산하여 결과에 추가하는 방식으로 구현할 수 있습니다. 또한, deque의 pop 연산을 사용할 때 len 연산을 사용하는 대신 deque의 pop 함수는 O(1) 시간을 사용하며 len 함수는 O(N) 시간을 사용하므로 pop 함수를 사용하는 것이 더 효율적입니다.
from collections import deque def solution(prices): n = len(prices) dq = deque() result = [] for i in range(n - 1, -1, -1): cnt = 0 while True: if len(dq) == 0: result.append(n - i - 1) dq.append([prices[i], i]) break top = dq[len(dq) - 1] if top[0] >= prices[i]: dq.pop() else: result.append(top[1] - i) dq.append([prices[i], i]) break return result[::-1]이석민
2024-08-25 22:18:58주어진 가격 목록에서 각 가격이 팔릴 때까지 걸리는 시간을 계산하는 알고리즘입니다. 스택을 이용하여 이전 가격보다 낮은 가격이 나타날 때까지 기다리며, 낮은 가격이 나타나면 스택에서 해당 가격을 꺼내 판매 시간을 계산합니다. 스택에 저장된 정보는 가격과 인덱스로 구성되어 있고, 스택이 비어있으면 현재 가격이 마지막 가격이므로 마지막 인덱스와 현재 인덱스 차이를 판매 시간으로 계산합니다. 반복문을 이용해 스택을 순회하면서 모든 가격에 대한 판매 시간을 계산할 수 있으며, 스택의 크기가 작아지면 판매 시간을 계산하는 데 걸리는 시간을 줄일 수 있습니다. 또한, 가격 비교 시 `if` 문과 `else` 문을 사용하는 대신, `if` 문과 `else` 문의 조건을 결합하여 하나의 `if` 문으로 처리할 수 있습니다. 이처럼 조건문을 통합하면 불필요한 비교 연산을 줄일 수 있습니다.
def solution(prices): s = list() answer = prices.copy() for x in range(len(prices)): while len(s) > 0: if s[-1][0] > prices[x]: item = s.pop() answer[item[1]] = (x - item[1]) else: break s.append((prices[x], x)) x = len(prices) - 1 for (_, i) in s: answer[i] = x - i return answer기능 개발
코드 제출 (6등) 문제 바로가기주병규
2024-09-01 18:28:05이 코드는 진행도와 속도를 입력으로 받아 각 기능의 개발 완료까지 걸리는 시간을 계산하고, 동시에 배포 가능한 기능의 묶음(배포 횟수)을 반환합니다. 각 기능별 남은 작업 시간을 계산하여 스택에 저장하고, 스택을 순회하며 이전 기능의 완료 시점과 현재 기능의 완료 시점을 비교하여 동시 배포 가능한 기능의 묶음을 구합니다. 시간 복잡도는 O(N)으로, N은 기능의 개수입니다. 스택을 활용한 순회를 통해 각 기능의 남은 작업 시간을 한 번씩만 계산하고 검사하며, 묶음 정보를 계산하는데 추가적인 반복문 없이 진행됩니다. 더 빠른 실행 시간을 위해, 남은 작업 크기와 속도를 이용하여 필요한 시간을 구할 때 나눗셈 연산 대신 곱셈 연산을 사용할 수 있습니다. 예를 들어, `num//speeds[idx]` 대신 `num * (1/speeds[idx])`를 사용하면 더 빠른 연산 처리가 가능합니다.
def solution(progresses, speeds): stack = [] for idx,progress in enumerate(progresses): num = 100-progress #남은 작업 크기 if num%speeds[idx]!= 0: #해당 작업을 끝내기 위해 필요한 시간 저장 stack.append(num//speeds[idx]+1) else: stack.append(num//speeds[idx]) cnt = 1 current = stack[0] answer = [] for num in stack[1:]: if current>=num: cnt+=1 #이전 직업이 끝난 시점에 지금 작업도 같이 끝났을 있으면(이전 작업에 필요한 시간이 현재 직업에 필요한 시간보다 크거나 같으면) 끝난 작업 + 1 else: answer.append(cnt) #현재 작업이 끝나기 위해 더 많은 시간이 필요하면(이전 작업에 필요한 시간이 현재 작업에 필요한 시간보다 작으면) 이때까지 끝난 작업을 answer에 append cnt =1 #끝낸 작업 초기화 current = num answer.append(cnt) return answer하지웅
2024-09-01 18:22:57주어진 진행도와 속도 리스트에서 각 기능의 개발 완료까지 걸리는 날짜를 계산하고, 동시에 배포할 수 있는 기능의 개수를 리스트 형태로 반환합니다. 각 기능의 개발 완료까지 걸리는 날짜를 계산할 때, 올림 함수를 사용하여 소수점 이하를 버리는 방식이 사용됩니다. 코드는 명확하고 이해하기 쉽지만, 배포 가능한 기능 개수를 계산하는 부분에서 `max_days` 변수를 활용하여 불필요한 반복이 발생할 수 있습니다. `max_days` 변수를 제거하고, `days` 리스트의 각 요소를 순회하며 이전 요소와 비교하여 배포 가능한 기능 개수를 계산하는 방식으로 개선하면 더 빠르게 동작할 수 있습니다.
import math def solution(progresses,speeds): days = [math.ceil((100 - p) / s) for p, s in zip(progresses, speeds)] result = [] max_days = days[0] cnt = 0 for day in days: if day > max_days: result.append(cnt) cnt = 1 max_days = day else: cnt += 1 result.append(cnt) return result이현석
2024-09-01 01:55:10주어진 진행도와 속도를 이용하여 각 작업이 100% 완료되는 데 걸리는 일 수를 계산하고, 같은 날 완료되는 작업들의 개수를 구하는 코드입니다. 각 작업에 대한 진행도와 속도를 이용하여 100% 완료되는 날짜를 계산하고, 같은 날 완료되는 작업들의 개수를 리스트에 담아 반환합니다. 현재 코드는 작업별로 진행도를 100%까지 채우는 날짜를 계산하고, 매번 List에서 pop을 이용하여 진행도와 속도를 제거하는 과정을 수행하고 있습니다. `for` loop 를 사용하여 작업들을 순차적으로 처리하면 List에서 `pop` 하는 시간을 줄여 실행 속도를 개선할 수 있습니다. 또한 각 작업이 100% 완료되는 데까지 걸리는 일수를 `while` 문 내부에서 계산하는 대신, 미리 계산하여 별도의 리스트에 저장하고, 현재 날짜와 비교하는 방식을 사용하면 불필요한 계산을 줄여 더 빠르게 실행될 수 있습니다.
def solution(progresses, speeds): answer = [] days = 0 complete = 0 while len(progresses) > 0: task = progresses[0] speed = speeds[0] if(task + days * speed) >= 100: progresses.pop(0) speeds.pop(0) complete += 1 else: if complete > 0: answer.append(complete) complete = 0 else: days += 1 answer.append(complete) return answer이석민
2024-08-30 01:28:27주어진 진도율과 속도 배열을 입력받아 각 기능의 개발 완료까지 걸리는 날짜를 계산하고 그룹화하여 배포 시기를 나타내는 배열을 반환합니다. 각 기능의 개발 완료까지 걸리는 날짜를 계산하고, 그 다음 날부터 개발이 완료되는 기능들을 같은 그룹으로 묶는 방식으로 배포 시기를 구합니다. 현재 코드는 while 문을 사용하여 각 기능의 개발 완료까지 걸리는 날짜를 일일이 계산하고, 이를 기준으로 그룹화하여 배포 시기를 구합니다. `for`문 안에서 `math.ceil` 연산을 반복적으로 사용하는 부분은 속도 저하의 원인이 될 수 있습니다. `math.ceil` 연산 대신 `//` 연산자를 사용하면 연산 속도를 개선할 수 있습니다. 또한, `del` 연산으로 배열을 수정하는 대신 새로운 배열을 생성하여 삽입하는 방법을 사용하면 연산 속도가 개선될 수 있습니다.
import math def solution(progresses, speeds): days_going = 0 result = [] while progresses: remain_days = math.ceil((100 - progresses[0]) / speeds[0]) - days_going waiting_cnt = 0 for idx, p in enumerate(progresses[1:], 1): if math.ceil((100 - progresses[idx]) / speeds[idx]) - days_going <= remain_days: waiting_cnt += 1 else: break result.append(1 + waiting_cnt) del progresses[:1 + waiting_cnt] del speeds[:1 + waiting_cnt] return result배수훈
2024-08-26 13:23:34주어진 진행도와 속도를 이용하여 각 기능의 개발 완료까지 걸리는 시간을 계산하고, 동시에 배포할 수 있는 기능의 개수를 리스트 형태로 반환합니다. 각 기능의 개발 완료까지 걸리는 시간을 계산할 때, `math.ceil`을 사용하여 올림 처리를 수행합니다. 기능의 개발 완료까지 걸리는 시간을 계산하는 과정에서 `zip`을 사용하여 두 리스트를 동시에 순회하고, `if`문을 사용하여 이전 기능의 개발 완료 시간과 현재 기능의 개발 완료 시간을 비교하여 동시 배포 가능 여부를 판단합니다. `math.ceil`을 사용하는 대신, `//` 연산자를 사용하여 나눗셈 결과를 내림 처리하면 연산 속도를 높일 수 있습니다. 또한, `for` 루프 내에서 `if`문으로 비교 연산을 반복적으로 수행하는 대신, 한 번에 모든 기능의 개발 완료 시간을 계산하고, 이를 기반으로 동시 배포 가능 기능의 개수를 계산하는 방식으로 코드를 간소화하여 더욱 빠르게 실행될 수 있습니다.
import math def solution(progresses, speeds): result = [] before = math.ceil((100 - progresses[0]) / speeds[0]) cnt = 1 for p, s in zip(progresses[1:], speeds[1:]): d = math.ceil((100 - p) / s) if before >= d: cnt += 1 else: result.append(cnt) before = d cnt = 1 result.append(cnt) return result이석민
2024-08-25 22:19:15주어진 진행도와 속도 리스트를 입력받아 각 기능 개발 완료까지 걸리는 날짜를 계산하고, 동시에 배포될 수 있는 기능의 개수를 리스트로 반환하는 코드입니다. 각 기능의 개발 완료까지 걸리는 날짜를 계산하는 days 함수를 사용하며, 계산 결과를 기반으로 배포 가능한 기능 그룹 단위로 묶어 답을 생성합니다. 코드의 효율성을 높이기 위해 days 함수에서 `math.ceil` 대신 `(100 - p + s - 1) // s` 를 사용하여 소수점을 처리하는 것이 더 효율적입니다. `//` 연산은 몫을 구하는 연산으로, 나머지 연산 없이 정수형으로 결과를 얻을 수 있어 `math.ceil` 함수보다 빠릅니다. 또한, `for` 루프를 사용하는 대신 이진탐색을 사용하여 배포 가능한 기능 그룹을 찾는 것이 더 효율적입니다. 이진탐색은 `logN` 시간 복잡도를 가지므로 `N` 시간 복잡도를 가지는 `for` 루프보다 더 빠릅니다.
import math def solution(progresses, speeds): answer = [] calculated = [] for x in range(len(progresses)): calculated.append(days(progresses[x], speeds[x])) i = 0 limit = len(calculated) answer = [1, ] last = calculated[0] for d in calculated[1:]: if last < d: answer.append(0) last = d answer[-1] += 1 return answer def days(p, s): return math.ceil((100 - p) / s)가장 먼 노드
코드 제출 (6등) 문제 바로가기주병규
2024-09-01 18:39:56주어진 그래프에서 모든 노드까지의 최단 거리를 BFS를 이용하여 구하고, 최단 거리가 가장 긴 노드의 개수를 반환합니다. 그래프에서 두 노드 사이의 연결 관계를 저장할 때 set 데이터 타입을 사용하여 중복 저장을 방지하고, BFS 과정에서 해당 노드까지의 최단 거리를 계산하여 value 딕셔너리에 저장합니다. BFS 과정에서 visited 배열 대신 최단 거리를 비교하여 queue에 추가함으로써 불필요한 탐색을 줄이고 코드의 실행 속도를 개선할 수 있습니다. 최단 거리를 계산할 때 `cnt + 1` 연산은 `cnt` 값을 더하고 1을 더하는 것과 동일하며, `cnt << 1 | 1` 연산으로 대체하여 비트 연산을 이용하여 속도를 개선할 수 있습니다.
from collections import deque def solution(n, edge): graph = {} for vertext in edge: #그래프 만들기 start = vertext[0] to = vertext[1] graph[start] = graph.get(start, set()) graph[start].add(to) graph[to] = graph.get(to, set()) graph[to].add(start) #두 노드끼리 서로 오고 갈 수 있음을 저장 value = {i: 50000 for i in range(1, n+1)} queue = deque([(1, 0)]) value[1] = 0 #value의 key값은 노드의 번호 값은 그 노드까지 가는데 필요한 최소 비용 while queue: #BFS start, cnt= queue.popleft() for to in graph[start]: if cnt + 1 < value[to]: #BFS를 하는데 이때 VISITED를 사용하는게 아니라 해당 노드까지 가는데 걸린 비용이 더 짧을 경우(최단 거리일 경우) 만 queue에 추가해주고 value에 저장해 준다(이미 존재 할 경우 cnt+1로 초기화) queue.append((to, cnt + 1)) value[to] = cnt + 1 maxVal = 0 answer = 0 for num in value.values(): #해당 노드까지 가는데 필요한 최소 비용이 가장 크거나 같을 경우만 +1 if num > maxVal: maxVal = num answer=1 elif num == maxVal: answer+=1 return answer하지웅
2024-09-01 18:13:37주어진 그래프에서 1번 노드에서 가장 멀리 떨어진 노드까지의 거리를 구하고, 그 거리와 같은 거리를 가지는 노드의 개수를 반환합니다. 다익스트라 알고리즘을 사용하여 모든 노드까지의 최단 거리를 계산합니다. 힙에 거리가 아닌 음수 거리를 저장하면 `cur_dist > distance[cur_node]` 조건 없이 진행할 수 있어 불필요한 비교 연산을 줄일 수 있습니다. 힙은 기본적으로 최솟값 우선순위 큐이기 때문에, 거리가 아닌 음수 거리를 저장하면 우선순위가 반대로 정렬되어 가장 먼 노드부터 탐색하게 됩니다. `graph` 배열에 간선 정보를 저장할 때, `graph[u].append((v,1))` 과 `graph[v].append((u,1))` 과 같이 양방향으로 저장하여 동일한 정보를 두 번 저장하는 비효율성을 줄일 수 있습니다.
import heapq def solution(n, edge): # 그래프 초기화 graph = [[]for _ in range(n + 1)] for u, v in edge: graph[u].append((v,1)) graph[v].append((u,1)) # 거리 배열 초기화 distance = [float('inf')] * (n+1) distance[1] = 0 heap = [(0,1)] # 다익스트라 while heap: cur_dist, cur_node = heapq.heappop(heap) if cur_dist > distance[cur_node]: continue for adj, weight in graph[cur_node]: dist = cur_dist + weight if dist < distance[adj]: distance[adj] = dist heapq.heappush(heap, (dist, adj)) # 결과 max_dist = max(distance[1:]) return distance.count(max_dist)이현석
2024-09-01 03:22:49주어진 그래프에서 1번 노드로부터 가장 먼 노드의 개수를 반환하는 코드입니다. BFS 알고리즘을 사용하여 각 노드까지의 거리를 계산하고, 가장 먼 노드의 개수를 세어 반환합니다. BFS를 사용하는 대신 다익스트라 알고리즘을 사용하면 더 빠르게 동작할 수 있습니다. 다익스트라 알고리즘은 음수 간선이 없는 그래프에서 최단 경로를 찾는 데 사용되며, BFS보다 더 효율적입니다. 또한, `distances` 배열을 `max(distances)` 와 비교하는 부분을 `max_distance` 변수를 사용하여 미리 계산하면 연산 횟수를 줄일 수 있습니다.
from collections import deque def solution(n, edge): answer = 0 graph = [[] for _ in range(n+1)] for a,b in edge: graph[a].append(b) graph[b].append(a) distances = [-1] * (n+1) distances[1] = 0 q = deque([1]) while q: current = q.popleft() for n in graph[current]: if distances[n] == -1: distances[n] = distances[current] + 1 q.append(n) count = 0 for distance in distances: if distance == max(distances): count += 1 return count이석민
2024-08-30 02:15:15주어진 그래프에서 1번 노드로부터 가장 멀리 떨어진 노드의 개수를 구하는 문제입니다. 너비 우선 탐색(BFS) 알고리즘을 사용하여 그래프를 탐색하고 각 노드까지의 거리를 계산합니다. 현재 코드는 dict와 list 자료구조를 사용하여 그래프를 표현하며, 너비 우선 탐색을 통해 거리를 계산합니다. `to_visit` 리스트에 (현재 노드, 다음 노드) 튜플을 저장하는 대신, `queue` 자료구조를 사용하면 더 효율적으로 탐색할 수 있습니다. 이는 `pop(0)` 연산 대신 `pop()` 연산을 사용할 수 있기 때문입니다. 또한, `Counter` 객체를 사용하는 대신 최대 거리를 저장하는 변수를 사용하여 `distance` 리스트를 순회하며 개수를 세는 방식을 사용하면 더 빠른 속도로 개수를 계산할 수 있습니다.
from collections import Counter def solution(n, vertex): distance = [50_001] * (n + 1) distance[1] = 1 vd = dict() for ve in vertex: ve = sorted(ve) a, b = ve if a not in vd: vd[a] = list() if b not in vd: vd[b] = list() vd[a].append(b) vd[b].append(a) to_visit = list() for dst in vd[1]: to_visit.append((1, dst)) while to_visit: (src, dst) = to_visit.pop(0) if distance[dst] <= distance[src] + 1: continue distance[dst] = distance[src] + 1 if dst not in vd: continue for vde in vd[dst]: to_visit.append((dst, vde)) cntr = Counter(distance[1:]) k = max(cntr.keys()) return cntr[k]배수훈
2024-08-27 10:26:10주어진 그래프에서 1번 노드로부터 가장 먼 노드까지의 거리를 계산하고, 그 거리만큼 떨어진 노드의 개수를 반환하는 코드입니다. BFS 알고리즘을 사용하여 그래프를 탐색하며, 1번 노드로부터 각 노드까지의 거리를 계산합니다. DFS 알고리즘을 사용하면 큐를 사용하지 않고 재귀 함수를 통해 더 빠르게 탐색할 수 있습니다. 또한, defaultdict 대신 일반적인 리스트를 사용하여 메모리 사용량을 줄일 수 있습니다. 노드 간 연결 정보를 저장할 때, 연결 정보를 정렬하는 방식을 고려하여 캐싱 효과를 높여 실행 속도를 향상시킬 수 있습니다.
from collections import defaultdict, deque def solution(n, edge): map = defaultdict(list) for e in edge: map[e[0]].append(e[1]) map[e[1]].append(e[0]) arr = [-1 for i in range(n + 1)] arr[1] = 0 farthest = 0 que = deque() que.append(1) while len(que) > 0: i = que.popleft() for node in map[i]: if arr[node] == -1: arr[node] = arr[i] + 1 que.append(node) farthest = max(farthest, arr[node]) return arr.count(farthest)순위
코드 제출 (4등) 문제 바로가기주병규
2024-09-01 18:49:07주어진 선수들의 경기 결과를 이용하여 각 선수의 순위를 정확히 알 수 있는 선수의 수를 계산하는 알고리즘입니다. 그래프를 이용하여 선수 간의 승패 관계를 나타내고, BFS를 활용하여 각 선수가 이길 수 있는 선수와 질 수 있는 선수의 수를 계산합니다. BFS를 이용하여 모든 노드를 방문하는 대신, 각 노드별 이기는 노드와 지는 노드를 따로 관리하여 각 선수의 순위를 판단하는 방식은 효율성을 높이는 좋은 전략입니다. 더 빠른 실행 시간을 위해 이진 트리를 사용하여 그래프를 표현하는 방법을 고려할 수 있으며, BFS 대신 DFS를 활용하여 그래프 탐색을 수행할 수 있습니다. 또한, 각 노드별로 이기는 노드와 지는 노드의 수를 따로 계산하는 대신, 각 노드에 연결된 이기는 노드와 지는 노드의 수를 저장하는 방식으로 메모리를 절약할 수 있습니다.
from collections import deque def solution(n, results): winGraph = {} #이긴 경우를 저장해주는 그래프 looseGraph ={}#진 경우를 저장해주는 그래프 def bfs(start,graph): #BFS를 돌려 몇개의 노드를 방문하였는지 return시켜 준다 queue = deque([start]) visited = set() while queue: current = queue.popleft() if current not in visited: visited.add(current) for neighbor in graph.get(current,[]): queue.append(neighbor) return len(visited)-1 for vertext in results: node = vertext[0] #이긴 사람의 노드 neighbor = vertext[1] #진 사람의 노드 winGraph[node] = winGraph.get(node, set()) winGraph[node].add(neighbor) looseGraph[neighbor] = looseGraph.get(neighbor, set()) looseGraph[neighbor].add(node) answer = 0 for node in range(1,n+1): #승패를 따로 저장해둠으로써 만약 방문 가능한 모든 노드를 방문하였을 때 모든 노드를 방문하였으면 현재 노드의 등수는 정해져있다고 볼 수 있다 #예를 들어 2번 선수의 경우 bfs를 돌렸을 때 winGraph의 경우 1,3,4를 방문하였을 것이고 looseGraph의 경우 5번 경우를 방문하였기에 모든 노드를 방문하였다고 볼 수 있고 #5번선수의 경우 winGraph에서는 어떤 노드도 방문할 수 없지만 looseGraph의 경우 2번 노드를 방문 후 1,3,4노드를 방문 즉 2,1,3,4번 노드를 방문하여 모든 노드를 방문하였다고 볼 수 있다 wins = bfs(node,winGraph) looses = bfs(node,looseGraph) if n-1 == wins+looses: answer+=1 return answer이현석
2024-09-01 03:46:56주어진 결과 정보를 이용하여 각 선수가 이길 수 있는 선수와 질 수 있는 선수를 판별하고, 이를 바탕으로 각 선수가 승패를 확정할 수 있는 선수의 수가 n-1인 경우를 세어 답을 반환합니다. 플로이드-워셜 알고리즘을 이용하여 모든 선수 간의 승패 관계를 계산하는데, 시간 복잡도는 O(n^3)으로, 더 빠른 알고리즘을 사용하면 시간 초과를 방지할 수 있습니다. 예를 들어, 각 선수가 이길 수 있는 선수와 질 수 있는 선수를 DFS나 BFS를 이용하여 계산하면 시간 복잡도를 O(n * e) (e는 결과의 수)로 줄일 수 있습니다.
def solution(n, results): win_graph = [[False] * (n + 1) for _ in range(n + 1)] for winner, loser in results: win_graph[winner][loser] = True for k in range(1, n + 1): for i in range(1, n + 1): for j in range(1, n + 1): if win_graph[i][k] and win_graph[k][j]: win_graph[i][j] = True answer = 0 for i in range(1, n + 1): count = 0 for j in range(1, n + 1): if win_graph[i][j] or win_graph[j][i]: count += 1 if count == n - 1: answer += 1 return answer배수훈
2024-08-27 16:29:27주어진 결과 목록을 통해 선수 간의 승패 관계를 표현하는 2차원 배열을 만들고, 플로이드-워셜 알고리즘을 이용하여 모든 선수 간의 승패 관계를 파악합니다. 이후, 승패 관계가 모두 결정된 선수의 수를 반환합니다. 플로이드-워셜 알고리즘의 시간 복잡도는 O(n^3)으로, 입력 크기가 커지면 시간 초과가 발생할 수 있습니다. 따라서, 입력 크기별로 적절한 알고리즘을 선택하거나, 이진 검색 트리 등의 자료 구조를 활용하여 시간 복잡도를 줄일 수 있습니다. 또한, 2차원 배열 대신 인접 리스트를 사용하면 메모리 사용량을 줄일 수 있습니다.
def solution(n, results): arr = [[0 for j in range(n)] for i in range(n)] for r in results: arr[r[0] - 1][r[1] - 1] = 1 arr[r[1] - 1][r[0] - 1] = -1 for k in range(n): for i in range(n): for j in range(n): if arr[i][j] == 0 and arr[i][k] == 1 and arr[k][j] == 1: arr[i][j] = 1 if arr[i][j] == 0 and arr[i][k] == -1 and arr[k][j] == -1: arr[i][j] = -1 cnt = 0 for r in arr: if r.count(0) == 1: cnt += 1 return cnt길 찾기 게임
코드 제출 (3등) 문제 바로가기주병규
2024-09-01 18:56:22이 코드는 이진 트리를 구성하고 전위 순회와 후위 순회를 수행하여 각 순회 결과를 반환하는 알고리즘입니다. 입력으로 주어진 노드 정보를 y 좌표 기준으로 정렬하여 높은 레벨의 노드부터 트리를 구성하고 재귀 함수를 이용하여 전위 순회와 후위 순회를 진행합니다. 이 코드는 노드를 정렬하고 재귀 함수를 사용하여 트리를 구성하고 순회하는 방식으로 구현되어 있습니다. 시간 복잡도를 줄이기 위해 재귀 함수 대신 반복문을 사용할 수 있습니다. 또한, 트리 구성 시 노드 삽입을 위한 이진 탐색을 활용하면 시간 복잡도를 줄일 수 있습니다. 재귀 함수는 반복문보다 메모리를 더 많이 사용할 수 있으므로, 스택 오버플로우를 방지하기 위해 재귀 제한을 높였습니다.
import sys sys.setrecursionlimit(10**6) class Tree: def __init__(self, info): self.place = info[1:] #노드의 위치 self.idx = info[0] #노드의 번호 self.right = None self.left = None def makeTree(subTree): if not subTree: return None parent = Tree(subTree[0]) #y값은 sort가 되어있음으로 level이 높은 순서임으로 0번째가 가장 level이 높다 leftSub = [] rightSub = [] for node in subTree[1:]: #모든 자식 노드를 가져와 x값이 큰 것을 오른쪽 서브트리로 x값이 작은 것을 왼쪽 서브트리로 ㅁppend if node[1] < parent.place[0]: leftSub.append(node) else: rightSub.append(node) #분류한 자식 노드들을 가지고 다시 subTree를 만든다 parent.left = makeTree(leftSub) parent.right = makeTree(rightSub) return parent #만든 subTree를 return def solution(nodeinfo): nodeinfo = sorted([[idx + 1, *place] for idx, place in enumerate(nodeinfo)], key=lambda x: -x[2]) #y값을 기준으로 sort를 하여 Tree의 level의 순서대로 나오도록 정렬해주고 idx+1를 저장하여 해당 노드의 번호를 저장해준다 tree = makeTree(nodeinfo) preResult = [] postResult = [] def preOrder(node): #전위 순회 if node: preResult.append(node.idx) preOrder(node.left) preOrder(node.right) def postOrder(node): #후위 순회 if node: postOrder(node.left) postOrder(node.right) postResult.append(node.idx) preOrder(tree) postOrder(tree) return [preResult, postResult]이석민
2024-08-30 03:49:52이 코드는 주어진 노드 정보를 이용하여 이진 트리를 생성하고 전위 순회와 후위 순회 결과를 반환합니다. 이진 트리는 x 좌표를 기준으로 분할하여 재귀적으로 생성되며, 각 노드는 해당 노드의 x 좌표 범위를 저장합니다. 코드는 재귀적인 트리 생성 및 순회를 사용하여 효율성이 떨어질 수 있습니다. 재귀 대신 반복적인 방법으로 트리를 생성하고 순회하면 더 빠른 속도를 얻을 수 있습니다. 또한, x 좌표 범위를 이용하여 분할하는 대신, 이진 검색 트리와 같은 더 효율적인 자료구조를 사용하는 것도 고려할 수 있습니다.
import sys sys.setrecursionlimit(10000) to_visit = list() nodeinfo_cur = 1 class Tree: val = None left = None right = None cord = None x_start = None x_end = None def __init__(self, val, cord, x_start, x_end): self.val = val self.cord = cord self.x_start = x_start self.x_end = x_end def __str__(self): return "(" + str(self.left) + " " + str(self.val) + " " + str(self.right) + ")" def divide(parent, nodeinfo): global to_visit global nodeinfo_cur if nodeinfo_cur >= len(nodeinfo): return x_start = parent.x_start x_end = parent.x_end x_mid = parent.cord[0] # print(nodeinfo[nodeinfo_cur][1][0], x_start, x_end) # 내 child의 tree가 아님. sibling의 어느 부분일듯 if nodeinfo[nodeinfo_cur][1][0] < x_start or nodeinfo[nodeinfo_cur][1][0] > x_end: return # 일단 내 범위임 if nodeinfo[nodeinfo_cur][1][0] < x_mid: parent.left = Tree(nodeinfo[nodeinfo_cur][0], nodeinfo[nodeinfo_cur][1], x_start, x_mid) nodeinfo_cur += 1 # left만 있는 노드일 수도 있으므로, right 조건인지 체크 해야함 if nodeinfo_cur < len(nodeinfo) and x_mid < nodeinfo[nodeinfo_cur][1][0] <= x_end: parent.right = Tree(nodeinfo[nodeinfo_cur][0], nodeinfo[nodeinfo_cur][1], x_mid, x_end) nodeinfo_cur += 1 if parent.left is not None: to_visit.append(parent.left) if parent.right is not None: to_visit.append(parent.right) def post_trav(node, result): if node.left is not None: post_trav(node.left, result) if node.right is not None: post_trav(node.right, result) result.append(node.val) def pre_trav(node, result): result.append(node.val) if node.left is not None: pre_trav(node.left, result) if node.right is not None: pre_trav(node.right, result) def solution(nodeinfo): nodeinfo = sorted(enumerate(nodeinfo, 1), key = lambda c: (-c[1][1], c[1][0])) max_x = 0 for _, (x, y) in nodeinfo: if x > max_x: max_x = x global to_visit global nodeinfo_cur parent = Tree(nodeinfo[0][0], nodeinfo[0][1], 0, max_x) to_visit.append(parent) while to_visit: p = to_visit.pop(0) divide(p, nodeinfo) # print(parent) post_result = [] post_trav(parent, post_result) pre_result = [] pre_trav(parent, pre_result) # 전위탐색 1개, 후위탐색 1개 return [pre_result, post_result]
2024-08-25 21:00:00 (5문제)
피보나치 수
코드 제출 (5등) 문제 바로가기주병규
2024-08-25 04:47:28이 코드는 피보나치 수열의 n번째 항을 계산하여 1234567로 나눈 나머지를 반환합니다. 이 코드는 반복문을 사용하여 피보나치 수열을 계산하는데, 재귀 함수를 사용하는 것보다 효율적입니다. 각 항을 계산할 때 이전 두 항을 더하기 때문에 불필요한 계산이 발생할 수 있습니다. 이를 해결하기 위해 DP(Dynamic Programming) 기법을 사용하여 각 항을 한 번만 계산하도록 할 수 있습니다. 또한, 1234567로 나눈 나머지를 계산하는 부분을 최적화할 수 있는데, 각 항을 계산할 때마다 나머지를 계산하는 대신 마지막 항만 나머지를 계산하면 더 효율적입니다.
def solution(n): fibo = [0,1] for i in range(2,n+1): fibo.append(fibo[i-1]+fibo[i-2]) # 재귀로 계산하면 5를 계산하기 위해 4와 3를 호출하고 4를 계산하기 위해 다시 3와 2를 호출해야 함으로 비효율적 return fibo[n]%1234567이석민
2024-08-23 18:32:26주어진 정수 n까지 피보나치 수열을 구하는 코드입니다. 동적 계획법을 사용하여 이전 두 항의 합을 이용하여 현재 항을 계산합니다. 코드는 효율적이지만, 루프 내부에서 모듈 연산을 수행하는 대신 최종 결과에만 모듈 연산을 적용하여 속도를 향상시킬 수 있습니다. n이 커질수록 dp 배열의 크기가 커져 메모리를 많이 사용하게 됩니다. 따라서 재귀 함수를 사용하여 DP 테이블을 직접 생성하지 않고 필요한 값만 계산하는 것이 메모리 사용량을 줄이는 데 도움이 됩니다. 또한, 피보나치 수열은 재귀적으로 구현할 때 중복 계산이 발생하기 때문에 메모이제이션 기법을 활용하여 중복 계산을 방지함으로써 시간 복잡도를 줄일 수 있습니다.
def solution(n): dp = [0] * (n + 2) dp[1] = 1 for idx in range(2, n + 1): dp[idx] = dp[idx - 2] + dp[idx - 1] return dp[n] % 1234567이석민
2024-08-23 18:24:52입력받은 n에 대한 피보나치 수열을 재귀적으로 계산하여 1234567로 나눈 나머지를 반환하는 코드입니다. 재귀 호출 시 중복 계산을 방지하기 위해 딕셔너리를 이용하여 피보나치 수를 저장하고, 해당 값이 존재하면 저장된 값을 활용합니다. 재귀 함수를 이용하여 피보나치 수열을 구현했기 때문에 반복문을 이용한 방법에 비해 수행 속도가 느릴 수 있습니다. 또한, 피보나치 수를 저장하는 딕셔너리에 대한 추가적인 메모리 공간이 필요합니다. 재귀 호출 대신 반복문을 사용하여 피보나치 수열을 구현하면 더 빠른 속도로 실행할 수 있습니다. 또한, 딕셔너리를 사용하는 대신, 이전 두 개의 피보나치 수를 저장하는 변수를 사용하여 메모리 공간 사용을 줄일 수 있습니다.
import sys sys.setrecursionlimit(200000) fibo_cache = dict() def fibo(n): global fibo_cache if n <= 1: fibo_cache[n] = n return n f_idx_1 = n - 1 f_idx_2 = n - 2 if f_idx_2 not in fibo_cache: f_result_2 = fibo(f_idx_2) fibo_cache[f_idx_2] = f_result_2 if f_idx_1 not in fibo_cache: f_result_1 = fibo(f_idx_1) fibo_cache[f_idx_1] = f_result_1 f_result_1 = fibo_cache[f_idx_1] f_result_2 = fibo_cache[f_idx_2] return f_result_2 + f_result_1 def solution(n): return fibo(n) % 1234567이현석
2024-08-22 04:26:55이 코드는 피보나치 수열의 n번째 항을 구하는 동적 계획법 알고리즘입니다. 코드는 재귀 호출 대신 반복문을 사용하여 메모리 공간을 효율적으로 사용하고, 1234567로 나눈 나머지를 반환하여 큰 숫자를 처리할 수 있도록 합니다. 더 빠른 실행 속도를 위해, 반복문에서 dp[i - 1]과 dp[i - 2]를 계산할 때 불필요한 연산을 제거하여 (예: 변수를 사용하여 이전 두 값을 저장) 속도를 향상시킬 수 있습니다. 또한, 피보나치 수열의 공식을 이용하여 n이 커질수록 더 빠르게 계산할 수 있습니다.
def solution(n): if n == 0: return 0 elif n == 1: return 1 dp = [0] * (n + 1) dp[0] = 0 dp[1] = 1 for i in range(2, n + 1): dp[i] = dp[i - 1] + dp[i - 2] return dp[n] % 1234567배수훈
2024-08-20 11:39:44이 코드는 피보나치 수열의 n번째 항을 1234567로 나눈 나머지를 구하는 알고리즘입니다. 이 코드는 반복문을 사용하여 피보나치 수열을 계산하며, 각 항을 1234567로 나눈 나머지를 저장합니다. 이 코드의 시간 복잡도는 O(n)입니다. n이 매우 큰 경우 시간 초과가 발생할 수 있습니다. 더 빠른 알고리즘으로 피보나치 수열의 n번째 항을 구할 수 있습니다. 예를 들어, 행렬 거듭제곱을 사용하면 O(log n) 시간 복잡도로 해결 가능합니다. 또한, 피보나치 수열의 특성을 이용하여 더 빠르게 계산할 수 있는 방법도 존재합니다. 예를 들어, 피보나치 수열의 항은 규칙적인 패턴을 가지고 있기 때문에, 이 패턴을 이용하여 n번째 항을 훨씬 빠르게 계산할 수 있습니다.
def solution(n): a = 0 b = 1 for i in range(1, n): tmp = a a = b b = (tmp + b) % 1234567 return bN으로 표현
코드 제출 (3등) 문제 바로가기주병규
2024-08-25 04:51:21주어진 숫자 N을 이용해 사칙연산을 통해 number를 만들 수 있는 최소 연산 횟수를 찾는 코드입니다. 재귀 함수를 이용하여 가능한 모든 연산 조합을 시도하며, 딕셔너리에 연산 결과와 횟수를 저장하여 최솟값을 계산합니다. 코드는 DP(Dynamic Programming) 기법을 활용하면 더 빠르게 동작할 수 있습니다. 각 연산 결과를 딕셔너리에 저장하고, 이전 결과를 활용하여 중복 계산을 줄일 수 있습니다. 또한, 불필요한 계산을 줄이기 위해 연산 횟수가 8을 넘어가거나 계산 결과가 0인 경우에는 재귀 함수를 종료시키는 등의 최적화를 적용할 수 있습니다. 특히, 재귀 호출 시, 중복 계산되는 연산을 줄이기 위해, `dict`에 계산 결과와 연산 횟수를 저장하고, 이를 활용하여 중복 계산을 방지하는 것이 효과적입니다.
def solution(N, number): dict = {} def recursive(value,cnt): if cnt>8 or (cnt>0 and value==0): return #최솟값이 8보다 크거나 현재 계산된 값이 0이라면 의미가 없으므로 return 시킨다 dict[value] = min(dict.get(value,cnt),cnt) #현재 값이 이전 계산에서 있었는지 확인하고 더 작으면 저장 num = N for i in range(1,9): recursive(value+num,cnt+i) #값 + recursive(value-num,cnt+i) #값 - recursive(value*num,cnt+i) #값 * recursive(value/num,cnt+i) #값 / num = num*10+N #N이 9 일따 9,99,999을 사칙연산 이때 cnt의 값은 1,2,3 만큼 증가 recursive(0,0) return dict.get(number,-1)배수훈
2024-08-23 09:16:33주어진 숫자 N을 이용하여 연산(더하기, 빼기, 곱하기, 나누기)을 최대 8번까지 수행하여 target 숫자를 만들 수 있는지 확인하고, 가능하다면 최소 연산 횟수를 반환하는 코드입니다. 숫자 N을 반복하여 문자열로 변환하고 정수로 변환하여 연산 결과를 저장하는 방식으로 동작하며, 중복되는 연산을 제거하기 위해 set을 사용합니다. 해당 코드는 모든 경우의 수를 탐색하는 방식으로, 시간 복잡도가 높습니다. 더 빠른 연산 속도를 위해 동적 계획법(Dynamic Programming)을 활용하여 중복 연산을 줄일 수 있습니다. 예를 들어, 이미 연산된 결과를 저장해 두고, 같은 연산을 다시 수행하는 경우 저장된 결과를 활용하면 불필요한 연산을 줄일 수 있습니다. 또한, 연산 순서를 최적화하여 불필요한 연산을 줄일 수 있습니다.
def solution(N, number): arr = [] for count in range(1, 9): case = set() case.add(int(str(N)*count)) for i in range(count - 1): for op1 in arr[i]: for op2 in arr[-i - 1]: case.add(op1 + op2) case.add(op1 * op2) case.add(op1 - op2) if op2 != 0: case.add(op1 // op2) if number in case: return count arr.append(case) return -1정수 삼각형
코드 제출 (5등) 문제 바로가기주병규
2024-08-25 04:55:26주어진 삼각형에서 가장 큰 경로 합을 구하는 문제를 동적 프로그래밍 방식으로 해결했습니다. 각 층의 각 노드에 도달하는 최대 합을 저장하며 하향식으로 계산합니다. 코드는 삼각형의 각 층을 순회하며 상위 층에서 현재 노드로 도달할 수 있는 두 가지 경로의 합을 비교하여 더 큰 합을 현재 노드의 최대 합으로 저장합니다. 마지막 층에서 최대 합을 찾아 반환합니다. 시간 복잡도를 줄이기 위해, 불필요한 메모리 할당을 줄이고, 이터레이터를 사용하여 좀 더 간결하게 표현할 수 있습니다. 또한, 최대 값을 찾는 과정은 현재 층의 최대 값을 기억하며 진행하면 훨씬 효율적입니다.
def solution(triangle): grid = [[0] * (i + 1) for i in range(len(triangle))] grid[0][0] = triangle[0][0] for idx in range(1, len(triangle)): for j in range(len(triangle[idx])): #피라미드의 위에서 부터 오른쪽으로 하나씩 그려 나간다 if j == 0: #피라미드 층의 첫번째는 그림으로 보았을 때 상위 층의 왼쪽 값은 받을 수 없음으로 오른쪽 값만 더해 저장 grid[idx][j] = grid[idx - 1][j] + triangle[idx][j] elif j == idx: #피라미드 층의 마지막은 그림으로 보았을 때 상위 층의 오른쪽 값은 받을 수 없음으로 왼쪽 값만 더해 저장 grid[idx][j] = grid[idx - 1][j - 1] + triangle[idx][j] else: #피라미드 층의 중간에 있는 것들은 상위 층의 오른쪽 값이나 왼쪽값을 받을 수 있음으로 그 중 큰 값을 더해 저장 grid[idx][j] = max(grid[idx - 1][j - 1], grid[idx - 1][j]) + triangle[idx][j] return max(grid[-1]) #피라미드 마지막 층 중 가장 값이 큰 것을 return이현석
2024-08-24 15:07:46주어진 삼각형에서 가장 큰 경로 합을 찾는 동적 계획법 알고리즘입니다. 이 알고리즘은 각 노드에 이전 레벨의 두 노드 중 큰 값을 더하여 최대 경로 합을 계산합니다. 현재 코드는 이전 레벨의 두 노드를 비교할 때 max 함수를 사용하는데, 이는 비교 연산에 시간이 소요됩니다. 삼항 연산자를 사용하여 직접 비교하여 연산 시간을 줄일 수 있습니다. 또한, `max(triangle[-1])` 대신 마지막 레벨의 최대값을 변수에 저장하여 불필요한 반복을 줄일 수 있습니다.
def solution(triangle): for i in range(1, len(triangle)): for j in range(len(triangle[i])): if j == 0: triangle[i][j] += triangle[i - 1][j] elif j == len(triangle[i]) - 1: triangle[i][j] += triangle[i - 1][j - 1] else: triangle[i][j] += max(triangle[i - 1][j - 1], triangle[i - 1][j]) return max(triangle[-1])이석민
2024-08-23 19:57:26주어진 삼각형에서 가장 큰 합을 가지는 경로를 찾는 알고리즘입니다. 각 줄에서 이전 줄의 최대값을 더하여 다음 줄의 최대값을 계산하며, 마지막 줄의 최댓값을 반환합니다. 현재 코드는 모든 경로를 탐색하는 방식으로, 시간 복잡도가 높습니다. 각 줄의 최대값만 계산하여 저장하면 더 빠르게 연산할 수 있으며, 이는 동적 계획법을 활용한 최적화입니다. 또한, `max` 함수를 사용하는 대신 `if` 문으로 조건 비교를 수행하면 불필요한 함수 호출을 줄여 성능 향상을 기대할 수 있습니다.
def search(triangle, line_pos): max_tree = [[triangle[0][0]]] for line_idx, line in enumerate(triangle[1:], 1): this_line = [] for col_idx, col in enumerate(line): maxium_parent = [] # left if col_idx > 0: maxium_parent.append(max_tree[line_idx - 1][col_idx - 1]) # right if col_idx < len(line) - 1: maxium_parent.append(max_tree[line_idx - 1][col_idx]) this_line.append(max(maxium_parent) + col) max_tree.append(this_line) return max(max_tree[-1]) def solution(triangle): return search(triangle, 0)배수훈
2024-08-23 17:18:54주어진 삼각형에서 가장 큰 합을 가지는 경로를 찾는 동적 프로그래밍 방식의 코드입니다. 하단부터 시작하여 위로 올라가면서 각 칸의 값에 밑 두 칸의 최댓값을 더하여 최적의 경로를 계산합니다. 시간 복잡도를 줄이기 위해 반복문 순서를 바꾸어 봤습니다. 밑에서 위로 올라가는 방식으로 최솟값을 찾으면 동일한 칸을 여러 번 방문하는 것을 방지할 수 있습니다. 또한, 최댓값을 찾는 부분에서 if 문 대신 삼항 연산자를 사용하면 더 빠르게 연산할 수 있습니다. 마지막으로, 풀이 과정에서 불필요한 연산을 줄이기 위해 변수 대신 인덱스로 직접 값에 접근할 수 있습니다.
def solution(triangle): if len(triangle) > 1: for i in range(len(triangle) - 2, -1, -1): for idx, num in enumerate(triangle[i]): triangle[i][idx] += max(triangle[i + 1][idx], triangle[i + 1][idx + 1]); return triangle[0][0]등굣길
코드 제출 (5등) 문제 바로가기배수훈
2024-08-25 20:24:45주어진 맵에서 시작점에서 목표 지점까지 갈 수 있는 경로의 개수를 동적 프로그래밍 방식으로 계산합니다. 각 칸의 값은 해당 칸까지 도달하는 경로의 개수를 나타내며, 장애물이 있는 칸은 -1로 표시됩니다. 코드는 맵의 가장자리부터 시작하여 각 칸까지 도달하는 경로의 개수를 계산하고, 이를 이용하여 목표 지점까지 도달하는 경로의 개수를 계산합니다. 코드의 속도를 높이기 위해 불필요한 연산을 제거하고, 배열 접근 방식을 최적화할 수 있습니다. 예를 들어, puddles 배열을 반복하면서 칸을 -1로 표시할 때, 이미 -1로 표시된 칸을 다시 검사하는 것은 불필요합니다. 또한, 칸까지 도달하는 경로의 개수를 계산할 때, 이미 계산된 값을 재사용하는 방식을 사용하여 계산 시간을 줄일 수 있습니다.
def solution(m, n, puddles): map = [[0 for j in range(m)] for i in range(n)] for i in range(n): map[i][0] = 1 for j in range(m): map[0][j] = 1 for p in puddles: map[p[1] - 1][p[0] - 1] = -1 if p[1] == 1: for i in range(p[0], m): map[0][i] = -1 if p[0] == 1: for i in range(p[1], n): map[i][0] = -1 print(map) for i in range(1, n): for j in range(1, m): if map[i][j] == -1: continue if map[i - 1][j] != -1: map[i][j] = (map[i][j] + map[i - 1][j]) % 1000000007 if map[i][j - 1] != -1: map[i][j] = (map[i][j] + map[i][j - 1]) % 1000000007 print(map) return map[n - 1][m - 1] % 1000000007이현석
2024-08-25 15:35:57주어진 격자에서 시작점에서 끝점까지 갈 수 있는 경로의 개수를 동적 계획법으로 계산합니다. 물웅덩이가 있는 칸은 방문할 수 없습니다. 이 코드는 2차원 배열을 사용하여 각 칸까지의 경로 개수를 저장하며, 물웅덩이가 있는 칸은 -1로 표시합니다. 반복문을 이용하여 각 칸에 도달하는 경우의 수를 계산합니다. 시간 복잡도를 줄이기 위해 물웅덩이 정보를 사전(dictionary)으로 저장하고, 필요할 때만 탐색하는 방식으로 최적화할 수 있습니다. 또한, 칸을 방문했는지 여부를 기록하는 방문 배열을 사용하여 중복 계산을 줄일 수 있습니다.
def solution(m, n, puddles): dp = [[0] * (m + 1) for _ in range(n + 1)] dp[1][1] = 1 for i, j in puddles: dp[j][i] = -1 for i in range(1, n + 1): for j in range(1, m + 1): if dp[i][j] == -1: dp[i][j] = 0 continue dp[i][j] += dp[i - 1][j] + dp[i][j - 1] return dp[n][m] % 1000000007주병규
2024-08-25 05:03:08주어진 격자에서 출발점에서 도착점까지 갈 수 있는 경로의 수를 동적 계획법으로 계산합니다. puddles 위치에 도착할 수 없다는 점을 고려하여 경로 수를 계산합니다. 코드는 격자를 순회하며 각 칸에 도착할 수 있는 경로의 수를 저장합니다. 현재 칸에 도착하는 경우는 바로 위 칸이나 왼쪽 칸에서 도착하는 경우이므로 위 칸과 왼쪽 칸의 경로 수를 더하여 현재 칸의 경로 수를 계산합니다. 코드를 더 빠르게 실행하기 위해 `puddles` 리스트를 `set` 데이터 타입으로 변환하면 `in` 연산의 시간 복잡도를 $O(1)$로 줄일 수 있습니다. 또한, 모듈러 연산을 곱셈 연산 전에 수행하면 중간 결과가 너무 커지는 것을 방지할 수 있습니다.
def solution(m, n, puddles): grid = [[0] * m for _ in range(n)] #해당 위치로 갈 수 있는 방법의 수를 저장 for i in range(1,m): #처음에서 오른쪽으로만 움직였을 때(그림에서 가장 윗 층만 움직였을 때) 최단 거리로 갈 수 있는 방법이 하나밖에 없음으로 모두 1을 저장해주고 만약 puddles가 있다면 puddles 다음은 최단거리로 갈 수 있는 방법이 없음으로 0을 그대로 놔두어 준다 if [i+1,1] in puddles: break grid[0][i] = 1 for i in range(1,n): #처음에서 밑으로만 움직였을 때(그림에서 가장 왼쪽 만 움직였을 때) ~이하 위와 동문 if [1,i+1] in puddles: break grid[i][0] = 1 for i in range(1,n): for j in range(1,m): if [j+1,i+1] in puddles: #puddles에 도착하였을때 해당 경우는 무시 continue grid[i][j] = grid[i-1][j]+grid[i][j-1] #현재 위치로 올 수 있는 방법이 현재 위치의 위와 왼쪽에 도착하였을 경우 가 있는데 해당 위치(현재 위치의 위 아래)로 올 수 있는 경우의 수를 더해 현재 위치로 도착 할 수 있는 경우의 수를 정한다 return grid[-1][-1]%1000000007이석민
2024-08-24 00:29:56주어진 격자에서 웅덩이를 피해 (1, 1)에서 (x, y)까지 가는 경로의 수를 동적 계획법을 사용하여 계산합니다. 웅덩이를 제외한 각 칸에 도달하는 경로의 수는 위쪽 칸과 왼쪽 칸의 경로의 수를 더한 값입니다. 이 코드는 격자를 탐색하여 웅덩이를 피해 목표 지점까지 갈 수 있는 경로 수를 계산하는 동적 계획법 알고리즘을 구현했습니다. * 불필요한 초기화 부분을 제거하면 더 빠르게 실행될 수 있습니다. (최적화 전에 초기화 부분은 필요 없는 연산입니다.) * 웅덩이 정보를 딕셔너리로 저장하면 웅덩이 여부를 검사하는 시간 복잡도를 낮출 수 있습니다. (튜플로 저장하는 것보다 딕셔너리로 저장하는 것이 더 빠릅니다.) * `heatmap[line + 1][x_pos] + heatmap[line][x_pos + 1]` 연산을 한 번에 수행하는 대신 먼저 `heatmap[line + 1][x_pos]`를 더하고 `heatmap[line][x_pos + 1]`를 더하는 방식으로 연산 순서를 변경하면 더 빠르게 실행될 수 있습니다. (덧셈 연산의 순서를 바꿔도 결과는 동일하지만, 연산 순서가 약간 더 빠를 수 있습니다.)
def solution(x, y, puddles): heatmap = [[0] * (x + 1) for _ in range(y + 1)] # # fill bottom # for x_pos in range(x): # heatmap[y - 1][x_pos] = 1 # # fill right # for y_pos in range(y): # heatmap[y_pos][x - 1] = 1 heatmap[y - 1][x - 1] = 1 blocked = () if len(puddles[0]) > 0: blocked = tuple(map(lambda v: (v[0] - 1, v[1] - 1), puddles)) for line in range(y - 1, -1, -1): for x_pos in range(x - 1, -1, -1): if (x_pos, line) in blocked: heatmap[line][x_pos] = 0 continue elif (x_pos, line) == (x - 1, y - 1): continue heatmap[line][x_pos] = heatmap[line + 1][x_pos] + heatmap[line][x_pos + 1] return heatmap[0][0] % 1_000_000_007도둑질
코드 제출 (5등) 문제 바로가기배수훈
2024-08-25 20:53:31이 코드는 주어진 돈 배열에서 연속된 두 개의 숫자를 제외하고 최대 금액을 찾는 동적 계획법 알고리즘을 구현합니다. 첫 번째 집을 털지 않거나 털 수 있는 두 가지 경우를 고려하여 최대 금액을 계산합니다. 첫 번째 루프에서 dp1은 첫 번째 집을 털었을 때의 최대 금액을, 두 번째 루프에서 dp2는 첫 번째 집을 털지 않았을 때의 최대 금액을 저장하며, 마지막으로 두 경우 중 더 큰 금액을 반환합니다. 코드를 더 빠르게 실행하려면 인덱싱과 비교 연산을 최소화하여 불필요한 작업을 줄여야 합니다. 예를 들어, `dp1[i] = max(dp1[i - 1], money[i] + dp1[i - 2])` 부분에서 `dp1[i - 2]`를 미리 계산하여 별도의 변수에 저장하면 반복마다 불필요한 연산을 줄일 수 있습니다. 또한, `max` 함수를 직접 사용하는 대신, 비교 연산을 통해 최대 값을 직접 찾으면 속도를 향상시킬 수 있습니다.
def solution(money): n = len(money) dp1 = [0 for i in range(n)] dp1[0] = money[0] dp1[1] = max(money[0], money[1]) for i in range(2, n - 1): dp1[i] = max(dp1[i - 1], money[i] + dp1[i - 2]) dp2 = [0 for i in range(n)] dp2[0] = 0 dp2[1] = money[1] for i in range(2, n): dp2[i] = max(dp2[i - 1], money[i]+dp2[i - 2]) return max(max(dp1), max(dp2))이현석
2024-08-25 15:53:11주어진 돈 목록에서 연속되지 않은 숫자를 선택하여 합을 최대로 만드는 문제를 다이나믹 프로그래밍으로 해결합니다. 첫 번째 원소를 포함하는 경우와 첫 번째 원소를 포함하지 않는 경우 두 가지 경우를 따로 계산하여 최댓값을 반환 합니다. 첫 번째 원소를 포함하는 경우와 포함하지 않는 경우를 따로 계산하는 이유는, 도둑이 첫 번째 집을 털고 마지막 집을 털 수 없기 때문입니다. 두 가지 경우 모두 다이나믹 프로그래밍을 사용하여 계산하지만, 주어진 돈 목록의 크기가 3인 경우 별도로 처리해야 합니다. 이는 처음 두 원소를 연속적으로 선택하지 못하기 때문에 두 경우를 모두 계산할 필요가 없기 때문입니다. dp1 배열의 경우 첫 번째 원소를 포함하는 경우의 최댓값을 저장하고 dp2 배열은 첫 번째 원소를 포함하지 않는 경우의 최댓값을 저장합니다. 각 배열은 이전 두 원소의 최댓값을 계산하여 현재 원소까지의 최댓값을 구합니다. 이렇게 계산된 두 배열의 마지막 원소 중 더 큰 값을 반환합니다. 시간 복잡도는 O(n)이며, 공간 복잡도는 O(n)입니다. 다이나믹 프로그래밍 대신 그리디 알고리즘을 사용하면 더 빠르게 풀 수 있습니다. 예를 들어, 현재 원소까지의 최댓값을 계산할 때 이전 두 원소의 최댓값만 사용하기 때문에 이전의 모든 원소 정보를 저장할 필요 없이 현재 원소까지의 최댓값만 저장하면 됩니다. 또한, 주어진 돈 목록의 크기가 3인 경우를 따로 처리하는 부분을 제거하여 코드를 간소화할 수 있습니다. 주어진 돈 목록의 크기가 3인 경우에도 일반적인 다이나믹 프로그래밍 방식을 사용하여도 문제없이 정확한 결과를 얻을 수 있기 때문입니다.
def solution(money): n = len(money) if n == 3: return max(money) dp1 = [0] * n dp1[0] = money[0] dp1[1] = max(money[0], money[1]) for i in range(2, n-1): dp1[i] = max(dp1[i-1], dp1[i-2] + money[i]) dp2 = [0] * n dp2[0] = 0 dp2[1] = money[1] for i in range(2, n): dp2[i] = max(dp2[i-1], dp2[i-2] + money[i]) return max(dp1[n-2], dp2[n-1])주병규
2024-08-25 05:17:44코드는 주어진 돈 목록에서 연속된 두 집을 털지 않고 최대 금액을 얻는 문제를 해결합니다. 처음 집부터 시작하는 경우와 두 번째 집부터 시작하는 경우를 각각 계산하여 두 경우 중 최대 금액을 반환합니다. 처음 집부터 시작하는 경우와 두 번째 집부터 시작하는 경우를 각각 따로 계산하는 것이 더 효율적입니다. 또한, `max` 함수를 사용하여 최대 금액을 구하는 대신 두 배열을 합친 후 `max` 함수를 사용하면 코드가 더 간결해집니다. `firStartGrid`와 `secStartGrid` 배열을 합치는 대신 `max(firStartGrid[-1], secStartGrid[-1])`를 사용해 마지막 집을 털었을 때의 최대 금액을 직접 구하면 연산량을 줄일 수 있습니다. 또한, 각 배열의 마지막 원소에 마지막 집을 털었을 때의 금액을 저장하여 `max` 함수를 사용하기 전에 따로 계산할 필요가 없도록 코드를 간소화할 수 있습니다.
def solution(money): length = len(money) #처음에서 시작하였을 때와 두번째에서 시작하였을 때를 나누어야지 후에 마지막을 선택할지 안할지를 결정할 수 있다 firStartGrid = [0 for _ in range(length)] #처음 위치에서 시작하였을 때 firStartGrid[0] = money[0] firStartGrid[1] = money[0] #처음 위치가 시작 위치이기 때문에 2번째 값은 첫번째 값으로 대체 for i in range(2,length-1): #처음 위치가 시작 위치이기 때문에 마지막은 고를 수 없다 firStartGrid[i] = max(firStartGrid[i-2]+money[i],firStartGrid[i-1]) #현재 위치의 이전 이전 위치를 기준으로 보았을 때 이 위치(현재 위치의 이전 이전 위치)를 골라서 한칸을 띄운 위치의 집을 터는것이 이득인지 아니면 고르지 않음으로서 다음 위치의 집을 터는 것이 이득인지 확인 후 저장(집 2개를 터는 것 보다 한 개를 터는 것이 더 이득이여야지 현재 집을 털지 않고 넘어가는 것이 이득이다) secStartGrid = [0 for _ in range(length)] #두 번째 위치에서 시작하였을 때 secStartGrid[1] = money[1] #두 번째 위치에서 시작하였기 때문에 2번째 값을 저장하고 1번째 값은 그대로 두어도 괜찮다 for i in range(2,length): #두 번째 위치에서 시작하기 때문에 마지막을 고르거나 안고르거나 선택 할 수 이다 secStartGrid[i] = max(secStartGrid[i-2]+money[i],secStartGrid[i-1]) #이하동문 return max([*firStartGrid,*secStartGrid])이석민
2024-08-24 23:57:18주어진 돈 목록에서 연속하지 않는 숫자들을 더하여 얻을 수 있는 최대 합을 구하는 알고리즘입니다. 동적 계획법을 사용하여 각 인덱스별로 최대 합을 계산하고, 마지막 3개 인덱스에서 최댓값을 찾습니다. 코드는 3개 이하의 돈 목록에 대해서는 최댓값을 직접 반환하고, 3개 이상의 돈 목록에 대해서는 두 개의 배열을 사용하여 동적 계획법을 적용합니다. 하지만 3개 이상의 돈 목록에 대한 첫 번째 배열과 두 번째 배열을 따로 계산하는 부분은 중복되는 연산이 많습니다. 두 배열을 하나로 합쳐 연산을 줄일 수 있습니다. 또한, `max(money_agg[-3:], max(money_agg_1[-3:]))` 부분은 `max(money_agg + money_agg_1)` 로 대체할 수 있습니다.
def solution(money): money_agg = [0] * len(money) money_agg[0] = money[0] money_agg[1] = money[1] money_agg[2] = money[2] money_agg_1 = money_agg[:] # len <= 3일때는 모든곳이 근접함. 그러므로, 하나만 뽑을 수 있음 if len(money) <= 3: return max(money) # 이제부터는 최소 4개임. # 제로 부터 시작 (맨 마지막거는 못감) money_agg[2] = money_agg[0] + money[2] # 원래는 range(2, ···) 였는데, 이러면 idx -3 때문에 문제가 생겨서... 그렇다고 if문을 매번 하기에는 성능 문제 for idx in range(3, len(money) - 1): money_agg[idx] = max(money_agg[idx - 2], money_agg[idx - 3]) + money[idx] # 1부터 시작 (맨 마지막거 갈 수 있음) # 마찬가지로, idx == 3 일때 idx-3 때문에 0를 참조할 수 있음. 1부터 시작해야 하는게 조건이므로, 0이 안되게 특수조건화 money_agg_1[3] = money_agg_1[1] + money[3] for idx in range(4, len(money)): money_agg_1[idx] = max(money_agg_1[idx - 2], money_agg_1[idx - 3]) + money[idx] return max(max(money_agg[-3:]), max(money_agg_1[-3:]))
2024-08-18 21:00:00 (5문제)
완주하지 못한 선수
코드 제출 (5등) 문제 바로가기주병규
2024-08-16 03:26:14해당 코드는 참가자 목록 `participant` 와 완주자 목록 `completion` 을 입력받아 완주하지 못한 참가자의 이름을 반환하는 알고리즘입니다. 코드는 참가자 목록을 이용하여 딕셔너리를 생성하고 완주자 목록을 이용하여 딕셔너리의 값을 감소시켜 완주하지 못한 참가자를 찾는 방식입니다. 해당 코드는 `O(n)` 의 시간 복잡도를 가지고 있습니다. 더 빠른 시간 복잡도를 얻기 위해서는 해싱을 이용하여 딕셔너리 연산을 `O(1)` 시간 복잡도로 수행할 수 있습니다. 또한, `completion` 목록을 순회하면서 딕셔너리에서 값을 감소시키는 대신, `completion` 목록을 이용하여 `set` 을 생성하고 `participant` 목록을 순회하면서 `set` 에 없는 값을 찾는 방식을 사용하면 더 빠르게 완주하지 못한 참가자를 찾을 수 있습니다.
def solution(participant, completion): participants = {} for name in participant: participants[name] = participants.get(name,0)+1 #참가자이름:참가자이름을 가진 참여자의 수 for completionName in completion: participants[completionName]-=1 #completion에 있는 참가자를 제외 for name in participants: if participants[name]>0: return name #남은 참가자를 return이현석
2024-08-14 11:46:49주어진 참가자 명단과 완주자 명단에서 완주하지 못한 참가자를 찾는 코드입니다. 두 명단을 정렬한 후 차례대로 비교하여 일치하지 않는 참가자를 찾습니다. 정렬을 이용하여 시간 복잡도를 줄였지만, `in` 연산을 사용하는 것보다 `set` 자료구조를 활용하는 것이 더 효율적입니다. `set` 은 `in` 연산을 O(1) 시간에 처리하기 때문에 코드 실행 속도를 향상시킬 수 있습니다. 또한, 딕셔너리를 사용하여 참가자 수를 세고 완주자 수를 빼서 1인 경우를 찾는 방법도 고려해 볼 수 있습니다. 딕셔너리를 사용하면 O(N) 시간에 해결할 수 있습니다.
def solution(participant, completion): participant.sort() completion.sort() for i in range(len(completion)): if participant[i] != completion[i]: return participant[i] return participant[-1]배수훈
2024-08-13 11:13:37주어진 참가자 명단과 완주자 명단에서 완주하지 못한 참가자 한 명의 이름을 찾는 함수입니다. 딕셔너리를 이용하여 참가자 명단의 출현 횟수를 기록하고, 완주자 명단의 출현 횟수를 빼서 완주하지 못한 참가자를 찾습니다. 시간 복잡도를 줄이기 위해 `collections.Counter`를 사용하는 것이 더 효율적입니다. `Counter`는 딕셔너리와 유사하지만, 카운팅 기능을 제공하여 불필요한 `+=` 연산을 줄여줍니다. 또한 `runner[c] == 1` 조건문을 제거하고 `runner[c] -= 1` 을 `runner[c] -= 1 if runner[c] > 0 else runner.pop(c) `와 같이 `if` 문으로 대체하여 불필요한 비교 연산을 줄일 수 있습니다.
import collections def solution(participant, completion): runner = collections.defaultdict(int) for p in participant: runner[p] += 1 for c in completion: if runner[c] == 1: runner.pop(c, None) continue runner[c] -= 1 return list(runner.keys())[0]이석민
2024-08-11 22:51:28주어진 참가자 명단과 완주자 명단에서 완주하지 못한 참가자를 찾는 코드입니다. 두 명단을 정렬한 후, 각 원소를 비교하여 불일치하는 원소를 반환합니다. 정렬을 통해 시간 복잡도를 O(n log n)으로 줄였지만, 더 빠른 선형 시간 복잡도를 위해 해시 테이블을 사용하는 것이 유리합니다. 또한, 마지막 원소를 별도로 처리하는 대신, `for` 루프를 한 번 더 돌려 모든 원소를 비교하여 불필요한 연산을 줄일 수 있습니다.
def solution(participant, completion): participant.sort() completion.sort() for i in range(len(completion)): if participant[i] != completion[i]: return participant[i] answer = participant[-1] return answer전화번호 목록
코드 제출 (5등) 문제 바로가기주병규
2024-08-16 03:26:23주어진 전화번호 목록에서 어떤 전화번호가 다른 전화번호의 접두어인지 확인하는 함수입니다. 전화번호의 모든 접두어를 dictionary에 저장하고, 각 전화번호가 다른 전화번호의 접두어인지 확인하여 중복되는 접두어가 있으면 False, 없으면 True를 반환합니다. dictionary를 활용하여 모든 접두어를 저장하는 방식은 시간복잡도가 O(n*m)으로, n은 전화번호 개수, m은 전화번호의 평균 길이입니다. 해시 테이블을 사용하여 전화번호를 정렬하고 이진 검색을 이용하면 O(n*log(m))으로 시간복잡도를 줄일 수 있습니다. 또한, 현재 코드는 접두어가 존재하는지 확인할 때 모든 접두어를 dictionary에서 확인하지만, 전화번호가 사전순으로 정렬되어 있다면 현재 전화번호보다 짧은 전화번호만 확인하면 됩니다.
def solution(phone_book): phoneNumDic = {} for phoneNum in phone_book: text = "" for i in range(len(phoneNum)): text += phoneNum[i] phoneNumDic[text] = phoneNumDic.get(text,0)+1 #전화번호의 모든 접두어를 dictionary에 기억한다 for phoneNum in phone_book: if phoneNumDic.get(phoneNum, 0) > 1: #해당 전화번호가 자신을 제외하고 다른 전화번호의 접두어가 가능할 경우 해당 전화번호 key의 value값이 2이상임으로 이때 false를 return시켜준다 return False return True이현석
2024-08-14 12:03:59주어진 전화번호 목록에서 접두사가 되는 전화번호가 존재하는지 확인하는 알고리즘입니다. 주어진 전화번호 목록을 정렬한 후 순차적으로 접두사 여부를 확인하여 접두사가 존재하면 False를 반환하고, 존재하지 않으면 True를 반환합니다. 전화번호 목록을 정렬하는 과정은 최적화가 어렵지만, 접두사 확인 과정은 해시 테이블을 사용하여 시간 복잡도를 O(n)에서 O(1)로 줄일 수 있습니다. 또한, 접두사를 확인하는 과정에서 문자열 비교 대신 접두사 길이만큼만 비교하여 연산량을 줄일 수 있습니다.
def solution(phone_book): phone_book.sort() for i in range(len(phone_book)-1): if phone_book[i+1].startswith(phone_book[i]): return False return True이현석
2024-08-14 11:56:40주어진 전화번호 목록에서 접두사 관계가 있는 전화번호 쌍이 존재하는지 확인하는 함수입니다. 전화번호 목록을 정렬한 후 인접한 전화번호 쌍의 접두사 관계를 검사하여 판별합니다. 정렬 후 접두사 관계 검사를 순차적으로 진행하는 방식은 시간 복잡도가 O(n log n)입니다. 해시 테이블을 활용하면 접두사 관계를 더 빠르게 검사할 수 있어 시간 복잡도를 O(n)으로 줄일 수 있습니다. 예를 들어, 전화번호를 키로, 존재 여부를 값으로 하는 해시 테이블을 만들고, 각 전화번호의 접두사를 순차적으로 검사하여 해시 테이블에 존재하는지 확인하면 됩니다. 이 경우 접두사가 해시 테이블에 존재한다면 접두사 관계가 존재하는 것이므로 False를 반환합니다.
def solution(phone_book): phone_book.sort() for i in range(1, len(phone_book)-1, 1): if(phone_book[i].startswith(phone_book[i-1]) or phone_book[i+1].startswith(phone_book[i])): return False return True배수훈
2024-08-13 11:14:41주어진 전화번호 목록에서 접두사가 다른 전화번호가 있는지 확인하는 함수입니다. 모든 전화번호의 접두사를 저장하고 각 전화번호가 접두사 집합에 있는지 확인합니다. 시간 복잡도를 줄이기 위해 해시 테이블을 사용하는 것이 효율적입니다. 또한 접두사를 저장할 때 전화번호의 길이를 기준으로 정렬하여 불필요한 비교를 줄일 수 있습니다. 주어진 코드는 모든 접두사를 저장하기 때문에 불필요한 비교 연산이 발생합니다. 접두사를 저장할 때 전화번호 길이 순으로 정렬하여 길이가 짧은 접두사부터 비교하면 시간 복잡도를 줄일 수 있습니다.
def solution(phone_book): header = set() for p in phone_book: for i in range(1, len(p)): header.add(p[:i]) for p in phone_book: if p in header: return False return True이석민
2024-08-11 22:51:36전화번호 목록을 정렬한 후 연속된 두 전화번호가 접두사 관계인지 확인하여 중복 여부를 판별하는 알고리즘입니다. 시간 복잡도는 O(N log N)으로 정렬 과정에 의해 발생하며, 비교 연산은 최악의 경우 O(N^2) 시간이 소요될 수 있습니다. 전화번호 목록을 해시 테이블에 저장하여 접두사 관계를 빠르게 확인하면 시간 복잡도를 O(N)으로 줄일 수 있습니다. 이는 해시 테이블의 빠른 검색 속도를 이용하여 접두사 관계 여부를 O(1) 시간에 확인할 수 있기 때문입니다. 또한, 전화번호 길이를 기준으로 정렬하여 불필요한 비교를 줄이면 시간 복잡도를 더욱 개선할 수 있습니다.
def solution(phone_book): phone_book.sort() for p in range(len(phone_book) - 1): if phone_book[p] == phone_book[p+1][0:(len(phone_book[p]))]: return False answer = True return answer위장
코드 제출 (5등) 문제 바로가기이현석
2024-08-16 14:18:16주어진 옷 목록에서 옷 종류별로 옷 개수를 세고, 각 종류별 옷 개수에 1을 더한 값들을 모두 곱한 후 1을 뺀 값을 반환합니다. 이 코드는 옷 종류별로 옷 개수를 세기 위해 딕셔너리를 사용하며, 각 종류별 옷 개수에 1을 더한 값들을 곱하는 과정에서 시간 복잡도가 O(n)이 발생합니다. 딕셔너리를 사용하는 대신, 각 옷 종류별 옷 개수를 세기 위해 Counter 객체를 사용하면 더 빠르게 동작합니다. 딕셔너리 대신 Counter 객체를 사용하면 코드를 간결하게 작성할 수 있으며, Counter 객체는 해시 테이블을 기반으로 구현되어 룩업 속도가 빠르기 때문에 더 빠르게 동작합니다. 또한, for 루프 대신 `collections.Counter`를 사용하면 코드를 더 간결하게 작성할 수 있습니다.
def solution(clothes): dict = {} answer = 1 for cloth in clothes: category = cloth[1] if category in dict: dict[category].append(cloth[0]) else: dict[category] = [cloth[0]] for category in dict: answer *= (len(dict[category]) + 1) return answer - 1주병규
2024-08-16 03:26:32옷 종류별 개수를 세어, 각 종류별로 입는 경우와 입지 않는 경우를 고려하여 모든 경우의 수를 계산합니다. 옷을 하나도 입지 않는 경우를 제외하여 최종 결과를 반환합니다. 딕셔너리에 모든 경우의 수를 저장하는 대신, 곱셈 연산을 통해 직접 결과를 계산하여 메모리 사용량을 줄일 수 있습니다. `clothesDic.get` 대신 `collections.Counter`를 사용하여 더 간결하게 옷 종류별 개수를 세고 더 빠르게 연산할 수 있습니다.
def solution(clothes): answer = 0 clothesDic = {} for cloth in clothes: clothesDic[cloth[1]] = clothesDic.get(cloth[1],0)+1 #종류: 해당 종류의 의상 개수 (같은 이름을 가진 의상이 존재하지 않음으로 무조건 개수가 1씩 늘어난다) answer = 1 for cloth in clothesDic: answer*=clothesDic[cloth]+1 #경우의 수=(해당 종류의 의상 중 하나를 고를 경우의 수 + 해당 옷을 입지 않을 경우의수)*반복 return answer-1 #옷을 하나도 입지 않을 경우의 수 제거배수훈
2024-08-13 13:14:50옷 종류별 개수를 세고, 각 종류별 옷을 입거나 안 입는 경우의 수를 곱하여 모든 경우의 수를 계산합니다. 마지막으로 아무것도 안 입는 경우를 제외하여 최종 결과를 반환합니다. 옷 종류별 개수를 세는 부분에서 `collections.defaultdict`를 사용하는 대신, `dict`를 사용하고 `get` 메서드를 이용하면 더 빠르게 동작합니다. 옷 종류별 곱셈 연산을 수행하는 부분은 `reduce` 함수를 사용하여 코드를 간결하게 만들 수 있습니다. 옷 종류별 곱셈 연산은 `for` 루프 대신 `reduce` 함수를 사용하면 코드를 간결하게 만들 수 있습니다.
import collections def solution(clothes): clothes_dict = collections.defaultdict(int) for c in clothes: clothes_dict[c[1]] += 1 cnt = 1 for c in clothes_dict: cnt *= clothes_dict[c] + 1 return cnt - 1이석민
2024-08-11 22:51:53옷 종류별 개수를 세고, 각 종류별 옷을 모두 입는 경우의 수를 계산하여 1을 뺀 값을 반환합니다. 옷 종류별 개수를 세는 과정에서 딕셔너리 대신 리스트를 사용하면 룩업 시간을 줄일 수 있습니다. 곱셈 연산 대신 덧셈 연산을 사용하면 연산 속도를 개선할 수 있습니다. for 루프를 사용하여 각 종류의 옷을 입거나 안 입는 경우의 수를 계산하는 대신, 2진수를 이용하여 모든 경우의 수를 효율적으로 계산할 수 있습니다.
def solution(clothes): w = dict() for (name, t) in clothes: if t not in w: w[t] = 1 w[t] += 1 s = 0 w = list(w.values()) answer = 1 for x in w: answer *= x return answer - 1오픈 채팅방
코드 제출 (5등) 문제 바로가기이현석
2024-08-16 18:04:30입력으로 주어진 기록에서 각 사용자의 입장 및 퇴장 메시지를 생성하는 코드입니다. 입력 기록을 두 번 순회하여 사용자별 닉네임을 저장한 후, 입장/퇴장 메시지를 생성합니다. 입력 기록을 한 번만 순회하여 메시지를 생성하면 시간 복잡도를 줄일 수 있습니다. (입력 기록을 한 번만 순회하여 닉네임을 저장하고, 메시지를 동시에 생성하면 더 효율적입니다.) 딕셔너리 대신 해시 테이블을 사용하면 닉네임 조회 속도를 향상시킬 수 있습니다. (해시 테이블은 딕셔너리보다 키 값을 빠르게 찾아낼 수 있습니다.)
def solution(record): answer = [] dict = {} for r in record: r = r.split(" ") if r[0] == "Enter" or r[0] == "Change": dict[r[1]] = r[2] for r in record: r = r.split(" ") if r[0] == "Enter": answer.append(f"{dict[r[1]]}님이 들어왔습니다.") elif r[0] == "Leave": answer.append(f"{dict[r[1]]}님이 나갔습니다.") return answer주병규
2024-08-16 03:26:41주어진 기록에서 유저의 행동(입장, 퇴장)과 닉네임 변화를 파악하여 각 유저의 행동에 대한 메시지를 출력하는 코드입니다. 딕셔너리를 이용하여 유저 아이디를 키로, 닉네임을 값으로 저장하고, 'Change' 행동을 제외한 나머지 행동과 유저 아이디를 리스트에 저장하여 결과를 생성합니다. 코드는 딕셔너리와 리스트를 활용하여 메시지를 효율적으로 생성합니다. 하지만, 딕셔너리에서 값을 찾는 과정과 리스트에 추가하는 과정이 반복적으로 수행되어 시간 복잡도가 O(n)으로 높습니다. 시간 복잡도를 줄이기 위해 딕셔너리 대신 해시 테이블을 사용하여 검색 시간을 O(1)로 줄일 수 있습니다. 또한, 리스트에 추가하는 대신 문자열 조작을 통해 결과 문자열을 바로 생성하여 시간 복잡도를 줄일 수 있습니다.
def solution(record): userDic = {} idRecord=[] for getRecord in record: getRecord = getRecord.split(" ") if len(getRecord)==3: userDic[getRecord[1]] = getRecord[2] #행동, 유저아이디, 닉네임 순으로 들어오는데 닉네임이 들어올 시 유저의 닉네임이 변경됨으로 이를 key를 유저아이디로 value를 닉네임으로 dictionary에 저장한다 if getRecord[0]!="Change": idRecord.append((getRecord[1],getRecord[0])) #닉네임 변경은 result에 포함되지 않음으로 이를 제외한 행동들과 유저의 아이디를 기록해둔다 answer = [] for userId,act in idRecord: text =userDic[userId]+"님이 " #유저의 아이디를 닉네임으로 변경 if act == "Enter": text+="들어왔습니다." else: text+="나갔습니다." answer.append(text) return answer배수훈
2024-08-13 13:27:33입력으로 주어진 로그 기록에서 사용자의 입장과 퇴장을 나타내는 문자열을 생성하는 코드입니다. 사용자 이름과 닉네임을 저장하는 딕셔너리를 사용하여 닉네임을 추출하여 문자열을 생성합니다. 딕셔너리에서 닉네임을 찾는 과정에서 불필요한 반복문이 존재합니다. 딕셔너리의 키 조회는 O(1) 시간 복잡도를 가지고, 반복문은 O(N) 시간 복잡도를 가지므로 전체 시간 복잡도를 줄일 수 있습니다. 코드에서 'Change' 명령어는 결과 문자열에 영향을 주지 않으므로 'Change' 명령어를 처리하는 부분을 제거하여 불필요한 연산을 줄일 수 있습니다.
def solution(record): user = dict() for r in record: tmp = r.split(" ") if tmp[0] in ['Enter', 'Change']: user[tmp[1]] = tmp[2] result = [] for r in record: tmp = r.split(" ") if tmp[0] == 'Enter': result.append(f"{user[tmp[1]]}님이 들어왔습니다.") continue if tmp[0] == 'Leave': result.append(f"{user[tmp[1]]}님이 나갔습니다.") continue return result이석민
2024-08-11 23:10:14주어진 기록에서 사용자의 입장/퇴장 정보를 추출하여 각 사용자의 닉네임을 이용해 메시지를 만드는 코드입니다. 사용자 ID와 닉네임을 저장하는 딕셔너리를 사용하여 중복 탐색을 줄이고, 입력 정보를 한 번만 처리하여 메시지를 생성합니다. 입출력 정보가 모두 문자열이기 때문에, 문자열 비교 연산 속도를 높이기 위해 `==` 대신 `is` 연산자를 사용할 수 있습니다. `id_to_nick` 딕셔너리의 키를 `str`로 캐스팅하여 해싱 연산 속도를 높일 수 있습니다. 그리고, `template` 딕셔너리에 `Change` 키가 없는 부분을 제거하여 불필요한 연산을 줄일 수 있습니다. 시간 복잡도를 줄이기 위해 입력 정보를 한 번에 처리하는 방식을 사용하였습니다. 특히, `Enter`, `Change` 명령에 대한 정보를 미리 처리하여, `Leave` 명령 처리 시 `id_to_nick` 딕셔너리에서 닉네임을 찾는 과정을 최소화하였습니다.
def solution(record): id_to_nick = {} for r in record: r = r.split(' ') if r[0] in ('Enter', 'Change'): id_to_nick[r[1]] = r[2] template = { 'Enter': '{user}님이 들어왔습니다.', 'Leave': '{user}님이 나갔습니다.', 'Change': None } result = [] for r in record: r = r.split(' ') if r[0] in ('Enter', 'Leave'): result.append(template[r[0]].replace('{user}', id_to_nick[r[1]])) return result베스트 앨범
코드 제출 (5등) 문제 바로가기이현석
2024-08-16 18:17:12장르별 재생 횟수를 계산하고, 각 장르 내에서 재생 횟수가 높은 노래 2개를 선택합니다. 선택된 노래들의 인덱스를 순서대로 담아 반환합니다. 장르별 재생 횟수를 계산하는 부분에서 `Counter` 클래스를 사용하면 더 간결하고 빠르게 계산할 수 있습니다. 노래 정보를 정렬하는 부분에서 `sorted` 함수 대신 `heapq`를 사용하면 더 빠르게 정렬할 수 있습니다. `song_dict`에 `plays` 정보만 담으면 `sorted` 함수에서 `x[0]`만 비교하면 되므로 속도를 더 향상시킬 수 있습니다.
def solution(genres, plays): answer = [] count_dict = {} song_dict = {} for i in range(len(genres)): if genres[i] not in count_dict: count_dict[genres[i]] = 0 count_dict[genres[i]] += plays[i] if genres[i] not in song_dict: song_dict[genres[i]] = [] song_dict[genres[i]].append((plays[i], i)) sorted_genres = sorted(count_dict.keys(), key=lambda x: count_dict[x], reverse=True) for genre in sorted_genres: songs = sorted(song_dict[genre], key=lambda x: (-x[0], x[1])) answer.extend([song[1] for song in songs[:2]]) return answer주병규
2024-08-16 03:26:49코드는 주어진 장르와 재생 횟수 목록에서 장르별 재생 횟수 합계를 기준으로 내림차순 정렬하고, 각 장르에서 재생 횟수가 높은 순서대로 최대 2곡씩 선택하여 고유 번호를 반환합니다. 이 코드는 장르별로 재생 횟수를 저장하고 정렬하는 방식으로 구현되어 있습니다. 더 빠른 실행 시간을 위해서는 장르별 재생 횟수 합계를 계산하는 과정에서 `collections.Counter`를 사용하여 코드를 간소화하고 연산 속도를 높일 수 있습니다. `sorted` 함수를 사용하여 정렬하는 대신 `heapq` 모듈의 `nlargest` 함수를 사용하면 장르별 상위 2개 곡을 빠르게 찾을 수 있어 전체 실행 시간을 단축시킬 수 있습니다.
def solution(genres, plays): genreDic = {} genreTotalDic = {} for idx, (genre, play) in enumerate(zip(genres, plays)): genreDic[genre] = genreDic.get(genre,[]) genreDic[genre].append((play,idx)) #장르별로 고유번호와 재생횟수를 기록 genreTotalDic[genre] = genreTotalDic.get(genre,0)+play #장르별 총 재생횟수를 기록 genreTotalArr = genreTotalDic.items()#array로 변경 answer = [] for genre, _ in sorted(genreTotalArr, key=lambda x: -x[1]): #많이 재생된 순으로 장르를 정렬 cnt = 0 #최대 2개씩만 기록되도록 제한 for _,idx in sorted(genreDic[genre],key=lambda x: (-x[0], x[1])): #장르별 많이 재생된 순으로 같으면 고유번호가 낮은 순으로 정렬 cnt+=1 answer.append(idx) if cnt >=2: break return answer배수훈
2024-08-13 14:29:03장르별 재생 횟수를 기준으로 정렬하여, 각 장르에서 재생 횟수가 높은 두 곡의 인덱스를 담아 반환하는 코드입니다. 장르별 곡 정보와 재생 횟수를 defaultdict를 활용하여 효율적으로 저장하고, 정렬을 통해 원하는 결과를 얻습니다. 장르별 곡 정보를 저장할 때, 튜플 형태로 저장하여 인덱스 정보를 함께 관리하는 방식 대신, 별도의 리스트에 인덱스를 저장하면 메모리 사용량을 줄일 수 있습니다. 정렬 과정에서 key 함수를 사용하여 코드 가독성을 높였지만, 직접 비교 연산을 수행하는 방식으로 변경하면 속도를 향상시킬 수 있습니다.
from collections import defaultdict def solution(genres, plays): genre_song_dict = defaultdict(list) genre_count_dict = defaultdict(int) for i, (genre, play) in enumerate(zip(genres, plays)): genre_song_dict[genre].append((i, play)) genre_count_dict[genre] += play answer = [] for genre in sorted(genre_count_dict, key=lambda genre: genre_count_dict[genre], reverse=True): for num in sorted(genre_song_dict[genre], key=lambda zipped_song: zipped_song[1], reverse=True)[:2]: answer.append(num[0]) return answer이석민
2024-08-11 22:52:32이 코드는 장르별 재생 횟수가 주어지면 재생 횟수가 높은 장르 순으로, 각 장르 내에서 재생 횟수가 높은 두 곡의 고유 번호를 반환하는 알고리즘을 구현했습니다. 딕셔너리를 사용하여 장르별 재생 횟수와 곡 정보를 저장하고, 정렬을 통해 원하는 순서대로 결과를 도출하는 방식을 사용했습니다. 장르별 재생 횟수를 계산하는 과정에서 불필요한 반복문 사용으로 시간 복잡도가 증가할 수 있습니다. `collections.Counter`와 같은 자료 구조를 활용하면 효율적인 계산이 가능합니다. 장르별 곡 정보를 정렬하는 부분 역시, `heapq` 모듈을 사용하면 더 빠른 정렬 속도를 얻을 수 있습니다. 또한, `take2` 함수는 슬라이싱 대신 `heapq.nlargest` 함수를 사용하면 더 효율적인 방법으로 상위 2개 곡을 선택할 수 있습니다.
def solution(genres, plays): g = dict() p = dict() for i in range(len(genres)): k = genres[i] if genres[i] not in g: g[k] = 0 p[k] = list() g[k] += plays[i] p[k].append((i, plays[i])) g = list(g.items()) g.sort(key=sort_key, reverse=True) answer = [] for x in g: for i in take2(p[x[0]]): answer.append(i[0]) return answer def sort_key(g): return g[1] def take2(g): g.sort(key=sort_key, reverse=True) return g[:2] def map_first(i): return i[0]
2024-08-11 21:00:00 (4문제)
입국심사
코드 제출 (5등) 문제 바로가기주병규
2024-08-11 19:53:02이 코드는 이진 탐색을 이용하여 n명의 사람을 심사하는 데 걸리는 최소 시간을 찾는 알고리즘입니다. 주어진 심사관들의 심사 시간 정보를 이용하여 이진 탐색 범위를 좁혀가며 최적의 시간을 찾습니다. 시간 복잡도는 O(N log M)으로, N은 사람의 수, M은 최대 심사 시간입니다. 더 빠른 실행 시간을 위해서 `for` 루프 내부에서 `middle//time` 연산을 최적화할 수 있습니다. 나눗셈 연산 대신 곱셈 연산을 사용하면 더 빠른 연산 속도를 얻을 수 있습니다. 또한, 이진 탐색 범위를 줄이기 위해 탐색 범위를 초기화 할때 `max(times)*n` 대신 **`n * min(times)`**로 설정하면 더 효율적인 탐색이 가능합니다.
def solution(n, times): left= 1 right = max(times)*n #걸리는 시간을 기준으로 binary search answer = 0 while left <= right: checkN = 0 middle = (left+right)//2 for time in times: checkN+=middle//time #선택한 시간(middle)일때 해당 심사관은 몇명을 상대할 수 있는가 if checkN>=n: break #n이 넘어가버리면 시간을 더 짧게 할 수 있으므로 이후의 for문은 필요하지 않음 if checkN>=n: #현재 선택한 시간일때 심사관이 더 많은 사람들을 심사할 수 있음 answer = middle right = middle-1 else: #현재 선택한 시간일때 심사관이 원하는 명 수(n)만큼 심사 할 수 없다 left = middle+1 return answer이석민
2024-08-11 09:10:35주어진 시간 내에 n명의 사람을 모두 처리할 수 있는 최소 시간을 이분 탐색을 사용하여 찾는 알고리즘입니다. 주어진 시간 내에 처리 가능한 사람 수를 계산하여 이분 탐색 범위를 조정합니다. 이진 탐색 대신 힙 자료구조를 사용하여 더 빠른 시간 복잡도를 얻을 수 있습니다. 힙을 이용하면 시간 순서대로 사람들을 처리할 수 있으며, 현재 시간과 비교하여 처리 가능 여부를 빠르게 판단할 수 있습니다. 시간 복잡도를 낮추기 위해 이진 탐색 대신 힙 자료구조를 사용하고, 이진 탐색에서 사용하는 `target_time // time` 연산을 `target_time / time` 연산으로 변경하여 연산 속도를 향상시킬 수 있습니다.
def solution(n, times): times.sort() answer = 0 left, right = 1, times[-1] * n while left <= right: target_time = (left + right) // 2 total_processed = 0 for time in times: total_processed += (target_time // time) if total_processed >= n: break if total_processed < n: left = target_time + 1 elif total_processed >= n: right = target_time -1 return left이석민
2024-08-11 08:59:49이 코드는 n명의 사람이 각각의 시간(times)만큼 걸리는 검문소를 통과하는데, 가장 늦게 통과하는 사람의 시간을 구하는 알고리즘입니다. 우선순위 큐(힙)을 이용하여, 각 사람의 통과 시간을 관리하고, 가장 빨리 통과하는 사람부터 다음 검문소로 이동하도록 구현했습니다. 힙에 들어가는 값은 (통과 시간, 원래 시간, 사람 인덱스)로 구성되어 있으며, 이를 통해 다음 검문소 통과 시간을 계산하고 다시 힙에 넣습니다. 이 코드는 heapq 모듈을 사용해서 힙을 관리하는데, 더 빠른 힙 구현(예를 들어, C++ STL의 priority_queue)을 사용하면 더 빠르게 동작할 수 있습니다. heapq는 Python의 기본 힙 구현으로, C++ STL의 priority_queue보다 느립니다. 또한, 이 코드는 n-1번의 반복을 수행하는데, 반복문의 횟수를 줄일 수 있는 알고리즘이 있다면 더 빠르게 동작할 수 있습니다. 예를 들어, 각 사람의 통과 시간을 계산하는 대신, 최대 통과 시간을 계산하는 방식으로 바꾸면 반복문의 횟수를 줄일 수 있습니다.
import heapq def solution(n, times): heap = [] for idx, time in enumerate(times): heapq.heappush(heap, (time, time, idx)) for _ in range(n - 1): earliest, t, idx = heapq.heappop(heap) heapq.heappush(heap, (t + earliest, t, idx)) return heapq.heappop(heap)[0]이석민
2024-08-10 15:57:39이 코드는 각 심사관이 1분에 처리할 수 있는 사람 수를 더하여 전체 처리 속도를 계산하고, 그 속도로 n명을 처리하는 데 걸리는 시간을 올림하여 반환합니다. Decimal 자료형을 사용하여 정밀도를 높였지만, `sum` 함수를 사용하여 반복 계산을 수행하고 `math.ceil` 함수를 사용하여 올림 연산을 수행하여 속도가 느릴 수 있습니다. `Decimal` 자료형 대신 `float` 자료형을 사용하고, `for` 루프를 사용하여 `process_per_min`을 계산하면 더 빠른 속도를 얻을 수 있습니다. 또한, `math.ceil` 대신 `int` 함수를 사용하여 올림 연산을 수행하면 더 빠른 속도를 얻을 수 있습니다.
from decimal import * import math def solution(n, times): process_per_min = sum(map(lambda t: 1 / Decimal(t), times)) return math.ceil(n / process_per_min)이현석
2024-08-09 23:27:20이 코드는 이진 탐색을 이용하여 n명의 사람을 times 리스트에 주어진 속도로 검사하는 데 걸리는 최소 시간을 찾습니다. 시간 복잡도는 O(N log(M*N))이며, M은 times 리스트의 최댓값입니다. 이 코드는 이진 탐색을 사용하고 있지만, cnt 변수를 계산하는 부분에서 불필요한 반복문을 사용하고 있습니다. `mid // time` 연산을 통해 각 심사관이 처리할 수 있는 사람 수를 계산할 때, `cnt` 변수가 n 이상이 되는 순간 `break`를 통해 반복문을 종료시키면 더 빠르게 연산할 수 있습니다. 또한, 이진 탐색 범위를 `max(times) * n`으로 설정하는 대신, `sum(times)`로 설정하면 더 적절한 범위를 설정할 수 있습니다. 이는 최악의 경우, 모든 심사관이 가장 느린 속도로 검사를 진행할 때 발생할 수 있는 최대 시간이 `sum(times)`라는 점을 고려한 것입니다.
def solution(n, times): answer = 0 left = 1 right = max(times) * n while left <= right: mid = (left+ right) // 2 cnt = 0 for time in times: cnt += mid // time if cnt >= n: break if cnt >= n: answer = mid right = mid - 1 else: left = mid + 1 return answer배수훈
2024-08-06 09:35:59이 코드는 주어진 시간 내에 n명의 사람을 모두 처리할 수 있는 최소 시간을 찾는 알고리즘입니다. 이진 탐색을 통해 최소 시간을 찾으며, 각 시간에 처리할 수 있는 사람의 수를 계산하여 목표 인원을 만족하는 시간을 찾습니다. 이진 탐색을 사용하여 시간 복잡도를 O(n log n)에서 O(log n)으로 줄였지만, 더 빠른 알고리즘을 사용하여 시간 복잡도를 O(n)으로 줄일 수 있습니다. 예를 들어, 각 심사관의 시간을 정렬한 후, 각 심사관이 처리할 수 있는 최대 인원을 누적합으로 계산하여 n명을 처리하는 데 필요한 최소 시간을 구할 수 있습니다. 또한, `m // t` 연산을 `m / t`로 변경하여 나눗셈 연산을 줄일 수 있습니다. 나눗셈 연산은 곱셈 연산보다 느리기 때문에 곱셈 연산으로 바꿔주면 성능 향상을 기대할 수 있습니다. 마지막으로, `cnt >= n` 조건을 `cnt > n`으로 변경하여 탐색 범위를 줄임으로써 탐색 시간을 단축할 수 있습니다.
def solution(n, times): if n == 1: return min(times) if len(times) == 1: return times[0] * n s = 0 e = max(times) * n max_time = e while s <= e: m = (s + e) // 2 cnt = sum([m // t for t in times]) if cnt >= n and max_time > m: max_time = m if cnt < n: s = m + 1 else: e = m - 1 return max_time순위 검색
코드 제출 (5등) 문제 바로가기주병규
2024-08-11 19:53:25이 코드는 지원자 정보와 쿼리 정보를 이용하여 일치하는 지원자 수를 계산하는 알고리즘을 구현합니다. 지원자 정보는 언어, 직군, 경력, 소울푸드, 점수로 이루어져 있으며, 쿼리는 각 항목에 대한 조건을 포함합니다. 코드는 모든 지원자 정보를 가능한 모든 조합으로 나누어 dictionary에 저장하고, 쿼리에 맞는 조합을 찾아 이진 검색을 통해 일치하는 지원자 수를 계산합니다. 시간 복잡도를 줄이기 위해 itertools.combinations를 사용하여 모든 조합을 생성하는 부분을 더 효율적인 알고리즘으로 변경할 수 있습니다. 예를 들어, 비트 연산을 사용하여 조합을 생성하고, 이진 검색 대신 이분 탐색을 활용하는 것이 더 빠른 속도를 제공할 수 있습니다. 또한, 쿼리 정보를 전처리하여 쿼리 조건을 빠르게 검색할 수 있는 자료 구조를 사용하는 것이 좋습니다.
import itertools def solution(info, query): infoDic = {"": []} def inputInfoDic(array, score): for i in range(5): for combination in itertools.combinations(array, i): text = ''.join(combination) if text in infoDic: infoDic[text].append(score) else: infoDic[text] = [score] for getInfo in info: getInfo = getInfo.rsplit(" ", 1) #지원자 정보(언어,직군,경력,소울푸드) score = int(getInfo[1]) #점수 inputInfoDic(getInfo[0].split(" "), score) #지원자 정보를 가능한 모든 조합으로 뽑고 이를 join시켜 하나의 str로 만든 후 dictionary에 넣는다. 이렇게 하면 query에 빈 정보("-")가 들어와도 다른 정보들을 비교하여 찾을 수 있음 for key in infoDic: infoDic[key].sort() def binarySearch(arr, num): start, end = 0, len(arr) while start < end: mid = (start + end) // 2 if arr[mid] >= num: end = mid else: start = mid + 1 return start answer = [] for getQuery in query: getQuery = getQuery.rsplit(" ", 1) #지원자 query(언어,직군,경력,소울푸드) score = int(getQuery[1]) #지원자 score key = getQuery[0].replace("and", "").replace(" ", "").replace("-", "") #"-"을 제외한 query 정보들을 join matched = infoDic.get(key,[]) #해당 query에 맞는 정보를 가진 지원자들의 score 배열을 가져오는데 없을시 빈 배열을 가져옴 startPoint = binarySearch(matched, score) #지원자들의 score 배열 중 원하는 점수 이상의 시작점을 찾음 answer.append(len(matched) - startPoint) return answer이석민
2024-08-11 18:55:07주어진 정보와 질의에 대한 답을 찾는 알고리즘 코드입니다. 이 코드는 정보를 정렬하고 이진 탐색을 사용하여 질의에 대한 답을 찾습니다. 이 코드는 이진 탐색을 반복적으로 수행하여 질의에 대한 답을 찾습니다. 더 효율적인 방법은 이진 트리를 사용하여 하나의 이진 탐색으로 질의에 대한 답을 찾는 것입니다. 또한, 코드 내의 반복문을 더 빠른 알고리즘으로 대체하는 것도 고려할 수 있습니다. 예를 들어, `filter_only_match` 함수의 경우, 범위를 직접 계산하여 반복문을 제거할 수 있습니다. 코드를 최적화할 수 있는 다른 방법으로는 불필요한 정렬을 제거하거나, 맵 데이터 구조를 사용하여 이진 탐색을 더 빠르게 수행하는 방법이 있습니다.
def map_convert(col): s = col.split(' ') return (s[0], s[1], s[2], s[3], -1 if s[4] == '-' else int(s[4])) def find_range_int(rows, lower, col_idx): start, end = 0, len(rows) while start < end: mid = (start + end) // 2 val = rows[mid][col_idx] if val < lower: start = mid + 1 elif val >= lower: end = mid return start def filter_only_match(rows, col_idx, match): if match == '-': return (0, len(rows)) start, end = 0, len(rows) while start < end: mid = (start + end) // 2 val = rows[mid][col_idx] if val < match: start = mid + 1 elif val >= match: end = mid pos_start = start end = len(rows) while end > start: mid = (start + end) // 2 val = rows[mid][col_idx] if val <= match: start = mid + 1 elif val > match: end = mid pos_end = end return (pos_start, pos_end) def solution(info, query): rows = sorted(map(map_convert, info), key = lambda v: v[4]) result = [] for q in query: lang, _, position, _, exp, _, food, score = q.split(' ') cur_rows = rows[find_range_int(rows, int(score), 4):] q = (lang, position, exp, food) for col_idx in range(4): cur_rows = sorted(cur_rows, key = lambda v: v[col_idx]) start, end = filter_only_match(cur_rows, col_idx, q[col_idx]) cur_rows = cur_rows[start:end] result.append(len(cur_rows)) return result이현석
2024-08-10 23:03:22주어진 정보를 조건별로 분류하여 저장하고, 이진 탐색을 통해 각 조건에 맞는 지원자 수를 계산하는 알고리즘입니다. 조건별 분류 시 모든 조합을 생성하여 저장하는 과정에서 시간 복잡도가 높아질 수 있습니다. 조건별 분류 과정을 효율적으로 개선하면 더 빠른 시간 안에 결과를 얻을 수 있습니다. 예를 들어, 조건별로 분류된 정보를 트리 형태로 저장하여 탐색 속도를 높일 수 있습니다.
from itertools import combinations def binary_search(scores, target): left, right = 0, len(scores) while left < right: mid = (left + right) // 2 if scores[mid] >= target: right = mid else: left = mid + 1 return left def solution(info, query): info_dict = {} for i in info: i = i.split() conditions = i[:-1] score = int(i[-1]) for n in range(5): for comb in combinations([0, 1, 2, 3], n): temp = conditions.copy() for c in comb: temp[c] = '-' key = ''.join(temp) if key in info_dict: info_dict[key].append(score) else: info_dict[key] = [score] for key in info_dict: info_dict[key].sort() answer = [] for q in query: q = q.replace("and ", "") q = q.split() key = ''.join(q[:-1]) score = int(q[-1]) if key in info_dict: scores = info_dict[key] idx = binary_search(scores, score) answer.append(len(scores) - idx) else: answer.append(0) return answer배수훈
2024-08-06 11:04:52주어진 정보를 이용하여 각 조건에 맞는 지원자 수를 계산하는 코드입니다. 정보는 조건별로 나누어 저장하고, 이진탐색을 이용하여 조건을 만족하는 지원자 수를 빠르게 찾습니다. 조건별로 분류하는 부분에서 조합을 이용하여 모든 조건 조합을 만들고 이를 defaultdict에 저장하는데, 이는 공간 복잡도를 증가시키고, 불필요한 연산을 수행합니다. 딕셔너리 대신 리스트를 사용하고, 조건별로 인덱싱하여 조건을 만족하는 지원자 수를 빠르게 계산할 수 있습니다. 또한, 이진탐색을 사용하는 대신 해당 조건을 만족하는 지원자 수를 직접 계산할 수 있습니다. 이진탐색 대신에 직접 계산하는 방식을 사용하면, 이진탐색으로 인한 연산량을 줄이고 코드의 실행 속도를 개선할 수 있습니다.
from itertools import combinations from collections import defaultdict from bisect import bisect_left, bisect_right def solution(info, query): table = sorted([data.split(" ") for data in info]) score = [int(row.pop()) for row in table] combi = defaultdict(list) result = [] for idx, row in enumerate(table): for i in range(5): for c in combinations(row, i): combi["".join(c)].append(score[idx]) for i in combi.keys(): combi[i].sort() for q in query: q = q.split(" and ") tmp = q.pop().split(" ") s = int(tmp[-1]) q.append(tmp[0]) q = ["" if i == "-" else i for i in q] q = "".join(q) idx = bisect_left(combi[q], s) result.append(len(combi[q]) - idx) return result징검다리
코드 제출 (5등) 문제 바로가기이석민
2024-08-17 14:12:29주어진 거리 내에 있는 돌들을 제거하여 최대 간격을 갖도록 하는 알고리즘입니다. 이진 탐색을 사용하여 최대 간격을 찾아냅니다. 시간 복잡도는 O(N log N)이며, 이진 탐색을 사용하여 더 빠르게 최적화될 수 있습니다. `rocks` 배열을 정렬하는 대신 `collections.Counter`를 사용하여 `rocks` 배열을 `dict`로 변환하여 `rocks` 정렬을 제거하면 더 빠른 시간 복잡도를 가질 수 있습니다. 또한 이진 탐색의 종료 조건을 `start == end` 대신 `start + 1 == end` 로 변경하면 더 빠르게 종료될 수 있습니다.
def solution(distance, rocks, remove_cnt_target): rocks = sorted(rocks) rocks.append(distance) start, end = 0, distance answer = 0 while start <= end: target_distance = (start + end) // 2 last_position = 0 remove_cnt = 0 for r in rocks: if r - last_position < target_distance: remove_cnt += 1 else: last_position = r if remove_cnt_target < remove_cnt: break if remove_cnt_target < remove_cnt: end = target_distance - 1 else: answer = target_distance start = target_distance + 1 # # 5개를 제거할 생각이었는데, 실제로는 4개를 제거함 # if remove_cnt_target >= remove_cnt: # # 일단 최대값을 저장함. # answer = target_distance # # 최소값을 높일 필요가 있음. # start = target_distance + 1 # else: # end = target_distance - 1 return answer주병규
2024-08-11 19:53:50주어진 거리 안에 있는 바위들을 제거하여, 인접한 바위 사이의 최소 거리를 최대화하는 문제입니다. 이진 검색을 이용하여 최소 거리의 최댓값을 찾습니다. 코드상에 중복 계산을 줄이는 방법이 있습니다. 바위의 위치가 정렬되어 있기 때문에 현재 바위와 이전 바위 간의 거리에 대한 계산은 이전 바위의 위치를 저장하여 불필요한 연산을 줄일 수 있습니다. 또한, `count > n` 조건이 이전 반복에서도 검사되는 것을 고려하여 조기 종료 조건을 추가하면 불필요한 연산을 줄일 수 있습니다.
def solution(distance, rocks, n): rocks = sorted(rocks) rocks.append(distance) #처음 바위는 for문에서 0부터 시작하면 되니까 따로 append안시키고 마지막 바위의 위치만 append result = 0 start,end = 0,distance while start<=end: mid = (start+end)//2 #이 크기 만큼은 돌 사이 거리가 있어야 한다는 최소 거리 before = 0 count = 0 for rock in rocks: if rock-before<mid: count+=1 #사이 거리가 부족하다면 해당 바위 제거 후 부순 바위+=1 else: before = rock #사이 거리가 충분하다면 다음 바위 비교 if count >n: break #부순 바위의 수가 제거할 바위의 수(n)보다 많아지만 이후 for문이 필요 없음 if count>n: #부순 바위의 수가 제거할 바위의 수(n)보다 많을 때 최소 사이 거리를 줄임 end= mid-1 else: #부순 바위의 수가 제거할 바위의 수(n)보다 적을 때 최소 사이 거리를 늘임 result = mid start = mid+1 return result이현석
2024-08-11 17:20:30주어진 거리에서 최대 간격으로 n개의 돌을 제거했을 때, 남은 돌 사이의 최소 거리를 찾는 알고리즘입니다. 이진탐색을 이용하여 최소 거리를 찾습니다. 시간 복잡도를 줄이기 위해 이진탐색의 범위를 조정하고, 불필요한 연산을 제거하는 방식으로 최적화할 수 있습니다. 예를 들어, rocks 배열을 정렬하는 과정에서 이진 탐색의 범위를 조정하여 탐색 범위를 줄일 수 있습니다. 또한, rocks 배열을 순회하며 거리를 계산하는 과정에서 불필요한 연산을 제거하여 시간 복잡도를 줄일 수 있습니다.
def solution(distance, rocks, n): answer = 0 left = 1 right = distance rocks.sort() rocks.append(distance) while left <= right: mid = (left + right) // 2 cnt = 0 prev_rock = 0 for rock in rocks: if rock - prev_rock < mid: cnt += 1 if cnt > n: break else: prev_rock = rock if cnt > n: right = mid -1 else: answer = mid left = mid + 1 return answer배수훈
2024-08-07 11:35:08주어진 길이에서 n개의 돌을 제거하여 인접한 돌 사이의 최소 거리를 최대화하는 문제를 이분 탐색을 통해 해결합니다. 최소 거리를 기준으로 이분 탐색을 수행하여 제거해야 할 돌의 개수를 계산하고 이를 n과 비교하여 탐색 범위를 좁혀 최적값을 찾습니다. 시간 복잡도는 O(N log N)으로, 이분 탐색 횟수는 log N, 매 이분 탐색마다 모든 돌을 순회하기 때문에 N 번의 순회가 필요합니다. 시간 복잡도를 줄이기 위해 이분 탐색 범위를 줄이는 방법을 고려할 수 있습니다. 예를 들어, 이분 탐색 범위를 초기 거리의 절반으로 줄일 수 있습니다. 또한, 이분 탐색 조건을 최적화하여 탐색 횟수를 줄일 수 있습니다. 예를 들어, 제거해야 할 돌의 개수가 n보다 작으면 탐색 범위를 줄이는 대신 바로 최적값을 갱신하고 탐색을 종료할 수 있습니다.
def solution(distance, rocks, n): answer = 0 rocks.sort() s, e = 0, distance #바위가 아닌 거리를 기준으로 탐색함 while s <= e: m = (s + e) // 2 #중간 거리 즉 이 m이 최소 거리가 되려면 몇 개의 바위를 제거해야 하는지 구해야함 pre = 0 cnt = 0 for rock in rocks: if cnt > n: #이미 n개 초과의 바위를 없애야 하는 경우 break #앞의 바위와의 거리를 비교함 if rock - pre < m: #거리가 작은 경우 cnt += 1 else: #큰 경우에는 앞의 돌을 현재 돌로 기억한다. pre = rock #거리가 작은 돌은 삭제 해야하기 때문 if distance - pre < m: #마지막 돌과 목적지까지 거리 계산 cnt += 1 # 삭제해야 할 돌의 개수를 확인해 비교하고 s, e를 제어하여 다음 탐색 위치로 이동 if cnt > n: e = m - 1 else: answer = m s = m + 1 return answer징검다리 건너기
코드 제출 (5등) 문제 바로가기이석민
2024-08-17 15:25:25이 코드는 주어진 돌들의 목록과 최대 연속해서 건널 수 없는 돌의 개수(`k`)를 입력받아, 모든 사람이 안전하게 건널 수 있는 최대 사람 수를 반환하는 이진 검색 알고리즘입니다. 이 코드는 주어진 돌의 높이를 기준으로 이진 검색을 수행하여 최적의 사람 수를 찾습니다. 현재 코드는 `max(stones)`를 이용하여 초기 `end`를 설정하는데, 이 과정은 불필요하게 시간을 낭비할 수 있습니다. `end`를 `max(stones)` 대신 `len(stones)`로 설정하여 초기 설정 시간을 단축시킬 수 있습니다. 또한 `less_then_ppl` 변수를 사용하는 대신 `k`개의 연속된 돌을 체크하여 `current_ppl`보다 작은 돌의 개수를 직접 계산하는 것이 더 효율적입니다. `current_ppl` 보다 작은 돌을 만나면 `k` 개의 돌을 검사한 뒤 다음 돌부터 `k` 개를 검사하는 방식으로 `k` 개의 연속된 돌 검사를 진행하면 불필요한 루프 반복을 줄일 수 있습니다.
def solution(stones, k): ppl = 0 start, end = 0, max(stones) while start <= end: current_ppl = (start + end) // 2 less_then_ppl = 0 for s in stones: if s < current_ppl: less_then_ppl += 1 if less_then_ppl >= k: break else: less_then_ppl = 0 if less_then_ppl >= k: end = current_ppl - 1 else: ppl = current_ppl start = current_ppl + 1 return ppl주병규
2024-08-11 19:54:19이진 탐색을 이용하여 최대 k개의 연속된 돌을 건너뛸 수 있는 최대 사람 수를 찾는 알고리즘입니다. stones 리스트를 순회하며 각 돌의 높이를 현재 사람 수와 비교하여 k개 이상 연속된 돌을 뛰어넘어야 하는 경우를 판단합니다. 시간 복잡도는 O(N log M)으로, N은 stones의 길이, M은 stones의 최댓값입니다. mid값을 구할 때 `(start+end)//2`를 사용하던 것을 `(start+end+1)//2` 로 바꿔서 더 정확하게 중간값을 구할 수 있습니다. 또한, `jump` 변수를 사용하는 대신, k개 이상 연속된 돌을 건너뛰는지 확인하는 부분을 더 간결하게 표현할 수 있습니다.
def solution(stones, k): start,end = 0,max(stones) #기준을 사람 수로 잡음 사람 수가 디딤돌이 적힌 수의 최댓값일때 모든 바위를 넘어가야하기 때문에 end값이 됨 answer = 0 while start<=end: mid = (start+end)//2 #사람의 수 jump=0 #뛰어야하는 크기 canJump = True for stone in stones: if stone<mid: jump+=1 #해당 stone이 사람의 수(사람이 건넌 수)보다 적으면 그 바위는 뛰어가야 하는 바위임으로 jump+=1 else: jump = 0 #아니라면 0으로 초기화 if jump>=k: #뛰어야하는 크기의 제한(k)보다 많이 뛰어야하면 뒤의 for문이 필요 없음 canJump = False break if canJump: #제한(k)에 걸리지 않고 모든 바위를 넘어갔을 경우 answer = mid start = mid+1 #사람의 수를 늘림 else: end = mid-1 #제한(k)에 걸렸을 경우 사람의 수를 줄임 return answer이현석
2024-08-11 17:30:35이 코드는 주어진 돌들의 리스트와 연속된 k개의 돌을 건너뛰는 최대 숫자를 입력으로 받아, 모든 돌을 건너기 위해 건너뛸 수 있는 가장 큰 숫자를 반환하는 이진 탐색 알고리즘을 구현한다. 현재 코드는 `mid`값을 이용하여 이진 탐색을 수행하고 있으며, 탐색 범위를 줄여 나가면서 최적의 값을 찾고 있지만, 탐색 횟수를 줄이기 위해 `mid`를 계산할 때 `left`와 `right`의 평균 대신 `left + (right - left) // 2`를 사용하는 것이 더 효율적일 수 있다. 또한, `stones` 리스트를 순회하는 부분을 이진 탐색으로 대체하여 더 빠르게 탐색할 수 있다. 마지막으로 `max_count` 변수는 현재 코드에서 사용되지 않으므로 제거하는 것이 좋다.
def solution(stones, k): left = 1 right = max(stones) while left <= right: mid = (left + right) // 2 count = 0 max_count = 0 for stone in stones: if stone - mid <= 0: count += 1 if count >= k: break else: count = 0 if count >= k: right = mid - 1 else: left = mid + 1 return left배수훈
2024-08-10 22:52:38주어진 돌들에서 k개 이상의 연속된 돌이 제거될 수 없는 가장 큰 사람의 무게를 찾는 이진 탐색 기반 알고리즘입니다. `isGoOver` 함수는 특정 무게의 사람이 주어진 돌들을 건널 수 있는지 확인하는 역할을 수행하며, `solution` 함수는 이진 탐색을 사용하여 최적의 무게를 찾습니다. 실행 속도를 향상시키기 위해 `isGoOver` 함수에서 `cnt` 변수 대신 `for` 루프를 `break`로 조기 종료시키는 방법을 사용하는 것이 좋습니다. 이는 연속된 `k`개의 돌이 발견되면 더 이상 루프를 반복할 필요가 없기 때문입니다. 또한, `max(stones)`를 사용하는 대신 `stones` 배열의 첫 번째 값을 초기값으로 사용하여 `e`를 설정하는 것을 고려해 볼 수 있습니다.
def isGoOver(stones, man, k): cnt = 0 for stone in stones: if stone < man: cnt += 1 else: cnt = 0 if cnt >= k: return False return True def solution(stones, k): s, e = 1, max(stones) m = 0 result = 0 while s <= e: m = (s + e) // 2 if isGoOver(stones, m, k): result = max(result, m) s = m + 1 else: e = m - 1 return result
2024-08-04 21:00:00 (4문제)
두 개 뽑아서 더하기
코드 제출 (7등) 문제 바로가기이현석
2024-08-04 17:33:14주어진 숫자 리스트에서 두 숫자의 모든 가능한 합을 구한 후 중복을 제거하고 오름차순으로 정렬하여 반환하는 코드입니다. 이중 반복문을 사용하여 모든 숫자 쌍의 합을 구하기 때문에 시간 복잡도가 O(N^2)로 비교적 느립니다. 더 빠른 실행 시간을 위해 이중 반복문 대신 해시 테이블을 활용하여 합을 계산하고 저장하는 방법을 고려할 수 있습니다. 또한, 정렬 작업을 할 때 파이썬의 내장 정렬 함수인 `sorted()` 대신 `sorted(answer)`와 같은 방식으로 정렬하면 더 빠르게 작동할 수 있습니다. 합을 구하는 과정에서 불필요한 연산을 제거하고, 데이터 구조를 효율적으로 사용하여 시간 복잡도를 줄이는 방법을 고려하면 더욱 빠르게 실행되는 코드를 작성할 수 있습니다.
def solution(numbers): answer = set() for i in range(len(numbers)): for j in range(i + 1, len(numbers)): answer.add(numbers[i] + numbers[j]) return sorted(answer)주병규
2024-08-04 15:13:24주어진 숫자 리스트에서 두 숫자를 조합하여 가능한 모든 합을 구하고, 중복을 제거한 후 오름차순으로 정렬하여 반환합니다. 순열을 사용하여 모든 조합을 구하고 집합 연산을 통해 중복을 제거하는데, 조합 대신 itertools.combinations를 사용하면 더 빠르게 코드를 실행할 수 있습니다. 집합 연산 후 정렬하는 과정에서, 입력 숫자의 최대값과 최소값을 이용하여 범위를 제한하고 이 범위 내에서만 정렬하면 시간 복잡도를 줄일 수 있습니다.
import itertools def solution(numbers): numberSet = set() for num1,num2 in itertools.permutations(numbers,2): #조합 numberSet.add(num1+num2) return list(sorted(numberSet))#정렬하지웅
2024-07-29 22:46:53주어진 숫자 리스트에서 2개의 숫자를 뽑아 합을 구한 후, 중복을 제거하고 오름차순으로 정렬하여 반환합니다. itertools.combinations를 사용하여 조합을 생성하고, set을 사용하여 중복을 제거합니다. 더 빠른 실행 시간을 위해 itertools.combinations 대신 이중 반복문을 사용하여 조합을 생성할 수 있습니다. 이는 조합 생성 과정에서 추가적인 메모리 할당을 줄여줍니다. 또한, 중복 제거를 위해 set을 사용하는 대신, 사전을 사용하여 합계를 키로, 해당 합계의 횟수를 값으로 저장하여 중복 여부를 확인할 수 있습니다. 이 방식은 set보다 더 빠른 중복 제거 속도를 제공합니다. 코드 내에서 직접적인 최적화 외에도, 더 빠른 알고리즘을 사용하는 것이 효과적일 수 있습니다. 예를 들어, 입력 리스트의 크기가 크고, 입력 리스트가 정렬되어 있다면, 투 포인터 알고리즘을 사용하여 2개의 숫자를 뽑아 합을 구하는 과정을 더 빠르게 수행할 수 있습니다.
import itertools def solution(numbers): answer = [] comb = itertools.combinations(numbers, 2) for i in comb: answer.append(sum(i)) ans_sum = list(set(answer)) return sorted(ans_sum)배수훈
2024-07-29 22:04:54주어진 숫자 리스트에서 2개의 숫자를 조합하여 합을 구하고, 중복을 제거한 후 오름차순으로 정렬하여 반환합니다. 이 코드는 조합을 생성하기 위해 `itertools.combinations`를 사용하고, 중복을 제거하기 위해 `set`을 사용하고, 정렬하기 위해 `sorted`를 사용합니다. 이 코드는 `itertools.combinations`를 사용하기 때문에 시간 복잡도가 O(n^2)이고, 이는 입력 크기가 커질수록 실행 시간이 기하급수적으로 증가한다는 단점이 있습니다. `itertools.combinations` 대신 두 개의 중첩 루프로 조합을 생성하면 더 빠르게 실행될 수 있습니다. 또한, 중복 제거를 위해 `set`을 사용하는 것보다 hash map을 사용하는 것이 더 빠릅니다. 결론적으로, `itertools.combinations`를 사용하는 대신 두 개의 중첩 루프를 사용하고, 중복 제거를 위해 hash map을 사용하면 실행 시간을 단축할 수 있습니다.
import itertools def solution(numbers): return sorted(list(set(nums[0] + nums[1] for nums in itertools.combinations(numbers, 2))))배수훈
2024-07-29 22:04:07주어진 숫자 리스트에서 두 숫자를 조합하여 만들 수 있는 모든 합을 구하고, 중복을 제거한 후 오름차순으로 정렬하여 반환하는 코드입니다. itertools 라이브러리를 사용하여 순열을 생성하고, 두 숫자를 더하여 합을 구하는 방식으로 구현되었습니다. 더 빠른 실행 시간을 위해 itertools 라이브러리 대신 직접 순열을 구현하는 방법을 고려해볼 수 있습니다. 또한, 중복 제거를 위해 set을 사용하는 대신, 정렬된 상태에서 중복을 제거하는 방식을 사용하면 더 빠른 성능을 얻을 수 있습니다. 리스트에서 중복을 제거하는 과정에서, 해당 리스트를 정렬한 후 중복 제거를 수행하여 더 빠르게 중복을 제거할 수 있습니다. 이는 set을 사용하는 것보다 더 빠른 방식입니다.
import itertools def solution(numbers): return sorted(list(set(nums[0] + nums[1] for nums in itertools.permutations(numbers, 2))))이지민
2024-07-29 15:29:15주어진 숫자 리스트에서 가능한 모든 2개의 숫자 조합을 구하여 합계를 계산하고 중복을 제거하여 오름차순으로 정렬하여 반환하는 함수입니다. itertools 라이브러리를 사용하여 조합을 생성하고, set 자료구조를 사용하여 중복을 제거하는 방식을 사용했습니다. 조합 생성 시 itertools.combinations_with_replacement 를 사용하면 더 빠르게 모든 조합을 구할 수 있으며, 반복문 대신 list comprehension을 사용하면 코드 가독성을 높일 수 있습니다.
import itertools def solution(numbers): answer = [] c = list(itertools.combinations(numbers,2)) for i in c: a,b = i answer.append(a+b) set_answer = set(answer) arr = list(set_answer) arr.sort() return arr이석민
2024-07-28 22:05:49주어진 숫자 리스트에서 두 숫자를 조합하여 만들 수 있는 모든 합을 구하고, 중복을 제거한 후 오름차순으로 정렬하여 반환합니다. itertools.combinations를 사용하여 조합을 생성하는 부분은 효율적이지만, set을 사용하여 중복을 제거하는 부분은 시간 복잡도가 O(N)으로 비교적 높습니다. 이 부분을 해시 테이블을 사용하여 O(1) 시간 복잡도로 중복을 제거하면 더 빠르게 실행될 수 있습니다. 또한, 정렬하는 부분도 시간 복잡도가 O(N log N)이므로, 이 부분을 최적화할 수 있습니다. 예를 들어, 합을 구하는 과정에서 바로 정렬된 상태로 저장하면, 별도의 정렬 과정이 필요하지 않습니다.
import itertools def solution(numbers): return sorted(list(set(n1 + n2 for n1, n2 in itertools.combinations(numbers, 2))))이석민
2024-07-28 22:04:17주어진 숫자 배열의 모든 두 숫자 조합의 합을 구하고 중복을 제거하여 오름차순으로 정렬합니다. itertools.permutations를 사용하여 모든 순열을 생성하고, 합을 구한 후 집합으로 중복을 제거하고, sorted 함수를 사용하여 오름차순으로 정렬합니다. 순열 대신 조합을 사용하면 시간 복잡도를 줄일 수 있습니다. 왜냐하면 permutations는 모든 순열을 생성하지만 조합은 순서에 상관없이 모든 조합을 생성하기 때문입니다. 또한, 중복 제거를 위해 set을 사용하는 것보다 중복을 제거하는 알고리즘(예: HashSet)을 사용하면 더 빠른 성능을 얻을 수 있습니다. 시간 복잡도를 줄이기 위해 해시 테이블을 사용하여 두 숫자의 합을 저장하고 중복을 제거할 수 있습니다. 이렇게 하면 중복 제거를 위한 별도의 연산이 필요하지 않고 시간 복잡도를 줄일 수 있습니다.
import itertools def solution(numbers): return sorted(list(set(n1 + n2 for n1, n2 in itertools.permutations(numbers, 2))))H-index
코드 제출 (6등) 문제 바로가기이현석
2024-08-04 19:38:50해당 코드는 주어진 인용 횟수 목록에서 히어링 지수를 계산하는 알고리즘입니다. 히어링 지수는 최소 h개의 논문이 h번 이상 인용된 값 중 최댓값을 의미하며, 이 코드는 주어진 인용 횟수 목록을 탐색하며 히어링 지수를 찾습니다. 시간 복잡도를 개선하기 위해 이분 탐색을 사용하는 것이 더 빠릅니다. 이분 탐색은 주어진 인용 횟수 목록을 정렬한 후 히어링 지수를 찾는 방식으로, O(n log n)의 시간 복잡도를 가지는 코드보다 더 빠른 O(log n)의 시간 복잡도를 가지는 코드를 구현할 수 있습니다. 또한, 주어진 인용 횟수 목록의 최댓값을 미리 찾는 대신, 인용 횟수 목록을 직접 정렬하여 이분 탐색을 수행하는 방법도 있습니다. 이 방법은 최댓값을 찾는 과정을 생략하여 시간 복잡도를 줄이는 효과를 기대할 수 있습니다.
def solution(citations): max_value = max(citations) chk = [0] * max_value res = 0 for i in range(1, max_value): for c in citations: if c >= i: chk[i] += 1 if chk[i] >= i and i > res: res = i return res주병규
2024-08-04 15:17:20주어진 논문 인용 횟수 리스트에서 h-index를 찾는 알고리즘입니다. 논문 인용 횟수를 내림차순으로 정렬한 후, 인용 횟수가 인덱스보다 작거나 같아지는 지점을 찾아 해당 인덱스를 h-index로 반환합니다. 정렬 과정에서 이진탐색을 사용하면 시간 복잡도를 O(n log n)에서 O(log n)으로 줄일 수 있습니다. 또한, 인용 횟수 리스트의 최댓값을 미리 구하여 인덱스 범위를 제한하는 방식으로 불필요한 반복을 줄일 수 있습니다.
def solution(citations): citations = sorted(citations,reverse=True) #정렬 arrLen = len(citations) for i in range(arrLen): if citations[i]<=i: #h편이상(citations[i]편 이상)이 h편(i) 이상 return i #citations[i]가 return되지 않는 이유는 [0,3,5,5,5,5]일때 3이상이여도 되지만 4이상이여도 성립하기 때문에i값을 return 시켜야 더 큰 값이 return 된다 return arrLen이지민
2024-08-02 12:23:34이 코드는 주어진 논문 인용 횟수 리스트에서 h-index를 찾는 알고리즘입니다. 주어진 리스트를 내림차순으로 정렬한 후, 인덱스와 인용 횟수를 비교하여 h-index를 반환합니다. 리스트를 정렬하는 과정은 이진탐색과 같이 더 효율적인 방법으로 대체할 수 있으며, 인덱스와 인용 횟수를 비교하는 부분은 이진탐색을 이용하여 시간 복잡도를 줄일 수 있습니다. 또한, 인용 횟수가 0인 경우를 미리 처리하면 불필요한 반복을 줄일 수 있습니다.
def solution(citations): citations.sort(reverse=True) for idx , citation in enumerate(citations): if idx >= citation: return idx return len(citations)이석민
2024-08-02 03:54:35이 코드는 주어진 논문 인용 횟수 목록에서 하이어 인덱스(h-index)를 계산하는 알고리즘을 구현합니다. 코드는 인용 횟수 목록을 정렬한 후 이진 검색을 이용하여 h-index를 찾습니다. 시간 복잡도를 줄이기 위해 이진 검색 대신 투 포인터 기법을 사용할 수 있습니다. 투 포인터 기법은 정렬된 목록에서 특정 조건을 만족하는 요소를 효율적으로 찾는 데 유용합니다. 또한, 정렬된 목록에서 h-index를 찾는 과정을 이진 검색보다 빠르게 수행할 수 있는 더 효율적인 알고리즘이 존재합니다.
def solution(citations): citations.sort() max_h = 0 for h in range(1, len(citations) + 1): if (citations[len(citations) - h] >= h) and (citations[len(citations) - h - 1] <= h or len(citations) == h): max_h = h return max_h배수훈
2024-07-29 23:13:28주어진 논문 인용 횟수 목록에서 h-index를 계산하는 알고리즘입니다. 10001개의 원소를 가지는 리스트를 이용하여 인용 횟수별 논문 개수를 저장하고, 해당 리스트를 순회하며 h-index를 찾습니다. 리스트의 크기를 10001로 고정하는 것은 메모리 낭비이며, 인용 횟수의 최대값을 이용하여 리스트의 크기를 동적으로 조정할 수 있습니다. 또한, 인용 횟수를 기준으로 이분 탐색을 사용하면 h-index를 더 빠르게 찾을 수 있습니다. 이진 탐색을 사용하면 O(logN) 시간 복잡도로 h-index를 찾을 수 있는 반면, 현재 알고리즘은 O(N^2) 시간 복잡도를 가지므로 시간 초과 발생 가능성이 높습니다.
def solution(citations): answer = [0 for i in range(10001)] size = len(answer) h_index = 0 for i, num in enumerate(citations): for j in range(0, num + 1): answer[j] += 1 # print(answer) for i, num in enumerate(answer): # print(num, ">=", i, len(citations) - num, "<=", i) if num >= i and len(citations) - num <= i: h_index = i return h_index문자열 내 마음대로 정렬하기
코드 제출 (6등) 문제 바로가기이현석
2024-08-04 19:43:58주어진 문자열 리스트에서 n번째 문자를 앞으로 옮긴 후 사전 순으로 정렬하여 다시 리스트로 반환하는 함수입니다. 문자열을 정렬하기 전에 n번째 문자를 앞으로 옮기는 과정을 통해 문자열을 사전 순으로 정렬하는 효율적인 방법을 사용합니다. 문자열을 순회하면서 n번째 문자를 앞으로 옮기는 과정에서 문자열을 새로 생성하는 대신 슬라이싱을 사용하여 메모리 사용량을 줄일 수 있습니다. 또한 정렬 시 문자열 전체를 비교하는 대신 n번째 문자부터 비교하도록 변경하여 속도를 개선할 수 있습니다.
def solution(strings, n): answer = [] for i in range(len(strings)): strings[i] = strings[i][n] + strings[i] strings.sort() for i in range(len(strings)): answer.append(strings[i][1:]) return answer주병규
2024-08-04 15:17:55주어진 문자열 리스트에서 n번째 문자를 기준으로 오름차순 정렬하여 반환하는 함수입니다. 람다 함수를 사용하여 문자열의 n번째 문자와 전체 문자열을 튜플로 만들어 정렬 기준으로 사용합니다. 현재 코드는 파이썬의 내장 정렬 함수를 사용하기 때문에 시간 복잡도가 O(n log n)입니다. 더 빠른 속도를 위해서는 radix sort와 같은 선형 시간 정렬 알고리즘을 사용할 수 있습니다. 또한 n번째 문자를 비교할 때, ASCII 코드를 이용하여 직접 비교하는 것이 더 빠르며, 문자열 비교 연산 대신 문자 코드를 직접 비교하여 시간을 단축할 수 있습니다.
def solution(strings, n): return sorted(strings,key=lambda x :(x[n],x))이지민
2024-08-02 12:27:46주어진 문자열 리스트에서 n번째 문자를 기준으로 오름차순 정렬하여 반환하는 코드입니다. 람다 함수를 사용하여 n번째 문자와 문자열 전체를 결합하여 정렬 기준으로 사용합니다. 현재 코드는 `sort` 함수를 사용하고 있어, 시간 복잡도가 O(n log n)입니다. `bucket sort`와 같은 더 빠른 정렬 알고리즘을 사용하면 시간 복잡도를 O(n)으로 줄일 수 있습니다. n번째 문자가 알파벳이라는 점을 활용하여 각 알파벳에 해당하는 버킷을 만들고 문자열을 버킷에 넣은 후 버킷을 순회하며 문자열을 연결하면 됩니다. `sort` 함수 대신 `sorted` 함수를 사용하여 새로운 리스트를 생성하도록 변경하면 원본 리스트를 보존할 수 있습니다. `sorted` 함수는 `sort` 함수와 동일한 시간 복잡도를 가지지만, 원본 리스트를 수정하지 않고 새로운 리스트를 반환합니다.
def solution(strings, n): strings.sort(key= lambda x : x[n]+x) return strings배수훈
2024-07-29 23:18:03주어진 문자열 리스트에서 n번째 문자를 기준으로 오름차순 정렬한 후, 동일한 n번째 문자를 가진 문자열은 사전순으로 정렬하는 함수입니다. 람다 함수를 사용하여 정렬 기준을 설정하여 코드 가독성을 높였습니다. n번째 문자를 비교하는 부분을 이진 검색으로 변경하면 더 빠르게 동작할 수 있습니다. 또한, 파이썬의 `sorted` 함수는 `Timsort` 알고리즘을 사용하는데, 입력 데이터에 따라 다른 정렬 알고리즘을 적용하여 성능을 최적화할 수 있습니다. 만약 `strings` 리스트가 이미 정렬되어 있다면, `sorted` 함수 대신 `list.sort()` 메서드를 사용하여 시간 복잡도를 줄일 수 있습니다.
def solution(strings, n): return sorted(strings, key = lambda key: (key[n], key))이석민
2024-07-28 22:33:08주어진 문자열 리스트에서 n번째 문자를 기준으로 오름차순 정렬하는 함수입니다. lambda 함수를 사용하여 정렬 기준을 정의하고, extract_key 함수를 통해 n번째 문자를 앞에 붙여서 정렬 기준으로 삼습니다. 시간 복잡도를 줄이기 위해, n번째 문자를 기준으로 문자열을 분류하고 각 그룹 내에서 다시 정렬하는 방식을 사용할 수 있습니다. 또한, n번째 문자를 추출하는 과정에서 문자열 복사를 제거하여 성능을 향상시킬 수 있습니다. 이는 불필요한 메모리 할당을 줄이고 연산 속도를 높이기 위함입니다.
def extract_key(s, n): return s[n] + '_' + s def solution(strings, n): return sorted(strings, key = lambda v: extract_key(v, n))가장 큰 수
코드 제출 (6등) 문제 바로가기이현석
2024-08-04 19:56:20주어진 숫자 리스트를 문자열로 변환하여 3배 반복한 값 기준으로 내림차순 정렬하여 가장 큰 수를 만드는 코드입니다. 숫자가 0으로 시작할 경우 "0"을 반환합니다. 3배 반복한 값을 비교하는 대신 문자열 비교를 통해 더 빠르게 정렬할 수 있습니다. 큰 수를 구성하기 위해 숫자를 정렬할 때 앞 자리부터 크게 비교하는 것이 더 효율적입니다. 숫자를 문자열로 변환하는 대신 `sorted` 함수를 사용하면 메모리 사용량을 줄일 수 있습니다.
def solution(numbers): numbers_str = list(map(str, numbers)) numbers_str.sort(key=lambda x: x*3, reverse=True) answer = ''.join(numbers_str) if answer[0] == '0': return '0' return answer주병규
2024-08-04 15:29:36주어진 숫자 리스트에서 가장 큰 수를 만들기 위해 각 숫자를 문자열로 변환하여 4번 반복한 문자열의 앞 4자리를 기준으로 내림차순 정렬한 후 이어 붙여 문자열로 반환하는 코드입니다. 숫자를 문자열로 변환하여 비교하는 방식은 시간 복잡도가 높을 수 있으므로, 정수 비교 기반의 정렬 알고리즘을 사용하거나 숫자를 10진수로 변환하는 대신 2진수로 변환하여 비교하는 방법이 더 효율적입니다. 또한, 숫자를 4번 반복한 문자열을 만들어 비교하는 대신, 숫자를 2개씩 묶어 비교하는 방법을 사용하면 메모리 사용량을 줄일 수 있습니다.
def solution(numbers): numberList = list(map(str, sorted(numbers, key=lambda x: (str(x)*4)[:4], reverse=True))) #최대 크기가 1000임으로 길이가 6이 될때까지 늘려 원소들을 비교한다 ex) 1과 1000을 비교하기 위해 result = "".join(numberList) return str(int(result)) #result 0000이었을 때를 위해이지민
2024-08-02 12:47:23주어진 숫자들을 문자열로 변환하여 3번 반복했을 때 큰 순서로 정렬한 뒤 합쳐서 가장 큰 수를 만드는 코드입니다. 숫자의 크기 비교를 위해 문자열 3번 반복하여 비교하는 방식을 사용했지만, 더 빠른 비교 방법을 사용하면 더욱 빠르게 동작할 수 있습니다. 예를 들어 문자열을 숫자로 변환하여 비교하거나, 문자열 3번 반복 대신 숫자를 비교하는 함수를 사용하는 방법도 생각해볼 수 있습니다.
def solution(numbers): answer = '' numbers= list(map(str,numbers)) numbers.sort(key=lambda x : x*3,reverse=True) for i in numbers: answer = answer + i return str(int(answer))이석민
2024-08-02 03:58:42주어진 숫자 배열의 모든 순열을 생성하여 가장 큰 수를 찾는 코드입니다. 주어진 숫자들을 문자열 형태로 변환하여 순열을 생성한 후, 다시 정수로 변환하여 최댓값을 찾습니다. 이 코드는 itertools 라이브러리를 사용하여 순열을 생성하는데, 이는 파이썬 내장 함수보다 효율적이지 않을 수 있습니다. 또한, map 함수를 두 번 사용하는 대신 리스트 내포를 사용하여 코드를 간결하게 작성할 수 있습니다. 순열 생성을 위해 `itertools.permutations` 대신 `itertools.islice` 와 `itertools.product`를 활용하면 속도 향상을 기대할 수 있습니다. `itertools.permutations`는 모든 순열을 생성하지만, `itertools.product`는 조건에 맞는 특정 순열만 생성하여 불필요한 연산을 줄일 수 있습니다. `itertools.islice`를 사용하면 특정 개수의 순열만 생성하도록 제한할 수 있어 더욱 빠르게 최댓값을 찾을 수 있습니다.
import itertools def solution(numbers): return str(max(map(lambda s: int(''.join(s)), itertools.permutations(map(str, numbers)))))배수훈
2024-07-29 23:23:25주어진 숫자 배열을 사전순으로 정렬하여 가장 큰 수를 만드는 알고리즘입니다. 두 숫자의 크기를 비교할 때 문자열로 변환하여 합쳐서 비교하는 방법을 사용합니다. `cmp_to_key` 함수를 사용하여 정렬 함수에 비교 함수를 적용하였는데, 이는 `sorted` 함수의 `key` 인자에 직접 함수를 전달하는 것보다 느릴 수 있습니다. `sorted` 함수의 `key` 인자에 직접 비교 함수를 전달하거나, `lambda` 함수를 사용하여 더 빠르게 처리할 수 있습니다. `str_result` 변수를 사용하여 결과를 문자열로 변환하는 과정에서 `join` 함수를 사용하는 것은 `map` 함수와 `join` 함수를 분리하여 처리하는 것보다 느릴 수 있습니다. `map` 함수를 사용하여 모든 숫자를 문자열로 변환하고, 이후 `"".join(result)` 와 같이 `join` 함수를 사용하여 문자열을 연결하는 것이 더 효율적입니다.
from functools import cmp_to_key def my_compare(a, b): if a == 0: return 1 str_a = str(a) str_b = str(b) return int(str_b+str_a) - int(str_a+str_b) def solution(numbers): result = sorted(numbers, key=cmp_to_key(my_compare)) str_result = "".join(map(str, result)) return "0" if int(str_result) == 0 else str_result
2024-07-28 21:00:00 (5문제)
모의고사
코드 제출 (6등) 문제 바로가기주병규
2024-07-28 07:46:04주어진 답변 목록에 대해 각 학생의 답변 패턴을 비교하여 가장 높은 점수를 받은 학생의 번호를 반환하는 함수입니다. 각 학생의 답변 패턴은 정해진 배열로 이루어져 있으며, 입력된 답변 목록과 비교하여 일치하는 답변이 있으면 점수를 1점씩 부여합니다. 더 빠른 실행 시간을 위해 각 학생의 답변 배열을 미리 계산하여 저장할 수 있습니다. 예를 들어, 첫 번째 학생의 답변 배열을 `[1,2,3,4,5,1,2,3,4,5,...]` 처럼 반복적으로 생성하여 사용하면 불필요한 연산을 줄일 수 있습니다. 또한, `max` 함수를 사용하는 대신 최댓값을 변수에 저장하여 비교 횟수를 줄일 수 있습니다. 주어진 배열에서 원소를 탐색할 때 `i%5`, `i%8`, `i%10` 연산은 비트 연산을 사용하여 더 빠르게 수행할 수 있습니다. 예를 들어, `i%2` 연산 대신 `i&1` 연산을 사용하는 것이 더 빠릅니다.
def solution(answers): result = [] first,second,third = 0,0,0 #점수들 firAn = [1,2,3,4,5] secAn = [2,1,2,3,2,4,2,5] thrAn = [3,3,1,1,2,2,4,4,5,5] for i,answer in enumerate(answers): first += 1 if firAn[i%5] == answer else 0 second += 1 if secAn[i%8] == answer else 0 third += 1 if thrAn[i%10] == answer else 0 maxScore = max([first,second,third]) for i,score in enumerate([first,second,third]): if score == maxScore: result.append(i+1) return result이현석
2024-07-27 12:05:41이 코드는 세 명의 사람이 낸 답변과 정답 목록을 입력받아 가장 많은 문제를 맞힌 사람의 번호를 출력하는 알고리즘입니다. 세 명의 사람이 낸 답변 패턴은 각각 정해져 있으며, 입력받은 답변 목록과 비교하여 각 사람이 맞힌 문제의 개수를 세고, 가장 많은 문제를 맞힌 사람의 번호를 출력합니다. 시간 복잡도를 줄이기 위해 각 사람의 답변 패턴을 미리 계산하고, 입력받은 답변 목록과 비교하는 과정에서 `%` 연산을 사용하여 반복적인 패턴을 효율적으로 확인합니다. 더 빠른 실행 시간을 위해 각 사람의 답변 패턴을 `for` 루프를 사용하여 한 번에 계산하는 것이 아니라, 각 사람의 답변 패턴을 별도의 함수로 만들어서 한 번만 계산하는 방법을 고려할 수 있습니다. 또한, `max` 함수를 사용하여 최댓값을 찾는 대신, `if` 문과 `max` 변수를 사용하여 최댓값을 찾으면 더 빠르게 최댓값을 찾을 수 있습니다.
def solution(answers): a = [1,2,3,4,5] b = [2,1,2,3,2,4,2,5] c = [3,3,1,1,2,2,4,4,5,5] person = [0] * 3 answer = [] for i in range(len(answers)): if(answers[i] == a[i%5]): person[0] += 1 if(answers[i] == b[i%8]): person[1] += 1 if (answers[i] == c[i%10]): person[2] += 1 winner = max(person) for i in range(len(person)): if person[i] == winner: answer.append(i+1) return answer배수훈
2024-07-25 22:38:24주어진 답변 목록 `answers`와 세 명의 수포자들의 답변 패턴을 비교하여 가장 많은 답변을 맞힌 수포자의 번호를 반환하는 코드입니다. 각 수포자의 답변 패턴은 `fuck_math` 리스트에 저장되어 있으며, `answers` 리스트의 각 답변과 비교하여 맞는 답변의 갯수를 `cnt` 리스트에 누적합니다. 이 코드는 `answers` 리스트의 크기만큼 반복하며 각 답변을 비교하기 때문에 시간 복잡도가 O(N)입니다. `fuck_math` 리스트를 사용하여 각 수포자의 답변 패턴을 저장하는 대신, `for` 루프 내에서 답변 패턴을 직접 계산하는 방법을 사용하면 메모리 사용량을 줄일 수 있습니다. 또한, `cnt` 리스트를 생성하는 대신, `max_cnt` 변수를 사용하여 최대 갯수를 기록하고 최대 갯수를 가진 수포자의 번호만 저장하면 더 효율적으로 코드를 작성할 수 있습니다.
def solution(answers): answer = [] fuck_math = [[1, 2, 3, 4, 5], [2, 1, 2, 3, 2, 4, 2, 5], [3, 3, 1, 1, 2, 2, 4, 4, 5, 5]] cnt = [0, 0, 0] for i, ans in enumerate(answers): for j, jjick in enumerate(fuck_math): if jjick[i % len(jjick)] == ans: cnt[j] += 1 max_cnt = max(cnt) for i, c in enumerate(cnt): if c == max_cnt: answer.append(i + 1) return answer이석민
2024-07-24 23:01:02주어진 답변 목록에 대해 세 명의 학생이 각자의 패턴으로 답변을 맞힌 횟수를 계산하여 가장 많이 맞힌 학생의 번호를 반환하는 함수입니다. 세 학생의 패턴은 각각 1, 2, 3, 4, 5를 반복하는 패턴, 2, 1, 2, 3, 2, 4, 2, 5를 반복하는 패턴, 3, 3, 1, 1, 2, 2, 4, 4, 5, 5를 반복하는 패턴입니다. 각 학생의 답변 패턴을 미리 계산하여 배열로 저장하고, 답변 목록과 비교하여 맞힌 횟수를 계산하는 방식으로 속도를 높일 수 있습니다. 또한, 최댓값을 찾는 부분에서 `max` 함수 대신 직접 비교 연산을 수행하면 좀 더 빠르게 처리할 수 있습니다.
def solution(answers): answer = ( (1, 2, 3, 4, 5), (2, 1, 2, 3, 2, 4, 2, 5), (3, 3, 1, 1, 2, 2, 4, 4, 5, 5) ) correct_score = [] for a in answer: correct_cnt = 0 pos = 0 for pa in answers: if pa == a[pos]: correct_cnt += 1 pos = (pos + 1) % len(a) correct_score.append(correct_cnt) max_score = max(correct_score) result = [] for idx, score in enumerate(correct_score): if score == max_score: result.append(idx + 1) return result이지민
2024-07-23 22:42:52주어진 답변 목록에 대해 세 명의 사람이 낸 답변 패턴과 비교하여 가장 많이 맞힌 사람의 번호를 오름차순으로 반환하는 함수입니다. 각 사람의 답변 패턴은 미리 정의된 리스트로 주어집니다. 코드는 반복문을 사용하여 각 답변을 비교하는데, 답변 패턴을 인덱스 연산으로 접근하는 부분에서 불필요한 조건문이 사용되었습니다. 모듈로 연산을 활용하면 더 간결하고 빠르게 인덱스를 계산할 수 있습니다. 또한, 최대값을 구하는 부분에서 `max` 함수를 사용하는 대신, 직접 비교하여 최대값을 구하면 연산 속도를 높일 수 있습니다.
def solution(answers): ans = [] first_person = [1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,1,2,3,4,5] second_person = [2,1,2,3,2,4,2,5,2,1,2,3,2,4,2,5,2,1,2,3,2,4,2,5,2,1,2,3,2,4,2,5,2,1,2,3,2,4,2,5] third_person = [3,3,1,1,2,2,4,4,5,5,3,3,1,1,2,2,4,4,5,5,3,3,1,1,2,2,4,4,5,5,3,3,1,1,2,2,4,4,5,5] first_answer,second_answer, third_answer = 0,0,0 for i in range(len(answers)): if i >39: idx= i%40 else: idx = i if answers[i] == first_person[idx]: first_answer +=1 if answers[i] == second_person[idx]: second_answer +=1 if answers[i] == third_person[idx]: third_answer +=1 max_num = max(first_answer,second_answer,third_answer) if first_answer == max_num: ans.append(1) if second_answer == max_num: ans.append(2) if third_answer == max_num: ans.append(3) ans.sort() return ans카펫
코드 제출 (6등) 문제 바로가기주병규
2024-07-28 07:46:13주어진 갈색 칸의 개수 `brown`과 노란색 칸의 개수 `yellow`를 이용하여 노란색 칸의 가로, 세로 길이를 찾는 코드입니다. 노란색 칸의 가로, 세로 길이를 조합하여 갈색 칸의 개수를 계산하여 `brown`과 일치하는 경우 해당 가로, 세로 길이에 2를 더하여 노란색 칸을 포함한 전체 가로, 세로 길이를 반환합니다. 더 빠른 수행 시간을 위해 노란색 칸의 가로, 세로 길이를 계산할 때 제곱근을 사용하여 탐색 범위를 줄일 수 있습니다. 노란색 칸의 가로 길이가 `row`이고 세로 길이가 `col`일 때 `row * col == yellow`이므로 `row`의 범위를 `1`부터 `yellow`의 제곱근까지 탐색하면 됩니다. 또한, `brown`을 계산하는 부분에서 `2 * (row + col)` 연산을 `row + col` 연산 후 곱하기 2를 하는 것보다 `row + col` 연산 결과에 2를 먼저 곱해주는 것이 더 빠릅니다.
def solution(brown, yellow): for row in range(1, yellow + 1): if yellow % row == 0: col = yellow // row #yellow의 column과 row을 구한 뒤 if 2 * (row + col) + 4 == brown: #brown을 둘렀을때 크기가 같으면 return [col + 2, row + 2]이석민
2024-07-27 23:41:01이 코드는 주어진 갈색 칸 수와 노란색 칸 수로 구성된 정사각형 모양의 타일의 가로와 세로 길이를 찾는 알고리즘입니다. 코드는 루프를 사용하며 최대 가로 길이를 제한하고, 가로 길이를 하나씩 줄여가며 노란색 칸 수 조건을 만족하는 경우 가로와 세로 길이를 반환합니다. 현재 코드는 루프를 이용해 모든 경우의 수를 확인하는 방식으로 시간 복잡도가 O(sqrt(size)) 정도로 높습니다. 루프를 사용하는 대신 이분 탐색을 이용하면 시간 복잡도를 O(log(size))로 줄일 수 있습니다. 또한, 가로 길이의 범위를 미리 좁혀서 루프를 돌리는 횟수를 줄일 수도 있으며, `math.ceil` 대신 비트 연산자를 사용하면 연산 속도를 향상시킬 수 있습니다.
import math def solution(brown, yellow): size = brown + yellow # sqrt를 통해서는 범위제한만 가능. (아직 이게 width임을 보장할 수는 없음) max_width = math.ceil(math.sqrt(size)) for width in range(max_width, 0, -1): height = size / width if not height.is_integer(): continue width = int(width) height = int(height) if (width - 2) * (height - 2) == yellow: return [max(width, height), min(width, height)]이현석
2024-07-27 12:30:55주어진 갈색 타일의 개수와 노란색 타일의 개수를 입력받아 가로, 세로 길이를 계산하여 반환하는 함수입니다. 노란색 타일의 가로, 세로 길이를 찾기 위해 1부터 노란색 타일 개수의 제곱근까지 반복하며 약수를 찾고, 가로, 세로 길이를 이용하여 갈색 타일의 갯수와 일치하는지 확인합니다. 반복문을 이용하여 약수를 찾는 과정은 시간 복잡도가 O(sqrt(n))으로, 더 빠르게 처리할 수 있습니다. 예를 들어, 제곱근까지의 약수를 찾으면 나머지 약수는 제곱근까지 찾은 약수를 이용하여 쉽게 구할 수 있습니다. 또한, 갈색 타일의 갯수를 이용하여 노란색 타일의 가로, 세로 길이를 계산하는 단계에서 나눗셈 연산을 사용하는데, 이는 나눗셈 연산보다 비트 연산(쉬프트 연산, AND 연산 등)을 사용하는 것이 더 빠릅니다.
def solution(brown, yellow): # 답을 저장할 리스트 answer = [] # 노란 타일의 세로와 가로를 저장할 변수 yellow_width = 0 yellow_height = 0 for height in range(1, int(yellow**0.5) + 1): if yellow % height == 0: yellow_width = yellow // height yellow_height = height if (yellow_width + yellow_height) * 2 + 4 == brown: answer.append(yellow_width + 2) answer.append(yellow_height + 2) return sorted(answer, reverse=True) return answer이지민
2024-07-26 20:53:17주어진 갈색 칸의 개수(brown)와 노란색 칸의 개수(yellow)를 입력받아 가로, 세로 길이를 반환하는 함수입니다. 노란색 칸의 개수를 기반으로 가능한 모든 경우의 수를 탐색하여 갈색 칸의 개수를 만족하는 경우의 가로, 세로 길이를 반환합니다. 가능한 모든 경우의 수를 탐색하는 방식은 시간 복잡도가 높아, 입력 크기가 커지면 시간 초과가 발생할 가능성이 높습니다. 노란색 칸의 개수의 제곱근을 이용하여 탐색 범위를 줄이거나, 이분 탐색을 이용하여 더 효율적으로 탐색하는 방식을 고려할 수 있습니다. 또한, 노란색 칸의 개수가 주어졌을 때, 가로, 세로 길이를 쉽게 계산할 수 있는 공식을 활용하면 더 빠르게 문제를 해결할 수 있습니다.
def solution(brown, yellow): answer = [] def count(a,b): hap =0 board = [[0] *b for i in range(a)] for i in range(a): for j in range(b): if i==0 or j==0: board[i][j] = 1 if i == (a-1) or j==(b-1): board[i][j] =1 for i in board: hap += sum(i) if hap == brown: return True else: return False for i in range(3, (brown+yellow)//2+1): if (brown + yellow) %i==0: b = (brown+yellow) // i a,b = i,b if a>=b: ans = count(a,b) if ans == True: break answer.append(a) answer.append(b) return answer배수훈
2024-07-25 22:46:05이 코드는 주어진 갈색 칸의 개수와 노란 칸의 개수를 입력받아 가로, 세로 길이를 계산하여 반환하는 코드입니다. 코드는 주어진 면적을 기반으로 모든 가능한 가로, 세로 길이를 순차적으로 확인하며 조건에 맞는 경우 반환합니다. `math.sqrt()` 연산 대신 제곱근을 직접 계산하거나, 배열을 활용하여 미리 면적을 계산해 놓으면 속도를 높일 수 있습니다. 또한, 제곱근 연산은 한 번만 수행되어도 됩니다.
import math def solution(brown, yellow): answer = [0, 0] area = brown + yellow for i in range(3, int(math.sqrt(2005000)) + 1): j = area // i if area % i == 0 and j >= 3: width = i if i > j else j height = i if i < j else j brown_cnt = (width * 2) + ((height - 2) * 2) if brown_cnt == brown: answer[0] = width answer[1] = height break return answer소수 찾기
코드 제출 (5등) 문제 바로가기주병규
2024-07-28 07:46:23주어진 숫자들을 이용하여 만들 수 있는 모든 조합을 구하고, 각 조합에 대한 소수 판별을 진행하여 소수의 개수를 반환하는 코드입니다. 순열을 이용하여 모든 조합을 구하고, 각 조합에 대해 2부터 제곱근까지 나누어 떨어지는지 확인하여 소수 판별을 진행합니다. 소수 판별 함수에서 제곱근까지 확인하는 부분을 에라토스테네스의 체를 이용하면 더 빠르게 소수 여부를 판별할 수 있습니다. 또한, 순열을 구하는 부분에서 재귀 함수를 사용하는 대신, itertools 라이브러리의 permutations 함수를 사용하면 코드를 간결하게 작성할 수 있습니다.
def solution(numbers): result = 0 for num in joinPieces(numbers): result += 1 if checkSum(int(num)) else 0 #귀찮아서 체를 안썼는데 쓰는것이 빠를듯 return result def checkSum(num): #소수인지 확인 if num == 1 or num == 0: return False for i in range(2,int(num**0.5)+1): if num%i==0: #나누어지는 수가 있으면 소수가 아님 return False return True def joinPieces(numbers): #순열 구하는 함수 result = [] def perm(idx, n, piece): if idx == n: result.append(int("".join(piece[:n]))) else: for i in range(idx, len(piece)): #idx+1부터 시작하면 안바꾸었을때를 포함하지 못함 piece[idx], piece[i] = piece[i], piece[idx] #순서 변경 perm(idx + 1, n, piece) piece[idx], piece[i] = piece[i], piece[idx] #순서 원위치 for i in range(1, len(numbers) + 1): #i = 부분집합의 크기 perm(0, i, list(numbers)) return set(result)이석민
2024-07-28 00:22:11주어진 숫자들을 이용하여 만들 수 있는 모든 조합을 생성하고, 그 중 소수의 개수를 세는 프로그램입니다. 주어진 숫자들을 이용하여 만들 수 있는 모든 조합을 순열을 이용하여 생성하며, 소수 판별은 에라토스테네스의 체를 이용하여 구현했습니다. 생성된 모든 조합을 먼저 set 자료형에 저장하여 중복을 제거하면 시간복잡도를 줄일 수 있습니다. 큰 수를 소수 판별할 때는 에라토스테네스의 체 대신 더 빠른 소수 판별 알고리즘을 사용하면 시간 복잡도를 줄일 수 있습니다. 마지막 for 루프에서 `to_remove` 와 `numbers` 에서 모두 remove하는 부분에서 `to_remove` 를 `numbers` 에 바로 add 하면 루프를 1개 줄일 수 있습니다.
import itertools import math def primes_count(numbers): alive = [] for i in range(2, int(math.sqrt(max(numbers))) + 1): to_remove = [] for n in numbers: if n == i: alive.append(n) if n % i == 0: to_remove.append(n) for n in to_remove: numbers.remove(n) return len(alive) + len(numbers) def solution(numbers): combination_set = set() for l in range(1, len(numbers) + 1): for i in itertools.permutations(numbers, l): num = int(''.join(i)) if num <= 1: continue combination_set.add(num) return primes_count(combination_set)이석민
2024-07-28 00:13:32주어진 숫자들을 이용해 만들 수 있는 모든 수 중 소수의 개수를 반환하는 함수입니다. 에라토스테네스의 체를 이용하여 소수를 판별하고, 주어진 숫자들을 이용해 만들 수 있는 모든 수를 순열을 이용하여 생성합니다. 에라토스테네스의 체를 이용한 소수 판별은 최적화가 가능합니다. 예를 들어, 루트 n 까지의 소수만 확인하면 됩니다. 또한, itertools.permutations 대신 재귀 함수를 사용하여 순열을 생성하는 것이 더 빠를 수 있습니다. 순열 생성을 위해 itertools.permutations 대신 재귀 함수를 사용하면 메모리 사용량을 줄일 수 있습니다. 또한, 에라토스테네스의 체를 이용하여 소수를 판별하는 코드를 최적화하여 실행 시간을 단축할 수 있습니다.
import itertools import math def eratos(num): max_table_search = math.ceil(math.sqrt(num)) table = [False for _ in range(num + 1)] for i in range(2, max_table_search): ptr = i if table[ptr]: continue ptr += i while ptr < len(table): table[ptr] = True ptr += i table[0] = True table[1] = True return table def solution(numbers): possible_num = sorted(tuple(numbers), reverse=True) max_available = int(''.join(possible_num)) eratos_table = eratos(max_available) lookup_num = set() for l in range(1, len(possible_num) + 1): lookup_num.update(map(lambda s: int(''.join(s)), itertools.permutations(possible_num, r = l))) return len(tuple(filter(lambda n: eratos_table[n] == False, lookup_num)))이지민
2024-07-26 23:39:09주어진 문자열 숫자들을 조합하여 만들 수 있는 모든 숫자들을 생성하고, 소수인지 판별하여 소수의 개수를 반환하는 코드입니다. 숫자 조합 생성 부분에서 순열을 이용하며, 소수 판별은 주어진 숫자의 제곱근까지의 모든 수로 나누어 떨어지는지 확인하는 방식을 사용합니다. 코드의 시간 복잡도는 조합 생성 부분 때문에 매우 높습니다. 특히 숫자의 길이가 길어질수록 순열의 개수가 기하급수적으로 증가하여 시간 초과가 발생할 가능성이 높습니다. 더 빠른 알고리즘으로는 에라토스테네스의 체를 이용하여 미리 소수를 구해놓고, 조합하여 생성된 숫자가 소수인지 빠르게 확인하는 방법을 사용할 수 있습니다. 또한, 소수 판별 시 제곱근까지의 모든 수로 나누는 대신, 미리 소수를 구해놓고 소수로만 나누어 떨어지는지 확인하는 방식으로 시간 복잡도를 줄일 수 있습니다.
import math from itertools import permutations def prima(num): if num <2: return False for x in range(2, int(math.sqrt(num))+1): if num % x ==0: return False return True def solution(numbers): answer = 0 arr = [] for st in numbers: arr.append(st) products_arr = [] for i in range(1, len(numbers)+1): for j in permutations(arr , i): products_arr.append(int("".join(j))) for i in list(set(products_arr)): if prima(i) == True: print(i) answer +=1 return answer배수훈
2024-07-25 22:46:56주어진 숫자들을 이용해 만들 수 있는 소수의 개수를 구하는 코드입니다. 재귀 함수를 이용하여 가능한 모든 숫자 조합을 생성하고, 각 조합에 대해 소수 판별을 수행합니다. 시간 복잡도를 줄이기 위해, 소수 판별 과정에서 제곱근까지만 나누어 보는 방식을 사용하였습니다. 또한, 중복된 조합을 제거하기 위해 set 자료구조를 사용하였습니다. 재귀 함수 내부에서 `for` 루프를 사용하여 모든 조합을 생성하는 부분에서, 조합 생성 순서를 최적화할 수 있습니다. 예를 들어, 숫자를 오름차순으로 정렬한 후, 작은 숫자부터 사용하도록 하면 불필요한 조합 생성을 줄일 수 있습니다. 또한, 소수 판별 과정에서 에라토스테네스의 체와 같은 더 빠른 알고리즘을 사용할 수 있습니다.
import math; result = set() def recur(numbers, size, cur_num, use_list): if len(cur_num) == size: tmp = int(cur_num) if tmp < 2: return if tmp == 2: result.add(2) return for i in range(2, int(math.sqrt(tmp))+1): if tmp%i==0: return result.add(tmp) return for i in range(0, len(numbers)): if i not in use_list: use_list.add(i) recur(numbers, size, cur_num+numbers[i], use_list) use_list.remove(i) def solution(numbers): for i in range(1, len(numbers)+1): recur(numbers, i, "", set()) return len(result)불량 사용자
코드 제출 (5등) 문제 바로가기주병규
2024-07-28 07:46:33정규 표현식을 이용하여 사용자 아이디를 제재 아이디와 비교하고, 깊이 우선 탐색으로 제재 아이디가 중복되지 않도록 모든 경우의 수를 탐색합니다. 중복 제거를 위해 set을 활용하고 탐색 결과를 출력합니다. 정규 표현식을 이용한 문자열 비교는 시간 복잡도가 높을 수 있습니다. `re.fullmatch` 함수 대신 문자열 비교를 직접 구현하여 시간 복잡도를 줄일 수 있으며, 탐색 과정에서 중복을 제거하는 알고리즘을 사용하여 성능을 향상시킬 수 있습니다. `frozenset`을 사용하여 중복 제거하는 대신, 탐색 과정에서 중복을 미리 제거하는 방식을 적용하면 시간 복잡도를 줄일 수 있습니다.
import re def solution(user_ids, banned_input): banned_ids = [banned_id.replace('*', '.') + '$' for banned_id in banned_input] #*을 .으로 바꿔준후 $을 더해 정규 표현식으로 표현해 준다 error_ids = [[] for _ in range(len(banned_ids))] for i, banned_id in enumerate(banned_ids): for user_id in user_ids: if re.fullmatch(banned_id, user_id): error_ids[i].append(user_id) #[불량사용자 배열의 번호][제재 아이디] answer = set() #[1,2,3] [2,3,1]과 같은 중복도 잡아줌 def recursive(idx, checkArr): if idx == len(error_ids): answer.add(frozenset(checkArr)) #제재 아이디가 중복되지 않는 배열 add #frozenset을 해야지 수정불가능한 객체가 되어서 set에 넣을 수 있다 return for user_id in error_ids[idx]: #불량사용자 별 제재 아이디를 하나씩 if user_id not in checkArr: #불량사용자 별이기 때문에 중복이 있을 수 있음 recursive(idx + 1, checkArr + [user_id]) recursive(0, []) return len(answer)이지민
2024-07-28 00:50:15주어진 사용자 ID 목록에서 금지된 ID 목록과 일치하는 사용자 ID 조합의 개수를 찾는 알고리즘입니다. 사용자 ID와 금지된 ID 목록을 순회하며 일치하는 조합을 찾고 중복을 제거하여 개수를 반환합니다. 현재 코드는 모든 순열을 생성하여 비교하기 때문에 시간 복잡도가 높습니다. `itertools.permutations` 대신 `itertools.combinations`를 사용하여 조합만 생성하면 시간 복잡도를 줄일 수 있습니다. `checkBan` 함수에서 `len(banned_id[i]) != len(user_id[i])` 조건을 미리 확인하여 불필요한 비교를 줄일 수 있습니다.
import itertools def checkBan(user_id, banned_id): for i in range(len(banned_id)): for j in range(len(user_id[i])): if len(banned_id[i]) != len(user_id[i]): return False if banned_id[i][j] == '*': continue if banned_id[i][j] != user_id[i][j]: return False return True def solution(user_id, banned_id): answer = [] for permu in itertools.permutations(user_id, len(banned_id)): if checkBan(permu, banned_id): user = list(set(permu)) user.sort() if user not in answer: answer.append(user) return len(answer)이석민
2024-07-28 00:49:19이 코드는 주어진 user_id 목록에서 banned_id 패턴과 일치하는 사용자 목록을 찾아, 모든 가능한 조합을 구하여 그 개수를 반환하는 코드입니다. banned_id 패턴은 와일드카드 '*'를 포함할 수 있으며, 각 패턴에 대해 일치하는 사용자 목록을 생성한 후 재귀적으로 모든 조합을 생성하여 집합에 추가하고, 중복을 제거한 후 개수를 반환합니다. 재귀 함수 내부에서 사용자 목록을 순회하며 현재 집합에 없는 사용자를 추가하여 재귀 호출을 수행하고, 이후 사용자를 제거하는 방식으로 모든 조합을 생성합니다. 이 코드는 재귀를 통해 모든 조합을 생성하지만, 중복된 조합을 제거하는 효율성이 떨어지며, 조합의 수가 증가할수록 시간 복잡도가 기하급수적으로 증가하는 단점이 있습니다. 시간 복잡도를 줄이기 위해 재귀 대신 반복문을 사용하여 조합을 생성하고, 중복을 제거하는 알고리즘을 적용할 수 있습니다. 또한, 정규식 매칭 대신 문자열 비교를 이용하여 속도를 향상시킬 수 있습니다. 예를 들어, banned_id 패턴에 '*'가 있는 경우, 해당 위치에 모든 문자를 대입하여 비교하는 방식을 사용할 수 있습니다.
import re def pick_recursive(current, available, picked): if len(available) == 0: current_pick = '-'.join(sorted(current)) if current_pick not in picked: picked.add(current_pick) return picked for user in available[0]: if user in current: continue current.add(user) pick_recursive(current, available[1:], picked) current.remove(user) return picked def solution(user_id, banned_id): banned_id_re = tuple(map(lambda pattern: re.compile('^' + pattern.replace("*", '.') + '$'), banned_id)) banned_id_list = [] for pattern in banned_id_re: banned_id_re_list = [] for uid in user_id: if pattern.match(uid): banned_id_re_list.append(uid) banned_id_list.append(banned_id_re_list) picked = set() current = set() return len(pick_recursive(current, banned_id_list, picked))배수훈
2024-07-25 22:55:40주어진 사용자 ID 목록에서 금지된 ID 패턴과 일치하는 사용자 ID의 조합을 찾는 코드입니다. `find` 함수는 재귀적으로 모든 가능한 조합을 탐색하고, `match` 함수는 사용자 ID와 금지된 ID 패턴이 일치하는지 확인합니다. 해당 코드는 조합을 찾는 모든 경우를 순회하여 탐색하는 방식으로 구현되어 시간 복잡도가 높습니다. `find` 함수에서 조합을 추가하는 부분에서 중복된 조합이 발생할 수 있으며, 중복 제거를 위해 `set`을 사용하고 있습니다. 더 빠른 실행 시간을 위해 `find` 함수에서 조합을 생성하는 부분을 `itertools` 라이브러리의 `combinations` 함수를 이용하여 개선할 수 있습니다. `combinations` 함수를 사용하면 조합을 생성하는 과정을 더 효율적으로 처리할 수 있고, `set`을 사용하여 중복 제거하는 부분도 생략할 수 있습니다. 또한, `ban_user` 배열을 사용하여 사용자 ID를 인덱싱하는 방식 대신, 각 금지된 ID 패턴에 해당하는 사용자 ID를 `set`으로 저장하여 `match` 함수에서 `in` 연산을 통해 빠르게 일치 여부를 확인할 수 있습니다.
combinations = set() def find(ban_user, depth, combination): if depth == len(ban_user): combinations.add("".join(sorted([str(i) for i in combination]))) return for id in ban_user[depth]: if id in combination: continue combination.append(id) find(ban_user, depth + 1, combination) combination.remove(id) def match(id, pattern): if len(id) != len(pattern): return False for i in range(len(id)): if pattern[i] == "*": continue if id[i] != pattern[i]: return False return True def solution(user_id, banned_id): ban_user = [[] for i in banned_id] for i, id in enumerate(user_id): for j, pattern in enumerate(banned_id): if match(id, pattern): ban_user[j].append(i) find(ban_user, 0, []) return len(combinations)수식 최대화
코드 제출 (5등) 문제 바로가기주병규
2024-07-28 07:46:40주어진 수식의 연산자 우선순위를 바꿔가며 계산하여 나오는 결과 값 중 최댓값을 찾는 알고리즘입니다. 모든 연산자 순서의 경우의 수를 순회하며 계산하고 최댓값을 반환합니다. `changeOrder` 함수에서 연산자 우선순위에 따라 숫자를 계산하고 압축하는 과정이 반복되는데, 이 과정에서 배열의 요소를 삭제하고 삽입하는 연산이 많아 시간 복잡도가 높습니다. `findOper` 함수 내에서 `arr = arr[:idx - 1] + [result] + arr[idx + 2:]` 부분을 `arr[idx-1:idx+2] = [result]`로 변경하면 배열의 삽입 및 삭제 연산을 줄여 시간 복잡도를 개선할 수 있습니다. `changeOrder` 함수에서 `for` 루프 대신 재귀 함수를 사용하면 코드를 더 간결하게 작성할 수 있습니다. 더 빠른 알고리즘으로는, `stack` 자료구조를 활용해 연산자 우선순위를 관리하는 방법이 있습니다.
operator = ["*", "-", "+"] def solution(expression): arr = split(expression) maxVal = 0 for i in range(3): fir = operator[i % 3] #operator 순서 sec = operator[(i + 1) % 3] thr = operator[(i + 2) % 3] maxVal = max(maxVal, abs(changeOrder(arr[:], fir, sec, thr)),abs(changeOrder(arr[:], fir, thr, sec))) #두 번째 세 번째 순서를 바꾼 값을 비교 return maxVal def changeOrder(arr, fir, sec, thr): def findOper(arr, oper): #받은 operator을 찾아 그 앞 뒤 배열의 숫자를 operator에 맞게 계산해서 압축 idx = 1 while idx < len(arr): if arr[idx] == oper: #operator을 발견 result = cal(oper, arr[idx - 1], arr[idx + 1]) #앞 뒤 숫자로 계산 arr = arr[:idx - 1] + [result] + arr[idx + 2:] #3개의 배열을 없애고 계산한 값을 끼워 넣음 #idx +=1을 안해야지 순서가 맞음 else: idx += 1 return arr arr = findOper(arr, fir) arr = findOper(arr, sec) arr = findOper(arr, thr) return arr[0] def cal(oper, a, b): #oper:str을 받아 계산해주는 함수 if oper == "+": return a + b elif oper == "-": return a - b elif oper == "*": return a * b def split(sentence): #expression을 배열로 바꾸어주는 함수 arr = [] start = 0 #start와 end 포인터 두개로 가늠 for end in range(len(sentence)): if sentence[end] in operator: #+,-,*을 만났을때 앞과 해당 operator을 배열로 넣음 arr.append(int(sentence[start:end])) arr.append(sentence[end]) start = end + 1 arr.append(int(sentence[start:])) #마지막 숫자 append return arr이석민
2024-07-28 02:04:18주어진 수식에서 연산자 우선순위를 바꿔가며 계산한 결과 중 최댓값을 찾는 코드입니다. 연산자 우선순위에 따라 계산 결과가 달라질 수 있으므로 모든 연산자 우선순위 순열을 순회하며 계산 결과를 비교합니다. 현재 코드는 모든 연산자 우선순위 순열을 순회하며 계산하므로 시간 복잡도가 $O(n!)$로 높습니다. 연산자 우선순위 순열을 생성하는 부분을 제외하고는 연산 과정이 $O(n)$에 가깝기 때문에, 시간 복잡도를 줄이기 위해 연산자 우선순위 순열을 생성하는 부분을 최적화해야 합니다. 예를 들어, 모든 순열을 생성하는 대신 3개의 연산자에 대해 가능한 우선순위 조합 6개만을 직접 생성하면 시간 복잡도를 $O(1)$로 줄일 수 있습니다. 또한, `calculate` 함수 내부에서 연산을 수행하는 방식을 개선하면 더욱 빠른 속도를 얻을 수 있습니다. `calculate` 함수 내부에서 `pop` 메서드를 사용하는 대신, `itertools.chain`을 통해 연산자와 숫자들을 연결하고, `zip` 함수로 그룹핑하여 더 빠르게 연산을 진행할 수 있습니다. 또한, 코드 내부에서 연산자 우선순위를 정하는 부분에서 불필요한 순회가 발생합니다. `itertools.permutations`를 사용하여 모든 순열을 생성하는 대신, 3개의 연산자에 대해 가능한 우선순위 조합 6개만을 직접 생성하면 불필요한 연산을 줄일 수 있습니다.
import re import itertools oper = ('+', '-', '*') def calculate(exp, op_priority): cc = { '+': lambda n1, n2: n1 + n2, '-': lambda n1, n2: n1 - n2, '*': lambda n1, n2: n1 * n2 } remain = exp[:] for op in op_priority: ptr = 0 while ptr < len(remain): if remain[ptr] != op: ptr += 1 continue run = cc[op] remain[ptr] = run(int(remain[ptr - 1]), int(remain[ptr + 1])) remain.pop(ptr + 1) remain.pop(ptr - 1) return remain[0] def solution(expression): token = re.findall('\d+|\+|-|\*', expression) op_priority = itertools.permutations(oper) return max(map(lambda op: abs(calculate(token, op)), op_priority))이지민
2024-07-28 00:00:41주어진 수식의 모든 연산자 순서에 대해 계산을 수행하고, 그 결과 중 절댓값이 가장 큰 값을 반환하는 알고리즘입니다. 연산자 순서를 생성하기 위해 itertools.permutations를 사용하고, 각 순서에 대해 계산을 수행하여 최댓값을 갱신합니다. 현재 코드는 모든 연산자 순서에 대해 계산을 수행하기 때문에 시간 복잡도가 O(n!)입니다. 시간 복잡도를 줄이기 위해서는, 불필요한 계산을 줄이는 방법을 고려해야 합니다. 예를 들어, 같은 연산자 순서에 대해 여러 번 계산되는 경우, 계산 결과를 저장하여 재사용하면 시간을 단축할 수 있습니다. 또한, 연산자 우선 순위를 고려하여 불필요한 계산을 생략하는 방법도 고려할 수 있습니다.
import itertools def solution(expression): answer = 0 for permu in itertools.permutations(['*','-','+'],3): numbers = [] signs = [] num = '' for char in expression: if char.isdigit(): num += char else: numbers.append(int(num)) signs.append(char) num = '' numbers.append(int(num)) result = 0 for sign in permu: while sign in signs: idx = signs.index(sign) if sign == '*': value = numbers[idx] * numbers[idx+1] if sign == '-': value = numbers[idx] - numbers[idx+1] if sign == '+': value = numbers[idx] + numbers[idx+1] numbers[idx] = value del signs[idx] del numbers[idx+1] answer = max(answer, abs(numbers[0])) return answer배수훈
2024-07-25 23:00:32주어진 수식에서 연산자의 순서를 바꿔가며 계산하여 나올 수 있는 최대 절댓값을 구하는 프로그램입니다. itertools 라이브러리를 활용하여 연산자 순열을 생성하고, eval 함수를 사용하여 각 순열에 따른 계산 결과를 구합니다. eval 함수를 사용하는 대신 직접 연산을 구현하면 속도를 향상시킬 수 있습니다. 연산자 순열을 생성하는 대신 재귀 함수를 사용하면 더 효율적으로 순열을 생성할 수 있습니다. 더 빠른 알고리즘을 사용하면 속도를 더욱 향상시킬 수 있습니다. 예를 들어, 수식을 트리 형태로 표현하고 후위 표기법으로 변환하여 계산하는 방법을 사용하면 더 효율적으로 계산할 수 있습니다.
import itertools import re def solution(exp): answer = 0 splited_exp = re.split("(\*|\-|\+)", exp) for ordered_opers in itertools.permutations(["*", "-", "+"], 3): tmp_exp = splited_exp for op in ordered_opers: while op in tmp_exp: for i, x in enumerate(tmp_exp): if x == op: num = eval(tmp_exp[i - 1] + x + tmp_exp[i + 1]) tmp_exp = tmp_exp[:i - 1] + [str(num)] + tmp_exp[i + 2:] break answer = max(abs(int(tmp_exp[0])), answer) return answer
2024-07-21 21:00:00 (4문제)
콜라츠 추측
코드 제출 (6등) 문제 바로가기주병규
2024-07-21 04:37:09이 코드는 입력받은 숫자를 2로 나누거나 3을 곱하고 1을 더하는 연산을 반복하여 1이 될 때까지 횟수를 세는 재귀 함수를 사용합니다. 500번 연산을 수행해도 1이 되지 않으면 -1을 반환합니다. 재귀 함수를 반복문으로 변경하면 함수 호출 오버헤드를 줄여 속도를 향상시킬 수 있습니다. 또한, 짝수/홀수 판별을 비트 연산자를 이용하면 mod 연산보다 더 빠르게 처리할 수 있습니다. 마지막으로, 입력 범위가 크다면 1까지 도달하는 횟수를 미리 계산하여 저장해두는 방식을 사용하면 시간복잡도를 줄여 더 빠르게 실행할 수 있습니다.
def solution(num): return recursive(num,0) def recursive(num,cnt): if num ==1 : return cnt if cnt == 500: return -1 if num %2 ==0 : return recursive(num//2, cnt+1) else: return recursive(num*3+1, cnt+1)이지민
2024-07-20 14:07:58주어진 숫자를 1이 될 때까지 2로 나누거나 3을 곱하고 1을 더하는 연산을 반복하며, 500번 이하의 연산으로 1이 되면 연산 횟수를 반환하고, 그렇지 않으면 -1을 반환하는 코드입니다. 반복문을 이용하여 한 번에 하나의 연산을 수행하는 방식으로 구현되어 있으며, 이진탐색이나 동적 계획법과 같은 더 효율적인 알고리즘을 활용하면 더 빠른 시간 안에 답을 구할 수 있습니다. 연산 과정에서 짝수/홀수 판별을 위한 `% 2` 연산 대신 비트 연산자 `& 1`을 사용하면 더 빠르게 연산할 수 있습니다. 더 나아가, 콜라츠 추측의 특징을 이용하여 1이 될 확률이 높은 숫자들을 사전에 계산해 저장해 두면 탐색 횟수를 줄여 더 빠른 성능을 얻을 수 있습니다.
def solution(num): answer = 0 while (num != 1): if answer > 500: answer = -1 break else: if (num %2 ==0): num = num // 2 else: num = num *3 +1 answer +=1 return answer양민철
2024-07-19 12:02:13이 코드는 콜라츠 추측을 구현하여 입력된 숫자가 1이 될 때까지 걸리는 단계 수를 반환합니다. 재귀 함수를 사용하여 짝수일 경우 2로 나누고 홀수일 경우 3을 곱하고 1을 더하는 과정을 반복합니다. 하지만 이 코드는 500단계를 넘으면 -1을 반환하도록 제한되어 있기 때문에, 시간 복잡도가 높고 콜라츠 추측의 성질을 제대로 활용하지 못합니다. 더 빠른 코드를 위해서는 반복문을 사용하여 콜라츠 수열을 직접 계산하는 것이 효율적입니다. 또한, 이미 계산된 값을 저장하는 메모이제이션 기법을 적용하면 중복 계산을 줄일 수 있어 시간 복잡도를 더욱 개선할 수 있습니다.
def solution(num): def collatz(num, count): if num == 1: return count if count == 500: return -1 if num % 2 == 0: return collatz(num // 2, count + 1) else: return collatz(num * 3 + 1, count + 1) return collatz(num, 0)배수훈
2024-07-17 16:05:35이 코드는 콜라츠 추측을 구현한 코드로, 주어진 숫자가 1이 될 때까지 콜라츠 연산을 반복하여 깊이를 계산합니다. 깊이가 500을 넘어가면 -1을 반환합니다. 이 코드는 재귀 함수를 사용하여 콜라츠 추측을 구현했지만, 반복문을 사용하는 것이 더 빠릅니다. 또한, 콜라츠 추측은 아직 증명되지 않은 문제이기 때문에, 깊이 제한을 두는 대신 숫자가 특정 범위를 벗어나면 -1을 반환하는 방식으로 개선할 수 있습니다.
def collatz(num, depth): if num == 1: return depth if depth == 500: return -1 if num % 2 == 0: num//=2 else: num = num * 3 + 1 return collatz(num, depth + 1) def solution(num): return collatz(num, 0)배수훈
2024-07-17 16:03:10주어진 숫자가 1이 될 때까지 짝수이면 2로 나누고, 홀수이면 3을 곱하고 1을 더하는 연산을 수행하며, 500번 이내에 1이 되지 않으면 -1을 반환하는 코드입니다. 시간 복잡도를 줄이기 위해 범위를 줄이거나, 반복문 대신 재귀 함수를 사용하는 방식을 고려해볼 수 있으며, 콜라츠 추측의 특징을 활용하여 더 효율적인 알고리즘을 적용할 수 있습니다.
def solution(num): for i in range(500): if num == 1: return i if num % 2 == 0: num//=2 else: num = num * 3 + 1 return -1이석민
2024-07-15 04:53:10주어진 정수 num이 1이 될 때까지 2로 나누거나 3을 곱하고 1을 더하는 연산을 반복하며, 500번 이하의 연산으로 1이 되지 않으면 -1을 반환합니다. 이 코드는 for 루프를 사용하여 연산을 반복하고, 조건문을 통해 짝수인 경우 2로 나누고 홀수인 경우 3을 곱하고 1을 더하는 연산을 수행합니다. 이 코드는 500번 이하의 연산으로 1이 되지 않으면 -1을 반환하는데, 이는 연산 횟수 제한이 너무 적기 때문에 효율적이지 않습니다. 500번 제한을 제거하거나, 더 빠른 알고리즘을 사용하면 더 효율적으로 해결할 수 있습니다. 예를 들어, num의 값이 짝수인 경우 2로 나누는 연산을 계속 수행하면 연산 횟수를 줄일 수 있습니다. 또한, 콜라츠 추측에 대한 더 효율적인 알고리즘이 존재할 수 있으므로, 이에 대한 연구가 필요합니다.
def solution(num): for cnt in range(500): if num == 1: return cnt if num & 1 == 0: num //= 2 else: num = num * 3 + 1 return -1하노이 탑
코드 제출 (6등) 문제 바로가기이지민
2024-07-21 15:23:17해당 코드는 하노이의 탑 문제를 재귀적으로 풀이하여 이동 순서를 리스트에 저장하는 코드입니다. n개의 원반을 시작 위치에서 목표 위치로 옮기는 최소 이동 횟수와 이동 순서를 계산합니다. 재귀 호출 횟수를 줄이기 위해 반복문을 사용하는 것이 더 효율적일 수 있습니다. 예를 들어, 최상단 원반을 제외한 나머지 원반을 목표 위치로 옮기는 과정을 반복문을 통해 구현하면 불필요한 재귀 호출을 줄일 수 있습니다. 또한, 이동 순서를 저장하는 리스트 대신, 이동 횟수를 카운트하는 변수를 사용하여 메모리 사용량을 줄일 수 있습니다.
def hanoi(n,start , to,by,answer): if n==0: return else: hanoi(n-1 , start, by, to,answer) answer.append([start, to]) hanoi(n-1,by, to, start,answer) def solution(n): answer = [[]] hanoi(n,1,3,2,answer) return answer[1:]주병규
2024-07-21 04:37:24이 코드는 재귀 함수를 사용하여 하노이 탑 문제를 푸는 알고리즘입니다. 이 알고리즘은 원반을 이동하는 순서를 리스트에 담아 반환합니다. 리스트에 값을 추가하는 부분을 `append` 대신 `+=` 연산자를 사용하면 좀 더 빠르게 동작할 수 있습니다. 이는 `append`가 새로운 리스트를 생성하고 값을 추가하는 방식인 반면, `+=`는 기존 리스트에 값을 추가하는 방식이기 때문입니다. 또한, 각 재귀 호출에서 중간값을 계산하는 부분을 미리 계산하고 저장하면 불필요한 계산을 줄일 수 있습니다. 예를 들어, `recursive` 함수 내부에서 `middle` 변수를 미리 계산하여 전달하면 됩니다. 재귀 함수를 반복문으로 변경하면 메모리 사용량을 줄이고 속도를 향상시킬 수 있습니다. 재귀 호출은 스택에 메모리를 사용하기 때문입니다.
def solution(n): return recursive(n, 1, 3, 2, []) def recursive(n, start, end, middle, answer): if n == 1: answer.append([start, end]) else: recursive(n-1, start, middle, end, answer) #n-1개의 원반을 중간으로 이동 answer.append([start, end]) #n-1개를 옮겼으니 마지막에 남은건 가장 무거운 원반 #따라서 이를 마지막으로 이동 recursive(n-1, middle, end, start, answer) #중간으로 옮겼던 n-1개의 원반을 #다시 마지막으로 이동 return answer이석민
2024-07-21 03:56:42해당 코드는 하노이 탑 문제를 재귀적으로 해결하는 코드이며, move_log 리스트에 이동 순서를 기록합니다. **코드는 재귀 함수를 이용하여 하노이 탑 문제를 효율적으로 해결하지만, 더 빠른 실행 속도를 위해 몇 가지 개선이 가능합니다.** * `move_log`에 이동 순서를 저장하는 대신, **이동 순서를 직접 출력하는 방식으로 변경**하면 리스트 생성 및 저장에 필요한 시간을 줄일 수 있습니다. (리스트 생성 및 저장은 시간 복잡도가 O(n)이기 때문에, 특히 대량의 데이터를 다룰 때 성능 저하를 유발할 수 있습니다.) * `hanoi` 함수의 `depth` 매개변수는 함수 호출 시마다 1씩 감소하기 때문에, **반복문을 사용하여 재귀 호출을 대체**할 수 있습니다. (재귀 호출은 스택 오버플로우를 유발할 수 있는 문제를 가지고 있고, 반복문은 일반적으로 재귀 호출보다 빠르게 실행됩니다.) * **조건문을 최적화**하여 불필요한 연산을 줄일 수 있습니다. (예를 들어 `if depth == 0` 조건문은 `depth > 0` 조건문으로 대체할 수 있습니다.)
# 일단 알고리즘을 어캐해야할지 감도 안와서... 전체 흐름을 적어봄 # 1) [1 -> 3] # 2) <1 -> 2, [1 -> 3], 2 -> 3> # 3) (1 -> 3, <1 -> 2>, 3 -> 2), [1 -> 3], (2 -> 1, <2 -> 3>, 1 -> 3) move_log = [] def hanoi(depth, src, dst): # 맨 위의것이 될 때 까지 함수 호출 들어감. if depth == 0: return stopover = 6 - src - dst hanoi(depth - 1, src, stopover) move_log.append([src, dst]) hanoi(depth - 1, stopover, dst) return def solution(n): global move_log # 어쨋든 맨 아래의 것을 (n-1) 1 -> 3으로 옮김 (wrap) hanoi(n, 1, 3) return move_log양민철
2024-07-19 11:43:51해당 코드는 재귀 함수를 이용하여 하노이 탑 문제를 해결하는 코드입니다. `hanoi` 함수는 원반의 개수, 시작 위치, 중간 위치, 목표 위치, 이동 순서를 담는 리스트를 입력받아 원반을 이동하는 순서를 리스트에 저장합니다. 코드는 효율적이지만, **재귀 호출 횟수가 너무 많아 시간 복잡도가 높습니다.** **각 함수 호출마다 리스트에 데이터를 추가하는 방식 대신, `yield` 키워드를 사용하여 제너레이터를 활용하면 메모리 사용량을 줄이고, 시간 복잡도를 개선할 수 있습니다.**
def hanoi(n, start, mid, end, answer): if n == 1: answer.append([start, end]) return hanoi(n-1, start, end, mid, answer) answer.append([start, end]) hanoi(n-1, mid, start, end, answer) def solution(n): answer = [] hanoi(n, 1, 2, 3, answer) return answer배수훈
2024-07-17 16:19:29해당 코드는 하노이의 탑 문제를 재귀적으로 풀이하는 코드입니다. `hanoi` 함수는 `n` 개의 원반을 `a` 에서 `c` 로 옮기는 과정을 재귀적으로 구현하고, `solution` 함수는 `n` 개의 원반에 대한 하노이의 탑 이동 순서를 리스트 형태로 반환합니다. 재귀 호출을 이용한 해결 방식은 이해하기 쉽지만, 반복문을 활용하는 것이 더 빠른 속도를 제공합니다. 특히, `n` 이 커질수록 재귀 호출의 깊이가 깊어지면서 스택 오버플로우가 발생할 위험도 있습니다. 또한, `result.append([a, c])` 부분에서 리스트 생성을 매번 수행하는 것보다, 미리 리스트를 생성하고 인덱스를 통해 값을 할당하는 방식이 더 효율적입니다.
def hanoi(n, a, b, c, result): if n == 0: return result hanoi(n-1, a, c, b, result) result.append([a, c]) hanoi(n-1, b, a, c, result) def solution(n): answer = [] hanoi(n, 1, 2, 3, answer) return answer모음 사전
코드 제출 (5등) 문제 바로가기주병규
2024-07-21 04:38:07주어진 단어를 만들 수 있는 모든 가능한 조합을 재귀적으로 탐색하여 단어가 생성될 때까지 탐색 횟수를 세는 알고리즘입니다. 탐색 횟수는 전역 변수 `count`를 사용하여 계산합니다. 반복문 내에서 불필요한 비교 연산을 최소화하고, 재귀 호출 횟수를 줄여 성능을 향상시킬 수 있습니다. 예를 들어, `findWord == word` 비교는 재귀 호출 전에 수행하여 불필요한 호출을 줄일 수 있으며, `len(word) == 5` 조건을 재귀 호출 전에 검사하여 불필요한 탐색을 줄일 수 있습니다.
count = 0 def solution(word): global count for alphabet in ['A','E','I','O','U']: if dfs(word,alphabet): return count def dfs(findWord,word): global count count +=1 if findWord == word : return True if len(word) == 5: return False for alphabet in ['A','E','I','O','U']: if dfs(findWord,word+alphabet): return True주병규
2024-07-21 04:37:37주어진 문자열의 각 문자를 "AEIOU" 에서의 순서에 따라 1부터 5까지의 숫자로 변환한 뒤, 해당 숫자에 5의 거듭제곱으로 이루어진 가중치를 곱하여 합산합니다. 즉, 주어진 문자열을 5진수로 변환하는 알고리즘입니다. 코드는 주어진 문자열의 각 문자를 순회하며 "AEIOU" 에서의 순서에 따라 가중치를 계산하고 곱하는 방식으로 구현되어 있습니다. 연산 속도를 높이기 위해, 각 문자의 "AEIOU" 에서의 순서를 미리 저장하는 dictionary 를 사용하면 "index" 함수를 통해 얻는 시간을 줄일 수 있으며, 5의 거듭제곱을 미리 계산하여 배열에 저장하면 반복적인 계산을 줄일 수 있습니다. 또한, 5의 거듭제곱을 계산할 때, 5**i 를 i번 곱하는 대신 이전 결과값에 5를 곱하는 방식으로 계산하면 연산 횟수를 줄일 수 있습니다. 나머지 연산은 비트 연산을 사용하여 시간을 단축할 수 있습니다.
def solution(word): answer = 0 for i, n in enumerate(word): answer+= (5**(5-i)-1) / 4 * "AEIOU".index(n) +1 return answer #첫번째 글자가 정해졌을때 나올 수 있는 경우의 수가 5**4+5**3+5**2+5**1+1 이고 #첫번째와 두번째 글자가 정해졌을때 경우의 수가 5**3+5**2+5**1+1이기 때문에 이에 +1한 값이 #해당 글자의 순서이다 이를 점화식으로 나타내면 시그마 i=0 부터 j까지 5의 i제곱 이므로 #등비수열의 합에 의해 1*(5**(5-i)) / (5-1) 이 된다이지민
2024-07-20 18:44:41주어진 단어가 사전 순으로 몇 번째 단어인지 찾는 코드입니다. 알파벳 'A', 'E', 'I', 'O', 'U'로 만들 수 있는 모든 단어를 생성하고 사전 순으로 정렬한 후 주어진 단어의 인덱스를 반환합니다. 모든 단어를 생성한 후 정렬하는 방식은 시간 복잡도가 높습니다. 모든 단어를 생성하지 않고 주어진 단어와 비교하며 사전 순으로 몇 번째인지 탐색하는 방식이 더 효율적입니다. 주어진 단어의 길이에 따라 생성되는 단어의 수가 기하급수적으로 증가하기 때문에 가능한 단어의 길이를 제한하여 더 빠르게 탐색할 수 있습니다. 예를 들어, 주어진 단어의 길이가 3이면 길이가 4 이상인 단어는 탐색하지 않아도 됩니다.
from itertools import product def solution(word): answer = 0 words = ['A','E','I','O','U'] ans = [] for i in range(1, 6): for j in product(words,repeat = i): ans.append("".join(j)) ans.sort() return ans.index(word)+1이석민
2024-07-18 22:15:36주어진 단어를 만들 수 있는 가능한 모든 조합을 재귀적으로 탐색하여 가능한 조합의 수를 계산하는 알고리즘 입니다. 모든 조합을 탐색하기 때문에 시간 복잡도가 높아, 입력 단어의 길이가 길어지면 시간 초과가 발생할 수 있습니다. 재귀 함수 내에서 `current.append(alpha)` 와 `current.pop()` 연산이 반복적으로 수행되는데, 이 과정에서 불필요한 메모리 할당과 해제가 발생합니다. 가능한 조합을 생성하는 과정에서 문자열 연결 연산을 사용하는 대신, 비트 연산을 활용하여 효율적으로 조합을 생성할 수 있습니다. 또한, 현재 노드에서 가능한 모든 조합을 탐색하는 대신, 목표 단어와 일치하는 조합을 찾으면 탐색을 중단하여 시간을 단축할 수 있습니다.
alphabet = ['A', 'E', 'I', 'O', 'U'] count = 0 def find(word, current): global count count += 1 if current == word: return True if len(current) >= 5: return False for alpha in alphabet: current.append(alpha) if find(word, current): return True current.pop() def solution(word): global count word = list(word) current = [] for alpha in alphabet: current.append(alpha) if find(word, current): return count current.pop()배수훈
2024-07-17 16:53:53주어진 코드는 재귀 함수를 사용하여 "A", "E", "I", "O", "U"를 이용하여 만들 수 있는 모든 5글자 이하의 단어를 생성하고, 입력으로 주어진 단어가 몇 번째로 생성되는지 찾는 코드입니다. 재귀 함수를 사용하였기 때문에 시간 복잡도가 높아 알고리즘 경진대회에서 시간 제한에 걸릴 가능성이 높습니다. 모든 단어를 생성하는 대신 입력으로 주어진 단어를 직접 생성하는 방식으로 변경하면 시간 복잡도를 크게 줄일 수 있습니다. 또한, 입력으로 주어진 단어가 유효한 단어인지 검사하는 부분이 없어 오류가 발생할 수 있습니다.
alpha = ["A", "E", "I", "O", "U"] def aeiou(word, result): if len(word) >= 5: return for ch in alpha: tmp = word + ch result.append(tmp) aeiou(tmp, result) def solution(word): answer = [] aeiou("", answer) return answer.index(word) + 1호텔 방 배정
코드 제출 (5등) 문제 바로가기이지민
2024-07-21 16:41:05주어진 방 번호 목록에서 각 방 번호에 대한 최소한의 가능한 방 번호를 찾는 문제를 해결하는 코드입니다. 딕셔너리를 사용하여 방 번호와 그 다음 가능한 방 번호를 저장하고, 이미 사용된 방 번호가 있다면 가장 가까운 비어있는 방 번호를 찾아 할당합니다. 코드는 딕셔너리 `rooms`에 방 번호와 그 다음 가능한 방 번호를 저장하여 효율적으로 방 번호를 할당하고, 이미 사용된 방 번호에 대해서는 반복문을 사용하여 가장 가까운 비어있는 방 번호를 찾습니다. 코드의 속도를 더 향상시키려면 반복문 대신 재귀 함수를 사용하여 비어있는 방 번호를 찾을 수 있습니다. 재귀 함수는 반복문보다 빠르게 동작할 수 있으며, 특히 큰 입력 데이터에 대해 속도 향상 효과가 더 크게 나타납니다. 또한, 딕셔너리 대신 해시 테이블을 사용하면 방 번호를 더 효율적으로 저장하고 검색할 수 있습니다. 해시 테이블은 딕셔너리보다 빠른 검색 속도를 제공하며, 특히 큰 데이터 집합에 대해 더욱 효과적입니다.
def solution(k, room_number): answer = [] rooms = {} for room in room_number: numbers = rooms.get(room, 0) # rooms 에 room이 있다면 value 반환 아니면 0 반환 if numbers: temp = [room] while True: index = numbers numbers = rooms.get(numbers,0) if not numbers: answer.append(index) rooms[index] = index+1 for i in temp: rooms[i] = index + 1 break temp.append(numbers) else: answer.append(room) rooms[room] = room+1 return answer주병규
2024-07-21 04:38:39주어진 방 번호 목록에서 각 고객에게 할당할 방을 찾고, 이미 할당된 방이 있다면 인접한 빈 방을 찾아 할당하는 알고리즘입니다. 고객이 이미 방을 할당 받았을 경우 해당 고객을 위한 방을 찾을 때까지 인접한 방을 따라가는 방식을 이용합니다. 현재 코드는 빈 방을 찾을 때마다 `visits` 리스트에 방 번호를 저장하고, 다시 방을 할당할 때 `visits` 리스트의 방 번호를 순회하며 방을 할당하는 방식으로 구현되어 있으므로 불필요한 반복이 발생합니다. `visits` 리스트를 사용하는 대신 현재 방 번호를 저장하는 변수를 사용하고, 해당 변수를 업데이트하면서 방을 할당하면 불필요한 반복을 줄일 수 있습니다. 또한 재귀 함수를 사용하면 `visits` 리스트를 사용하지 않고 간결하게 코드를 작성할 수 있습니다.
def solution(k, room_number): rooms = dict() for customer in room_number: visits=[] while customer in rooms: visits.append(customer) customer = rooms[customer] for visit in visits: rooms[visit] = customer +1 rooms[customer] = customer +1 return list(rooms)주병규
2024-07-21 04:38:22이 코드는 주어진 방 번호 목록에서 각 고객에게 할당할 수 있는 가장 작은 방 번호를 찾는 알고리즘을 구현합니다. 재귀 함수를 사용하여 방 번호 충돌을 처리하고 고객에게 가장 작은 방 번호를 할당하며, 이를 통해 방 번호 할당 문제를 해결합니다. 이 코드는 재귀 함수를 사용하여 방 번호 충돌 처리를 수행합니다. 하지만, 반복문을 사용하여 같은 동작을 수행하면 재귀 호출 오버헤드를 줄일 수 있습니다. 또한, `rooms` 딕셔너리에 대한 조회 연산을 최적화하여 `in` 연산 대신 `get` 함수를 사용하면 더 빠른 속도를 얻을 수 있습니다.
import sys sys.setrecursionlimit(2000) #파이썬은 기본 재귀 함수 제한이 1000 이를 2000으로 수정하는 코드 def solution(k, room_number): rooms = {} def find(customer): if customer not in rooms: rooms[customer] = customer + 1 return customer rooms[customer] = find(rooms[customer]) return rooms[customer] return [find(customer) for customer in room_number]이석민
2024-07-18 22:18:33주어진 방 번호 리스트에서 각 방 번호에 해당하는 가장 작은 비어있는 방 번호를 찾아 반환하는 코드입니다. 해시맵을 이용하여 방 번호와 할당된 방 번호를 매핑하여 중복 방 번호 처리를 효율적으로 수행합니다. 코드는 해시맵을 이용하여 방 번호와 할당된 방 번호를 매핑합니다. 이를 통해 탐색 시간을 줄여 효율성을 높였지만, 방 번호의 범위를 고려할 때 방 번호가 연속적으로 할당되는 경우, 할당된 가장 작은 방 번호를 찾는 과정이 비효율적일 수 있습니다. 더 빠른 실행 시간을 위해 방 번호를 순차적으로 할당하여 가장 작은 비어있는 방 번호를 찾는 방법을 고려할 수 있습니다. 이는 탐색 시간을 줄이고 시간 복잡도를 개선할 수 있습니다. 또한, 해시맵 대신 방 번호를 저장할 수 있는 배열을 사용하여 더 빠른 탐색과 삽입 연산을 수행할 수 있습니다.
def solution(k, room_number): hashmap = {} result = [] for room in room_number: follow = room visited = [follow, ] while follow in hashmap: follow = hashmap[follow] visited.append(follow) result.append(follow) for v in visited: hashmap[v] = follow + 1 return result배수훈
2024-07-18 00:09:14주어진 방 번호 목록에서, 각 방 번호에 대해 가능한 가장 작은 빈 방 번호를 할당하는 코드입니다. 재귀 함수를 사용하여 빈 방을 찾고, dictionary를 이용하여 방 번호와 할당된 번호를 저장합니다. 재귀 호출 횟수를 줄이기 위해 `room_table`에 할당된 번호를 바로 업데이트하여 불필요한 재귀 호출을 방지할 수 있습니다. 또한, `room_table`에 할당된 번호를 저장하는 방법으로 `set`을 사용하면 `key` 존재 여부 확인을 더 빠르게 할 수 있습니다. DFS 기반 탐색 방식이므로 입력 크기에 따라 시간 복잡도가 높아질 가능성이 있으므로, 입력 크기가 큰 경우 다른 알고리즘 (예: Union-Find) 활용을 고려할 수 있습니다.
import sys sys.setrecursionlimit(10000) def find_room(num, room_table): if num not in room_table: room_table[num] = num + 1 return num + 1 next_room = find_room(room_table[num], room_table) room_table[num] = next_room return next_room def solution(k, room_number): room_table = {} for num in room_number: find_room(num, room_table) return list(room_table.keys())배수훈
2024-07-18 00:03:09주어진 방 번호 리스트에서, 각 방 번호에 대해 가장 가까운 비어있는 방을 찾아 그 방 번호를 리턴하는 코드입니다. 재귀 함수를 사용하며, 이미 할당된 방 번호의 경우 다음 비어있는 방을 탐색합니다. 이 코드는 재귀 함수를 사용하여 직관적이지만, 반복문을 통해 같은 작업을 수행하는 것이 더 효율적입니다. 또한, 딕셔너리 대신 리스트를 사용하면 메모리 사용량을 줄일 수 있습니다. 예를 들어, `room_table`을 리스트로 변경하고, `room_table[num] = num + 1` 대신 `room_table[num] = True`와 같이 비어있는 방 표시를 간단하게 할 수 있습니다. 마지막으로, 현재 솔루션은 각 방 번호에 대해 모든 비어있는 방을 순차적으로 탐색합니다. 하지만, 이진 탐색과 같은 더 효율적인 탐색 알고리즘을 사용하면 속도를 더욱 향상시킬 수 있습니다.
import sys sys.setrecursionlimit(10000) def find_room(num, room_table, result): if num not in room_table: room_table[num] = num + 1 result.append(num) return num + 1 next_room = find_room(room_table[num], room_table, result) room_table[num] = next_room return next_room def solution(k, room_number): room_table = {} result = [] for num in room_number: find_room(num, room_table, result) return result
2024-07-14 21:00:00 (10문제)
시저 암호
코드 제출 (7등) 문제 바로가기이현석
2024-07-14 12:00:55주어진 문자열 s의 각 문자를 n만큼 쉬프트하는 알고리즘으로, 대문자와 소문자를 구분하여 쉬프트 연산을 수행합니다. 알파벳 순환을 위해 모듈러 연산을 사용하며, 문자열을 리스트로 변환하여 각 문자에 접근합니다. 알고리즘은 직관적이지만, 문자열 처리 부분을 더 효율적으로 개선할 수 있습니다. Python의 `string.ascii_uppercase`, `string.ascii_lowercase`를 활용하면 코드 가독성을 높이고, `ord`와 `chr` 함수 사용을 줄여 속도를 향상시킬 수 있습니다. 또한, `enumerate`를 사용하여 인덱스와 문자를 동시에 처리하는 방식을 활용하면 더 간결한 코드를 작성할 수 있습니다.
def solution(s, n): s = list(s) for i in range(len(s)): if s[i].isupper(): s[i] = chr((ord(s[i]) - ord('A') + n) % 26 + ord('A')) elif s[i].islower(): s[i]=chr((ord(s[i])-ord('a')+ n)%26+ord('a')) return "".join(s)주병규
2024-07-11 15:52:05주어진 문자열 s에서 각 알파벳을 n만큼 밀어서 암호화하는 함수입니다. 알파벳의 경우 대문자와 소문자를 구분하여 각각 시작 아스키 값을 기준으로 연산합니다. 문자열의 각 문자를 순회하며 알파벳인 경우 아스키 코드를 이용하여 암호화하고, 공백은 그대로 유지합니다. 알고리즘 대회에서는 ASCII 코드 값을 직접 사용하는 대신 `ord()`와 `chr()` 함수를 활용하여 코드 가독성을 높일 수 있습니다. 또한, `itertools.cycle`을 활용하여 알파벳 순환을 더 효율적으로 처리할 수 있습니다.
def solution(s, n): answer = '' for i in range(len(s)): if s[i] == ' ': answer += ' ' continue first = ord('A') if s[i].isupper() else ord('a') answer += chr((ord(s[i]) - first + n) % 26 + first) #해당아스키 값 - 알파벳의 시작 아스키 값 + n을 26으로 나눈 나머지를 다시 알파벳의 시작 아스키 값에 더해준다 return answer양민철
2024-07-10 21:20:11이 코드는 문자열 s의 각 문자를 알파벳 순서대로 n만큼 이동시켜 암호화하는 알고리즘을 구현합니다. 문자열을 순회하며 각 문자를 ASCII 코드를 활용하여 변환하고, 26으로 나눈 나머지를 이용해 알파벳 범위를 유지합니다. 이 풀이는 brute force 방식으로 문자열을 순회하며 각 문자를 변환하는 방식입니다. 코드의 가독성을 높이기 위해 문자열 슬라이싱 대신 `itertools.cycle`을 사용하여 알파벳 순환을 표현할 수 있으며, `ord` 함수를 이용해 문자를 ASCII 코드로 변환하는 부분을 `string.ascii_uppercase` 와 `string.ascii_lowercase` 를 사용해 간소화할 수 있습니다.
def solution(s, n): answer = "" for c in s: if 'A' <= c <= 'Z': answer += chr((ord(c) - ord('A') + n) % 26 + ord('A')) elif 'a' <= c <= 'z': answer += chr((ord(c) - ord('a') + n) % 26 + ord('a')) else: answer += c return answer배수훈
2024-07-08 20:53:14주어진 문자열 s의 각 문자를 n만큼 밀어서 새로운 문자열을 만드는 코드입니다. 알파벳의 범위를 벗어나는 경우에는 다시 처음으로 돌아가도록 구현했습니다. 문자열 처리를 더 효율적으로 하기 위해 `ord`와 `chr` 함수를 활용하였고, 범위를 벗어나는 경우를 `if`문으로 처리했습니다. `ord`와 `chr` 함수를 사용하는 대신 `string` 모듈의 `ascii_lowercase`, `ascii_uppercase`를 활용하여 코드를 더 간결하게 만들 수 있습니다. 또한, `for` 루프 대신 `map` 함수를 사용하면 코드를 더욱 간결하게 표현할 수 있습니다.
def solution(s, n): result = "" for i in range(len(s)): ch = s[i] if ch == " ": result+=" " continue tmp = ord(ch) + n if "A" <= ch <= "Z": if tmp > 90: tmp-=26 if "a" <= ch <= "z": if tmp > 122: tmp-=26 result+=chr(tmp) return result이지민
2024-07-08 09:01:46주어진 문자열 s의 각 문자를 n만큼 밀어서 새로운 문자열을 만드는 알고리즘입니다. 알파벳을 숫자로 변환한 후 n을 더하고 다시 숫자를 알파벳으로 변환하는 방식을 사용합니다. 문자열을 순회하며 공백은 그대로 유지하고 알파벳은 숫자로 변환한 후 n을 더하여 다시 알파벳으로 변환합니다. 숫자는 26으로 나눈 나머지 값을 사용하여 알파벳 범위를 유지합니다. 문자열을 숫자로 변환하는 과정에서 딕셔너리를 활용했는데, 딕셔너리 대신 ord() 함수를 사용하면 더 간결하게 표현할 수 있습니다. 또한, 문자열을 숫자로 변환하고 다시 알파벳으로 변환하는 과정을 한 번에 수행할 수 있는 chr() 함수를 활용하면 더 효율적입니다.
def solution(s, n): answer = '' dicts = {'a':0, 'b':1, 'c':2, 'd':3, 'e':4, 'f':5, 'g':6,'h':7,'i':8,'j':9,'k':10,'l':11,'m':12,'n':13, 'o':14,'p':15,'q':16,'r':17,'s':18,'t':19,'u':20,'v':21, 'w':22,'x':23,'y':24,'z':25} convert_dict = {v:k for k,v in dicts.items()} for i in range(len(s)): if s[i] == ' ': answer +=' ' elif s[i] not in dicts : alphbet=s[i].lower() num = dicts[alphbet] +n ans = convert_dict[num%26] answer+= ans.upper() else: num = dicts[s[i]] +n ans = convert_dict[num%26] answer+= ans return answer이석민
2024-07-07 21:58:45주어진 문자열 s의 각 문자를 n만큼 회전시켜 새로운 문자열을 반환하는 함수입니다. 알파벳 문자는 순환적으로 이동하며, 숫자와 특수문자는 그대로 유지됩니다. 문자열을 순회하며 각 문자를 ASCII 코드로 변환하여 대문자, 소문자, 숫자/특수문자 여부에 따라 처리합니다. 알파벳 문자는 n만큼 이동 후 모듈 연산을 통해 알파벳 범위 내에서 순환하도록 구현했습니다. 문자열 처리 시 `itertools.cycle`을 사용하면 코드를 더욱 간결하게 작성할 수 있습니다. 또한, ASCII 코드 대신 `string.ascii_lowercase`와 `string.ascii_uppercase`를 사용하면 코드 가독성을 높일 수 있습니다. 모듈 연산을 사용하는 대신 `ord`와 `chr` 함수를 활용해 `if` 문을 사용하지 않고 바로 변환하는 방법도 고려해볼 만합니다.
def solution(s, n): result = [] a = ord('a') z = ord('z') A = ord('A') Z = ord('Z') alphabet = z - a for c in s: ch = ord(c) # 대문자 if (ch >= A and ch <= Z): ch = (ch - A + n) % (alphabet + 1) + A result.append(chr(ch)) elif (ch >= a and ch <= z): ch = (ch - a + n) % (alphabet + 1) + a result.append(chr(ch)) else: result.append(c) return ''.join(result)이상한 문자 만들기
코드 제출 (7등) 문제 바로가기이현석
2024-07-14 12:09:02주어진 문자열에서 각 단어의 짝수 번째 글자는 대문자로, 홀수 번째 글자는 소문자로 바꾸는 알고리즘입니다. 문자열을 공백 기준으로 분리하여 각 단어를 순회하며 인덱스를 기준으로 대소문자를 변환합니다. 코드는 직관적이며 이해하기 쉬우나, 반복문을 사용하여 짝수/홀수 여부를 판단하는 부분을 `itertools.cycle`을 활용하면 더 효율적으로 표현할 수 있습니다. 또한, 마지막 공백을 제거하는 부분은 슬라이싱 대신 `rstrip` 함수를 사용하는 것이 더 간결하고 직관적입니다.
def solution(s): answer = '' for word in s.split(' '): for i in range(len(word)): if i % 2 == 0: answer += word[i].upper() else: answer += word[i].lower() answer += ' ' return answer[0:-1]주병규
2024-07-11 15:52:23주어진 문자열에서 짝수 번째 위치의 문자는 대문자로, 홀수 번째 위치의 문자는 소문자로 변환하여 새로운 문자열을 반환하는 코드입니다. 공백 문자는 그대로 유지됩니다. 이 코드는 반복문을 사용하여 문자열을 순회하며 문자의 위치에 따라 대소문자를 변환하는 직관적인 방식으로 작성되었습니다. 더 효율적으로 코드를 개선하려면 `enumerate` 함수를 사용하여 인덱스와 문자를 동시에 순회할 수 있으며, `ord` 함수를 사용하여 문자의 ASCII 코드를 가져와서 대소문자를 변환하는 방식을 고려해볼 수 있습니다.
def solution(s): answer = '' index = 0 for i in range(len(s)): alphabet = s[i] if alphabet == " ": #공백 초기화 answer+= alphabet index = 0 continue if index%2 == 0:# 짝일경우 answer += alphabet.upper() else: #나머지 answer += alphabet.lower() index += 1 return answer양민철
2024-07-10 21:28:29주어진 문자열에서 띄어쓰기가 아닌 각 문자를 번갈아가며 대문자와 소문자로 변환하는 함수입니다. 문자열을 순회하며 짝수 번째 위치에 있는 문자를 대문자로, 홀수 번째 위치에 있는 문자를 소문자로 변환하여 새로운 문자열을 생성합니다. 문자열을 순회하면서 짝수/홀수 여부를 판별하는 대신 `itertools.cycle`을 활용하여 번갈아 대문자와 소문자를 적용하는 방식으로 코드를 간결하게 표현할 수 있습니다. 학습 효과를 높이기 위해 다양한 방법으로 동일한 문제를 해결해보는 것이 좋습니다. 예를 들어, `enumerate` 함수를 사용하여 인덱스와 문자를 함께 처리하거나, 문자열 슬라이싱을 이용하여 짝수/홀수 번째 문자를 분리하여 처리하는 방식을 시도해볼 수도 있습니다.
def solution(s): answer = "" idx = 0 for c in s: if c == ' ': idx = 0 elif idx % 2 == 0: c = c.upper() idx += 1 else: c = c.lower() idx += 1 answer += c return answer이지민
2024-07-10 13:56:00주어진 문자열에서 홀수 번째 인덱스의 문자는 대문자로, 짝수 번째 인덱스의 문자는 소문자로 변환하는 알고리즘입니다. 공백 문자는 그대로 유지하며, 공백 이후에는 다시 홀수 인덱스부터 시작합니다. 이 코드는 명확하고 직관적인 방식으로 문제를 해결하지만, 좀 더 효율적으로 개선할 수 있습니다. 예를 들어 `itertools.cycle`을 사용하여 홀수/짝수 인덱스를 번갈아 처리하거나, `enumerate`를 사용하여 인덱스를 추적하는 대신 인덱스를 직접 사용하는 방식으로 코드를 간결하게 만들 수 있습니다.
def solution(s): ans = '' idx = 0 for i in s: idx +=1 if i ==' ': ans +=' ' idx =0 continue elif idx % 2==1: ans += i.upper() else: ans += i.lower() return ans배수훈
2024-07-08 21:02:15주어진 문자열에서 짝수 번째 글자는 대문자로, 홀수 번째 글자는 소문자로 변환하여 새로운 문자열을 만드는 코드입니다. 공백을 기준으로 문자열을 분리하여 각 단어에 대해 반복문을 수행하며 글자의 위치에 따라 대소문자를 변환합니다. 이 코드는 굳이 반복문을 사용하지 않고 `str.upper()`와 `str.lower()`를 활용하여 더 간결하고 효율적으로 작성될 수 있습니다. 또한, 짝수 번째 인덱스를 찾는 방법 대신 `enumerate`를 사용하면 코드 가독성을 높일 수 있습니다. 이러한 개선을 통해 코드의 효율성과 가독성을 높여 경쟁 환경에서 더 빠르고 정확한 솔루션을 구현할 수 있습니다.
def solution(s): answer = '' arr = s.split(" ") for word in arr: for i in range(0, len(word)): tmp = word[i] if i%2==0: tmp = tmp.upper() else: tmp = tmp.lower() answer+=tmp answer+=" " return answer[:-1]이석민
2024-07-07 21:59:00이 코드는 문자열을 입력받아 각 단어의 홀수 번째 글자는 소문자로, 짝수 번째 글자는 대문자로 변환하는 알고리즘을 구현했습니다. 즉, 입력 문자열 "hello world"를 "HeLlO WoRlD"로 변환하는 것입니다. 코드는 반복문을 사용하여 문자열을 단어 단위로 분리하고 각 단어의 글자를 순회하며 짝수 번째 글자는 대문자, 홀수 번째 글자는 소문자로 변환하는 방식으로 동작합니다. 코드에서 반복문을 사용하는 대신 `enumerate` 내장 함수를 활용하면 더 간결하고 효율적인 코드를 작성할 수 있습니다. 또한, 이 문제는 `s.split(' ')` 함수를 사용하여 단어를 분리한 후 처리하는 방식으로 구현되었지만, `itertools` 모듈의 `zip` 함수를 사용하여 짝수 번째 글자와 홀수 번째 글자를 번갈아 가며 처리하며 더욱 직관적인 코드를 구현할 수 있습니다.
def solution(s): result = [] for s in s.split(' '): word = [] for idx, c in enumerate(s): if idx % 2 == 0: word.append(c.upper()) else: word.append(c.lower()) result.append(''.join(word)) print(result) return ' '.join(result)튜플
코드 제출 (6등) 문제 바로가기이현석
2024-07-14 15:38:40이 코드는 중첩 집합을 입력받아 각 집합에 포함된 요소를 오름차순으로 정렬하여 리스트에 담아 반환하는 알고리즘입니다. 입력 문자열을 ','로 분리하여 집합을 만들고, 집합의 크기 기준으로 정렬한 후 각 집합의 요소를 순차적으로 리스트에 추가하며 중복을 제거합니다. 시간 복잡도를 개선하기 위해 집합의 크기 기준으로 정렬하는 대신, 입력 문자열을 숫자로 변환하여 Counter 객체를 활용하는 것이 효율적입니다. 또한, 중복 제거 과정에서 `set` 자료형을 사용하여 더욱 간결하고 효율적으로 코드를 작성할 수 있습니다.
def solution(s): answer = [] s = s[2:-2] s = s.split('},{') s.sort(key = len) for i in s: li = i.split(',') for ele in li: if int(ele) not in answer: answer.append(int(ele)) return answer양민철
2024-07-14 14:35:36주어진 문자열에서 중괄호 안의 숫자들을 추출하여 오름차순으로 정렬하여 반환하는 함수입니다. 문자열을 탐색하여 중괄호 위치를 찾고, 각 중괄호 안의 숫자들을 리스트로 변환하여 정렬한 후, 중복 제거하여 최종 결과를 반환합니다. 이 코드는 중괄호 위치 찾기, 숫자 분리, 정렬, 중복 제거 등의 알고리즘을 사용하여 문제를 해결하는 좋은 예시입니다. 하지만 코드의 가독성을 높이기 위해, `for` 루프를 사용하는 부분을 `itertools` 모듈의 `groupby` 함수를 이용하여 더 효율적으로 표현할 수 있습니다. 또한, 숫자를 분리하는 과정에서 `split` 함수를 사용하는 대신 `re` 모듈의 `findall` 함수를 사용하여 정규 표현식으로 더 직관적으로 숫자만 추출할 수 있습니다.
def solution(s): s = "".join(list(s)[1 : len(s) - 1]) start = [] end = [] for i in range(len(s)): if s[i] == '{': start.append(i + 1) if s[i] == '}': end.append(i) cases = [] for i in range(len(start)): s_set = s[start[i] : end[i]] cases.append(list(map(int, s_set.split(',')))) cases.sort(key=len) answer = [] answer_set = set() for c in cases: for e in c: if e in answer_set: continue answer_set.add(e) answer.append(e) return answer배수훈
2024-07-14 12:03:38이 코드는 주어진 문자열에서 중첩된 집합을 추출하여 오름차순으로 정렬하는 알고리즘을 구현합니다. 문자열을 쪼개고 집합의 크기 순으로 정렬한 후, 중복을 제거하며 원소를 추가하는 방식으로 문제를 해결합니다. 코드의 효율성을 높이기 위해 중복 확인에 `set` 자료구조를 활용하고, `sorted` 함수를 사용하여 집합의 크기에 따른 정렬을 수행하는 것이 효과적입니다. `for` 루프를 이용하여 문자열을 순회하는 과정을 `itertools.chain` 함수를 사용하면 코드를 더 간결하게 표현할 수 있습니다.
def solution(s): answer = [] ss = sorted(s[2:-2].split("},{"), key = len) set_answer = set() for arr in ss: i_arr = list(map(int, arr.split(","))) for num in i_arr: if num in set_answer: continue answer.append(num) set_answer.add(num) return answer주병규
2024-07-11 15:52:33주어진 문자열을 튜플로 변환한 후 튜플의 길이를 기준으로 정렬하여 튜플의 원소를 순서대로 answer 리스트에 추가하는 알고리즘입니다. 중복된 원소를 제거하기 위해 `not in` 연산을 사용하는데, `set` 자료구조를 활용하면 더 효율적으로 중복 제거를 수행할 수 있습니다. 튜플을 정렬하는 부분에서 `collections.Counter` 를 사용하여 튜플의 원소 빈도를 계산하여 빈도가 높은 순서대로 정렬하면 더 빠르게 튜플을 정렬하고 원하는 결과를 얻을 수 있습니다.
def solution(s): tuples = [] answer = [] for tuple in s[2:-2].split("},{"): #튜플로 변환 tuple = list(map(lambda x: int(x),tuple.split(","))) tuples.append(tuple) tuples = sorted(tuples,key= lambda tuple: len(tuple)) # list 길이에 따른 정렬 for tuple in tuples: #같은것만 for i in range(len(tuple)): num = tuple[i] if num not in answer: answer.append(num) return answer이석민
2024-07-07 21:59:14주어진 문자열에서 중괄호로 묶인 숫자들을 추출하여 오름차순으로 정렬하여 반환하는 코드입니다. 중복된 숫자는 제거하고, 숫자들의 크기 순서대로 결과 리스트에 추가합니다. 코드는 효율성을 높이기 위해 정규 표현식을 사용하고, 중복 숫자를 방지하기 위해 딕셔너리를 활용합니다. 더 빠른 코드를 위해 정규 표현식 대신 문자열 슬라이싱을 사용하여 중괄호를 제거하는 것이 더 효율적입니다. 또한, 숫자 리스트를 정렬하는 대신, `set` 자료형을 사용하여 중복을 제거하고 자동으로 정렬할 수 있습니다. 빠른 코드를 위해 `sorted` 대신 `collections.OrderedDict`를 사용하여 정렬하는 것이 더 효율적입니다. 입력 문자열에서 중괄호를 제거한 후, 숫자를 추출하고 정렬하는 과정을 최적화하는 것이 중요합니다.
import re def solution(s): r = re.compile("{([\d, ]+)}") find = r.findall(s) result = [] find = sorted(find, key=len) shown = {} for f in find: splited = map(int, f.split(',')) for num in splited: if num in shown: continue result.append(num) shown[num] = None return result짝지어 제거하기
코드 제출 (7등) 문제 바로가기이현석
2024-07-14 15:41:43이 코드는 스택 자료구조를 활용하여 주어진 문자열에서 괄호 쌍이 올바르게 짝지어져 있는지 확인하는 알고리즘입니다. 각 문자를 순회하며 스택에 넣고, 같은 종류의 괄호가 나오면 스택에서 꺼내는 방식으로 짝을 맞춰나갑니다. 스택을 이용한 풀이는 직관적이지만, 괄호 종류가 다양해지거나 복잡한 조건이 추가될 경우 코드가 길어질 수 있습니다. 문자열 처리 기능을 활용하여 더 간결하고 효율적인 코드를 작성하는 것을 고려해볼 수 있습니다. 또한, 괄호 짝을 맞추는 문제는 재귀 함수를 이용하여 더욱 효율적으로 해결할 수도 있습니다.
def solution(s): stack = [] for i in s: if len(stack) == 0: stack.append(i) elif stack[-1] == i: stack.pop() else: stack.append(i) if len(stack) == 0: return 1 else: return 0배수훈
2024-07-14 13:14:06이 코드는 스택 자료구조를 활용하여 주어진 문자열 's'의 괄호 짝이 맞는지 확인하는 알고리즘을 구현합니다. 입력 문자열을 순회하며 괄호가 열릴 때 스택에 추가하고 닫힐 때 스택에서 제거하는 방식으로 짝을 검사합니다. 스택을 사용하는 대신 문자열 슬라이싱 방식을 사용하여 코드를 더 간결하게 작성할 수 있으며, 특히 반복되는 문자열 처리 작업에서 효율성을 높일 수 있습니다. 문자열을 반복적으로 탐색하는 대신 딕셔너리를 활용하여 괄호의 짝을 효율적으로 매칭하는 방식을 사용하는 것이 더욱 효과적입니다. 자료구조 선택과 알고리즘 구현에 있어 다양한 방법을 숙지하고 문제 상황에 맞는 최적의 방법을 선택하는 연습이 필요합니다.
from collections import deque; def solution(s): stack = deque() for ch in s: if len(stack) == 0: stack.append(ch) elif stack[-1] == ch: stack.pop() else: stack.append(ch) return 1 if len(stack) == 0 else 0주병규
2024-07-11 15:52:45주어진 문자열에서 괄호 쌍이 올바르게 짝지어져 있는지 확인하는 코드입니다. 스택을 이용하여 문자열을 순회하며 괄호 쌍을 검사하고, 짝이 맞는 괄호가 있으면 스택에서 제거하고, 짝이 맞지 않으면 스택에 추가합니다. 이 코드는 스택을 사용하여 괄호 쌍을 효율적으로 검사하는 좋은 예시입니다. 하지만 괄호 종류가 하나뿐인 경우, 더 간단하게 문자열의 길이를 이용하여 짝을 확인할 수 있습니다. 괄호 종류가 여러 개인 경우, 딕셔너리 자료 구조를 활용하여 짝을 매칭하는 방식을 시도해 볼 수 있습니다.
def solution(s): stack = [] for char in s: if stack and stack[-1] == char: #짝수로 붙어있기 때문에 stack에 넣고 빼기 stack.pop() else: stack.append(char) return 1 if not stack else 0양민철
2024-07-10 23:21:08주어진 문자열에서 괄호 쌍이 올바르게 짝지어져 있는지 판별하는 함수입니다. 스택을 이용하여 문자열을 순회하며 괄호 쌍을 검사하는 방식으로 구현되어 있습니다. 해당 코드는 스택의 활용을 통해 효율적으로 괄호 쌍을 검사하는 알고리즘을 보여줍니다. 더욱 효율적인 풀이를 위해 `collections.deque`를 사용하여 스택을 구현하면 삽입 및 삭제 연산에 있어 더욱 빠른 속도를 기대할 수 있습니다. 또한, `itertools.cycle`을 활용하여 괄호 쌍 검사를 더욱 간결하게 표현할 수 있습니다. 이를 통해 코드의 가독성을 높이고, 알고리즘 경진 대회에서 더욱 효율적인 코드 작성이 가능합니다.
def solution(s): answer = -1 stack = [] for c in s: if(len(stack) == 0): stack.append(c) continue if(stack[-1] == c): stack.pop() else: stack.append(c) return 1 if len(stack) == 0 else 0이지민
2024-07-10 14:26:44이 코드는 스택 자료구조를 활용하여 주어진 문자열 s에서 괄호 쌍이 올바르게 짝지어졌는지 확인하는 알고리즘을 구현합니다. 스택에 문자를 추가하고 짝이 맞는 괄호가 나타나면 스택에서 제거하는 방식으로 괄호 쌍이 모두 제거될 경우 올바른 짝지어짐을 판단합니다. 코드를 개선할 여지가 있습니다. 스택 대신 딕셔너리를 사용하여 괄호 쌍을 관리하면 괄호 종류에 대한 제한 없이 일반화할 수 있고, 코드 가독성을 향상시킬 수 있습니다. 또한, 문자열을 순회하는 반복문 대신 itertools.cycle을 사용하면 더 효율적인 코드를 작성할 수 있습니다.
def solution(s): answer = -1 stack =[] for i in s: if len(stack) ==0: stack.append(i) elif stack[-1] == i: stack.pop() else: stack.append(i) if len(stack) ==0: answer = 1 else: answer =0 return answer이석민
2024-07-07 21:59:25주어진 문자열에서 연속된 같은 문자를 제거하는 함수입니다. 스택 자료구조를 활용하여 문자열을 순회하며 같은 문자가 연속적으로 나타나면 제거하는 방식으로 동작합니다. 시간 복잡도는 O(N)으로 입력 문자열의 길이에 비례합니다. 더 빠른 실행 시간을 위해, 스택 자료구조를 사용하는 대신, 두 개의 포인터를 사용하여 문자열을 순회하는 방법을 고려할 수 있습니다. 이 방법을 사용하면 불필요한 pop 연산이 줄어들어 더 빠른 속도로 동작합니다. 예를 들어, `tmp` 배열을 사용하는 대신, 두 개의 포인터를 사용하여 연속된 문자를 비교하고 필요에 따라 앞 포인터를 이동하는 방식을 사용할 수 있습니다.
def solution(s): tmp = [] for c in s: tmp.append(c) while len(tmp) >= 2 and tmp[-1] == tmp[-2]: tmp.pop() tmp.pop() return 1 if len(tmp) == 0 else 0문자열 압축
코드 제출 (5등) 문제 바로가기배수훈
2024-07-14 16:32:09주어진 문자열을 압축하는 문제를 해결하는 코드입니다. 코드는 문자열을 다양한 크기로 분할하여 압축 가능성을 확인하며 가장 짧은 압축 결과를 반환합니다. 반복문을 통해 문자열을 압축하는 방식은 직관적인 방법이지만, 시간 복잡도가 높을 수 있습니다. 최적화된 풀이를 위해 문자열 패턴을 분석하는 알고리즘이나 압축 결과에 대한 캐싱을 활용할 수 있습니다. 문제 해결에 필요한 기술을 연습하는 데 도움이 되는 코드이며, 더 효율적인 알고리즘을 활용하여 코드의 성능을 향상시키는 연습을 할 수 있습니다.
def solution(s): answer = len(s) for size in range(1, len(s)//2 + 1): tmp = "" cur = s[:size] cnt = 1 for i in range(size, len(s) + size, size): # 마지막 스트링까지 더해주기 위해 범위 설정 if cur == s[i:i+size]: cnt+=1 continue if cnt == 1: tmp += cur else: tmp += str(cnt) + cur cur = s[i:i+size] cnt = 1 answer = min(answer, len(tmp)) return answer이현석
2024-07-14 16:11:44주어진 문자열을 압축하는 알고리즘으로, 문자열을 여러 길이의 단위로 나누어 반복되는 부분을 숫자로 압축하여 가장 짧은 결과를 찾습니다. 모든 가능한 단위 길이에 대해 압축을 시도하고, 가장 짧은 결과를 반환합니다. 코드는 모든 가능한 단위 길이를 반복하며 압축 결과를 계산하는 방식으로, 효율성 측면에서 개선 가능성이 있습니다. 특히, 압축 결과를 저장하는 comp_str을 매번 새로 만드는 부분을 최적화할 수 있습니다. 또한, 반복문 내에서 동일한 문자열 비교를 여러 번 수행하는 부분을 최적화하여 코드의 속도를 향상시킬 수 있습니다. 알고리즘 대회에서는 시간 복잡도를 줄이는 것이 중요하며, 이 코드는 O(n^2)의 시간 복잡도를 가지므로 더 효율적인 해결책을 찾아야 합니다. 예를 들어, 접두사 트리를 이용하거나 동적 프로그래밍 기법을 적용하여 시간 복잡도를 줄일 수 있습니다.
def solution(s): if len(s) == 1: return 1 answer = len(s) for s_len in range(1, len(s) // 2 + 1): comp_str = "" prev_str = s[:s_len] count = 1 for j in range(s_len, len(s), s_len): next_str = s[j:j + s_len] if prev_str == next_str: count += 1 else: comp_str += prev_str if count == 1 else str(count) + prev_str prev_str = next_str count = 1 comp_str += prev_str if count == 1 else str(count) + prev_str answer = min(answer, len(comp_str)) return answer배수훈
2024-07-14 14:21:18이 코드는 문자열 압축 문제를 풀이하는 함수로, 주어진 문자열을 반복되는 부분 문자열로 압축하여 가장 짧은 길이의 결과 문자열을 반환합니다. 코드는 주어진 문자열을 다양한 크기의 부분 문자열로 나누어 압축을 시도하고, 가장 짧은 결과를 찾는 방식으로 작동하며, 반복문과 조건문을 사용하여 압축 과정을 구현합니다. 이 코드는 Brute Force 방식으로 모든 가능한 압축 방식을 시도하기 때문에 시간 복잡도가 높습니다. 효율성을 높이기 위해 Sliding Window 기법을 사용하여 압축 가능한 최대 길이를 찾고, 이를 기반으로 압축을 진행하는 방식을 고려할 수 있으며, 압축 결과를 저장하는 과정에서 StringBuilder를 사용하면 문자열 연결 연산의 효율성을 높일 수 있습니다.
def solution(s): answer = len(s) for size in range(1, len(s)): tmp = "" cur = s[:size] cnt = 1 for i in range(size, len(s) + size, size): # 마지막 스트링까지 더해주기 위해 범위 설정 if cur == s[i:i+size]: cnt+=1 continue if cnt == 1: tmp += cur else: tmp += str(cnt) + cur cur = s[i:i+size] cnt = 1 answer = min(answer, len(tmp)) return answer주병규
2024-07-11 15:52:59주어진 문자열을 최대 압축할 수 있는 단위를 찾는 알고리즘입니다. 주어진 문자열을 다양한 크기의 단위로 나눈 후, 동일한 단위가 연속해서 나타나는 횟수를 계산하여 압축된 문자열 길이를 계산합니다. 문자열을 나누는 크기를 1부터 문자열 길이의 절반까지 순차적으로 증가시키면서 압축된 문자열 길이를 비교하여 최소 길이를 찾습니다. 코드는 `textwrap.wrap`을 사용하여 문자열을 나누는 방식을 사용하고, `for` 루프를 통해 압축된 문자열 길이를 계산하는 방식을 사용합니다. 더 효율적인 방법으로는, 압축된 문자열 길이를 직접 계산하는 방식을 사용할 수 있습니다. 예를 들어, 현재 단위의 문자열과 이전 단위의 문자열이 동일하다면, 압축된 문자열 길이는 현재 단위의 길이에서 이전 단위의 길이를 뺀 값과 동일한 문자열의 숫자를 표현하는 문자열의 길이를 더한 값으로 계산할 수 있습니다. 이렇게 하면 압축된 문자열 길이를 계산하는 시간을 단축할 수 있습니다.
import textwrap def solution(s): inputLen = len(s) answer = None for i in range(1,inputLen//2+2): stack = textwrap.wrap(s,i) #i 크기 만큼 나누기 presentLen = inputLen isDuplicate = 0 #중복된 횟수 present = 0 for present in range (len(stack)-1): if stack[present] == stack[present+1]: #중복되었을 때 isDuplicate +=1 presentLen -= i # i크기 만큼 줄어듬 else: if isDuplicate != 0: #중복 종료 presentLen += len(str(isDuplicate+1)) #중복된 횟수의 크기만큼 늘어남 # 첫번째는 안쓰고 두번째부터 쓰기 때문에 +1 isDuplicate = 0 if isDuplicate !=0: presentLen += len(str(isDuplicate+1)) #마지막이 중복일 경우 answer = presentLen if answer is None else min(answer,presentLen) return answer #솔직히 더해가는게 더 좋을듯이석민
2024-07-07 21:59:37이 코드는 문자열을 최소 단위로 압축하는 알고리즘을 구현합니다. `word_spliter` 함수를 통해 문자열을 주어진 단위로 나누고, `solution` 함수에서는 각 단위에 대해 압축된 문자열의 길이를 계산하여 가장 짧은 압축 결과를 반환합니다. 반복문을 사용하여 압축 단위를 하나씩 증가시키며 압축 결과를 계산하는 방식은 다소 직관적이지만, `itertools.cycle` 을 사용하여 반복문을 더 간결하게 표현할 수 있습니다. 또한, 압축된 문자열의 길이를 계산하는 부분에서 `join` 을 사용하는 것보다 `sum(len(x) for x in compressed)` 와 같이 더 효율적인 방법을 사용하는 것이 좋습니다.
import math def word_spliter(word, step): pos = step s_len = len(word) remain = s_len % step while pos <= s_len: yield word[pos - step:pos] pos += step if remain > 0: yield word[-remain:] def solution(s): s_len = len(s) cnt = {} for step in range(1, math.ceil(s_len / 2) + 1): compressed = [] count = 1 last = '' for c in word_spliter(s, step): if last == c: count += 1 else: if count > 1: compressed.append(str(count)) compressed.append(last) last = c count = 1 if count > 1: compressed.append(str(count)) compressed.append(last) cnt[step] = len(''.join(compressed)) return min(cnt.values())3진법 뒤집기
코드 제출 (6등) 문제 바로가기이현석
2024-07-14 16:14:21이 코드는 10진수 정수를 3진수로 변환하는 함수입니다. `divmod` 함수를 사용하여 10진수를 3으로 나눈 몫과 나머지를 구하고, 나머지를 문자열로 변환하여 answer에 누적합니다. 마지막으로 answer를 3진수로 변환하여 반환합니다. 이 코드는 3진수 변환을 위해 반복문을 직접 사용하는 직관적인 방식을 사용합니다. 하지만 재귀 함수를 이용해 더 간결하게 코드를 작성할 수 있습니다. 또한, 3진수 변환 과정에서 발생하는 문자열 조작 부분을 `str.join` 함수를 활용하여 더 직관적으로 표현할 수 있습니다.
def solution(n): answer = '' while n > 0: n, r = divmod(n,3) answer += str(r) return int(answer, 3)배수훈
2024-07-14 14:55:20주어진 숫자를 3진수로 변환한 후, 3진수 자릿수를 역순으로 곱하여 10진수로 변환하는 알고리즘입니다. 3진수 변환 과정에서 몫과 나머지를 활용하고, 10진수 변환을 위해 3의 거듭제곱을 사용합니다. 코드는 명확하고 이해하기 쉬우나, 3진수 변환 부분을 재귀 함수로 구현하면 코드를 더욱 간결하게 표현할 수 있습니다. 또한, 3의 거듭제곱을 미리 계산하여 저장하면 10진수 변환 과정에서 불필요한 연산을 줄일 수 있습니다.
def solution(n): answer = 0 n3 = "" while n >= 3: n3 += str(n % 3) n//=3 n3+=str(n) if n > 0 else "" mul3 = 1 for i in range(len(n3) - 1, -1, -1): answer += int(n3[i]) * mul3 mul3 *= 3 return answer양민철
2024-07-13 18:18:51이 코드는 10진수 정수를 3진수로 변환한 후, 3진수를 다시 10진수로 변환하는 알고리즘을 구현합니다. `convert3` 함수는 입력받은 10진수를 3으로 나눈 나머지를 역순으로 리스트에 저장하여 3진수를 표현하고, `solution` 함수는 3진수 리스트를 다시 10진수로 변환하는 과정을 수행합니다. 코드는 깔끔하고 직관적인 방식으로 작성되었지만, 3진수 변환 과정에서 `insert(0, ...)`를 이용하여 리스트 앞에 값을 추가하는 방식은 시간 복잡도 측면에서 비효율적일 수 있습니다. 3진수 변환 과정에서 `append`를 사용하거나, 3진수 변환을 위한 별도의 함수를 사용하여 코드를 더 효율적으로 개선할 수 있습니다.
def solution(n): triple = convert3(n) sum = 0 for i in range(len(triple)): sum += triple[i] * (3 ** i) return sum def convert3(num): list_s = [] while(True): if num == 0: break list_s.insert(0, num % 3) num = num // 3 return list_s주병규
2024-07-11 15:53:13이 코드는 10진수 정수를 3진수로 변환하는 알고리즘을 구현합니다. 10진수를 3으로 나눈 나머지를 순차적으로 저장하고, 역순으로 3의 거듭제곱을 곱하여 3진수 값을 계산합니다. 이 코드는 간결하고 명확하지만, 3진수 변환 과정을 직관적으로 파악하기 어렵습니다. `divmod` 함수를 활용하여 몫과 나머지를 동시에 계산하면 코드의 가독성을 높일 수 있습니다. 또한, 최종 3진수 값을 계산하는 부분에 `sum` 함수와 `enumerate` 함수를 사용하면 코드를 더욱 간결하게 작성할 수 있습니다.
def solution(n): output =[] while n >2 : output.append(n%3) n = n//3 output.append(n) digit = 1 answer = 0 for i in range(len(output)-1,-1,-1): answer += int(output[i]) * digit digit *= 3 return answer이석민
2024-07-07 21:59:48이 코드는 10진수를 3진수로 변환한 후 다시 10진수로 변환하는 알고리즘을 구현합니다. 먼저 `jinsu` 함수는 10진수를 입력받아 3진수로 변환하는 과정을 수행하고, `solution` 함수는 `jinsu` 함수의 결과를 다시 10진수로 변환합니다. `jinsu` 함수는 반복문을 통해 입력받은 10진수를 3으로 나누고, 나머지를 리스트에 추가하는 방식으로 3진수를 구합니다. 더 효율적인 3진수 변환 방법을 사용하여 코드를 간소화할 수 있습니다. 예를 들어, `itertools.cycle` 함수를 사용하여 3진수 변환을 수행하면 반복문 대신 더 간결한 코드를 작성할 수 있습니다. 또한, `int` 함수를 이용하여 3진수 문자열을 바로 10진수로 변환하는 방법을 사용하면 코드의 가독성을 높일 수 있습니다.
def jinsu(n, r): result = [] d, m = n, 0 while d > 0: d, m = divmod(d, r) result.append(str(m)) return ''.join(result) def solution(n): return int(jinsu(n, 3), 3)이진 변환 반복하기
코드 제출 (6등) 문제 바로가기이현석
2024-07-14 16:26:21이 코드는 주어진 이진 문자열 `s`를 "1"이 될 때까지 0을 제거하고 길이를 이진수로 변환하는 과정을 반복하며, 이 과정이 몇 번 수행되었는지(cnt)와 0이 총 몇 개 제거되었는지(zero_cnt)를 반환합니다. 이 코드는 반복문을 사용하여 문제를 해결하는 전형적인 브루트포스 방식의 풀이이며, `s.count("0")`이나 `s.replace("0",'')`와 같은 문자열 연산을 자주 사용합니다. 이 코드는 효율성 측면에서 개선될 여지가 있습니다. `s.count("0")` 대신 `s.replace("0", '').count("0")`을 사용하여 0을 제거하면서 0의 개수를 동시에 계산할 수 있습니다. 또한, `bin(len(s))[2:]`를 사용하는 대신, `len(s)`를 2진수로 변환하는 함수를 별도로 만들어 코드 가독성을 높일 수 있습니다.
def solution(s): zero_cnt = 0 cnt = 0 while True: if s == "1": break zero_cnt += s.count("0") s = s.replace("0",'') s = bin(len(s))[2:] cnt += 1 return [cnt,zero_cnt]배수훈
2024-07-14 15:14:00주어진 문자열 s에 대해 "0"을 제거하고, 남은 1의 개수를 이진수로 변환하는 과정을 반복하며 "1"이 될 때까지 진행합니다. 이 과정에서 "0"을 제거한 횟수와 변환 과정을 거친 횟수를 각각 계산하여 반환합니다. 코드는 반복문을 사용하여 문제를 해결하는 직관적인 방식을 보여줍니다. 하지만 반복문 대신 재귀 함수를 활용하면 코드를 더욱 간결하게 표현할 수 있습니다. 또한, 이진수 변환 과정은 `bin` 함수를 사용하는 대신 비트 연산을 활용하여 효율성을 높일 수 있습니다.
def solution(s): answer = [0, 0] while s!="1": cnt = s.count("0") s = s.replace("0", "") length = len(s) s = bin(length)[2:] s = s[::-1] answer[0] += 1 answer[1] += cnt return answer배수훈
2024-07-14 15:08:16이 코드는 주어진 문자열 s를 "1"이 될 때까지 반복적으로 변환하는 알고리즘을 구현합니다. 각 변환 단계에서 문자열에서 "0"의 개수를 세고, "0"을 제거한 후 2진수로 변환합니다. 코드는 반복문과 문자열 조작을 사용하며, 좀 더 효율적인 방법으로 개선될 수 있습니다. 예를 들어, "0"의 개수를 세는 부분은 `s.count("0")` 함수를 사용하여 간단하게 처리 가능하며, 2진수 변환은 `bin(int(s, 2))`와 같은 함수를 활용하면 더 명확하게 표현할 수 있습니다. 알고리즘 대회에서는 코드의 효율성과 가독성이 중요하므로, 함수를 활용하고 불필요한 반복문을 줄여 코드를 간결하게 작성하는 것이 좋습니다. 또한, 시간 복잡도를 고려하여 더 효율적인 알고리즘을 찾으려고 노력하는 것이 중요합니다.
def solution(s): answer = [0, 0] while s!="1": cnt = 0 for num in s: if num == "0": cnt+=1 s = s.replace("0", "") length = len(s) s = "" while length >= 2: s += str(length % 2) length //= 2 s += str(length) if length > 0 else "" s = s[::-1] answer[0] += 1 answer[1] += cnt return answer양민철
2024-07-13 16:36:09주어진 문자열을 1로만 이루어질 때까지 1을 제외한 0을 제거하고 남은 1의 개수를 2진수로 변환하는 과정을 반복하며, 이 과정에서 제거된 0의 개수와 2진수 변환 횟수를 계산하여 반환하는 코드입니다. 이 코드는 반복문과 조건문을 사용하여 문제를 해결하는데, 2진수 변환 과정을 별도의 함수로 분리하여 코드 가독성을 높였습니다. 문제 해결 방식 자체는 효율적이지만, 2진수 변환 과정에서 문자열을 사용하여 리스트에 삽입하는 방식은 다소 비효율적입니다. Python의 `bin()` 함수를 활용하여 2진수 변환을 수행하면 코드를 간결하게 만들고 효율을 높일 수 있습니다. 또한, `is_one()` 함수는 불필요하게 복잡합니다. 단순히 `e == "1"` 조건문을 사용하는 것이 더 효율적입니다.
def solution(s): list_s = list(s) before = len(list_s) countBin = 0 count0 = 0 while(True): if len(list_s) == 1 and list_s[0] == "1": break before = len(list_s) list_s = list(filter(is_one, list_s)) count0 += before - len(list_s) list_s = convert2(len(list_s)) countBin += 1 return [countBin, count0] def is_one(e): return True if e == "1" else False def convert2(num): list_s = [] while(True): if num == 0: break list_s.insert(0, str(num % 2)) num = num // 2 return list_s주병규
2024-07-11 15:53:23이 코드는 주어진 문자열 `s`를 "1"이 될 때까지 0을 제거하고 길이를 이진수로 변환하는 과정을 반복하여 변환 횟수와 제거된 0의 개수를 반환하는 알고리즘을 구현합니다. `changeToBinary` 함수는 정수를 이진수 문자열로 변환하는 역할을 수행합니다. 코드는 간결하고 직관적이지만, `changeToBinary` 함수에서 `bin` 함수를 사용하는 대신 이진수 변환을 직접 구현하는 것이 더 효율적일 수 있습니다. 또한, `while` 루프 내에서 `len(s)-zero` 연산을 매번 수행하는 대신 변수를 사용하여 중복 연산을 줄일 수 있습니다.
def solution(s): count = 0 zeroCount = 0 while s != "1": count += 1 zero = s.count("0") #0의 개수 zeroCount += zero s= changeToBinary(len(s)-zero) #0을 제외한 길이를 이진수로 변환 answer = [count, zeroCount] return answer def changeToBinary(s): return bin(s).replace("0b","")이석민
2024-07-07 21:59:59이 코드는 주어진 문자열 s를 "1"이 될 때까지 0을 제거하고 남은 숫자의 이진수를 구하는 과정을 반복하는 알고리즘을 구현합니다. 이 과정에서 제거된 0의 개수와 수행된 단계 수를 계산하여 반환합니다. 코드는 명확하고 이해하기 쉽지만, 더 효율적인 방법으로 개선될 수 있습니다. 예를 들어, 0을 제거하는 부분은 `s.count('0')`을 사용하여 더 간결하게 표현할 수 있습니다. 또한 이진수 변환 과정은 `format(len(s), 'b')`를 사용하여 더 효율적으로 처리할 수 있습니다. 알고리즘 대회에서는 이러한 세부적인 개선을 통해 코드의 실행 속도를 높이고 효율성을 극대화할 수 있습니다.
def solution(s): step_count = 0 removed_zero = 0 while s != '1': step_count += 1 original_cnt = len(s) s = s.replace('0', '') removed_zero += (original_cnt - len(s)) s = str(bin(len(s))[2:]) return [step_count, removed_zero]신규 아이디 추천
코드 제출 (6등) 문제 바로가기이현석
2024-07-14 16:46:53이 코드는 주어진 문자열을 카카오 신규 아이디 규칙에 맞춰 변환하는 알고리즘을 구현했습니다. 소문자 변환, 허용된 문자만 추출, 연속된 마침표 제거, 앞뒤 마침표 제거, 최소 길이 유지 등의 단계를 거쳐 규칙에 맞는 아이디를 생성합니다. 코드는 각 단계를 명확하게 분리하여 가독성을 높였지만, 반복적인 문자열 조작을 사용하여 효율성이 다소 떨어질 수 있습니다. `itertools.cycle`이나 `regex`를 활용하면 코드를 단순화하고 실행 속도를 개선할 수 있습니다. 또한 마지막 단계에서 최소 길이를 맞추는 부분은 `new_id[-1] * (3 - len(new_id))` 와 같이 간단히 표현할 수 있습니다. 이러한 개선을 통해 코드의 효율성을 높이고 더욱 간결하고 명확하게 표현할 수 있습니다.
def solution(new_id): new_id = new_id.lower() allowed = "abcdefghijklmnopqrstuvwxyz0123456789-_." new_id = ''.join(c for c in new_id if c in allowed) result = [] for c in new_id: if result and result[-1] == '.' and c == '.': continue result.append(c) new_id = ''.join(result) new_id = new_id.strip('.') if not new_id: new_id = 'a' new_id = new_id[:15].rstrip('.') while len(new_id) < 3: new_id += new_id[-1] return new_id배수훈
2024-07-14 15:34:55이 코드는 카카오 2020 블라인드 채용 코딩 테스트 문제 중 하나인 "new_id 추천" 문제의 풀이입니다. 입력으로 주어진 아이디 문자열을 규칙에 맞춰 변환하는 과정을 정규 표현식을 사용하여 구현했습니다. 정규 표현식을 사용하여 아이디 문자열을 lowercase로 변환하고, 허용되지 않는 문자를 제거하고, 연속된 마침표를 하나로 줄이며, 시작과 끝의 마침표를 제거하고, 15자 이하로 제한하고, 마지막으로 최소 3자 이상이 되도록 마지막 문자를 복사하여 채웁니다. 정규 표현식 대신 `string.replace` 또는 `filter` 함수를 사용하는 것이 더 명확하고 읽기 쉬울 수 있습니다. 특히 연속된 마침표를 제거하는 부분은 `string.replace` 함수를 사용하는 것이 더 간결합니다. 또한, 마지막 3자 이상 조건을 만족시키기 위해 반복문 대신 `st.ljust` 함수를 사용하는 것이 더 효율적입니다.
import re def solution(new_id): st = new_id st = st.lower() st = re.sub('[^a-z0-9\-_.]', '', st) st = re.sub('[.]+', '.', st) st = re.sub('^[.]|[.]$', '', st) st = 'a' if len(st) == 0 else st[:15] st = re.sub('^[.]|[.]$', '', st) st = st if len(st) > 2 else st + "".join([st[-1] for i in range(3-len(st))]) return st배수훈
2024-07-14 15:29:47이 코드는 카카오 신입 개발자 공채 코딩 테스트의 "new_id" 문제를 푸는 파이썬 코드로, 입력받은 아이디를 주어진 규칙에 따라 변환하는 기능을 수행합니다. 정규 표현식을 활용하여 아이디를 소문자로 변환하고 허용되지 않은 문자를 제거하며, 연속된 마침표를 하나로 줄이고, 길이를 제한하고, 최소 길이를 맞추는 과정으로 구성되어 있습니다. 이 코드에서 정규 표현식을 사용하여 문자열 처리를 하는 대신, `string` 모듈의 함수들을 활용하면 더욱 직관적이고 효율적인 코드를 작성할 수 있습니다. 또한, `for` 루프를 이용해 문자열을 반복 처리하는 부분을 `itertools` 모듈의 `cycle` 함수를 사용하여 간결하게 표현할 수 있습니다.
import re def solution(new_id): st = new_id st = st.lower() st = re.sub('[^a-z0-9\-_.]', '', st) st = re.sub('\.+', '.', st) st = re.sub('^[.]|[.]$', '', st) st = 'a' if len(st) == 0 else st[:15] st = re.sub('^[.]|[.]$', '', st) st = st if len(st) > 2 else st + "".join([st[-1] for i in range(3-len(st))]) return st양민철
2024-07-14 13:08:54주어진 문자열을 특정 규칙에 따라 변환하는 함수입니다. 문자열을 소문자로 변환 후, 허용된 문자만 남기고 연속된 마침표를 하나로 줄이며, 양쪽 끝의 마침표를 제거합니다. 문자열이 비어있으면 'a'를 추가하고 길이가 15를 넘으면 15개만 남기는 방식으로 처리합니다. 이 코드는 스택 자료 구조를 사용하여 효율적으로 문자열을 처리하지만, `itertools.cycle`을 사용하면 5단계 조건문을 더 간결하게 표현할 수 있습니다. 또한 문자열 연산의 경우 `trim` 함수를 활용하면 더 효율적으로 코드를 작성할 수 있습니다. 마지막으로 `checkPolicy` 함수는 불필요한 조건문이 많으므로 `in` 연산자를 사용하여 간결하게 표현하는 것이 좋습니다.
def solution(new_id): new_id = new_id.lower() list_id = list(new_id) stack = [] for i in range(len(list_id)): # 2 if not checkPolicy(list_id[i]): continue # 3 if len(stack) > 0: if list_id[i] == '.': if stack[-1] == list_id[i]: continue stack.append(list_id[i]) list_id = stack # 4 if len(list_id) > 0 and list_id[0] == '.': list_id.pop(0) if len(list_id) > 0 and list_id[-1] == '.': list_id.pop() # 5 if len(list_id) == 0: list_id.append('a') while(not (3 <= len(list_id))): list_id.append(list_id[-1]) if not (len(list_id) <= 15): list_id = list_id[:15] if list_id[-1] == '.': list_id.pop() return ''.join(list_id) def checkUpper(c): return 'A' <= c <= 'Z' def convertToLower(c): return chr(ord(c) + (ord('a') - ord('A'))) def checkPolicy(c): if ('a' <= c <= 'z'): return True if (c.isdigit()): return True if (c == '-'): return True if (c == '_'): return True if (c == '.'): return True return False주병규
2024-07-11 15:53:36주어진 코드는 문자열을 입력받아 특정 규칙에 맞춰 변환하는 알고리즘 문제의 풀이입니다. 코드는 입력 문자열을 소문자로 변환하고, 허용된 특수 문자와 숫자만 추출하여 새로운 문자열을 생성한 뒤, 연속된 마침표를 하나로 줄이고, 앞뒤 마침표를 제거하는 과정을 거칩니다. 마지막으로 문자열 길이가 15를 넘으면 15자리로 자르고, 길이가 2 이하이면 마지막 문자를 반복하여 3자리로 만들어 반환합니다. 코드는 명확하게 작성되어 있지만, 반복문을 사용하여 문자열을 처리하는 부분을 더 효율적으로 개선할 수 있습니다. 예를 들어, `re` 모듈을 활용하여 정규 표현식으로 허용된 문자를 추출하고, `itertools` 모듈의 `groupby` 함수를 이용하여 연속된 마침표를 처리하는 방식이 더 효율적입니다. 또한, 마지막 문자를 반복하는 부분은 `str.zfill()` 함수를 사용하여 간결하게 처리할 수 있습니다. 이러한 개선을 통해 코드의 가독성을 높이고 수행 시간을 단축할 수 있습니다.
def solution(new_id): new_id = new_id.lower() specialCheck = "" for i in range(len(new_id)): asciiNum = ord(new_id[i]) if asciiNum == 45 or asciiNum ==46 or 48<=asciiNum<=57 or asciiNum == 95 or 97<=asciiNum<=122: specialCheck += new_id[i] isDotDuplicate = False answer = "" for i in range(len(specialCheck)): if specialCheck[i] == '.' : if not isDotDuplicate: answer += specialCheck[i] isDotDuplicate = True else: answer += specialCheck[i] isDotDuplicate = False if answer[0] == ".": answer = answer[1:] if len(answer) == 0: return "aaa" if answer[-1] == ".": answer = answer[:-1] if len(answer) == 0: return "aaa" answer = answer[:15] if answer[-1] == ".": answer = answer[:-1] if len(answer) <= 2: while len(answer) < 3: answer += answer[-1] return answer이석민
2024-07-07 22:01:31주어진 문자열을 특정 규칙에 따라 변환하는 함수입니다. 소문자, 숫자, '-', '_', '.' 만 남기고 나머지 문자를 제거하고, 연속된 '.'을 하나로 줄이며, 시작 또는 끝의 '.'을 제거하는 등의 처리를 수행합니다. 정규 표현식을 사용하여 문자열을 처리하는 방식은 효율적이지만, 가독성이 떨어질 수 있습니다. 반복문을 활용하여 각 규칙을 명확하게 표현하는 방식을 고려해 보는 것이 좋습니다. 또한, 각 규칙별로 함수를 분리하여 코드를 재사용 가능하도록 구성하면 유지보수성을 높일 수 있습니다.
import re def convert(new_id): new_id = new_id.lower() new_id = re.compile('[^a-z0-9\-_\.]').sub('', new_id) new_id = re.compile('\.{2,}').sub('.', new_id) new_id = re.compile('^\.').sub('', new_id) new_id = re.compile('\.$').sub('', new_id) if new_id == '': new_id = 'a' if len(new_id) >= 16: new_id = new_id[:15] new_id = re.compile('\.$').sub('', new_id) while len(new_id) < 3: new_id = new_id + new_id[-1] return new_id def solution(new_id): return convert(new_id)문자열 다루기 기본
코드 제출 (6등) 문제 바로가기배수훈
2024-07-14 15:52:41이 코드는 문자열 `s`가 4자리 또는 6자리 숫자로만 이루어져 있는지 검사하는 함수입니다. 문자열의 길이가 4 또는 6이고, 모든 문자가 숫자인지 확인합니다. 이 코드는 간결하고 직관적이지만, 더 효율적인 방법으로 개선될 수 있습니다. 예를 들어, `isdigit()` 메서드를 사용하는 대신 `try-except` 구문을 사용하여 숫자 변환 가능 여부를 확인할 수 있습니다. 또한, 코드의 가독성을 높이기 위해 `len(s) == 4 or len(s) == 6` 부분을 `len(s) in (4, 6)`과 같이 표현할 수 있습니다.
def solution(s): return (len(s) == 4 or len(s) == 6) and s.isdigit()배수훈
2024-07-14 15:49:24주어진 문자열이 4자리 또는 6자리 숫자인지 확인하는 함수입니다. 정규 표현식을 사용하여 문자열을 검사하고, 4자리 또는 6자리 숫자에 일치하면 True를 반환합니다. 정규 표현식을 사용하는 대신 `len(s) == 4 or len(s) == 6` 과 `s.isdigit()` 을 사용하여 더 간결하고 효율적인 코드를 작성할 수 있습니다. 또한 입력 문자열이 숫자로만 구성되어 있는지 확인하는 추가 검증을 통해 코드의 견고성을 높일 수 있습니다.
import re def solution(s): r4 = re.fullmatch(r"\d{4}", s) r6 = re.fullmatch(r"\d{6}", s) return r4 != None or r6 != None이현석
2024-07-14 12:13:50이 코드는 주어진 문자열이 6자리 또는 4자리 숫자로 구성되었는지 확인하는 함수입니다. 문자열의 길이를 검사하고 숫자로만 이루어져 있는지 확인하여 유효성을 판단합니다. 코드는 간결하지만, 더 효율적인 방법으로 개선할 수 있습니다. `isdigit()` 메서드 대신 `all(c.isdigit() for c in s)` 와 같이 문자열 내 모든 문자가 숫자인지 확인하는 방법을 사용하면 더 명확하게 의도를 드러낼 수 있습니다. 또한, 6자리 또는 4자리가 아닌 경우를 바로 `False` 를 반환하는 대신, `return len(s) in (4, 6) and s.isdigit()` 와 같이 한 줄로 표현할 수 있어 가독성을 높일 수 있습니다.
def solution(s): answer = True if not (len(s) == 6 or len(s) == 4): return False if(not s.isdigit()): answer = False return answer이현석
2024-07-14 12:12:56이 코드는 주어진 문자열 `s`가 숫자로만 구성되어 있는지 확인하는 함수입니다. 입력 문자열이 숫자로만 구성되어 있으면 `True`를 반환하고, 그렇지 않으면 `False`를 반환합니다. 코드는 간단하고 직관적이지만, `isdigit` 함수를 이용하여 숫자인지 확인하는 방식은 더 효율적인 방법이 존재합니다. 예를 들어, `try-except` 블록을 사용하여 문자열을 정수로 변환하려고 시도하고, 예외가 발생하면 숫자가 아닌 것으로 판단하는 방식을 사용할 수 있습니다. 이는 입력 문자열의 형식에 대한 더 넓은 범위를 처리할 수 있으며, 예외 처리를 통해 더 안정적인 코드를 작성할 수 있습니다.
def solution(s): answer = True if(not s.isdigit()): answer = False return answer양민철
2024-07-13 14:12:46주어진 문자열이 4자리 또는 6자리 숫자인지 확인하는 함수입니다. 각 문자가 숫자인지 검사하여 조건을 만족하면 True, 아니면 False를 반환합니다. 문자열 길이 검사와 숫자 검사를 따로 하는 것이 아니라, `isdigit()` 메서드를 활용하여 한 번에 검사를 수행하면 코드를 더 간결하게 표현할 수 있습니다. 또한, `all()` 함수를 사용하여 모든 문자가 숫자인지 한 번에 확인하면 코드 가독성을 높일 수 있습니다.
def solution(s): s_list = list(s) if not (len(s) == 6 or len(s) == 4): return False for c in s_list: if (not c.isdigit()): return False return True주병규
2024-07-11 15:53:50이 코드는 주어진 문자열 s가 길이가 4 또는 6이고 모든 문자가 숫자인지 확인하는 함수입니다. 숫자로만 구성된 비밀번호 유효성 검사를 수행하는 예시 코드입니다. 이 코드는 명확하고 간결하게 작성되었지만, Python의 정규 표현식을 활용하면 더욱 간결하게 코드를 작성할 수 있습니다. 정규 표현식을 이용하면 문자열 패턴을 정확하게 표현할 수 있어 코드의 가독성을 높이고 오류를 줄일 수 있습니다.
def solution(s): if len(s) != 4 and len(s) != 6: return False for c in s: if c.isalpha(): return False return True이석민
2024-07-07 22:01:44이 코드는 주어진 문자열이 4자리 또는 6자리 숫자로 구성되었는지 확인하는 함수입니다. 정규 표현식을 사용하여 문자열이 숫자로만 이루어졌는지 검사하고, 문자열 길이가 4 또는 6인지 확인합니다. 정규 표현식을 이용한 방식은 유연하지만, 코드의 가독성을 떨어뜨릴 수 있습니다. 문자열 길이 검사 이후 `isdigit()` 함수를 활용하면 코드의 가독성을 높일 수 있습니다. 또한 길이 검사를 먼저 수행하고, 길이가 적절하면 숫자 여부를 검사하는 것이 더 효율적인 방법입니다.
import re def solution(s): if len(s) != 4 and len(s) != 6: return False if re.compile('^[\d]+$').match(s) == None: return False return True핸드폰 번호 가리기
코드 제출 (6등) 문제 바로가기배수훈
2024-07-14 15:54:36주어진 전화번호의 뒷 4자리를 제외한 나머지 부분을 '*'로 가리고, 뒷 4자리는 그대로 반환하는 함수입니다. 이 코드는 문자열 슬라이싱과 문자열 연결을 사용하여 간결하게 구현되었지만, `itertools.cycle`을 사용하여 '*'를 반복적으로 생성하는 방식이 더 효율적일 수 있습니다. 또한, `string.rjust` 함수를 사용하여 '*'를 왼쪽에 채우는 방식도 가능하며, 이는 코드 가독성을 향상시킬 수 있습니다.
def solution(phone_number): return (len(phone_number) - 4)*"*" + phone_number[-4:]이현석
2024-07-14 12:14:35이 코드는 주어진 전화번호의 뒷 4자리를 제외한 부분을 '*'로 가리고, 뒷 4자리는 그대로 보여주는 함수입니다. 문자열 슬라이싱과 문자열 더하기 연산을 이용하여 암호화된 전화번호를 생성합니다. 이 코드는 간결하고 직관적이지만, 더 효율적인 방법으로 개선할 수 있습니다. `string.rjust()` 함수를 사용하면 문자열을 오른쪽 정렬하고 빈 공간을 '*'로 채울 수 있어, 별도의 암호화 처리 없이 바로 암호화된 전화번호를 생성할 수 있습니다. 또한, 암호화된 전화번호를 저장하기 위한 별도의 변수 `hidden`을 사용하지 않고, 바로 `answer` 변수에 값을 할당하면 코드를 더 간결하게 만들 수 있습니다.
def solution(phone_number): answer = '' hidden = '*' * (len(phone_number)-4) answer = hidden + phone_number[-4:] return answer양민철
2024-07-13 11:11:19이 코드는 주어진 전화번호의 뒷 4자리를 제외한 나머지 부분을 '*'로 가리는 함수입니다. 리스트를 사용하여 문자열을 조작하고 다시 문자열로 합치는 방식으로 구현되었습니다. 이 코드는 간결하고 직관적이지만, Python의 문자열 슬라이싱과 문자열 결합 기능을 활용하면 더욱 간결하게 표현할 수 있습니다. 또한, 특정 범위의 문자를 '*'으로 대체하는 작업에 `itertools` 모듈의 `cycle` 함수를 활용하여 코드를 더욱 일반화할 수 있습니다.
def solution(phone_number): numbers = list(phone_number) for i in range(len(numbers) - 4): numbers[i] = "*" return "".join(numbers)주병규
2024-07-11 15:54:07이 코드는 전화번호의 뒷 4자리를 제외한 나머지 부분을 '*'으로 가리는 함수입니다. for 문을 이용해 문자열을 순회하며, 뒷 4자리 이전까지 '*'을 추가하고 나머지 부분은 그대로 더합니다. 이 코드를 개선하기 위해서는 슬라이싱을 활용하여 더 간결하게 표현할 수 있습니다. `answer = "*" * (len(phone_number) - 4) + phone_number[-4:]` 와 같이 슬라이싱을 이용하면 for 문을 사용하지 않고도 같은 결과를 얻을 수 있어 코드가 더욱 간결해집니다. 또한, 알고리즘 문제 풀이에서는 코드의 효율성뿐만 아니라 가독성도 중요합니다. 변수 이름을 더 명확하게 지어주고, 필요한 주석을 추가하면 다른 사람이 코드를 쉽게 이해할 수 있도록 도와줍니다.
def solution(phone_number): num = len(phone_number)-4 # 가려야할 문자의 수 answer = '' for i in range(len(phone_number)): if num > 0: answer += "*" num -= 1 else: answer += phone_number[i] return answer이석민
2024-07-07 22:01:57이 코드는 전화번호를 입력받아 마지막 4자리를 제외한 부분을 '*'로 가린 후, 전체 문자열을 반환하는 함수입니다. '*'를 사용하는 대신 `string.zfill` 함수로 0을 채워 가리는 방식을 사용하면 더욱 간결하고 효율적인 코드를 작성할 수 있습니다. 이 함수는 단순히 문자열 조작을 통해 암호화된 전화번호를 생성하는데, 실제 암호화에는 더욱 강력한 알고리즘이 필요하므로 암호화 목적으로 사용하는 것은 적절하지 않습니다.
def solution(phone_number): return ''.join(['*' * (len(phone_number) - 4)]) + phone_number[-4:]
2024-07-07 21:00:00 (5문제)
교점에 별 만들기
코드 제출 (5등) 문제 바로가기배수훈
2024-07-07 20:49:55주어진 직선들의 모든 교점을 찾아 별(*)로 표시하는 알고리즘입니다. itertools의 combinations 함수를 이용하여 모든 직선 쌍의 교점을 계산하고, 교점이 정수 좌표인 경우만 결과에 포함합니다. 최소 크기의 배열을 생성하여 교점 좌표에 '*'를 표시합니다. 이 코드는 직선 쌍의 교점을 계산하는 부분을 함수로 분리하여 코드 가독성을 높였습니다. 직선의 교점 계산 부분에서 기울기가 같은 경우 해가 없음을 명확히 처리하여 코드의 정확성을 높였습니다. 추가적으로, 리스트 컴프리헨션을 사용하여 좌표 변환과 배열 생성을 효율적으로 처리했습니다.
from itertools import combinations def calculation(eq1, eq2): x1, y1, c1 = eq1 # 직선1 x2, y2, c2 = eq2 # 직선2 # 기울기가 깉아 해가 없는 경우 if x1*y2 == y1*x2: return # 두 직선의 해 x = (y1*c2-c1*y2)/(x1*y2-y1*x2) y = (c1*x2-x1*c2)/(x1*y2-y1*x2) # 두 직선의 해 x, y가 모두 정수라면 반환 if x == int(x) and y == int(y): return [int(x), int(y)] def solution(lines): points = [] # 모든 선들의 교점 확인 for eq1, eq2 in combinations(lines, 2): point = calculation(eq1,eq2) if point: points.append(point) # 그림의 시작점과 마지막점 찾기 w1, w2 = min(points, key = lambda x : x[0])[0], max(points, key = lambda x : x[0])[0] + 1 h1, h2 = min(points, key = lambda x : x[1])[1], max(points, key = lambda x : x[1])[1] + 1 # 별을 포함하는 최소한의 크기 배열 생성 answer = [['.'] * (w2 - w1) for _ in range((h2 - h1))] # 그림의 시작점을 기준으로 교점 위치 "*" 변환 for x, y in points: answer[y-h1][x-w1] = '*' return [''.join(a) for a in answer][::-1]이현석
2024-07-07 20:43:20주어진 직선 집합의 교점을 찾는 알고리즘입니다. 이중 반복문을 사용하여 모든 직선 쌍의 교점을 계산하고, 교점이 정수 좌표이고 이미 추가되지 않았다면 배열에 추가합니다. 배열의 최소/최대 x, y 좌표를 찾아 교점을 표현할 2차원 배열을 생성하고, 각 교점에 '*'를 표시하여 결과를 반환합니다. 시간 복잡도를 줄이기 위해 교점 좌표를 찾는 과정에서 `set` 자료구조를 사용하여 중복 계산을 방지할 수 있습니다. `sort` 함수 대신 파이썬의 `min`, `max` 함수를 사용하여 최소/최대 x, y 좌표를 찾으면 코드를 더 간결하게 만들 수 있습니다.
def solution(line): arr = [] n = len(line) for i in range(n): a,b,e = line[i] for j in range(i+1,n): c,d,f = line[j] if a * d == b * c: continue x = (b * f - e * d)/(a * d - b * c) y = (e * c - a * f)/(a * d - b * c) if x == int(x) and y == int(y) and (x,y) not in arr: arr.append((int(x), int(y))) arr.sort(key = lambda x : x[0]) min_x, max_x = arr[0][0], arr[-1][0] arr.sort(key = lambda x : x[1]) min_y, max_y = arr[0][1], arr[-1][1] answer = [["."for j in range(max_x-min_x+1)] for i in range(max_y-min_y+1)] for x, y in arr : answer[y-min_y][x-min_x] = "*" return [''.join(row) for row in answer[::-1]]주병규
2024-07-07 17:05:32주어진 직선들의 교차점을 찾아, 교차점을 '*'로 표시하는 2차원 배열을 반환하는 코드입니다. 두 직선의 방정식을 이용하여 교차점을 계산하고, 교차점이 정수 좌표인 경우 해당 위치에 '*'를 표시합니다. 두 개의 for 루프를 사용하여 모든 직선 쌍에 대해 교차점을 계산하는 방식을 사용했으며, Brute Force 방식으로 모든 쌍을 검사합니다. xmin, xmax, ymin, ymax를 이용하여 교차점을 포함하는 최소 영역을 계산하여 공간 효율성을 높였습니다. 더욱 효율적인 알고리즘을 위해 직선을 기울기와 y절편으로 분류하여 교차 가능성을 빠르게 판단하는 방식을 고려할 수 있습니다.
def solution(line): crossing =[] xmin= None xmax= None ymin= None ymax= None for i in range(len(line)-1): for j in range(i+1, len(line)): a, b, e = line[i] c, d, f = line[j] if a*d - b*c != 0: x = (b*f - e*d) / (a*d - b*c) y = (e*c - a*f) / (a*d - b*c) if x == int(x) and y == int(y): x = int(x) y = int(y) xmin = min(x, xmin) if xmin!=None else x xmax = max(x, xmax) if xmax!=None else x ymin = min(y, ymin) if ymin!=None else y ymax = max(y, ymax) if ymax!=None else y crossing.append([x,y]) answer = [['.' for _ in range(xmax-xmin+1)] for _ in range(ymax-ymin+1)] for x, y in crossing: answer[ymax-y][x-xmin] = '*' return [''.join(row) for row in answer]이석민
2024-07-07 06:40:36두 직선의 교점을 구하는 `cross_point` 함수와 주어진 직선들의 교점을 표현하는 2차원 배열을 반환하는 `solution` 함수로 구성되어 있습니다. `solution` 함수는 주어진 직선들의 모든 조합에 대해 교점을 계산하고, 교점 좌표를 이용하여 2차원 배열에 표시합니다. `cross_point` 함수는 두 직선의 방정식을 입력받아 교점 좌표를 계산하는 공식을 사용합니다. `solution` 함수는 이 함수를 이용하여 모든 직선 조합에 대한 교점을 구하고, 교점 좌표를 이용하여 2차원 배열을 생성합니다. 이후 2차원 배열을 문자열 형태로 변환하여 반환합니다. `solution` 함수에서 `for` 루프를 사용하여 모든 직선 조합에 대한 교점을 계산하는 부분은 시간 복잡도가 O(n^2)로 비교적 높습니다. `cross_point` 함수의 계산 속도를 개선할 수 있으며, `for` 루프를 사용하는 대신 다른 알고리즘을 적용하여 시간 복잡도를 개선할 수 있습니다. 또한, `solution` 함수에서 2차원 배열을 생성하는 부분에 `numpy` 라이브러리를 활용하여 더 효율적으로 처리할 수 있습니다.
def cross_point(A, B, E, C, D, F): if A * D - B * C == 0: return False return ((B * F - E * D) / (A * D - B * C), (E * C - A * F) / (A * D - B * C)) def solution(line): result = [] filtered_result = [] for a in line: for b in line: if a == b: continue result.append(cross_point(*a, *b)) for r in result: if r is False: continue if int(r[0]) != r[0] or int(r[1]) != r[1]: continue filtered_result.append((int(r[0]), int(r[1]))) x_min = None x_max = None y_min = None y_max = None for result in filtered_result: if x_min is None or x_min > result[0]: x_min = result[0] if x_max is None or x_max < result[0]: x_max = result[0] if y_min is None or y_min > result[1]: y_min = result[1] if y_max is None or y_max < result[1]: y_max = result[1] bitmap = [['.' for _ in range(0, x_max - x_min + 1)] for _ in range(0, y_max - y_min + 1)] for result in filtered_result: x = result[0] - x_min y = result[1] - y_min bitmap[y][x] = '*' return list(map(lambda l: ''.join(l), reversed(bitmap)))행렬 테두리 회전
코드 제출 (6등) 문제 바로가기배수훈
2024-07-07 20:50:47주어진 행렬에서 주어진 쿼리에 따라 회전 연산을 수행하고 각 회전 시 최소값을 반환하는 알고리즘입니다. 쿼리 정보를 이용해 회전 영역의 숫자를 시계 방향으로 순회하며 저장 후, 한 칸씩 이동시키면서 최소값을 계산합니다. 회전 연산을 수행하는 핵심 로직은 숫자를 시계 방향으로 저장하고, 저장된 숫자를 다시 시계 방향으로 이동시키는 방식입니다. 최소값을 찾는 부분을 별도의 함수로 분리하여 코드 가독성을 높일 수 있습니다. 또한, 회전 연산 시 숫자를 저장하는 방식을 더 효율적으로 개선할 수 있습니다. 예를 들어, 회전 연산을 수행할 영역의 숫자를 미리 저장해 두고 필요할 때만 참조하는 방식을 통해 불필요한 저장 및 복사를 줄일 수 있습니다.
def solution(rows, columns, queries): answer = [] matrix = [[(i * columns) + (j + 1) for j in range(columns)] for i in range(rows)] for x1, y1, x2, y2 in queries: #다 읽어서 저장 nums = [] #좌상단부터 시계방향 for ny in range(y1 - 1, y2 - 1): nums.append(matrix[x1 - 1][ny]) for nx in range(x1 - 1, x2 - 1): nums.append(matrix[nx][y2 - 1]) for ny in range(y2 - 1, y1 - 1, -1): nums.append(matrix[x2 - 1][ny]) for nx in range(x2 - 1, x1 - 1, -1): nums.append(matrix[nx][y1 - 1]) #밀어서 넣기 matrix[x1 - 1][y1 - 1] = nums[len(nums) - 1] nums_idx = 0 min_num = nums[len(nums) - 1] for ny in range(y1, y2 - 1): matrix[x1 - 1][ny] = nums[nums_idx] nums_idx += 1 min_num = min_num if min_num < matrix[x1 - 1][ny] else matrix[x1 - 1][ny] for nx in range(x1 - 1, x2 - 1): matrix[nx][y2 - 1] = nums[nums_idx] nums_idx += 1 min_num = min_num if min_num < matrix[nx][y2 - 1] else matrix[nx][y2 - 1] for ny in range(y2 - 1, y1 - 1, -1): matrix[x2 - 1][ny] = nums[nums_idx] nums_idx += 1 min_num = min_num if min_num < matrix[x2 - 1][ny] else matrix[x2 - 1][ny] for nx in range(x2 - 1, x1 - 1, -1): matrix[nx][y1 - 1] = nums[nums_idx] nums_idx += 1 min_num = min_num if min_num < matrix[nx][y1 - 1] else matrix[nx][y1 - 1] answer.append(min_num) return answer이현석
2024-07-07 20:44:00주어진 행렬에서 회전 연산을 수행하고 각 회전마다 최소값을 찾는 알고리즘입니다. 회전 연산은 주어진 좌표 범위 내에서 시계 방향으로 값을 이동시키는 방식으로 구현되었습니다. 회전 연산 시 값 이동 과정에서 최소값을 기록하여 결과 배열에 저장합니다.
def solution(rows, columns, queries): grid = [[0 for _ in range(columns)] for _ in range(rows)] answer = [] n = 1 for i in range(rows): for j in range(columns): grid[i][j] = n n += 1 for qu in queries: start_row, start_col, end_row, end_col = [x-1 for x in qu] prev = grid[start_row][start_col] min_value = prev for col in range(start_col + 1, end_col + 1): grid[start_row][col], prev = prev, grid[start_row][col] min_value = min(min_value, prev) for row in range(start_row + 1, end_row + 1): grid[row][end_col], prev = prev, grid[row][end_col] min_value = min(min_value, prev) for col in range(end_col - 1, start_col - 1, -1): grid[end_row][col], prev = prev, grid[end_row][col] min_value = min(min_value, prev) for row in range(end_row - 1, start_row - 1, -1): grid[row][start_col], prev = prev, grid[row][start_col] min_value = min(min_value, prev) answer.append(min_value) return answer양민철
2024-07-07 18:59:57주어진 행렬에서 쿼리에 따라 회전 연산을 수행하며 각 회전마다 최솟값을 찾는 알고리즘입니다. 쿼리 정보를 이용하여 회전 영역을 지정하고, 해당 영역의 숫자를 시계 방향으로 회전시키면서 최솟값을 탐색합니다. 재귀 함수를 활용하여 회전 연산을 효율적으로 구현한 부분이 돋보입니다. 하지만, 회전 연산을 4번의 반복문으로 구현하여 코드 가독성이 떨어지고, 불필요한 반복이 존재합니다. 회전 연산을 좀 더 간결하고 효율적인 방식으로 구현하면 코드의 가독성과 성능을 향상시킬 수 있습니다.
def solution(rows, columns, queries): answer = [] arr = [] rowCnt = 0 for i in range(0, rows): arr.append([]) for j in range(0, columns): arr[i].append(i * columns + j + 1) for q in queries: q[0] -= 1 q[1] -= 1 q[2] -= 1 q[3] -= 1 # 행, 열 leftTop = arr[q[0]][q[1]] rightTop = arr[q[0]][q[3]] rightBottom = arr[q[2]][q[3]] leftBottom = arr[q[2]][q[1]] min = 10001 for i in range(q[1], q[3] + 1): min = arr[q[0]][i] if arr[q[0]][i] < min else min min = arr[q[2]][i] if arr[q[2]][i] < min else min for i in range(q[0], q[2] + 1): min = arr[i][q[3]] if arr[i][q[3]] < min else min min = arr[i][q[1]] if arr[i][q[1]] < min else min answer.append(min) if(q[3] != q[1]): for i in range(q[3], q[1] + 1, -1): arr[q[0]][i] = arr[q[0]][i - 1] arr[q[0]][q[1] + 1] = leftTop if(q[2] != q[0]): for i in range(q[2], q[0] + 1, -1): arr[i][q[3]] = arr[i - 1][q[3]] arr[q[0] + 1][q[3]] = rightTop if(q[1] != q[3]): for i in range(q[1], q[3] - 1): arr[q[2]][i] = arr[q[2]][i + 1] arr[q[2]][q[3] - 1] = rightBottom if(q[0] != q[2]): for i in range(q[0], q[2] - 1): arr[i][q[1]] = arr[i + 1][q[1]] arr[q[2] -1][q[1]] = leftBottom print(arr) return answer주병규
2024-07-07 17:14:55주어진 쿼리에 따라 2차원 배열의 경계를 회전시키는 알고리즘이며, 각 회전마다 최소값을 찾아 리스트에 저장합니다. 각 행과 열을 순회하며 배열의 값을 갱신하고, 최소값을 추적하는 반복적인 방식을 사용합니다. 회전 범위를 벗어나는 경우, 즉 배열의 크기를 넘어서는 경우 값을 다시 계산하여 갱신하는 부분이 코드의 효율성을 떨어뜨릴 수 있습니다. 배열의 크기를 넘어서는 경우 값을 미리 계산해 저장하거나, 회전 방향을 고려하여 범위를 제한하는 방식으로 개선하면 더 효율적인 코드 구현이 가능합니다.
def solution(rows, columns, queries): answer = [] grid={} for query in queries: rowMin, rowMax = min(query[0], query[2]), max(query[0], query[2]) columnMin, columnMax = min(query[1], query[3]), max(query[1], query[3]) minGridVal = None firstGridVal = None for i in range(rowMin, rowMax): val = grid.get((i+1,columnMin)) if i is rowMin: firstGridVal = grid.get((i,columnMin)) if val is None: val = ((i)*columns)+columnMin grid[(i,columnMin)] = val minGridVal = val if minGridVal is None else min(val, minGridVal) for i in range(columnMin, columnMax): val = grid.get((rowMax,i+1)) if val is None: val = ((rowMax-1)*columns)+i+1 grid[(rowMax,i)] = val minGridVal = min(val, minGridVal) for i in range(rowMax, rowMin, -1): val = grid.get((i-1,columnMax)) if val is None: val = ((i-2)*columns)+columnMax grid[(i,columnMax)] = val minGridVal = min(val, minGridVal) for i in range(columnMax, columnMin, -1): if i is columnMin+1: val = firstGridVal else: val = grid.get((rowMin,i-1)) if val is None: val = ((rowMin-1)*columns)+i-1 grid[(rowMin,i)] = val minGridVal = min(val, minGridVal) answer.append(minGridVal) return answer이석민
2024-07-07 16:51:18주어진 행렬에서 쿼리에 따라 지정된 영역을 회전시키고, 각 회전마다 가장 작은 값을 저장하는 알고리즘입니다. 쿼리에 따라 행렬의 특정 영역을 순차적으로 시계 방향으로 회전시키며, 회전하면서 발생하는 가장 작은 값을 리스트에 저장합니다. 회전 과정은 시계 방향으로 네 방향에 대해 반복하며, 각 방향에 대한 회전은 현재 값을 다음 위치에 저장하고, 다음 위치의 값을 현재 값으로 갱신하는 방식을 사용합니다. 이 과정에서 최소값을 추적하여 리스트에 저장합니다. 회전을 각 단계별로 계산하는 방식은 효율적이지만, 공간 복잡도를 줄이기 위해 회전 연산을 수행하는 동안 원본 행렬을 직접 수정하는 방법을 사용할 수 있습니다.
def solution(rows, columns, queries): matrix_original = [[y * columns + x + 1 for x in range(columns)] for y in range(rows)] matrix_result = [[y * columns + x + 1 for x in range(columns)] for y in range(rows)] lowest_list = [] for q in queries: y1, x1, y2, x2 = q y = y1 - 1 next_num = matrix_result[y][x1 - 1] lowest = next_num for x in range(x1 - 1, x2 - 1): if next_num < lowest: lowest = next_num store = matrix_result[y][x + 1] matrix_result[y][x + 1] = next_num next_num = store x = x2 - 1 for y in range(y1 - 1, y2 - 1): if next_num < lowest: lowest = next_num store = matrix_result[y + 1][x] matrix_result[y + 1][x] = next_num next_num = store y = y2 - 1 for x in range(x2 - 1, x1 - 1, -1): if next_num < lowest: lowest = next_num store = matrix_result[y][x - 1] matrix_result[y][x - 1] = next_num next_num = store x = x1 - 1 for y in range(y2 - 1, y1 - 1, -1): if next_num < lowest: lowest = next_num store = matrix_result[y - 1][x] matrix_result[y - 1][x] = next_num next_num = store lowest_list.append(lowest) return lowest_list삼각 달팽이
코드 제출 (6등) 문제 바로가기배수훈
2024-07-07 20:51:02주어진 정수 n을 입력받아 n x n 크기의 2차원 배열에 1부터 n^2까지의 숫자를 특정 패턴으로 채운 후 평탄화된 1차원 배열로 반환하는 알고리즘입니다. 이 코드는 초기값 설정 후, 좌하단에서 우상단까지 대각선 방향으로 숫자를 채우는 패턴을 구현하며, 반복문을 이용하여 각 방향별 숫자 채우기와 좌표 이동을 처리합니다. 코드의 가독성을 높이기 위해 변수명을 명확히 하고, 주석을 추가하여 코드의 동작 과정을 명확하게 표현할 수 있습니다. 또한, 함수의 기능을 명확하게 보여주는 이름을 사용하면 더욱 이해하기 쉬울 것입니다.
def solution(n): #크기에 맞게 리스트 생성 result = [[0 for j in range(i + 1)] for i in range(n)] #초기값 설정 num = 1 for i in range(n): result[i][0] = num num+=1 #초기값 설정 및 숫자 채우기 시작 go = n-1 state = 0 x, y = n-1, 0 while go > 0: for _ in range(go): #방향에 따라 좌표 이동 if state%3 == 0: y+=1 elif state%3 == 1: x-=1 y-=1 else: x+=1 result[x][y] = num num+=1 state+=1 go-=1 #평탄화 후 반환 return sum(result, [])양민철
2024-07-07 20:48:55이 코드는 주어진 정수 n에 대한 상향 삼각형 배열을 생성하는 알고리즘을 구현합니다. 코드는 시계 방향으로 숫자를 채우며, 각 층을 순회하는 동안 방향을 변경하여 모든 칸을 채웁니다. 재귀 함수보다는 반복문을 사용하여 더 간결하게 코드를 작성할 수 있습니다. 또한, 불필요한 변수를 줄이고, 각 변수의 역할을 명확하게 표현하여 가독성을 높일 수 있습니다. 마지막으로, 배열 생성 시, 크기를 미리 계산하여 메모리 사용량을 줄일 수 있습니다.
def solution(n): answer = [] arr = [] dr = [1, 0, -1] dc = [0, 1, -1] for r in range(n): arr.append([]) for c in range(r + 1): arr[r].append(0) cnt = 1 r = 0 c = 0 angle = 0 size = n * (n + 1) // 2 while(cnt <= size): arr[r][c] = cnt nr = r + dr[angle] nc = c + dc[angle] cnt += 1 if(0 <= nr < n and 0 <= nc <= nr and arr[nr][nc] == 0): r, c = nr, nc else: angle = (angle + 1)%3 r += dr[angle] c += dc[angle] for row in arr: for e in row: answer.append(e) return answer이현석
2024-07-07 20:44:30이 코드는 주어진 n에 대한 삼각형 형태의 배열을 생성하고, 1부터 시작하는 값을 대각선 방향으로 채워 넣는 알고리즘을 구현합니다. 1차원 배열 형태로 변환하여 반환하는 방식으로, 삼각형 배열에 값을 채우는 순서가 특징입니다. 코드 가독성을 높이기 위해 변수 명칭을 더 명확하게 사용하고, 3가지 조건문을 하나의 함수로 분리하여 코드를 더 간결하게 표현할 수 있습니다. 재귀 함수를 사용하면 삼각형 배열을 생성하는 과정을 더 효율적으로 표현할 수 있습니다.
def solution(n): triangle = [[0] * (i + 1) for i in range(n)] x,y = 0,-1 n = len(triangle) value = 1 for i in range(n): for _ in range(i, n): if i % 3 == 0: y += 1 elif i % 3 == 1: x += 1 else: x -= 1 y -= 1 triangle[y][x] = value value += 1 return sum(triangle,[])주병규
2024-07-07 17:16:15이 코드는 주어진 n에 대한 삼각형 형태의 배열을 생성하는 알고리즘을 구현합니다. 이 알고리즘은 n x n 사각형을 빙빙 돌며 삼각형 배열의 값을 채우는 방식으로 동작합니다. 코드는 명확하고 이해하기 쉽지만, 몇 가지 개선의 여지가 있습니다. `whereToGo` 변수를 사용하는 대신 `dx`와 `dy` 배열의 인덱스를 직접 사용하여 코드를 더 간결하게 만들 수 있습니다. `index` 변수를 계산하는 부분을 `i`와 `_`를 사용하여 더 직관적으로 계산할 수 있습니다. 마지막으로 `for` 루프의 조건을 더 명확하고 직관적으로 표현할 수 있습니다.
def solution(n): size = n * (n + 1) // 2 answer = [0] * size present_val = 1 x, y = 0, 0 whereToGo = 0 #0 is go down diagonal 1 is go right 2 is go up diagonal dx = [1, 0, -1] # x direction dy = [0, 1, -1] for i in range(1, n + 1): for _ in range(n - i + 1): index = x * (x + 1) // 2 + y answer[index] = present_val present_val += 1 if _ == n - i: whereToGo = (whereToGo + 1) % 3 x += dx[whereToGo] y += dy[whereToGo] return answer이석민
2024-07-07 16:54:36이 코드는 n x n 크기의 2차원 배열에 1부터 n^2까지의 숫자를 특정 패턴으로 채우는 알고리즘을 구현합니다. 좌측 상단부터 시작하여 아래, 오른쪽, 대각선 방향으로 순차적으로 숫자를 채우며, 해당 위치에 이미 숫자가 존재하면 다음 방향으로 이동합니다. 코드는 다소 복잡하고 가독성이 떨어집니다. `mode` 변수를 사용하여 이동 방향을 관리하는 방식은 직관적이지 않습니다. `if` 조건문을 간결하게 표현하고, 각 방향에 대한 이동 로직을 함수로 분리하여 코드의 가독성을 높일 수 있습니다.
def solution(n): def is_pos_ok(x, y, arr): if x >= len(arr) or x > y: return False if y >= len(arr): return False if arr[y][x] != None: return False return True arr = [[None for _ in range(n)] for _ in range(n)] arr[0][0] = 1 x, y = (0, 0) mode = "DOWN" idx = 1 while True: if mode == "DOWN": if is_pos_ok(x, y + 1, arr): y += 1 idx += 1 else: if is_pos_ok(x + 1, y, arr) is False: break mode = "RIGHT" elif mode == "RIGHT": if is_pos_ok(x + 1, y, arr): x += 1 idx += 1 else: if is_pos_ok(x - 1, y - 1, arr) is False: break mode = "SLASH" elif mode == "SLASH": if is_pos_ok(x - 1, y - 1, arr): x -= 1 y -= 1 idx += 1 else: if is_pos_ok(x, y + 1, arr) is False: break mode = "DOWN" arr[y][x] = idx result = [] for i in range(len(arr)): for j in range(i + 1): result.append(arr[i][j]) return result거리두기 확인하기
코드 제출 (5등) 문제 바로가기배수훈
2024-07-07 20:51:14이 코드는 5x5 크기의 맵에서 'P'로 표현된 사람들이 거리두기 규칙을 지키는지 확인하는 알고리즘입니다. 주어진 맵에서 각 사람 주변 1칸 이내에 다른 사람이 있거나 2칸 이내에 칸막이 'O'가 없이 사람이 있는 경우 거리두기 규칙을 위반한 것으로 판단합니다. 코드는 각 맵에 대해 모든 사람의 위치를 순회하며 주변 1칸, 2칸 거리 내에 다른 사람이 있는지, 2칸 거리 이내에 사람과 사람 사이에 칸막이 'O'가 있는지 확인합니다. 이를 통해 거리두기 규칙을 위반한 맵을 찾고 결과 리스트에 0을 반환합니다. 코드의 가독성을 위해 함수를 분리하여 코드를 더 명확하게 표현할 수 있습니다. 또한, 현재 직접적인 인덱스를 사용하는 방식 대신, 좌표를 나타내는 클래스 또는 튜플을 사용하면 더 효율적인 접근이 가능합니다. 마지막으로, 현재는 brute force 방식으로 모든 위치를 확인하고 있습니다. 맵의 특징을 이용하여 더 효율적인 방식으로 사람 위치를 찾고 거리두기 규칙을 검사하는 알고리즘을 고려할 수 있습니다.
def solution(places): def checkCondition(k, x, y): len1 = [[0, 1, 0, -1], [1, 0, -1, 0]] len2_1 = [[0, 2, 0, -2], [2, 0, -2, 0]] len2_2 = [[1, 1, -1, -1], [1, -1, -1, 1]] for i in range(4): nx = x + len1[0][i] ny = y + len1[1][i] if nx < 0 or nx >= 5 or ny < 0 or ny >= 5: continue if places[k][nx][ny] == "P": return False nx = x + len2_1[0][i] ny = y + len2_1[1][i] if nx < 0 or nx >= 5 or ny < 0 or ny >= 5: continue if places[k][nx][ny] == "P" and places[k][(x + nx) // 2][(y + ny) // 2] == "O": return False nx = x + len2_2[0][i] ny = y + len2_2[1][i] if nx < 0 or nx >= 5 or ny < 0 or ny >= 5: continue if places[k][nx][ny] == "P": if places[k][x + len1[0][i]][y + len1[1][i]] == "O" or places[k][x + len1[0][(i + 1) % 4]][y + len1[1][(i + 1) % 4]] == "O": return False return True result = [] for k in range(5): flag = True for i in range(5): if flag == False: break for j in range(5): if places[k][i][j] != "P": continue if checkCondition(k, i, j) == False: flag = False break result.append(1 if flag else 0) return result이현석
2024-07-07 20:48:42주어진 5x5 격자 공간에서 'P'로 표시된 사람들이 사회적 거리두기를 제대로 지키고 있는지 확인하는 함수입니다. 각 격자는 'P', 'O', 'X'로 표시되며, 'P'는 사람, 'O'는 빈 공간, 'X'는 벽을 나타냅니다. 각 'P'에 대해 상하좌우, 대각선, 두 칸 떨어진 위치까지 확인하여 거리두기 규칙을 위반하는 경우 False를 반환합니다. 각 격자의 모든 'P'를 순회하며 거리두기 규칙을 검사하는 방식으로, Brute Force 알고리즘을 사용하여 거리두기 규칙을 검사합니다. 함수의 가독성을 높이기 위해 거리두기 규칙 검사 로직을 별도의 `is_valid_place` 함수로 분리하여 코드를 더 명확하게 작성할 수 있습니다. 또한, 각 'P'에 대한 거리두기 규칙 검사를 조금 더 효율적으로 수행할 수 있는 방법을 고려하여 코드를 개선할 수 있습니다.
def solution(places): def is_valid_place(place): for i in range(5): for j in range(5): if place[i][j] == 'P': if j + 1 < 5 and place[i][j + 1] == 'P': return False if i + 1 < 5 and place[i + 1][j] == 'P': return False if i + 1 < 5 and j + 1 < 5 and place[i + 1][j + 1] == 'P': if place[i + 1][j] == 'O' or place[i][j + 1] == 'O': return False if i + 1 < 5 and j - 1 >= 0 and place[i + 1][j - 1] == 'P': if place[i + 1][j] == 'O' or place[i][j - 1] == 'O': return False if j + 2 < 5 and place[i][j + 2] == 'P' and place[i][j + 1] == 'O': return False if i + 2 < 5 and place[i + 2][j] == 'P' and place[i + 1][j] == 'O': return False return True answer = [] for place in places: if is_valid_place(place): answer.append(1) else: answer.append(0) return answer주병규
2024-07-07 17:16:36주어진 5x5 맵에서 'P'를 가진 사람들 간의 거리가 2칸 이하인지 확인하는 알고리즘입니다. 행, 열, 대각선 방향으로 'P'가 2칸 이내에 존재하는지 확인하며, 'O'는 빈 공간을 의미합니다. 각 행, 열, 대각선에 대해 'PP' 또는 'POP' 패턴이 존재하면 거리가 2칸 이하임을 의미하며, 해당 케이스를 제외한 나머지는 모두 거리가 2칸 이상입니다. 각 함수는 해당 방향에 대한 검사를 수행하고, 패턴이 발견되면 0을 반환하여 거리가 2칸 이하임을 나타냅니다. 모든 방향에서 패턴이 발견되지 않으면 1을 반환하며, 거리가 2칸 이상임을 의미합니다.
def solution(places): answer= [] for place in places: if checkCol(place) == 0: answer.append(0) continue if checkRow(place) == 0: answer.append(0) continue if checkDiagonal(place) == 0: answer.append(0) continue answer.append(1) return answer def checkCol(place): for i in range(5): if 'POP' in place[i] or 'PP' in place[i]: return 0 return 1 def checkRow(place): for i in range(5): row = '' for j in range(5): row += place[j][i] if 'POP' in row or 'PP' in row: return 0 return 1 def checkDiagonal(place): for i in range(4): for j in range(5): if place[i][j] == 'P': if j<4 and place[i+1][j+1] == 'P': if place[i+1][j] == 'O' or place[i][j+1] == 'O': return 0 if j>0: if place[i+1][j-1] == 'P': if place[i+1][j] == 'O' or place[i][j-1] == 'O': return 0 return 1이석민
2024-07-07 16:56:12주어진 5x5 공간에서 'P' 위치 간 거리가 2 이하인지, 'O'를 사이에 두고 'P'가 2개 있는지를 확인하는 알고리즘입니다. 이를 위해 각 'P' 위치를 기준으로 인접한 위치들을 탐색하여 조건에 맞는 경우 0을 반환합니다. 코드는 가독성을 높이기 위해 변수 이름을 명확하게 사용했지만, 불필요한 `can_xxx` 변수를 제거하고 조건문을 간소화하여 더욱 효율적으로 만들 수 있습니다. 또한, `getDistance` 함수는 핵심 알고리즘과 직접적인 관련이 없으므로 제거하고, `isOkay` 함수 내에서 직접 거리를 계산하는 것이 더 효율적입니다.
def getDistance(r1, c1, r2, c2): return abs(r1 - r2) + abs(c1 - c2) def isOkay(place): for x in range(5): for y in range(5): if place[y][x] != 'P': continue can_left = x > 0 can_right = x < 4 can_up = y > 0 can_down = y < 4 if x > 1 and place[y][x - 1] == 'O' and place[y][x - 2] == 'P': return 0 if x < 3 and place[y][x + 1] == 'O' and place[y][x + 2] == 'P': return 0 if y > 1 and place[y - 1][x] == 'O' and place[y - 2][x] == 'P': return 0 if y < 3 and place[y + 1][x] == 'O' and place[y + 2][x] == 'P': return 0 if can_left and place[y][x - 1] == 'P': return 0 if can_up and place[y - 1][x] == 'P': return 0 if can_left and can_up: if place[y][x - 1] == 'O' and place[y - 1][x - 1] == 'P': return 0 if place[y - 1][x] == 'O' and place[y - 1][x - 1] == 'P': return 0 if can_right and place[y][x + 1] == 'P': return 0 if can_right and can_up: if place[y][x + 1] == 'O' and place[y - 1][x + 1] == 'P': return 0 if place[y - 1][x] == 'O' and place[y - 1][x + 1] == 'P': return 0 if can_down and place[y + 1][x] == 'P': return 0 if can_left and can_down: if place[y][x - 1] == 'O' and place[y + 1][x - 1] == 'P': return 0 if place[y + 1][x] == 'O' and place[y + 1][x - 1] == 'P': return 0 if can_right and can_down: if place[y][x + 1] == 'O' and place[y + 1][x + 1] == 'P': return 0 if place[y + 1][x] == 'O' and place[y + 1][x + 1] == 'P': return 0 return 1 def solution(places): return list(map(isOkay, places))이석민
2024-07-07 16:55:07BFS 알고리즘을 이용하여 2명의 사람이 2칸 이내 거리에 있는지를 판별하는 코드입니다. 각 위치에서 BFS 탐색을 진행하여, 인접한 위치에 사람이 있는지 확인하고 2칸 이내 거리에 사람이 있으면 0을 반환합니다. 재귀 함수 `bfs`를 이용하여 BFS 탐색을 수행하며, 2칸 이내 거리가 될 때까지 탐색을 진행합니다. `bfs` 함수의 조건문을 명확하게 작성하여 코드 가독성을 높이고, 중복되는 코드 부분을 함수로 추출하여 코드 재사용성을 높일 수 있습니다.
def bfs_init(x, y, place): x_org, y_org = x, y queue = [] def bfs(x, y, distance): if x == x_org and y == y_org: return True if distance >= 2 or x < 0 or x > 4 or y < 0 or y > 4: return True if place[y][x] == 'P': return False if place[y][x] == 'X': return True if place[y][x] == 'O': queue.append((x - 1, y, distance + 1)) queue.append((x + 1, y, distance + 1)) queue.append((x, y - 1, distance + 1)) queue.append((x, y + 1, distance + 1)) if place[y][x] != 'P': return True queue.append((x - 1, y, 0)) queue.append((x + 1, y, 0)) queue.append((x, y - 1, 0)) queue.append((x, y + 1, 0)) while len(queue) > 0: cur = queue.pop(0) if bfs(*cur) is False: return 0 return 1 def place(place): for x in range(5): for y in range(5): if bfs_init(x, y, place) == 0: return 0 return 1 def solution(places): result = [] for p in places: result.append(place(p)) return result행렬의 곱셈
코드 제출 (6등) 문제 바로가기배수훈
2024-07-07 20:51:25이 코드는 두 행렬의 곱을 계산하는 알고리즘을 구현한 것입니다. 주어진 두 행렬을 입력받아 행렬 곱셈 연산을 수행하여 결과 행렬을 반환합니다. 이 알고리즘은 세 개의 중첩된 반복문을 사용하여 행렬 곱셈을 계산합니다. 각 행렬의 요소를 순회하여 두 행렬의 해당 요소의 곱을 더하여 결과 행렬의 요소를 계산합니다. 코드의 가독성을 높이기 위해 변수 이름을 더 명확하게 사용할 수 있습니다. 예를 들어, `arr1`, `arr2`를 `matrix1`, `matrix2`와 같이 변경하면 코드의 가독성이 향상됩니다. 또한, 코드의 효율성을 높이기 위해 행렬 곱셈 연산을 수행하는 데 더 효율적인 알고리즘을 사용할 수 있습니다. 예를 들어, Strassen 알고리즘이나 Coppersmith-Winograd 알고리즘을 사용하면 코드의 효율성을 향상시킬 수 있습니다.
def solution(arr1, arr2): n, m, p = len(arr1), len(arr2), len(arr2[0]) answer = [[0 for j in range(p)] for i in range(n)] for i in range(n): for j in range(p): for k in range(m): answer[i][j] += arr1[i][k] * arr2[k][j] return answer이현석
2024-07-07 20:44:45이 코드는 두 행렬의 곱을 계산하는 알고리즘을 구현한 것입니다. 두 개의 중첩 반복문을 사용하여 행렬의 각 원소를 순회하며, 세 번째 반복문을 통해 행렬 곱셈 연산을 수행합니다. 코드는 명확하고 간결하지만, 효율성을 높일 여지가 있습니다. 행렬 곱셈 연산을 벡터화하여 더 빠르게 계산할 수 있습니다. 또한, 불필요한 반복을 줄이기 위해 `numpy` 라이브러리의 `dot` 함수를 사용하는 것도 고려할 수 있습니다.
def solution(arr1, arr2): n, m = len(arr1), len(arr2[0]) answer = [[0 for _ in range(m)] for _ in range(n)] for i in range(n): for j in range(m): for k in range(len(arr2)): answer[i][j] += arr1[i][k] * arr2[k][j] return answer양민철
2024-07-07 19:14:08이 코드는 두 행렬의 곱을 계산하는 알고리즘으로, 행렬의 각 원소를 순회하며 곱셈 연산을 수행하여 결과 행렬을 반환합니다. 두 중첩 루프를 사용하여 행렬의 모든 원소를 순회하고, 각 원소의 곱셈 결과를 더하여 결과 행렬에 저장합니다. 코드는 매우 직관적이지만, 행렬의 곱셈은 행렬의 크기가 커질수록 연산량이 증가하여 시간 복잡도가 높아질 수 있습니다. 다차원 배열 대신 벡터형 자료 구조를 사용하여 메모리 사용량을 줄이고 연산 속도를 향상시킬 수 있습니다. 또한, 곱셈 연산 시 중첩 루프 대신 행렬 곱셈 알고리즘을 사용하여 연산 속도를 최적화할 수 있습니다.
def solution(arr1, arr2): answer = [] rowCnt = len(arr1) colCnt = len(arr2[0]) cnt = len(arr1[0]) for r in range(0, rowCnt): answer.append([]) for c in range(0, colCnt): sum = 0 for i in range(0, cnt): sum += arr1[r][i] * arr2[i][c] answer[r].append(sum) return answer주병규
2024-07-07 17:16:47이 코드는 두 행렬의 곱을 계산하는 알고리즘을 구현합니다. 두 중첩 반복문을 사용하여 각 행렬의 원소를 순회하며, 각 행렬 원소의 곱을 더하여 결과 행렬에 저장합니다. 코드의 가독성을 높이기 위해 리스트 컴프리헨션을 사용하여 더 간결하게 표현할 수 있습니다. 또한, 행렬 곱셈 연산을 위한 NumPy 라이브러리를 사용하면 더 효율적인 계산이 가능합니다. 마지막으로, 주석을 추가하여 코드의 동작을 명확히 설명하면 다른 개발자들이 코드를 더 쉽게 이해할 수 있습니다.
def solution(arr1, arr2): answer = [] for arr1Col in arr1: answerCol = [] for arr2Row in zip(*arr2): answerCol.append(sum([a*b for a,b in zip(arr1Col, arr2Row)])) answer.append(answerCol) return answer이석민
2024-07-07 16:56:28이 코드는 두 행렬(arr1, arr2)의 곱을 계산하는 알고리즘을 구현한 것입니다. 두 중첩 반복문을 사용하여 행렬 곱셈의 각 요소를 계산하며, 내부 반복문을 통해 두 행렬의 해당 요소를 곱한 값을 더하여 결과 행렬에 저장합니다. 코드는 명확하고 간결하지만, 성능 개선을 위해 numpy 라이브러리를 사용하여 행렬 연산을 수행할 수 있습니다. 또한, 행렬의 크기를 미리 계산하여 메모리 할당을 최적화할 수 있습니다. 마지막으로, 코드에 주석을 추가하여 각 부분의 기능을 명확하게 설명하면 가독성을 높일 수 있습니다.
def solution(arr1, arr2): multiply_len = len(arr2) result = [[0 for _ in range(len(arr2[0]))] for _ in range(len(arr1))] for y1 in range(len(arr1)): for x2 in range(len(arr2[0])): s = 0 for x1 in range(len(arr1[0])): s += arr1[y1][x1] * arr2[x1][x2] result[y1][x2] = s return result