input = [3,5,6,1,2,4]
def find_max_num(array):
for num in array:
for compare_num in array:
if num < compare_num:
break
else:
return num
result = find_max_num(input)
print(result)
input = [3, 5, 6, 1, 2, 4]
def find_max_num(array):
max_num = array[0] # 임의숫자 넣으면서 갈 것이기 때문에 초기값 설정해주는 것
for num in array:
if num > max_num:
max_num = num
return max_num
result = find_max_num(input)
print(result)
# str.isalpha()
print("a".isalpha()) # True
print("1".isalpha()) # False
s = "abcdefg"
print(s[0].isalpha()) # True
alphabet_occurrence_array = [0] * 26
# ord() 이용해서 아스키 값 받기
print(ord('a')) # 97
print(ord('a') - ord('a')) # 97-97 -> 0
print(ord('b') - ord('a')) # 98-97 -> 1
def find_alphabet_occurrence_array(string):
alphabet_occurrence_array = [0] * 26
for char in string:
if not char.isalpha():
continue # 코드실행 건너뛰기
arr_index = ord(char) - ord("a") ## 97-97
alphabet_occurrence_array[arr_index] += 1
return alphabet_occurrence_array
print(find_alphabet_occurrence_array("hello my name is sparta"))
# [3, 0, 0, 0, 2, 0, 0, 1, 1, 0, 0, 2, 2, 1, 1, 1, 0, 1, 2, 1, 0, 0, 0, 0, 1, 0]
input = "hello my name is sparta"
def find_max_occurred_alphabet(string):
alphabet_array = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",
"t", "u", "v", "x", "y", "z"] # 각 문자열 비교를 위해
max_occurrence = 0 # 최고로 많이 나온 횟수를 저장하는 변수
max_alphabet = alphabet_array[0] # 최고로 많이 나온 알파벳 저장하는 변수
for alphabet in alphabet_array:
occurrence = 0
for char in string:
if char == alphabet:
occurrence += 1
if occurrence > max_occurrence:
max_alphabet = alphabet
max_occurrence = occurrence
return max_alphabet
result = find_max_occurred_alphabet(input)
print(result)
input = "hello my name is sparta"
def find_max_occurred_alphabet(string):
alphabet_occurrence_array = [0] * 26
for char in string:
if not char.isalpha():
continue # 코드실행 건너뛰기
arr_index = ord(char) - ord("a") # 97-97
alphabet_occurrence_array[arr_index] += 1
max_occurrence = 0
max_alphabet_index = 0
for index in range(len(alphabet_occurrence_array)):
# index 0 -> alphabet_occurrence 3
alphabet_occurrence = alphabet_occurrence_array[index]
if alphabet_occurrence > max_occurrence:
max_alphabet_index = index
max_occurrence = alphabet_occurrence
print(max_alphabet_index)
return chr(max_alphabet_index + ord("a"))
result = find_max_occurred_alphabet(input)
print(result)
아스키코드를 인덱스로 바꾸는 방법
처음 a를 0으로 만들기 위해
ord(a)-> 97 - ord(a) = 0인덱스를 문자로 만드는 방법
0을 a로 만들려면
0 + ord(a)->97 -> chr(97) -> achr(97) == 'a' chr(0 + ord('a')) == 'a' chr(0 + 97) == 'a' chr(1 + 97) == 'b'
for num in array: # array 길이 만큼 아래 연산 실행
for compare_num in array: # array 길이 만큼 아래 연산 실행
if num < compare_num: # 비교 연산 1번 실행
break
else:
return num
max_num = array[0] # 연산 1번 실행
for num in array: # array의 길이만큼 아래 연산 실행
if num > max_num: # 비교 연산 1번 실행
max_num = num # 대입 연산 1번 실행
return max_num
첫번째 : N2 | 두번째 : 2N + 1
- N이 커질수록 큰 차이가 남
- N의 지수 먼저 비교
∴ N의 지수 비교 후 시간 복잡도 분석
- 상수는 신경쓰지말고, 입력값에 비례해서 어느 정도로 증가하는지만 파악
- 상수의 연산량이 필요하다면, 만큼의 연산량이 필요하다고 하면 됨
alphabet_array = ["a", "b", "c", ..., "x", "y", "z"]# 26개 공간 사용
max_occurrence = 0 # 1개 공간 사용
max_alphabet = alphabet_array[0] # 1개 공간 사용
for alphabet in alphabet_array:
occurrence = 0 # 1개 공간 사용
alphabet_occurrence_array = [0] * 26 # 26개 공간
for char in string:
if not char.isalpha():
continue # 코드실행 건너뛰기
arr_index = ord(char) - ord("a") # 1개 공간 # 97-97
alphabet_occurrence_array[arr_index] += 1
max_occurrence = 0 # 1개 공간
max_alphabet_index = 0 # 1개 공간
for index in range(len(alphabet_occurrence_array)):
# index 0 -> alphabet_occurrence 3
alphabet_occurrence = alphabet_occurrence_array[index] # 1개 공간
if alphabet_occurrence > max_occurrence:
max_alphabet_index = index
max_occurrence = alphabet_occurrence
for alphabet in alphabet_array: # alphabet_array 의 길이(26)만큼 아래 연산이 실행
occurrence = 0 # 대입 연산 1번 실행
for char in string: # string 의 길이만큼 아래 연산이 실행
if char == alphabet: # 비교 연산 1번 실행
occurrence += 1 # 대입 연산 1번 실행
if occurrence > max_occurrence: # 비교 연산 1번 실행
max_alphabet = alphabet # 대입 연산 1번 실행
max_occurrence = number # 대입 연산 1번 실행
for char in string: # string 의 길이만큼 아래 연산이 실행
if not char.isalpha(): # 비교 연산 1번 실행
continue
arr_index = ord(char) - ord('a') # 대입 연산 1번 실행
alphabet_occurrence_list[arr_index] += 1 # 대입 연산 1번 실행
max_occurrence = 0 # 대입 연산 1번 실행
max_alphabet_index = 0 # 대입 연산 1번 실행
for index in range(len(alphabet_occurrence_list)): # alphabet_array 의 길이(26)만큼 아래 연산이 실행
alphabet_occurrence = alphabet_occurrence_list[index] # 대입 연산 1번 실행
if alphabet_occurrence > max_occurrence: # 비교 연산 1번 실행
max_occurrence = alphabet_occurrence # 대입 연산 1번 실행
max_alphabet_index = index # 대입 연산 1번 실행
- 뒤에 상수는 버리고 N만큼 시간 작동한다고 말하기
- 공간을 희생해서라도 시간복잡도 좋게 만들기
빅오표기법 – 최악의 성능 나올 때 어느정도 연산량이 걸릴지
빅오메가 표기법 – 최선의 성능이 나올 때 까지 어느 정도의 연산량이 걸릴지
빅오 O(N)이면 빅오메가는 Ω(1)
input = [3, 5, 6, 1, 2, 4]
def is_number_exist(number, array):
for element in array: # array의 길이만큼 아래 연산 실행
if number == element: # 비교 연산 1번 실행
return True # N * 1 = N만큼
return False
result = is_number_exist(3, input)
print(result)
N번만큼의 시간복잡도를 가짐
운이 좋으면 1번의 연산으로 답을 찾을 수 있지만,
찾고자 하는 것이 제일 마지막에 있다면,
마지막 원소 끝까지 찾다가 겨우 결과값 반환하게 됨알고리즘 성능은 항상 동일한 것이 아니라 입력값에 따라 달라질 수 있는 것
다음과 같이 0 혹은 양의 정수로만 이루어진 배열이 있을 때,
왼쪽부터 오른쪽으로 하나씩 모든 숫자를 확인하며
숫자 사이에 '✕' 혹은 '+' 연산자를 넣어
결과적으로 가장 큰 수를 구하는 프로그램을 작성하시오.
(단, '+' 보다 '✕' 를 먼저 계산하는 일반적인 방식과는 달리, 모든 연산은 왼쪽에서 순서대로 이루어진다.)
input = [0, 3, 5, 6, 1, 2, 4]
def find_max_plus_or_multiply(array):
multiply_sum = 0 # 0으로 설정했기 때문에 여기도 고려해야 함
for num in array:
if num <= 1 or multiply_sum <= 1:
multiply_sum += num
else:
multiply_sum *= num
return multiply_sum
result = find_max_plus_or_multiply(input)
print(result)
위 함수의 복잡도는 O(N) = N
함수 구문 하나하나를 보지 않더라도, 1차 반복문이 나왔고, array 의 길이 만큼 반복하기 때문
다음과 같이 영어로 되어 있는 문자열이 있을 때,
이 문자열에서 반복되지 않는 첫번째 문자를 반환하시오.
만약 그런 문자가 없다면 _ 를 반환하시오.
input = "abadabac"
def find_not_repeating_character(string):
alphabet_occurrence_array = [0] * 26
for char in string:
if not char.isalpha():
continue
arr_index = ord(char) - ord("a")
alphabet_occurrence_array[arr_index] += 1
not_repeating_character_array = []
for index in range(len(alphabet_occurrence_array)):
alphabet_occurrence = alphabet_occurrence_array[index]
if alphabet_occurrence == 1:
not_repeating_character_array.append(chr(index + ord("a")))
# 알파벳으로 전환해야하기 때문에 index 그대로 넣으면 안됨
# print(not_repeating_character_array)
# 여기서 하면 알파벳 순서대로 반환, c와 d가 모두 다 나옴
for char in string: # 알파벳 순서가 아닌 들어온 문자열 순서에 맞게 반환
if char in not_repeating_character_array:
return char
return "_"
result = find_not_repeating_character(input)
print(result)
항상 고민할 것
- 문제가 찾는 조건이 어떤 것인지
- 내가 구현한 것은 어떤 조건을 통해 값을 내려주는 것인지
정수를 입력 했을 때, 그 정수 이하의 소수를 모두 반환하시오.
소수는 자신보다 작은 두 개의 자연수를 곱하여 만들 수 없는 1보다 큰 자연수이다.
input = 20
def find_prime_list_under_number(number):
prime_list = []
for n in range(2, number + 1):
for i in prime_list:
if n % i == 0 and i * i <= n:
break
else:
prime_list.append(n)
return prime_list
result = find_prime_list_under_number(input)
print(result)
0과 1로만 이루어진 문자열이 주어졌을 때,
이 문자열에 있는 모든 숫자를 전부 같게 만들려고 한다.
할 수 있는 행동은 문자열에서 연속된 하나 이상의 숫자를 잡고 모두 뒤집는 것이다.
뒤집는 것은 1을 0으로, 0을 1로 바꾸는 것을 의미한다.
예를 들어 S=0001100 일 때, 전체를 뒤집으면 1110011이 된다.
4번째 문자부터 5번째 문자까지 뒤집으면 1111111이 되어서 2번 만에 모두 같은 숫자로 만들 수 있다.
하지만, 처음부터 4번째 문자부터 5번째 문자까지 문자를 뒤집으면
한 번에 0000000이 되어서 1번 만에 모두 같은 숫자로 만들 수 있다.
주어진 문자열을 모두 0 혹은 모두 1로 같게 만드는 최소 횟수를 반환하시오.
input = "011110"
def find_count_to_turn_out_to_all_zero_or_all_one(string):
count_to_all_zero = 0
count_to_all_one = 0
if string[0] == '0':
count_to_all_one += 1
elif string[0] == '1':
count_to_all_zero += 1
for i in range(len(string) - 1):
if string[i] != string[i + 1]:
if string[i + 1] == '0':
count_to_all_one += 1
if string[i + 1] == '1':
count_to_all_zero += 1
return min(count_to_all_one, count_to_all_zero)
result = find_count_to_turn_out_to_all_zero_or_all_one(input)
print(result)
2주차 배울 내용 미리보기
어레이와 링크드리스트
- 어레이
- 순차적으로 데이터 저장
- 링크드리스트
- 다음 node라고 불리는 공간에 데이터 저장
- 그 다음 공간을 지목하는 포인터라는 공간이 있음
이진탐색과 재귀 함수
- 이진탐색
- 반을 쪼개고 탐색하고, 반을 쪼개고 탐색하는 방식
- 순차탐색
- 각각 하나하나하나 탐색
- 재귀함수
- 자기 자신을 부르는 함수
연결고리 : 포인터
화물칸 : 노드
Array | LinkdeList | |
---|---|---|
특정 원소 조회 | O(1) | O(N) |
중간에 삽입 삭제 | O(N) | O(1) |
데이터 추가 | 데이터 추가시 모든 공간이 다 차버렸다면 새로운 메모리 공간을 할당 받아야 한다. | 모든 공간이 다 찼어도 맨 뒤의 노드만 동적으로 추가하면 된다. |
정리 | 데이터에 접근하는 경우가 빈번하다면 Array를 사용 | 삽입과 삭제가 빈번하다면 LinkdeList를 사용 |
파이썬의 배열은 링크드 리스트로 쓸 수도 있고, 배열로도 쓸 수 있게 만든 효율적인 자료구조
class Person:
# pass # 빈 클래스로 두겠다는 의미
def __init__(self, param_name): # self는 자기자신
print("메렁", self)
self.name = param_name # name이라는 변수에 param_name 저장하겠다는 의미
def talk(self):
print("안녕하세요. 저는", self.name, "입니다.")
person_1 = Person("유재석") # Person()은 Person클래스를 통해 새로운 객체를 만들겠다는 것
print(person_1.name)
person_1.talk()
print(person_1)
# <__main__.Person object at 0x000001EDF9ACEAD0> 주소값: AD0
## at 뒤는 객체 공간 주소값
person_2 = Person("박명수")
print(person_2.name)
person_2.talk()
print(person_2)
# <__main__.Person object at 0x000001EDF9ACEB30> 주소값: B30
## at 뒤는 객체 공간 주소값
솔직히 이해가 안되서 정리 안하면서 봄
내일 오전 중으로 다시 한번 더 보기
class Node:
def __init__(self, data):
self.data = data
self.next = None
# 3을 가진 Node 를 만드려면 아래와 같이 하면 됩니다!
node = Node(3) # 현재는 next 가 없이 하나의 노드만 있습니다. [3]
class LinkedList:
def __init__(self, value):
self.head = Node(value) # head 에 시작하는 Node 를 연결합니다.
def append(self, value): # LinkedList 가장 끝에 있는 노드에 새로운 노드를 연결합니다.
cur = self.head
while cur.next is not None: # cur의 다음이 끝에 갈 때까지 이동합니다.
cur = cur.next
cur.next = Node(value)
linked_list = LinkedList(5)
linked_list.append(12)
# 이렇게 되면 5 -> 12 형태로 노드를 연결한 겁니다!
linked_list.append(8)
# 이렇게 되면 5 -> 12 -> 8 형태로 노드를 연결한 겁니다!
def print_all(self):
cur = self.head
while cur is not None:
print(cur.data)
cur = cur.next
append 함수 + 모든 원소 출력하기
class Node: def __init__(self, data): self.data = data self.next = None class LinkedList: def __init__(self, value): self.head = Node(value) def append(self, value): cur = self.head while cur.next is not None: cur = cur.next cur.next = Node(value) def print_all(self): cur = self.head while cur is not None: print(cur.data) cur = cur.next linked_list = LinkedList(5) linked_list.append(12) linked_list.print_all()
def get_node(self, index):
node = self.head
count = 0
while count < index:
node = node.next
count += 1
return node
def add_node(self, index, value):
new_node = Node(value)
node = self.get_node(index - 1)
next_node = node.next
node.next = new_node
new_node.next = next_node
def delete_node(self, index):
if index == 0:
self.head = self.head.next
return
node = self.get_node(index - 1)
node.next = node.next.next
Q. 다음과 같은 두 링크드 리스트를 입력받았을 때, 합산한 값을 반환하시오.
예를 들어 아래와 같은 링크드 리스트를 입력받았다면,
각각 678, 354 이므로 두개의 총합
678 + 354 = 1032 를 반환해야 한다.
단, 각 노드의 데이터는 한자리 수 숫자만 들어갈 수 있다.
linked_list_1 = [6] -> [7] -> [8]
linked_list_2 = [3] -> [5] -> [4]
def get_linked_list_sum(linked_list_1, linked_list_2):
sum_1 = 0
head_1 = linked_list_1.head
while head_1 is not None:
sum_1 = sum_1 * 10 + head_1.data
head_1 = head_1.next
sum_2 = 0
head_2 = linked_list_2.head
while head_2 is not None:
sum_2 = sum_2 * 10 + head_2.data
head_2 = head_2.next
return sum_1 + sum_2
# 비슷한 변수, 중복되는 로직이 많으므로
# 아래 와 같이 하면 코드 간결성 높아짐
def get_linked_list_sum(linked_list_1, linked_list_2):
sum_1 = _get_linked_list_sum(linked_list_1)
sum_2 = _get_linked_list_sum(linked_list_2)
return sum_1 + sum_2
def _get_linked_list_sum(linked_list):
sum = 0
head = linked_list.head
while head is not None:
sum = sum * 10 + head.data
head = head.next
return sum
요세푸스 문제