내일배움캠프 5기 합류 전 기본적인 강의를 들어야 한다고 한다.
웹개발을 위한 기본적인 강의 (HTML, CSS, JavaScript)
진도
- 간단한 CSS 태그들을 이용해서 로그인 페이지 만들기
-h1~h6
(글씨 크기, h1은 구글 검색에 이용),div
(구역 나눔),p
(문단 구분),button
(버튼)
- class: 태그 명찰 ( style에서 .태그 이름 {}로 스타일 지정 가능 )
- style:
color
,font-size
,background
,width
,height
,border-radius
등- style:
padding
( 안쪽 위치 조정 ),margin
( 바깥쪽 위치 조정 )Shift + Alt + F
로 코드 탭 위치 재조정구글폰트
를 이용해 페이지 폰트 바꾸기- 주석:
Ctrl + /
( HTML은 위치에 따라 주석 방법이 다르므로 단축키 기억하기 )- .css파일로 다른 파일을 링크해 스타일을 가져올 수 있다
감상
모호했던 css에 대해 좀 더 구체적으로 알 수 있었다
웹개발을 위한 기본적인 강의 (SQL)
진도
- 어제 배운 기본 구문(
SELECT
,WHERE
,LIKE
)를 이용해서 특정 조건을 만족하는 로우 구하기GROUP BY
( 동일한 범주를 갖는 데이터를 묶어서, 범주별 통계를 내줌 )- 통계:
MIN
,MAX
,AVG
,ROUND( , )
,SUM
ORDER BY
( 오름차순ASC
(ascending), 내림차순DESC
(descending) )- 배운 절들을 전부 사용해서 쿼리문 만들기
감상
어떤 걸 보고 싶을 땐 쿼리문을 어떻게 조합해야 되는 지 봐야하므로 구문에 익숙해져야겠다
파이썬 문제 풀어보기
def apartment_memo(k, n, cache):
#base case
if k == 0:
cache[k][n] = n + 1
return n + 1
elif n == 0 and k > 0:
cache[k][n] = 1
return 1
if cache[k][n] != 0:
return cache[k][n]
else:
cache[k][n] = apartment_memo(k - 1, n, cache) + apartment_memo(k, n - 1, cache)
return cache[k][n]
def apartment(k, n):
apt_cache = [[0] * (n + 1) for _ in range(k + 1)]
apt_cache[0][0] = 1
apartment_memo(k, n, apt_cache)
print(apt_cache[k][n])
T = int(input())
for i in range(T):
k = int(input())
n = int(input())
apartment(k, n - 1)
- 기존 재귀함수 풀이에 한번 계산한 값을 저장할 수 있는
apt_cache
라는 2차원 배열을 만들어 주었다. 이 Memoization을 이용하기 위해apartment_memo
라는 새로운 함수를 만들어 주었고apartment
함수를 호출하면 입력받은k
,n
값에 따라 그 크기만큼의 2차원 배열을 만들어 주고apartment_memo
라는 함수를 다시 호출해 Recursion으로 정답을 도출하는 코드이다.- Memoization을 이용해 확실히 값을 도출하는 시간은 비약적으로 빨라졌으나 시행착오 끝에 완성한 코드라 주석도 없고 시각적으로 난해하다. 그리고 더 획기적인 코드가 있을 것이라 생각한다.
- 예를 들어 문제에서
n
은 1호 이상의 값인데 내가 만든apt_cache
는 0부터 시작하므로 이걸 어떻게 적용해야 할 지 조금 난감했다. 그래서n
을 입력받고apartment
함수에n-1
을 매개변수로 집어넣는 방식으로 해결했다.
def people_num(k, n):
# 0층부터 n호까지의 사람 수를 먼저 계산한다
people = [i for i in range(n+1)]
# k층까지 각 호수별 사람 수를 누적해서 더한다
for i in range(1, k+1):
for j in range(1, n+1):
people[j] += people[j-1]
return people[n]
# 입력 예시에 대한 출력
print(people_num(1, 3)) # 6
print(people_num(2, 3)) # 10
챗GPT는 위 문제를 짧은 코드로 풀었다
- 0층의 사람 수
people
리스트를 1, 2, 3, 4, 5, ..., n로 먼저 초기화 해준 뒤에, 다음 층people[j]
는 아래층people[j]
와 전 호수people[j-1]
의 합과 같다는 점을 이용했다.- 예를 들어 k = 1, n = 3이라면
people = [1, 2, 3]
으로 시작해people = [1, 3(1+2), 6(3+3)]
,people = [1, 4(1+3), 10(4+6)]
이 된다.- 컴퓨터가 이해할 수 있는 규칙으로 단순화시키는 방법을 좀 더 고민해 봐야겠다.
개요: 3kg, 5kg 설탕봉지로 조합해 주어진 Nkg을 가장 적은 수의 봉지로 배달하는 방법을 구하는 문제
초기 구상: 5kg 설탕봉지로 딱 나누어 떨어질 때가 가장 이상적이므로 먼저 5로 나누어 떨어지는지 확인 후에 나누어 떨어지지 않으면 5kg 봉지 개수를 하나씩 줄이고 3kg봉지를 늘려 최적의 수를 찾도록 구상
N = int(input())
a = N
if N % 5 == 0:
print(N // 5)
else:
for five in range(N // 5, -1, -1):
for three in range(1, N // 3 + 1):
if N == 5 * five + 3 * three:
a = min(a, five + three)
if a != N:
print(a)
else:
print(-1)
정답은 도출했지만 min()
등을 쓰지 않고 중첩 for을 쓰지 않는 더 최적화된 방법이 있을 것 같다.
n = int(input())
# 5킬로그램 봉지를 최대한 많이 사용하기 위해, 5로 나누어 떨어질 때까지 5킬로그램 봉지 사용
quotient, remainder = divmod(n, 5)
if remainder == 0:
print(quotient)
else:
# 5킬로그램 봉지로 나누어 떨어지지 않는 경우, 3킬로그램 봉지로 나누어줌
for i in range(quotient, -1, -1):
j = (n - 5*i) // 3
if 5*i + 3*j == n:
print(i+j)
break
else:
print(-1)
챗GPT 코드는 for문을 하나로 구성하여 O(n)의 시간복잡도로 최적화되어있다.
- 챗GPT도 마찬가지로
divmod()
함수(n을 5로 나누어 몫과 나머지를 튜플로 리턴)를 이용해 5로 나누어 나머지가 0이면 몫을 바로 정답으로 하는 코드를 구성했다.- 5kg 봉지를 하나씩 줄여갈 때 for문을 사용하고 5kg 봉지로 최대한 봉지 수를 구성하고 남은 값을 3으로 나눈 몫을
j
에 저장했다. 그리고5 * i + 3 * j
가n
이 되었을 때i+j
를 출력하고 반복문을 중단시키는 코드로 최적화시켰다.- 중첩 for문을 줄일 수 있는 방안을 항상 생각해야겠다.
개요: 주로 사용되는 낮은 정수가 아니라 91283041284121 등 아주 큰 수를 더하는 문제
초기 구상: 파이썬에서는 변수 자료형에 따른 메모리의 제한이 없기 때문에 크게 문제가 없을 거라고 생각했다.
import sys
A, B= map(int, input().split())
print(A + B)
역시나 파이썬에서는 자료형에 크게 구애 받지 않아 간단한 코드로 작성이 가능했다.
만약 C나 perl같은 언어에서는 저렇게 큰 자료형이 없기 때문에 문자열로 받아 따로따로 처리해야 할 것으로 보인다.
#include <iostream>
#include <string>
using namespace std;
int main() {
string a, b;
cin >> a >> b;
string result = ""; // 결과를 저장할 문자열 변수
int carry = 0; // 자리 올림 수
int sum = 0; // 각 자리별 합
// 덧셈 연산
for (int i = 1; i <= max(a.length(), b.length()); i++) {
sum = carry; // 이전 자리에서의 자리올림을 더함
if (i <= a.length()) sum += a[a.length()-i] - '0'; // a의 해당 자리수 값 더함
if (i <= b.length()) sum += b[b.length()-i] - '0'; // b의 해당 자리수 값 더함
carry = sum / 10; // 자리 올림 계산
result = to_string(sum % 10) + result; // 해당 자리의 결과 값 저장
}
if (carry) result = to_string(carry) + result; // 마지막 자리 올림이 있으면 결과 문자열의 가장 앞에 추가
cout << result << endl; // 결과 출력
return 0;
}
챗GPT에게 C언어로 코딩을 부탁했다.
- 예상대로 a, b을 문자열로 받은 뒤에 max(a.length(), b.length())로 둘 중 더 큰 수 자리수 만큼 반복문을 돌며 각 자리수의 합을 구한다.
- 합이 10이 넘는다면 자리올림을 다음을 위해 저장해 두고 나머지를 이용해 해당 자리에 결과값을 저장한다.
- 파이썬이 아니라 다른 언어였다면 위와 같은 사항들을 고려했을 것이다.
개요: 주어진 수 N개 중에서 소수가 몇 개인지 찾아서 출력하는 문제
초기 구상: 리스트로 받은 값을 반복문으로 하나씩 가져오고 그 수를 또 다시 반복문으로 나눠가면서 나머지가 0이 되면 리스트에서 제거하는 방식을 구상했으나 더 복잡해졌다
N = int(input())
number_list = list(map(int, input().split()))
count = 0
for i in number_list:
check = 0
if i == 1:
check = 1
for j in range(2, i // 2 + 1):
if i % j == 0:
check = 1
if check == 0:
count += 1
print(count)
number_list
를 넘겨 받은 뒤에 for문으로 하나씩 호출하고 또 다시2 ~ i // 2 + 1
까지의 수로 나눠서 나머지가 0이 되면check
에 1을 넣었다.- 전체를 빠져나온 뒤에
check
가 여전히 0일 경우count
에 1을 더해줘서 소수를 구하는 방식이다.- N 리스트의 element가 무지 클 경우 위 방식은 너무 시간이 오래 걸린다.
# 소수 판별 함수
def is_prime(n):
if n < 2:
return False
for i in range(2, int(n ** 0.5) + 1):
if n % i == 0:
return False
return True
# 입력 받기
n = int(input())
numbers = list(map(int, input().split()))
# 소수 개수 구하기
count = 0
for num in numbers:
if is_prime(num):
count += 1
# 결과 출력
print(count)
- 챗GPT 역시 거의 비슷한 방식으로 답을 구했으나 최적화를 위해
i // 2 + 1
이 아닌int(i ** 0.5)
로 시간을 더 줄였다.- 제곱근을 쓴 이유는
어떤 요소 n
은a
,b
의 곱a * b
로 나타낼 수 있는데a
,b
중 적어도 하나는n의 제곱근
보다 작거나 같아야 하기 때문이다- 둘 다
n의 제곱근
보다 크면a * b
는n
보다 큰 값이 되어버린다.- 따라서
2
부터int(i ** 0.5)
까지만 나누어 줘도 소수 판별이 가능하다.
코드잇 코딩 공부 과정
4. 상속Ⅰ(부모로부터 물려받기)
- class와 class사이에 부모-자식 관계 설정 가능 (상속)
class 자식클래스(부모클래스): 내용
- 상속을 하면 자식 클래스가 부모 클래스의 변수와 메소드를 그대로 물려 받음
help(클래스)
함수로 상속 관계나 메소드 등을 알 수 있음- 특히
Method resolution order:
로부터 해당 인스턴스의 클래스가 어떤 부모 클래스를 가지는지 보여줌- 모든 클래스는
builtins.object
를 부모 클래스로 가짐
5. 상속과 관련된 메소드와 함수들
print(클래스.mro())
로mro()
메소드를 호출하면 해당 클래스가 상속하는 부모 클래스를 볼 수 있음print(isinstance(검사할 인스턴스, 기준 클래스))
로isinstance()
함수를 사용하면 검사할 인스턴스가 기준 클래스의 인스턴스인지 불린 값으로 리턴함print(issubclass(검사할 클래스, 기준이 되는 부모 클래스))
로issubclass()
를 사용하면 검사할 클래스가 부모 클래스의 자식 클래스인지 불린 값으로 리턴함
6. 상속Ⅱ(오버라이딩)
- 오버라이딩(overridding) : 부모로부터 물려받은 내용을 자식 클래스에 맞게 덮어 씌우는 것
- 오버라이딩 방법
1. 자식 클래스에 같은 이름의 부모 클래스 내용 붙여넣고 밑에 다른 내용 적기
2.부모 클래스.해당 메서드(파라미터)
로 부모 클래스 내용 붙여넣고 밑에 다른 내용 적기
3. 부모 클래스를super()
함수로 대체,super().해당 메서드(파라미터)
로 사용 (이 경우 파라미터에self
파라미터를 넘겨줄 필요가 없음)- 변수 오버라이딩 방법 : 자식 클래스에서 같은 이름의 변수를 수정해주면 된다.
7. 상속Ⅲ(mro)
- mro(method resolution order, 메소드 탐색 순서)
- 메소드 검색 방향: 자식 -> 부모
- 자식과 부모 클래스가 각각 같은 이름의 메소드가 있더라도 자식부터 검색되기 때문에 오버라이딩이 가능하다.
8. 상속Ⅳ(기능 추가하기)
- 이제 자식 클래스에 기능 추가는 기존대로 하면 된다.
9. 상속 정리
- 위의 내용 정리
12. 다중 상속
- 상속할 때 부모 클래스를 2개 이상 설정하면 다중 상속이 가능하다.
class 자식클래스(부모클래스1, 부모클래스2, ...): 내용
- 다만
__init__
메소드 등을 설정할 때super()
함수로는 어떤 부모 클래스의__init__
메소드를 가져와야 할 지 알 수 없으므로 직접 부모 메소드의 이름으로 메소드를 가져와야 한다.
13. 다중 상속의 위험성
- 다중 상속으로 2개 이상의 부모 클래스를 상속받았을 때 두 부모 클래스에 함께 있는 메소드를 호출하게 되면 어떤 부모 클래스의 메소드를 호출할 지 알 수 없다.
- mro()변수로 호출하면 그 순서를 알 수 있으며, 상속 시의 순서에 따라 순서가 바뀌기도 한다.
- python에서는 다중 상속이 가능하지만 java에서는 무조건 한 개의 상속만 가능하다.
- 해결방법 :
1. 부모 클래스끼리 같은 이름의 메소드를 갖지 않도록 하기
2. 같은 이름의 메소드는 자식클래스에서 오버라이딩 해버리기
감상
python의 Class 상속에 관해서 배울 수 있었다. 큰 단위의 프로젝트를 할 때 Class단위 사용을 많이 할텐데 사용법에 익숙해지고 눈에 익을 수 있도록 자주 봐야겠다.