https://github.com/sdoram/Algorithm
https://github.com/sdoram/algorithm_solving_process
1. 팀원과의 코드 리뷰 - 전국 대회 선발 고사
문제점
https://school.programmers.co.kr/learn/courses/30/lessons/181851
# rank는 등수, attendance는 참석 여부
# 1등부터 차례대로 참석가능한 3명 구하기
시도해 본 것들
최초의 방법
def solution(rank, attendance):
# rank는 등수, attendance는 참석 여부
# 1등부터 차례대로 참석가능한 3명 구하기
a_list = []
# 오름차순으로 1등부터 확인
for r in sorted(rank):
# print(r, rank.index(r)) # 등수와 그 등수가 위치한 인덱스 확인
# attendance의 [r의index와 동일한 index]가 True라면
if attendance[rank.index(r)]:
# index 번호를 추가
a_list.append(rank.index(r))
# True인 index만 추가했기 때문에 0번부터 2번까지 뽑아서 사용
return a_list[0]*10000+a_list[1]*100+a_list[2]
문제 지문은 어려워 보였지만, 최근에 사용빈도가 늘어난 index()를 사용해서 어렵지 않게 풀 수 있었다.
리팩토링
def solution(rank, attendance):
a_list = [rank.index(r) for r in sorted(rank) if attendance[rank.index(r)]]
return a_list[0]*10000+a_list[1]*100+a_list[2]
for문이 존재했기에 for문이 List Comprehension 안으로 들어가면 시간복잡도의 개선도 기대할 수 있어서 리팩터링 했다.
팀원과의 코드 리뷰
팀원의 dict 사용 코드
def solution(rank, attendance):
answer = 0
obj={}
for i in range(len(rank)):
if attendance[i]==True:
# dict에 key로 등수, value로 index 넣기
obj[rank[i]]=i
# key값을 기준으로 오름차순 정렬
player=dict(sorted(obj.items()))
print(player)
# key값을 기준으로 오름차순 정렬 후 key만 뽑아내기
key=list(sorted(obj.keys()))
return player[key[0]]*10000+player[key[1]]*100+player[key[2]]
등수와 index를 dict에 담아서 풀어낸 코드이다.
팀원의 인상 깊은 range 사용
def solution(rank, attendance):
answer = []
# rank가 1등부터 시작하므로 range == rank의 원소
for i in range(1, len(rank)+1):
num = rank.index(i)
if attendance[num] is True:
answer.append(num)
# 참석하는 3등까지 구하면 return
if len(answer) == 3:
return answer[0]*10000 + answer[1]*100 + answer[2]
이 문제에서 주어지는 rank가 무조건 1등부터 시작하며 끝은 len(rank)와 같다는 성질을 잘 이용한 코드였다.
코드 리팩토링
def solution(rank, attendance):
obj={}
for i in range(len(rank)):
if attendance[i]:
# dict에 key로 등수, value로 index 넣기
obj[rank[i]]=i
# key값을 기준으로 오름차순 정렬
obj=sorted(obj.items())
return obj[0][1]*10000+obj[1][1]*100+obj[2][1]
obj을 list로 sorted하고 거기서 원소 뽑아내서 사용하기
해결 방법
def solution(rank, attendance):
# rank는 등수, attendance는 참석 여부
# 1등부터 차례대로 참석가능한 3명 구하기
a_list = []
# 오름차순으로 1등부터 확인
for r in sorted(rank):
print(r, rank.index(r))
# attendance의 [r의index와 동일한 index]가 True라면
if attendance[rank.index(r)]:
# index 번호를 추가
a_list.append(rank.index(r))
if len(a_list) == 3:
# True인 index만 추가했기 때문에 0번부터 2번까지 뽑아서 사용
return a_list[0]*10000+a_list[1]*100+a_list[2]
팀원의 코드를 보고 3등까지 구하면 더 이상 코드가 실행되지 않아도 되기 때문에 return 하는 코드 추가
List Comprehension에서 추가할 수 있으면 좋겠지만, list를 만드는 도중에 조건이 충족되면 멈출 수 있는지 모르겠다.
알게 된 점
모든 상황에 통하는 방법이 아니라 이 문제에서만 사용가능한 range(1, len(rank)+1) 이 코드가 인상 깊었다. 문제를 읽고 핵심이 될 코드를 정하는 과정도 좋지만, 이렇게 이 문제에서만 사용가능한 방법이 존재하는지 찾는 것도 공부가 될 것 같다.
1. 프로그래머스 입문 - 안전지대
문제점
시도해 본 것들
폭탄이 위치한 곳 리스트로 만들기
def solution(board):
# board를 깊은 복사로 가져오기
new_board = board[::]
boom_list = []
# 이차원 배열에서 리스트 가져오기
for i1, b1 in enumerate(board):
# 리스트에서 원소 가져오기
for i2, b2 in enumerate(b1):
# 폭탄인 경우 추가하기
if b2 == 1:
boom_list.append([i1, i2])
for boom in boom_list:
print(boom)
return new_board
폭탄이 위치한 곳을 리스트로 만들었지만, 활용할 방법이 생각나지 않음
조건문으로 안전지대 제거하기
def solution(board):
new_board = board[::]
boom_list = []
for i1, b1 in enumerate(board):
for i2, b2 in enumerate(b1):
if b2 == 1:
# 이차원 배열의 최솟값과 최댓값을 넘는지 체크
if i1 != 0 and len(board)-1 != i1:
new_board[i1-1][i2], new_board[i1+1][i2] = 1, 1
if i2 != 0 and len(board)-1 != i2:
new_board[i1][i2-1], new_board[i1][i2+1] = 1, 1
print(id(board[i1][i2+1]), i1) # id 같음 확인
return new_board
print(solution([[0, 0, 0, 0, 0], [0, 0, 0, 0, 0], [
0, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 0]]))
# id :140721320817448, list index : 3
# id :140721320817448 list index : 4
값이 바뀌는 게 이상해서 확인해본 결과 [::]이 깊은 복사로 다른 id값을 가진다고 알고 있었지만, 확인한 결과는 동일한 id를 지니고 있었다. 심지어
if i1 != 0 and len(board)-1 != i1:
board[i1-1][i2], board[i1+1][i2] = 1, 1
if i2 != 0 and len(board)-1 != i2:
board[i1][i2-1], board[i1][i2+1] = 1, 1
print(id(board[i1][i2+1]), i1)
처음에는 이렇게 new_board가 아니라 board를 조작하고 있었는데 new_board까지 조작이 되고 있었다. 이 의미는 new_board와 board는 다른 id를 바라보고 있어도 new_board [0]과 board [0]은 같은 id를 바라보고 있다는 뜻이 된다.
4중 for문 사용하기
def solution(board):
new_board = board[::]
for i1, b1 in enumerate(board):
for i2, b2 in enumerate(b1):
# 폭탄일 때
if b2 == 1:
# 상하 index를 range로 표현
for n1 in range(i1-1, i1+2):
# 좌우 index를 range로 표현
for n2 in range(i2-1, i2+2):
print(n1, n2) # 위험 지대 확인
return new_board
2중 for문을 마지노선으로 생각하고 이리저리 생각해봤지만 답이 나오지 않아서 for문을 마음껏 늘려서 사용했다.
한 번에 많은 경우를 처리하지 말고 연산을 추가하더라도 모든 경우의 수를 확인했다.
얕은 복사 해결하기
new_board = [[0]*len(board) for _ in board]
모든 경우의 수를 확인하기로 마음을 먹었기 때문에 크기만 같은 이차원 배열을 만들어서 id가 같은 경우를 해결했다.
이차원 배열밖으로 나가는 경우 방지 하기
if len(board) > n2 >= 0:
해결 방법
def solution(board):
# 얕은 복사를 방지하기 위해서 for문을 사용한 이차원 배열 만들기
new_board = [[0]*len(board) for _ in board]
# index의 위치를 알기 위한 enumerate사용
for i1, b1 in enumerate(board):
for i2, b2 in enumerate(b1):
# 폭탄이 있으면
if b2 == 1:
# 상하 index를 range로 표현
for n1 in range(i1-1, i1+2):
# 이차원 배열 범위 밖으로 나가는 경우 방지
if len(board) > n1 >= 0:
# 좌우 index를 range로 표현
for n2 in range(i2-1, i2+2):
# 이차원 배열 범위 밖으로 나가는 경우 방지
if len(board) > n2 >= 0:
# print(n1, n2) # 위험 지대 확인
new_board[n1][n2] = 1
# board가 n*n의 이차원 배열이므로 len() **2으로 총 원소의 개수 구하기
# [sum(n) for n in new_board]으로 폭탄이 1이므로 각 리스트에서 폭탄 개수 구하기
# sum()으로 리스트의 결과값 더하기
return len(board)**2-sum([sum(n) for n in new_board])
sum()을 한 번에 두 번 써보는 특이한 방식으로 정답을 구했다.
알게 된 점
문제를 해결하고 깊은 복사에 대해서 찾아본 결과 이차원 배열 같은 mutable안에 mutable이 존재하면 id(board)와 id(new_board)는 다르지만 new_board [0]과 board [0]는 같은 주소를 사용하는 객체가 사용된다.
이차원 배열을 [::]으로 복사하면 결국 VSCode에서 Live Share를 사용하는 것처럼 다른 id지만 그 안을 조작하면 모두가 바뀌는 상태가 된다.
변수 선언을 잘해서 이상한 곳에서 값을 넣지 않도록 하자.
'개발일지 > TIL' 카테고리의 다른 글
TIL 23-05-05 코딩테스트 입문 완료 (0) | 2023.05.05 |
---|---|
TIL 23-05-04 팀원과의 코드 리뷰 - ad 제거하기 (1) | 2023.05.04 |
TIL 23-05-02 페어프로그래밍 - OX 퀴즈 (1) | 2023.05.02 |
TIL 23-05-01 팀원과의 코드리뷰 - 한 번만 등장한 문자 (0) | 2023.05.01 |
TIL 23-04-30 백준 알고리즘 - 수들의 합 (0) | 2023.04.30 |