# 재귀 함수로 구현한 이진 탐색
def binary_search(array, target, start, end):
if start > end:
return None
mid = (start + end) // 2
# 원하는 값 찾은 경우 인덱스 반환
if array[mid] == target:
return mid
# 원하는 값이 중간점의 값보다 작은 경우 왼쪽 부분(절반의 왼쪽 부분) 확인
elif array[mid] > target:
return binary_search(array, target, start, mid - 1)
# 원하는 값이 중간점의 값보다 큰 경우 오른쪽 부분(절반의 오른쪽 부분) 확인
else:
return binary_search(array, target, mid + 1, end)
# 반복문으로 구현한 이진 탐색
def binary_search(array, target, start, end):
while start <= end:
mid = (start + end) // 2
# 원하는 값 찾은 경우 인덱스 반환
if array[mid] == target:
return mid
# 원하는 값이 중간점의 값보다 작은 경우 왼쪽 부분(절반의 왼쪽 부분) 확인
elif array[mid] > target:
end = mid - 1
# 원하는 값이 중간점의 값보다 큰 경우 오른쪽 부분(절반의 오른쪽 부분) 확인
else:
start = mid + 1
return None
각 대기실별로 거리두기를 지키고 있으면 1을, 한 명이라도 지키지 않고 있으면 0을 배열에 담아.
예: [1, 0, 1, 1, 1]
내 코드
못생긴 코드ㅡ... 코드가 왜 이렇게 길지? ^__^
ㅎㅎ
모범코드 보면서 공부해야겠다..
from collections import deque
def solution(places):
answer = [1 for _ in range(5)]
next_i, next_j = [-1, 0, 0, 1], [0, -1, 1, 0]
doub_i, doub_j = [-2, 0, 0, 2], [0, -2, 2, 0]
cross_i, cross_j = [-1, -1, 1, 1], [-1, 1, -1, 1]
cnt = -1
for place in places:
cnt += 1
place = list(map(list, place))
p_lst = deque() #각 대기실에서 P가 있는 좌표 리스트
for i, row in enumerate(place):
for j, col in enumerate(row):
if place[i][j] == 'P':
p_lst.append((i,j))
loopbreak = False
while p_lst and (loopbreak == False):
(i,j) = p_lst.popleft() #현재 중심이 되는 좌표 (i,j)
for k in range(4): #위반 케이스 1
ci = i + next_i[k]
cj = j + next_j[k]
if ci <0 or ci>4 or cj<0 or cj>4:
continue
if place[ci][cj] == 'P':
answer[cnt] = 0
loopbreak = True
break
if loopbreak == True: break
for k in range(4): #위반 케이스 2
ci = i + doub_i[k]
cj = j + doub_j[k]
if ci <0 or ci>4 or cj<0 or cj>4:
continue
if place[ci][cj] == 'P':
if place[i + next_i[k]][j + next_j[k]] == "O":
answer[cnt] = 0
loopbreak = True
break
if loopbreak == True: break
for k in range(4): #위반 케이스 3
ci = i + cross_i[k]
cj = j + cross_j[k]
if ci <0 or ci>4 or cj<0 or cj>4:
continue
if place[ci][cj] == 'P':
if k == 0:
if place[i-1][j]=='X' and place[i][j-1]=='X': continue
elif k == 1:
if place[i-1][j]=='X' and place[i][j+1]=='X': continue
elif k == 2:
if place[i][j-1]=='X' and place[i+1][j]=='X': continue
elif k == 3:
if place[i][j+1]=='X' and place[i+1][j]=='X': continue
answer[cnt] = 0
loopbreak = True
break
return(answer)
테케 3, 8, 31번 오답의 반례 : 'POP'가 포함된 경우 '0'을 반환해야 한다
answer의 default 원소로 1 채워놓고, 위반하는 경우=> 0으로 바꿈 & 다음 place로 바로 이동(기존 반복문 break)
visited 리스트 이용해서 좀 더 효율적으로 구현했었는데 => 딱히 효과가 없다 ^__^ BFS 개념에 집착하지 말자,,
상하좌우 살피는 예쁜 코드 [-1,0,0,1] 등 사용해서 짰는데 (왜 전체 코드가 이리 장황할까?)
그래도 아래 코드는 유용하게 사용하쟈~
dx = [1,-1,0,0]
dy = [0,0,1,-1]
for k in range(4):
cx = i + dx[k]
cy = j + dy[k]
if cx < 0 or cx >= N or cy < 0 or cy >= M:
continue
if arr[cx][cy] != 1:
graph[i*M+j].append(cx*M+cy)
from collections import deque
def solution(tickets):
# 주어진 항공권은 모두 사용
# 주어진 공항수 꽤 많음
tickets.sort()
dic = {}
for tic in tickets:
if tuple(tic) not in dic.keys():
dic[tuple(tic)] = 1
else:
dic[tuple(tic)] +=1
for root in [x for x in tickets if x[0]=="ICN"]:
deq = deque()
deq.append([root]) #dic, visited list
while deq:
visited = deq.popleft() #현재 다루는 dic과 그것이 사용된 횟수
for tic in tickets:
if (visited[-1][1] == tic[0]) and (visited.count(tic) < dic[tuple(tic)]):
if len(visited)+1 == len(tickets):
mod = [x[1] for x in visited+[tic]]
mod.insert(0, visited[0][0])
# print(mod)
return mod
else:
deq.append(visited+[tic])
return #방문하는 공항 경로 #알파벳 순서가 앞서는 경로
알파벳 정렬은, 처음부터 input 리스트 'tickets'을 sort시키고 시작하면 해결된다.
DFS의 특이한 버전이었다.
- input에 동일한 티켓이 여러 장 포함될 가능성이 있다. 따라서 다음 탐색 노드를 추가할 때 visited 존재 여부로 결정해서는 안 된다. (이미 방문하여 visited에 존재하지만, 탐색 가능한 것이 여전히 남아 있을 수 있다) ✂︎ 미리 counter dictionary를 생성하고, visited가 포함하는 개수와 비교해야 한다: visited.count(tic) < dic[tuple(tic)]
- 지금까지 경로 데이터를 모두 가지고 있어야 한다 ✂︎ deque의 원소 자체를 visited 리스트로 저장 ✂︎ deep 하게 for문 돌 때, 기존 visited에 현재 탐색 원소를 append하여 기존 visited의 몸뚱아리를 키우는 것이 아니다. 별도의 리스트(visited + [tic])로 만들어 그것을 deque에 append한다. (효율성 괜찮나..? 싶었으나 더 간단한 방법이 떠오르지 않음)
리스트를 원소로 가지는 리스트의 처리는 Unhashable error에 주의해야 한다. 나는 dictionary 생성 및 count를 위해 각 리스트 원소를 tuple로 변환하였다. https://daewonyoon.tistory.com/363
class Node:
def __init__(self,data=None,prev=None,next=None):
self.prev= prev
self.data= data
self.next= next
class DoubleLinkedList:
def __init__(self,data=None):
# for easy calculate at end set two dummy head_dummy and tail_dummy
self.head = Node()
self.tail = Node()
# link two dummy
self.head.next = self.tail
self.tail.prev = self.head
self.current_ptr = self.head
self.delete_array = []
def init_insert(self,data):
new_node = Node(data)
# get tail-1 node
node = self.tail.prev
node.next = new_node
new_node.prev = node
new_node.next = self.tail
self.tail.prev = new_node
def set_current_ptr(self, num):
for i in range(num+1):
self.current_ptr = self.current_ptr.next
def c_instruction(self):
self.before_ptr = self.current_ptr
self.current_ptr = self.current_ptr.next
if(self.current_ptr == self.tail):
self.current_ptr = self.current_ptr.prev
self.current_ptr = self.current_ptr.prev
# delete!!
self.delete_array.append(self.before_ptr)
# modify linked list
self.before_ptr.prev.next = self.before_ptr.next
self.before_ptr.next.prev = self.before_ptr.prev
def u_instruction(self, num):
for i in range(num):
self.current_ptr = self.current_ptr.prev
def d_instruction(self, num):
for i in range(num):
self.current_ptr = self.current_ptr.next
def z_instruction(self):
node_to_z = self.delete_array.pop(-1)
node_to_z.prev.next = node_to_z
node_to_z.next.prev = node_to_z
def return_del_array(self):
to_return = []
for i in range(len(self.delete_array)):
to_return.append(self.delete_array[i].data)
return to_return
def solution(n,k,cmd):
answer_string = ["O"]*n
my_list = DoubleLinkedList()
for i in list(range(n)):
my_list.init_insert(i)
my_list.set_current_ptr(k)
for instruction in cmd:
if instruction[0] == "U":
instruction_list = instruction.split()
move_cnt = int(instruction_list[1])
my_list.u_instruction(move_cnt)
elif instruction[0] == "D":
instruction_list = instruction.split()
move_cnt = int(instruction_list[1])
my_list.d_instruction(move_cnt)
elif instruction[0] == "C":
my_list.c_instruction()
elif instruction[0] == "Z":
my_list.z_instruction()
deleted_element = my_list.return_del_array()
for element in deleted_element:
answer_string[element] = "X"
return ''.join(answer_string)
효율성 통과하지 못하는 코드
class Node:
def __init__(self, x):
self.item = x
self.before = None
self.next = None
class LinkedList:
def __init__(self):
dummy = Node(-1)
self.bins = [dummy]
self.tail = dummy
self.current = None
def append(self, x):
new = Node(x)
self.tail.next = new
new.before = self.tail
self.tail = new
return new
def up(self, x):
for _ in range(x):
self.current = self.current.before
def down(self, x):
for _ in range(x):
self.current = self.current.next
def delete(self):
self.bins.append(self.current)
if self.current.next == None:
self.current = self.current.before
self.current.next = None
else:
self.current.before.next = self.current.next
self.current.next.before = self.current.before
self.current = self.current.next
def restore(self):
if self.bins:
res_data = self.bins.pop()
res_data.before.next = res_data
if res_data.next != None:
res_data.next.before = res_data
def return_del(self):
del_lst = [x.item for x in self.bins]
return del_lst
def solution(n, k, cmd):
answer = [i for i in range(n)] #비효율의 원인
link_lst = LinkedList()
for i in answer:
if i == k:
link_lst.current = link_lst.append(i)
else:
link_lst.append(i)
for x in cmd:
if x[0] == "U":
link_lst.up(int(x[2:]))
elif x[0] == "D":
link_lst.down(int(x[2:]))
elif x[0] == "C":
link_lst.delete()
else:
link_lst.restore()
del_lst = link_lst.return_del()
final = ["O" if x not in del_lst else "X" for x in answer] #비효율의 가장 큰 원인: O(N)
final = ''.join(final)
# print(final)
return final
양방향 LinkedList까지 로직 참 좋았다 !
input의 크기가 무지막지하게 크다는 사실을 기억해야 한다
input 처리에 대한 단순한 코드때문에 => 눈덩이처럼 커진 비효율이,,,!!!!!!!
input의 value는 사실 중요하지 않다. 서로가 '중복되지 않음'만 확인되면 된다. 나는 처음에 각 Node를 생성하고 해당 노드의 value(Node.item)가 저장된 answer 리스트를 따로 생성했었다. 그러나, integer로 채워진 answer 리스트를 임의로 생성할 필요가 없었다. 생성하면 무조건 비효율 문제가 발생하게 된다 => answer 생성: O(N) + final 생성: O(N) = 2*O(N) 이미 각 Node들의 item 값은 서로 다르기때문에 '중복되지 않음'의 속성이 반영되어 있다.
초반에 append한 각 Node의 value 값과 idx 값이 동일함을 이용하여 answer 리스트의 원소로 미리 "O"를 넣어둔다
마지막에 del_lst의 item값을 answer의 idx값으로 이용하여 answer 리스트에서 해당 idx의 값을 "X"로 바꾸어준다 => final 리스트 따로 생성하지 않음! answer 리스트 내에서 변형. => O(N) + O(len(del_lst)) => 이때 N보다 del_lst가 작으므로, N이 무지막지한 크기인 본 문제에서 효율성을 크게 높일 수 있다..!!
최종 효율성 통과 코드
class Node:
def __init__(self, x):
self.item = x
self.before = None
self.next = None
class LinkedList:
def __init__(self):
dummy = Node(-1)
self.bins = [dummy]
self.tail = dummy
self.current = None
def append(self, x):
new = Node(x)
self.tail.next = new
new.before = self.tail
self.tail = new
return new
def up(self, x):
for _ in range(x):
self.current = self.current.before
def down(self, x):
for _ in range(x):
self.current = self.current.next
def delete(self):
self.bins.append(self.current)
if self.current.next == None:
self.current = self.current.before
self.current.next = None
else:
self.current.before.next = self.current.next
self.current.next.before = self.current.before
self.current = self.current.next
def restore(self):
if self.bins:
res_data = self.bins.pop()
res_data.before.next = res_data
if res_data.next != None:
res_data.next.before = res_data
def return_del(self):
del_lst = [x.item for x in self.bins]
return del_lst
def solution(n, k, cmd):
answer = ["O" for _ in range(n)] #효율 개선
link_lst = LinkedList()
for i in range(len(answer)):
if i == k:
link_lst.current = link_lst.append(i)
else:
link_lst.append(i)
for x in cmd:
if x[0] == "U":
link_lst.up(int(x[2:]))
elif x[0] == "D":
link_lst.down(int(x[2:]))
elif x[0] == "C":
link_lst.delete()
else:
link_lst.restore()
del_lst = link_lst.return_del()
for x in del_lst[1:]: #주의
answer[x] = "X" #효율 개선
answer = ''.join(answer)
print(answer)
return answer
N개의 수로 이루어진 수열 A[1], A[2], …, A[N]이 있다. 이 수열에 대해서 버블 소트를 수행할 때, Swap이 총 몇 번 발생하는지 알아내는 프로그램을 작성하시오.
(버블 소트는 서로 인접해 있는 두 수를 바꿔가며 정렬하는 방법이다. 예를 들어 수열이 3 2 1 이었다고 하자. 이 경우에는 인접해 있는 3, 2가 바뀌어야 하므로 2 3 1 이 된다. 다음으로는 3, 1이 바뀌어야 하므로 2 1 3 이 된다. 다음에는 2, 1이 바뀌어야 하므로 1 2 3 이 된다. 그러면 더 이상 바꿔야 할 경우가 없으므로 정렬이 완료된다.)
Tip & 풀이 핵심
1. '시간제한 1초' & '첫째 줄에 N(1 ≤ N ≤ 500,000)이 주어진다.'
(시간제한이 1초이면) input 길이가 10,000이 넘어가면 O(N**2)의 알고리즘으로 절대 풀 수 없음!!! => Bubble sort, Insertion sort, Selection sort: O(N**2) => Merge sort: O(N* logN) / Quick sort => Counting sort
2. Merge sort에서 swap하는 과정이 있더라!
=> "어떻게 하면 Merge sort 로직에 result 구하는 코드 구현?"
모범 코드
모범 코드 보면서 효율적이고 정확하게 코드 짜는 방법을 많이 배웠다.
import sys
input = sys.stdin.readline
result = 0 #최종 결과값
N = int(input())
A = list(map(int, input().split()))
A.insert(0,0) # 0 index에 0을 추가 # index 처리 쉽게 하기 위함
tmp = [0] *(N+1) # A배열의 크기를 맞춤 # A를 바로 처리하기 부담스러우므로 복제
def merge_sort(s, e):
global result
if e-s < 1: return
else:
m = (e+s) // 2
merge_sort(s, m)
merge_sort(m+1, e)
for i in range(s, e+1):
tmp[i] = A[i]
# two pointers
k = s #현재 바꾸어야 하는 A의 index
index1 = s
index2 = m+1
while index1 <= m and index2 <=e:
if tmp[index1] > tmp[index2]:
A[k] = tmp[index2] #swap
result += (index2-k)
k += 1
index2 += 1
# A[index2] = tmp[index1]
else:
A[k] = tmp[index1]
k += 1
index1 += 1
while index1 <= m:
A[k] = tmp[index1]
k += 1
index1 += 1
while index2 <= e:
A[k] = tmp[index2]
k += 1
index2 += 1
merge_sort(1, N) # 1번째 idx부터 N번째 idx까지 merge_sort 진행
print(result)
➡️ Becauserange(4)might be something empty (if you overwrite the built-inrange), in which case the loop body will never run andawill not get assigned. Which is a problem when it's supposed to get returned.
Maybe you can tell your IDE to ignore this and not show the warning. Or assign some meaningful default to 'a' before the loop.
➡️ Meaning of 'Unbound'
A symbol that has not been given a value by assignment or in a function call is said to be “unbound.”
An unbound variable is one that is not within the scope of a quantifier.
➡️ 해결: while문 선언 전 'mid'에 대한 default value를 할당해주었다.
줄을 서는 순서에 따라 돈을 인출하는 데 각 사람이 인출하는 데 필요한 시간의 합이 달라짐
Input
줄을 서 있는 사람 수 N (ex. 5)
각 사람이 돈을 인출하는 데 걸리는 시간 P (ex. 3 1 4 3 2)
Output
각 사람이 돈을 인출하는 데 필요한 시간의 합의 최솟값 (ex. 32)
문제 풀이
Pseudo Code
: for문으로 key를 하나씩 지정
각 key의 위치를 while문 통해 탐색
그렇게 필요한 위치를 하나씩 탐색.
비록 시간 복잡도는 n^2
(3, 1, 4, 3, 2)
1 2 3 4 5 => (3, 1, 4, 3, 2) => 39분 (작은 값을 마냥 앞에 배치한다고 개선되지 않음)
2 5 1 4 3 => (1, 2, 3, 3, 4) => 32분
결론: value의오름차순소팅! (삽입정렬로해결)
import sys
for t in range(2):
if t == 0:
n = int(sys.stdin.readline())
else:
inputs = list(map(int, sys.stdin.readline().split()))
for i in range(1, n):
key = inputs[i]
j = i-1
while j>=0 and key < inputs[j]:
inputs[j+1] = inputs[j] //swap
inputs[j] = key //swap
j -=1 //최종 목적지까지 계속 탐색
answer = [0]
for x in inputs:
answer.append(x+answer[-1])
print(sum(answer))