유튜브 강의가 있다고 써있긴 했는데 형식상의 강의 일 것 같아서 안찾아보고 chatgpt한테만 물어보고 이것도 이 유튜브를 검색한게 아니라 재귀함수로 검색한건데 낯읽은 책페이지가 보이더라구요 보니까 저자와 똑같은 유튜브 채널 이름... 퀄리티가 좋아요 진작 찾아볼껄 그랬어요 잘보겠습니다
invalid syntax는 구문에 오류가 있을 때 발생합니다! 따라서 괄호가 안 닫히지는 않았는지, for if while 등의 조건문 형태가 잘못되지 않았는지 살펴주시면 됩니다. 다음과 같이 여기에 오류가 있다고 하므로 여기 구문을 살펴보시면 되겠는데요. for i range(앉힌사람수, 앉힐수있는최대사람수+1): ^ SyntaxError: invalid syntax for i in range(ㅇㅇ) 형태로 가운데에 in을 넣어주시면 됩니다!
@@DailySangmin 피라미드는 9:50에 나오는 그림을 말하는 거고요. 댓글에 적은건 메모화를 이용할때 f(5)를 구하는 과정을 그 피라미드 방식으로 적은 것입니다. f 앞의 1. 2. 3...는 코드의 흐름 순서고요. f(5)구하려면 f(4)와 f(3)을 구해야 하고 f(4)와 f(3) 중 f(4)를 먼저 구해야 하니까 다음은 f(4)를 구해야 하고 그러려면 f(3)과 f(2)구해야 하고 f(3)구하려면 f(2)와 f(1)구해야 하는데 이 값은 함수에 1이라고 정해져있으므로 구해졌고 그다음 위에서 넘어갔던 f(2) 구할차례인데 메모에 있으므로 계산 안하죠. 나머지도 다 메모에 있습니다. 피라미드처럼 전부 계산 안하고 피라미드 맨 왼쪽부분만 계산하면 된다는 겁니다. 위에
재귀함수로 구현한 피보나치 수열에서요. (스스로 이해해보려고 했는데 도저히 안되는군요 ㅠㅠ) def fibonacci(n): ...생략.... return fibonacci(n-1)+fibonacci(n-2)에서 말이죠. 만약에 n에 5가 들어가면 리턴 값이 fibonacci(4)가 되면 뒤에 남은 더하기 연산(fibonacci(n-2))은 마저 하는 건가요, 아님 다시 fibonacci함수로 돌아가는 건가요? 전개가 어떻게 되는 건지요?
봐도봐도 이해 안되는 부분이 있어서 문의 드립니다. 메모화 패턴이 마치 for 문처럼 반복되는 이유가 뭔지 도무지 이해가 안됩니다. if에서 return 전 n 값을 출력해 보고, else에서 output 연산 후 n을 출력해 보면 변화 하는건 알겠는데, 값이 왜 증가가 되는지 이해가 안되는데, 설명해 주실 수 있을까요? f(10)을 넣었다고 가정하고, if 에서 return 전 print(n) 을 해보면 2 -> 2 -> 4 -> 6 -> 8이 출력되는데 n이 증가되는 이유를 모르겠네요... ㅜㅜ;
@@윤인성 답변 감사 드립니다. 그런데 아직 이해 안되는 부분이 있어서 추가로 문의 드립니다. f(10)을 입력했을 때 n이 3이 됐을 때 output = f(2) + f(1) = 2가 되는 것은 이해 됐고, dic[3]=2가 입력되는 부분까지는 이해가 되는데요, f(3) 이후 f(4) -> f(5) -> ... -> f(10)까지 반복 될 수 있는 원리가 이해되지 않네요... 부탁 드립니다.
인성쌤 ㅜㅜㅠㅠ def factorial(n): if n == 0: return 1 else: return n* factorial(n-1) print("4! =",factorial(4)) 라는 코드에서 n* factorial(n-1) 라는 코드 결과 값이 왜 n * (n-1)! 가 되는 지 잘 이해가 안 가요,,ㅠㅠ 너무 기본적인 거라 물어보는 것도 죄송한데 정말 짚고 넘어가지 않으면 안될 거 같아서 인터넷에서도 몇 번 찾아봤는데 잘 안 나와서요,, n* factorial(n-1) 결과 값이랑 n* (n-1) 결과 값이랑 같아야 하는 거 아닌가요??ㅠㅠ 결과가 다르게 나와서 왜 이렇게 나오는지 궁금해요.. 정말 여쭤보기도 죄송한 부분이지만 여쭤볼 곳이 마땅찮아서 ..ㅠㅠ죄송해요
`n - 1`과 `factorial(n-1)`이 코드 자체가 다르므로 같지 않습니다! factorial(a) = a * factorial(a - 1)로 작동하므로 factorial (a - 1) = (a - 1) * factorial(a - 1 - 1)이 됩니다. 이게 계속 반복적으로 동작해서, 계속해서 파고 들어가게 됩니다! 공부 단계에서는 질문을 빨리 주실수록 공부 속도가 빨라지므로 죄송해하시지 마시고 막 물어봐주세요 'ㅁ' ...!
@@윤인성 선생님 진도를 나가다가 결국 이 부분에서 이해가 안 간 상태로 진행하다 보니 재귀함수 자체에서 막혀버렸습니다.. 응용도 잘 안되네요,..ㅠㅠ '반복 적으로 동작해서, 계속 파고 들어가게 됩니다!' 라는 부분이 잘 이해가 안 가요ㅠㅠㅠ 다른 코딩 수업에서 진행하신 부분 중에 테이블 나눠서 앉는 문제 설명하시면서 말씀하신 노드랑 엣지 사용하는 트리를 보여주시면서 이해시켜주시는 수업을 반복해서 몇 번이고 봤는데 이 재귀함수 알고리즘이 이해가 안 갑니다 ㅠㅠㅠㅠㅠㅠ 그냥 함수자체를 외워버릴까요,,?ㅠ 어떻게 나아갈지 모르겠습니다.. 무시하고 일단 진도 나가도 성격 상 확실히 짚고 넘어가지 않으면 안되는 타입이라.. 어떻게 이해를 하면 좋을까요..? 다음 강의 문제 부분에서 def flatten(data): output = [] for i in data: if type(i) == list: output += flatten(i) else: output += [i] return output example = [[1,2,3],[4,[5,6]],7,[8,9]] print("원본:",example) print("변환:",flatten(example)) 이 코드 중에서 output += flatten(i) 를 실행시키면 어떤 결과가 어떻게 도출됐는지 도저히 이해를 할 수 가 없습니다..흑흑 연말에 너무 죄송하지만 갑갑한 마음에 여쭤봅니다 선생님..ㅠㅠㅠㅠ 새해 복 많이 받으세요 항상 친절한 강의와 답변 감사드립니다!
@@강희원-i4h 넵 함수 자체를 외워버리는 것도 좋습니다. 재귀 함수가 알고리즘 대회에서 꽤 고급 스킬이고 + 이게 실무에서도 "잘 못 쓰면 쓰지 말아라"라고 하는 금단의 위험한 스킬[?] 같은 것이라서 = 실무 분들도 많이들 잘 못 쓰고 안쓰려고 하는 편입니다. 따라서 일단 강의를 다 끝내고 다시 보시는 것도 추천드립니다! 새해복 많이 받으세요!!
@@윤인성 # f6 # f5 f4 # f4 f3 f3 f2 # f3 f2 f2 f1 f2 f1 f1 # f2 f1 f1 f1 f1 # f1 다 괜찮은데 피보나치 재귀함수가 도무지 이해가 안가서 책한권 다돌리고 다시 몇번을 봐도 이해가 안 가서 미칠지경이었는데 저런 식으로 이해 해보니까 이해가 갔네요 너무 하찮은 이해지만 진짜 해보고 눈물났습니다.. 수학을 못해서 뭔가 벽을 느낀거같고 함수만 나오면 이해하기가 어려워서 그만두고 싶었는데 이해가 조금은 된거같습니다.,ㅠ 감사합니다..
메모화를 이용한 피보나치수열 문제에서 f(5)=f(4)+f(3) f(4)=f(3)+f(2) f(3)=f(2)+f(1) 이처럼 하나하나 값을 알아야 구할수 있는데 코드 순서를 확인해 보니 f(3)를 메모에 추가하고 그 다음 f(4)를 메모에 추가하는 순서인데 이처럼 f(4),f(3)의 값을 따로따로 구한는게 아닌 작은 값부터 구하는 순 인가요?
선생님안녕하세요 혼자 복습중 궁금증이 생겨 질문드립니다. while 반복문 공부중에서 1. i = 0 2. while i < 10: 3. i += 3 4. print(i) ------------------ PS C:\혼자공부하는파이썬> python ex01.py 3 6 9 12 왜 12가 나오는 걸까요? 10보다 작게 입력했는데. 이 부분이 궁금합니다. (+ 추가 '+='는 무슨 뜻인가요?)
a += b는 a = a + b를 의미합니다. 마지막 반복에서 (1) i의 초기값은 9입니다. (2) 그래서 i < 10에 포함되므로 반복문 내부로 진입합니다. (3) i += 3을 하므로 i는 12가 됩니다. (4) print(i)하므로 12가 나옵니다. (1) 이제 i는 12입니다. (2) i < 10에 포함되지 않으므로 반복문을 벗어납니다. 해서 12는 출력이 됩니다!
def factorial_2(n): if n == 0: return 1 else: return n * factorial_2(n-1) print(factorial_2(10)) 재귀함수 부분에서 else: return n * factorial_2(n-1) return n 은 10으로 고정이 되있고 factorial_2(n-1)의 n이 0이 되서 if 문으로 갈때까지 도는게 맞나요? 제가 잘 이해한건지 모르겠어서 질문드립니다
처음 return n이 다음과 같이 쭉 대체되며 계산됩니다![표기를 간단하게 하려고 연산자 우선순위 무시했습니다] return n * factorial_2(n-1) return n * n-1 * factorial_2(n-2) return n * n-1 * n-2 * factorial_2(n-3) * .... * 0
@@윤인성 factorial_2(10-1), factorial_2(9-1), factorial_2(8-1),...(1-1) 이렇게 n의 수치가 줄어드는게 아니고 뒤에 -1, -2, -3...-10 으로 재귀될때마다 수치가 바뀌는건가요? 재귀 한번 할때마다 factorial_2(n-1-1) 이렇게 -1이 늘어나는건가요?
@@sangwoonoh7438 factorial(n)에서 n의 값이 그냥 계속 떨어질 뿐입니다. 이게 실질적으로 n으로서 계산되는게 아니라 10 들어가고, 9 들어가고, 8 들어가고 등으로 값이 들어가는거라 복잡하게 생각하지 마시고 그냥 값을 하나씩 넣어보면서 손으로 어떤 순서로 계산되는지 확인해보시기 바랍니다.
조기리턴 관련 질문입니다. 들여쓰기를 줄여 주기에 조기리턴을 이용한 코드가 요즘추세다 라고 하시는데 이게 어떻게 좋다는 의미 인지가 궁금합니다. 막연히 짐작하기에 혹시, 기계어 코드로 변환 될때 들여쓰기가 있는것과 아닌것의 코드 복잡도가 달라서 그런 걸까요? 항상 좋은 강의 감사합니다.
사내 교육 시험 준비로 연습문제만 다시 듣습니다. 두번째 들으니 처음 들을때 놓쳤던 부분도 보이고 이해도 더 잘되네요. 그런데 혼자 코딩하려면 막막한게 일단 외워야할까요? 뭔가 응용은 안되고 이론만 아는 정체된 느낌이에요. 공부의 절대량이 부족한거겠죠? 나름 시간투자는 많이 했는데.. 뭔가 머릿속 코딩에 대한 전구가 안켜진 느낌.. 좋은 방법이 있을까요?
두 가지 이유 때문이라고 생각하는데요. 1. 지식의 문제 일반적으로 초중고대학학교 16년 동안 수학을 배우면, 이게 모두 단순한 "암기"처럼 느껴집니다. 하지만 "암기"를 하면서도 조금씩 계속해서 나아가고 있는 것은 분명합니다. 프로그래밍도 초기 단계에서는 오랜 기간 동안 그런 생각이 드십니다. 하지만 분명 계속해서 나아가고 있는 것입니다. . 2. 방향성의 문제 공학 공부도 대학교까지는 진짜 모든걸 외우는데, 회사에서 과제를 받는 활용의 영역부터는 이게 암기의 영역이 아니게 됩니다. 프로그래밍도 실제로 해결해야하는 "답이 없는 과제"를 만나실 때부터 "내가 암기 이상의 것을 할 수 있었구나"하는 느낌을 받으실 수 있을 것이라 생각합니다! . 사실 알고리즘 시험과 같은 영역은 활용의 부분이라고 보기 약간 애매해서[대학교 때에 공학 공식들 외우는 기분이라], 현재 공부에서는 그런 느낌을 받을 수 밖에 없을 것이라 생각합니다! . 단순 공부와 함께 활용을 함께 진행하시면 약간 그런 느낌이 사라지리라 생각합니다!
재귀 함수는 직접 출력을 해보시는 것이 실행이 어떻게 되는지 이해하기가 쉽습니다. 1. 함수 정의 바로 아래에 print("factorial({})을 실행합니다".format(n))를 넣고 2. 리턴 부분의 return n * factorial(n - 1)을 temp = n * factorial(n - 1) print("{n} * factorial({})의 계산 결과 = {}".format(n, n-1, temp)) return temp 라고 적어서 함수의 시작과 끝에 출력을 해보시게 하면 "아아 이게 이렇게 실행되는거구나!!"하고 흐름을 볼 수 있을 것입니다!
안녕하세요 선생님! 코린이 입니다..책에 나와있는지 잘 모르겠지만 제가 해외에 있고 책을 현재 받아보기가 어려운 상황이라 부득이하게 영상으로만 보고 있어요. ㅠㅠ 팩토리얼(3:36)을 보다가 코드 순서를 정리해봤는데 이게 맞는지 궁금해서 댓글을 남기게 되었습니다. 저 6줄 안에 총 17번으로 코드가 읽히는 것이 맞나요? 맞다면 혹시 지정해준 함수 내부의 조건문이나 반복문이 길어지고 함수 속에 함수가 또 들어가고.. 그러면 결국 속도에 영향을 많이 줄까요? 코드가 달랑 6줄인데 17번이나 읽는다는게 왠지 비효율적으로 느껴져서요.. ㅠ_ㅠ 그리고... 이북 출간 생각 없으실까요...? ㅠ_ㅠ 이거 말고 다른 강의들도 책이랑 같이 보고 싶은데 배보다 배꼽이 더 커서 영상으로만 보고 있습니다ㅠㅠ def factorial(n): #2 #6 #10 #14 if n == 0 : #15 return 1 #16 else : #3 #7 #11 return n * factorial(n-1) #4 #8 #12 print(factorial(3)) #1 #5 #9 #13 #17
현재 5,9,13,17이 순서가 약간 잘못되어 있습니다. 이걸 제거하고 12번부터 시작한다면[factorial이 기니까 f로 적었습니다] 12. 2 * f(1) 해야하네 14. f(1) 하자 15. n == 1이네 16. return 1하자 [그 상위에서 f(1)을 호츌했던 곳으로 리턴][#12] 17.return 2 * f(1)[=1]니까 2 리턴하자 [그 상위에서 return 3 * f(2)했었던 쪽으로 리턴][#8] 18. return 3 * f(2)[=6]이니까 6리턴하자 [그 상위에서 print(f(3)했었던 쪽으로 리턴][#1] 19. print(f(3)[=3]) 구했으니 3 출력하자 해서 돌아 나오게 됩니다. 17번 정도 실행은 큰 문제없습니다. 일반적으로 입력(현재 코드에서 3)이 들어갈 때 함수 흐름이 몇 번 실행되냐가 중요한데[알고리즘 배울 때 오더 표기(빅오 표기)를 배웁니다]. 현재 코드는 f(3), f(2), f(1)로 입력 크기 3만큼 실행되는 코드라 실행 획수가 입력 크기 n과 비례합니다. 이건 시간적 관점에서는 좋은 알고리즘입니다. [입력이 1억이어도 1억 번만 돌리면 되므로] 이 다음에 나오는 예제 중에 (메모화가 없는) 피보나치 수열은 함수가 한 번 실행 될 때 내부에서 두 개씩 타고 들어가야 해서 2^n과 비례하는 알고리즘이 됩니다. 이건 입력이 10이면 대충 1024번, 20이면 대충 1,048,576번 반복합니다[입력이 1억이면(...), 읽을 수도 없을 만큼 처리가 실행되어야 합니다]. 이런게 비효율적인 알고리즘입니다!
@@윤인성 아! 저는 return을 하면 무조건 함수 밖으로 나간다고 생각했는데 아직 f(n)이 남아있는 상태에서는 당연히 함수 안을 도는거였네요! 생각해보니 함수 밖을 나가면 그것도 출력해야 하니 답이 하나가 아니라 여러줄로 나오고요. 깔끔하게 이해됐어요!! 시간 내 주셔서 이렇게 정성스럽게 답변 주셔서 정말 고맙습니다 :) 그리고.. 정가여도 좋으니 이북 출간 제발 고려해주세요 ㅠ_ㅠ 열심히 광고보며 보답하고 있지만 책도 꼭 구매하고 싶어요ㅠ_ㅠ 늘 좋은 강의 감사합니다!
함수는 재귀 호출하면 마트료시카 인형처럼 한 단계씩 들어갑니다. 5겹이면 return을 한다고 5겹을 한 번에 빠져 나오지 못하며 한 겹씩만 빠져나올 수 있습니다! 이북은 작년에 한국 인터넷에서 거대한 pdf 공유 사례가 발생해서 ㅠㅁㅜ [수 백 명이 수 백 권을 공유하는 카톡방 등이 생겨서], 당분간 힘들지 않을까 싶습니다 ㅠㅁㅜ
233쪽 재귀 함수로 구현한 피보나치 수열(2)에서 궁금한 점이 있어서 질문 드립니다! 21열을 작성하지 않고 19열까지만 작성하면 fibonacci(10)의 값이 출력되는데 21열을 작성하면 fibonacci(10)의 값이 출력되지 않고 21열만 출력되는 이유가 궁금합니다!
제가 질문의 의도를 정확하게 파악한 것인지 모르겠는데 화면에 무언가를 출력하려면 반드시 print() 함수를 사용하셔야 합니다. 20번째 줄과 21번째 줄에서 print() 함수로 "---"과 "fibonacci(10) 계산에 활용된 덧셈 횟수는 {}번입니다"를 출력하므로 이를 안 쓰면 이 두 줄이 출력되지 않습니다.
교수님 강의 잘 듣고 있습니다. return 키워드의 궁금한 점이 있습니다. 자료 없는 return은 만나는 순간 그 함수가 종료되는데 자료 있는 return 의 경우 어째서 for를 사용하지 않았는데도 계속 반복하는지 이해가 잘 안되네요. 예제) def f(n): if n == 1 or n == 2: return 1 else: return f(n-1) + f(n-2) print(f(10)) 위의 예제 경우 for가 없는데 여러번의 계산을 진행하는지 이해가 되지 않습니다.
선생님 메모화 파트를 공부중인데 이해가안되는게 있어서 질문드려요 ㅜㅜ else: output=fibo(n-1)+fibo(n-2) dictionary[n]=output return output 이구문을 통해서 예를들어 "n=3일 떄 dictionary에는 n=3일 때의 key값이 없으니까 dictionary[3]=output으로 딕셔너리에 key와 그 값이 추가된다" 라고 이해하면 되는건가요? 그리고 "그 n의 값들이 증가함에 따라 dictionary에 추가 되어 계산없이 사용이 가능하다 "라고 이해를 했는데 맞는지 궁금해서 글써봅니다... 조금 어려워지네요 ㅜㅜ
243쪽 확인 문제 1번을 이런식으로 data의 길이를 받아와서 range로 돌려서 풀면 안되는 이유가 궁금합니다.ㅠㅠ def flatten(data): output=[] for i in range(len(data)): if type(data[i])==list: output=output+flatten(data) else: output.append(data[i]) return output example=[[1,2,3],[4,[5,6]],7,[8,9]] print=("원본:",example) print=("변환:",flatten(example))
11:03 7행에 메모[n] = output 을 작성해주실때 "한번 계산했던 내용들이기 때문에"라고 언급해주셨고, 12:01 "이는 한번 계산했던 것은 더 계산하지 않고 그냥 메모했던 것을 다시 확인하기 때문"이라고 언급해주셨습니다. 실제로 메모[n] = output을 작성하거나 하지 않을 때, 속도 차이가 컸습니다.(메모화 여부로 판단됩니다.) 메모[n] = output을 작성함으로써 정확히 어떤 부분이 계산되지 않는지에 대한 개념을 조금 더 상세하게 듣고 싶습니다.
@@윤인성 감사합니다. 람다 부분까지 공부를 하다가 도저히 어려워서 책을 구매 후 복습 중에 있습니다 ㅠㅠ 6행에서 재귀함수를 다시 실행함으로써 그 결과 값이 7행을 통해, 1행에 추가되고 그로 인해 if 조건문 이하가 실행되지 않음을 깨닫는데에 시간이 소요되었습니다. 답변 감사합니다.
3일째 이해가 안되는게 있어서 질문드립니다. 243쪽 확인문제 1번에서 if 구문에서 output += flatten(item) 부분이 이해가 안됩니다. 제 생각에는 재귀함수인 flatten(item)만 써서 함수 호출하고 리스트 평탄화를 시켜서 else 구문으로 들어가게 되면 append 함수에 의해서 output에 리스트에 요소가 추가 된다고 생각합니다. output += 을 왜써야하는 지 모르겠습니다. def flatten(data): output = [] for item in data : if type(item) == list: output += flatten(item) else : output.append(item) return output example = [[1, 2, 3],[4, [5, 6]], 7, [8, 9]] print("원본:", example) print("변환:", flatten(example))
1. += 연산자는 마치 "리스트.extend()"처럼 동작합니다. 즉 여러 개의 요소를 추가합니다. 반면 "리스트.append()"는 하나의 요소만 추가합니다. 2. 함수는 실행 때마다 다른 변수 공간을 갖습니다. 따라서 재귀 함수의 각 실행 때마다 있는 output은 같은 대상이 아니라 모두 다른 대상입니다. PS. 일반적으로 이 코드가 헷갈린 경우 여기 2번을 헷갈리는 분들이 많더라구요! 3. 그래서 다음 단계에서 만들어진 output을 이전 단계에서 합쳐주는 과정이 필요합니다!
안녕하세요, format 관련 내용 질문있습니다. counter = 0 def fibonacci(n): global counter counter += 1 if n == 1: return 1 if n ==2: return 1 else: return fibonacci(n-1)+ fibonacci(n-2) print(fibonacci(4)) print("{} {}".format(counter, fibonacci(4)) ) 이렇게 작성하면 counter값이 제대로 출력 되는데, print(fibonacci(4)) 을 삭제하고 출력하면 값이 0, 3 이렇게 출력됩니다. 이유가 뭔지 궁금해서 질문드립니다. 코로나 조심하세요!
전역 위치에 있는 counter를 활용하기 때문에, 한 번만 제대로 실행 결과를 확인할 수 있고, 두 번 실행하면 그 카운터가 계속 증가되어서 제대로된 값이 안 나옵니다...![확인 용으로 넣은 카운터] 따라서 두 번째 실행하기 전에 카운터를 0으로 초기화 해주셔야(counter = 0 을 현재 올려주신 코드 print() 함수들 사이에 넣어야), 카운터가 계속 증가되는 일 없이 출력됩니다.
안녕하세요 선생님! 이번 강의가 제 발목을 붙잡네요..ㅠㅡㅠ memo = {1:1, 2:1} def f(n) : if n in memo : return memo[n] else : output = f(n-1) + f(n-2) memo[n] = output return output print(f(10)) 이것 대신 memo = {1:1, 2:1} def f(n) : if n in memo : return memo[n] else : memo[n] = f(n-1) + f(n-2) return memo[n] print(f(10)) 이렇게 써도 상관 없을까요? 결과값은 똑같이 나오고 굳이 output을 지정해주고 다시 그걸 메모에 넣는 것이 크게 의미가 없는 것 같아서 output 을 만들어주는 대신 memo[n]에 함수(f(n-1)+f(n-2)) 를 바로 집어넣고 memo[n]을 리턴값으로 넣어 프린트해봤더니 과정도 똑같이 나오더라구요. 제 생각에 두번째 풀이도 별 문제 없는 것 같은데.. 혹시 output을 만들어주고 그 output을 memo[n]에 넣어 준 후 리턴값을 output 으로 지정하신 이유가 있을까요?
넵 큰 상관은 없습니다 'ㅁ' 위의 코드는 그냥 컴퓨터가 내부적으로 - 딕셔너리[키]를 할 때 이 키에 해당하는 값을 찾기 위해 약간의 시간을 더 투자하므로[배열이면 빠른데 딕셔너리는 약간 더 걸려서], 미리 다른 변수를 만들고 그걸 리턴하게 한 것입니다[memo[n] 횟수를 최대한 줄인 것].
return을 넣고 안넣고의 차이는 뭘까요? def f(n): if n == 1 or 2: 1 else : f(n-1) + f(n-2) 이것과 def f(n): if n == 1 or 2: return 1 else : return f(n-1) + f(n-2) 함수단원 들어가기 전까지는 return을 넣지 않고도 조건문이 출력 됐었는데 그건 함수'값'이 아니라 그런건가요?
선생님~ 질문에 대한 대답을 항상 잘해주셔서 너무 감사합니다. 한가지 더 질문이 있는데, 교재 p.237에 메모화 해서 피보나치 수열 구하는 코드 중에 dictionary[n]=output을 꼭 써야 하나요? 이 부분이 메모화 같긴 한데...이해가 잘 되지 않습니다. 제 생각에는 딕셔너리에 메모된 값으로 리턴하는건데 else 구문 뒤에 왜 굳이 써야하는지 의문입니다. 이미 메모화가 된거가지고 쓰는데요....
안녕하세요 선생님 ! 항상 영상 잘 보고 있습니다. 5-2 연습문제 1번을 도전하는 와중에 for 반복문이 제가 사용하기 더 편하다는걸 느끼고 def flatten(data): output = [] for i in data:
if type(i) == list:
for n in i:
if type(n) == list: output.extend(n)
elif type(n) == int: output.append(n) elif type(i) == int: output.append(i) return output example = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]] print("원본:", example) print("변환:", flatten(example)) 이런 식으로 코드를 짜 봤더니 결과적으로 리스트를 평탄화 하는데는 성공했습니다. 그러나 생각해보니 리스트 안에 리스트가 다중으로 중첩될 경우 for 반복문보다는 재귀함수를 사용하는 것이 훨씬 더 편리하다는 생각이 들었는데요 ㅠㅠ 일반적으로 리스트 평탄화 할 때는 대부분 재귀함수를 사용하나요?
일반적으로 반복문과 재귀함수 두 가지를 모두 사용할 수 있을 때는 반복문을 사용합니다. 하지만 현재처럼 몇 번 중첩된지 모르는 경우에는 재귀 함수를 사용해야 합니다![몇 단계까지 파고 들어갈지 모르므로] 예를 들어 윈도우에서 검색 등으로 파일을 찾으면 현재 예제에서 『리스트 = 폴더, 숫자 = 파일』처럼 만들면서 모든 파일을 뒤지며 찾게 되는데요. 몇 단계까지 파고 들어가야 할지 모르므로 재귀 함수로 만들어야 합니다!
@@윤인성 예약관련 안드로이드 앱을 만들고 싶은데, 파이썬으론 힘들다면서 java 를 공부 해야한다고 하던데.. 맞는 말인가요? ㅠㅠ 혹시 그렇다면 JAVA 를 공부하기 위해 인성님이 만드신 추천 교재나 커리가 있으실까요? 지금 전 첫파이썬, 혼공파로 파이썬을 이론 공부하고 있고. html 과 css 는 그렇게 완벽하게 알지 않아도 된다고 해서 웹페이지 따라 만들기를 통해 공부 중인데. 제가 목표로 하는 앱을 만들기 위해서 어떤걸 어떻게 공부해야 할지 감이 잘 오질 않습니다.. 근처에 학원에 java 관련 학원에 등록하려 했는데 커리가 웹컨텐츠 제작이지 앱만드는게 포커스는 아니라고 해서 또 이걸 어떻게 해야하나.. 싶어서 이렇게 장문의 질문 글 올립니다. 좋은 영상 항상 감사드리면서 이만 줄입니다
@@빛나리-p9m 안드로이드 개발은 기본적으로 프로그래밍 언어로 자바 또는 코틀린을 사용합니다. 저의 경우는 없습니다 ;ㅁ; [안드로이드는 너무 버전 업데이트가 많다보니 관리가 힘들어서 쓰지 않았습니다 ;ㅁ;] HTML과 CSS의 경우는 "웹 개발"을 할 때에 의미 있는 공부입니다. 만약 안드로이드 앱을 만들고 싶으시다면, 전혀 의미가 없습니다(아주 없지는 않겠지만 거의 없습니다).
@@윤인성 답글 정말 감사드립니다. 학원에 다니면서 java 를 배우고 이력서에 NCS JAVA 과정 이수 한줄 쓰는게 나은지. (학원에서 하는 JAVA 커리엔 또 HTML 이나 CSS 같은 걸로 몇주 할애하는거 같이 적혀있고) 바로 앱을 만들기 위해 독학으로 JAVA 나 코틀린 같은걸 공부 할지 고심이 많아서요 ㅠ_ㅠ
사실 언어의 난이도 표현은 그냥 "한국어가 어미조사가 많아 제일 어렵데", "무슨 소리야 중국어 외울 글자가 얼마나 많은데", "프랑스어는 시제가 몇 개인데 까부냐"정도로 크게 의미없는 것이라 생각합니다 'ㅁ' ...! PS. 결국 자유롭게 표현을 하려면 + 모든 언어가 어려워서[...]....
233쪽에서는 global counter를 작성해줘서 함수내에서 함수 외부의 변수를 참조할수 있게했는데 241쪽에 '3.14를 PI라는 변수로 설정한 상태' 부분에서는 함수 외부에 작성된 PI값을 global로 함수 내부에 작성해주지않았는데 코드가 문제없이 실행되는 이유가 궁금합니다.
강의 잘 들었습니다~~^^ 2번째 팩토리얼 구현에서 def factorial_2(n): if n==0: return 1 else: return n*factorial_2(n-1) 음수까지 가지 않는다는 조건이 필요 없는 건가요? n-1하게 되면 결국 0까지 갈 것이고, factorial_2(0)이면 1을 반환할 테고 다음에는 factorial_2(-1)인데 그걸 통제하는 조건문이 없는지 궁금합니다~!!
0이면 if n == 0으로 들어가서 return 1을 하므로, else 부분은 실행되지 않아서 factorial(-1)은 호출되지 않습니다. 물론 처음 함수 실행 때 factorial(-1)을 해버리면 무한하게 감소하므로 입력이 음수인지 유효성을 검사하는 과정이 있으면 좋습니다!
일반적인 개발에서는 그렇게까지 사용되지는 않으며, 사실 사용 되는 경우에도 이정도까지 복잡한 형태로 사용하는 경우는 많지 않습니다. 책의 문제로 나오는 폴더 순회하기 등의 고정적인 형태에 사용되는 경우가 많으므로, 일단 너무 어려우시면 넘어 갔다가 이후에 살펴 보시는 것도 추천드립니다.
236페이지 메모화 예제에서 15열에 dictionary[n] = output을 넣어야 할 이유가 무엇인가요? 제 생각에 이미 11열에 리턴값에 return dictionary[n]을 넣었고 딕셔너리 변수 선언 범위(1~2)를 넘으면 else 로 넘어가서 dictionary[n]을 output을 넣을 필요가 없지 않나요?
안녕하세요 저자님 !!! 혹시 236p에 global 키워드 질문 좀 드려도 될까요? new_list = [8,9] def 반전(리스트): new_list[0] = "전역변수 없이 바꿔짐.." for i in range(len(리스트)): new_list.append(리스트[-i-1]) 반전([1,2,3]) print(new_list) ---> >>> ['전역변수 없이 바꿔짐..', 9, 3, 2, 1] 이렇게 global new_list를 함수에 선언 안했는데, 에러도 없이 인덱스[0] 값이 수정되거나 .append()도 사용되어지고.. new_list 변수를 어떻게 참조할 수 있는건가요?ㅜㅜㅜ
정확하게는 "변수에 들어 있는 것이 값이 아니라 레퍼런스(주소)인 경우에는 global 키워드를 사용하지 않아도 괜찮음"입니다. 숫자, 문자열, 불 등은 global을 사용해야 합니다. 책의 범위에서는 "레퍼런스"가 무엇인지 설명하는 것이 복잡하므로, "오류가 발생할 때 넣으세요"라고 했는데요. 레퍼런스는 "주소"라는 의미입니다. 이게 C 언어 같은 곳에서 학생들 멘탈을 터는 몇 주 짜리 과정이라 할 수 있는 포인터 비슷한 것이라 댓글로 자세하게 설명할 수는 없지만, 간단하게 구분할 수 있는 예를 보여드리면 a = 10 b = a b += 10 print(a, b) # 10 20이 출력되어서, a와 b가 아예 다른 값이 됩니다. a = [] b = a b.append(10) print(a, b) # [10] [10]을 출력합니다. 즉 a와 b가 지칭하는 대상이 같습니다. 이렇게 되는 변수들은 "리스트의 값 자체"가 들어있는 것이 아니라, "리스트의 주소를 나타내는 레퍼런스"가 들어있는 자료형입니다. 이런 레퍼런스 자료형은 global 키워드를 사용하지 않아도 내부에서 사용할 수 있습니다.
@@윤인성 아....... 저자님 너무나 감사합니다. 예시까지 너무 구체적으로 설명해주셔서 100%로는 아니지만, 레퍼런스 자료형이 내부에서 왜 사용이 가능한 지 충분히 이해했습니다. 늦은 시간에도 매번 질문 받아주시고 존경스럽습니다. 쌀쌀해졌는데 건강 유의하시고, 오늘도 좋은 밤 되시길 바라겠습니다ㅜㅜ :)
안녕하세요 243p 문제에서 질문이 있습니다. def flatten(data): output=[] for element in data: if type(element) is not list: output.append(element) else: flatten(element) return output example= [[1,2,3],[4, [5, 6]], 7, [8, 9]] print(flatten(example)) 코드를 이렇게 작성하면 결과가 7이 나오던데 어느 부분이 잘못된 걸까요? 항상 감사합니다
안녕하세요 질문이 있습니다. counter = 0 def fibonacci(n): print("피보나치{}를 구합니다.".format(n)) global counter counter += 1 위는 교재 233쪽인데, 이것 대신에 counter = 0 def fibonacci(n): print("피보나치{}를 구합니다.".format(n)) counter = 0 counter += 1 을 써도 프로그램이 잘 돌아가더라고요.(global counter 대신 counter = 0 으로 바꾸었습니다) global로 변수를 받지 않고 저런 방법으로 받아오는 것에 어떤 원리가 있는 건지 궁금합니다. 감사합니다!
메모 = {1:1, 2:1} def f(x): if x in 메모: return 메모[x] else: output = f(x-1)+ f(x-2) 메모[x] = output return output print(f(150)) 이 과정에서 f(x-1)+f(x-2) = output이라든지 output = 메모[x] 와 같이 순서를 바꿔적으면 오실행이 안되는 이유가 무엇일까요?
답변 감사합니다. 그러면 메모화의 원래 역할이 재귀함수가 느리게 작동하는 것을 극복하기 위해서인데 이 코드에서 함수 내부에 딕셔너리를 선언했을 때 해당 역할을 못하기 때문에 결과가 느리게 출력되는 문제가 발생한 것인가요?? 16번 째 줄에 return output에서 코드에서 최종적으로 출력해야 하는 것은 어차피 output이여서 dictionary가 사라지는 것은 문제가 되지 않는다고 생각했습니다. 실행해봤을 때 결과가 출력이 아예 안되는게 아니라 느리게 되는 것을 확인해서 이런 의문이 들었습니다.
@@홍선아-n6k 정확하게 어떤 코드를 사용하신지 모르겠지만, 함수 맨 앞에 그냥 만들어주셨다면 아무 효과도 못하고 사라집니다. 내부에 선언하면 아무 의미가 없습니다[딕셔너리가 남지 않으므로]. 직접 확인해보실 수 있는 방법은 - 1번 경우: 딕셔너리를 밖에 선언하고, 함수의 첫 번째 줄에서 딕셔너리를 print() 함수로 출력 - 2번 경우: 딕셔너리를 함수 첫 번째 줄에 선언하고, 그 아래에 print() 함수로 출력 해보고 확인해보시는 것입니다...!
안녕하세요! 11분에 나오는 메모이제이션 코드를 따라 작성해봤는데 1000 정도나 더 큰 수를 넣으면 에러가 뜨는데 왜 그런건지 궁금합니다 (약 900 정도까지는 값이 나와요) 아래는 코드와 에러에요 메모 = { 1: 1, 2: 1 } def f(n): if n in 메모: return 메모[n] else: output = f(n-1) + f(n-2) 메모[n] = output return output print(f(1000)) Traceback (most recent call last): File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 9, in print(f(1000)) File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 6, in f output = f(n-1) + f(n-2) File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 6, in f output = f(n-1) + f(n-2) File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 6, in f output = f(n-1) + f(n-2) [Previous line repeated 991 more times] RecursionError: maximum recursion depth exceeded
혹시 하나만 더 여쭤봐도 되나요? 학교 과제로 피보나치 수열을 프로그래밍으로 표현하는 걸 해보고 있는데, 공부하다 보니 다이내믹 프로그래밍(Dynamic Programming) 이랑 메모이제이션(Memoization)이 같은 건지, 메모가 DP의 한 방법인건지 모르겠는데 알려주시면 감사하겠습니다!
유튜브 강의가 있다고 써있긴 했는데 형식상의 강의 일 것 같아서 안찾아보고 chatgpt한테만 물어보고 이것도 이 유튜브를 검색한게 아니라 재귀함수로 검색한건데 낯읽은 책페이지가 보이더라구요 보니까 저자와 똑같은 유튜브 채널 이름... 퀄리티가 좋아요 진작 찾아볼껄 그랬어요 잘보겠습니다
감사합니다!
추가로 현재 개정판 강의가 훨씬 자세하게 되어 있어서,
개정판 강의를 보시는걸 추천드립니다!!
현재 시간 02시 30분 확인 2번 문제 영상 강의 한번 정독하고 몇 시간째 쳐다보고있는데 이해가 가지않는다.. 자고 일어나서 다시 처음부터 봐야겠다..
Thanks
11:41에서 각각 사용된 소괄호 중괄호 대괄호의 뚜렷한 역할을 알려주실수있을까요? 직접코딩할떄 무슨괄호를 써야할지 헷갈려서 ㅠㅠ
소괄호: 함수 호출
중괄호: 딕셔너리 생성
대괄호: 인덱스 또는 키로 요소에 접근 입니다.
안녕하세요 선생님
혼공파 페이지245, 05-2 확인문제 2번 질문있습니다.
앉힐수있는최대사람수=10
전체사람수=100
앉힐수있는최소사람수=2
count=0
def 문제(남은사람수, 앉힌사람수):
global count
if 남은사람수 < 0:
return
elif 남은사람수 == 0:
count=count+1
return
for i range(앉힌사람수, 앉힐수있는최대사람수+1):
문제(남은사람수-i,i)
문제(전체사람수,앉힐수있는최소사람수)
print(count)
이렇게 코드를 넣었는데요 ~~
invalid syntax라는 에러메시지가 뜨네요 뭐가 잘 못 된걸까요 ??
알고리즘퍼즐 69 동영상보고 따라했는데 잘 안되네요 ㅜㅜ
invalid syntax는 구문에 오류가 있을 때 발생합니다!
따라서 괄호가 안 닫히지는 않았는지, for if while 등의 조건문 형태가 잘못되지 않았는지 살펴주시면 됩니다.
다음과 같이 여기에 오류가 있다고 하므로
여기 구문을 살펴보시면 되겠는데요.
for i range(앉힌사람수, 앉힐수있는최대사람수+1):
^
SyntaxError: invalid syntax
for i in range(ㅇㅇ) 형태로 가운데에 in을 넣어주시면 됩니다!
질문이 많아서 죄송합니다ㅠ
memo = {
1: 1,
2: 1
}
cou = 0
def fib(n):
global cou
cou += 1
if n in memo:
return memo[n]
else:
output = fib(n-1) + fib(n-2)
memo[n] = output
return output
print(fib(5))
print("피보나치5 계산한 횟수(7이 나와야 맞음):", cou)
print(fib(10))
print("피보나치5 계산한 횟수(17이 나와야 맞음):", cou)
print(fib(50))
print("피보나치5 계산한 횟수(97이 나와야 맞음):", cou)
이것의 결과가
5
피보나치5 계산한 횟수(5가 나와야 맞음): 7
55
피보나치5 계산한 횟수(17이 나와야 맞음): 18
12586269025
피보나치5 계산한 횟수(97이 나와야 맞음): 99
이렇게 나왔습니다.
한번 피보나치 함수를 돌리고 나면 cou의 값이 0으로 안돌아가고 1씩 더해지게 되나요?
왜 한번 프로그램 돌릴때마다 1씩 더해져서 cou가 나오는 건지 모르겠습니다.
감사합니다.
앗 질문을 조금 더 자세히 주실 수 있을까요...! 일단 cou를 외부에 선언했으므로, 함수 실행 때 초기화하는 구문이 없어서, 계속 더해집니다.
@@윤인성 옙 다시 한번 생각해보고 모르겠으면 질문드리겠습니다. 감사합니다!
232쪽 예제에서
if n==1:
return 1
elif n==2:
return 1
부분을
if n==1 or 2:
return 1
이렇게 하면 왜 제대로 된 결과가 안 나오는 건가요,,?ㅜ
or 연산자는 양쪽 피연산자로 불이 와야 합니다.
n == 1 or 2처럼 숫자(2)가 오면 이상한 결과가 나옵니다!
다음 강의의 2분 19초 정도를 참고해주세요!
ruclips.net/video/SZHj7fS-HX0/видео.html
@@윤인성 감사합니다!! 혹시 개정판이랑 이전 책 많이 다른가요,,,??? 저는 이전 판으로 강의 보고 있는데 개정판을 새로 사야하나 싶어서요!
@@user-th6vd8ek5i 내용이 120페이지 정도 추가되었다이지 기본 내용은 큰 차이 없습니다! 유튜브 강의는 무료이므로 그냥 강의만 살펴보셔도 괜찮습니다!
메모화 이용한 경우 피라미드 한쪽 줄만 계산하면 끝.
1. f(5) =
2.f(4) , f(3)
3. f(3) , f(2)
4. f(2) = 1, 5. f(1) =1
좀 더 자세히 알 수 있을까요
@@DailySangmin 피라미드는 9:50에 나오는 그림을 말하는 거고요.
댓글에 적은건 메모화를 이용할때 f(5)를 구하는 과정을 그 피라미드 방식으로 적은 것입니다.
f 앞의 1. 2. 3...는 코드의 흐름 순서고요.
f(5)구하려면 f(4)와 f(3)을 구해야 하고
f(4)와 f(3) 중 f(4)를 먼저 구해야 하니까 다음은
f(4)를 구해야 하고 그러려면
f(3)과 f(2)구해야 하고
f(3)구하려면
f(2)와 f(1)구해야 하는데 이 값은 함수에 1이라고 정해져있으므로 구해졌고
그다음 위에서 넘어갔던 f(2) 구할차례인데 메모에 있으므로 계산 안하죠. 나머지도 다 메모에 있습니다.
피라미드처럼 전부 계산 안하고 피라미드 맨 왼쪽부분만 계산하면 된다는 겁니다.
위에
2:20 n!=n*(n-1) 에서 위키에 있는 것처럼 끝에 !이 빠져 있는 것이지요? 자막이 잘못 된 것이지요?
뒤에 !가 있어야 합니다 @_@!
재귀함수로 구현한 피보나치 수열에서요. (스스로 이해해보려고 했는데 도저히 안되는군요 ㅠㅠ) def fibonacci(n): ...생략.... return fibonacci(n-1)+fibonacci(n-2)에서 말이죠. 만약에 n에 5가 들어가면 리턴 값이 fibonacci(4)가 되면 뒤에 남은 더하기 연산(fibonacci(n-2))은 마저 하는 건가요, 아님 다시 fibonacci함수로 돌아가는 건가요? 전개가 어떻게 되는 건지요?
한 번 fibonacci 함수 앞에
print("현재 위치: fibonacci({})".format(n))
등을 넣어서 출력해보시는걸 추천드립니다!
봐도봐도 이해 안되는 부분이 있어서 문의 드립니다. 메모화 패턴이 마치 for 문처럼 반복되는 이유가 뭔지 도무지 이해가 안됩니다. if에서 return 전 n 값을 출력해 보고, else에서 output 연산 후 n을 출력해 보면 변화 하는건 알겠는데, 값이 왜 증가가 되는지 이해가 안되는데, 설명해 주실 수 있을까요? f(10)을 넣었다고 가정하고, if 에서 return 전 print(n) 을 해보면 2 -> 2 -> 4 -> 6 -> 8이 출력되는데 n이 증가되는 이유를 모르겠네요... ㅜㅜ;
반복문과 완전히 다르게 수학의 점화식 형태로 계산이 이루어집니다.
f(3) = f(2) + f(1)
→ f(2)와 f(1)은 각각 1이므로 = 2가 됩니다.
f(4) = f(3) + f(2) = {f(2) + f(1)} + f(2)가 됩니다.
f(5) = f(4) + f(3) = {f(3) + f(2)} + {f(2) + f(1)} = ...생략...
왼쪽에서 오른쪽으로 쭉 전개를 하고
리턴으로 값을 확정하면서
오른쪽에서 왼쪽으로 다시 차례차례 계산되며 빠져나옵니다.
@@윤인성 답변 감사 드립니다. 그런데 아직 이해 안되는 부분이 있어서 추가로 문의 드립니다. f(10)을 입력했을 때 n이 3이 됐을 때 output = f(2) + f(1) = 2가 되는 것은 이해 됐고, dic[3]=2가 입력되는 부분까지는 이해가 되는데요, f(3) 이후 f(4) -> f(5) -> ... -> f(10)까지 반복 될 수 있는 원리가 이해되지 않네요... 부탁 드립니다.
@@sanghyunyoon6727 반복이 되는 것이 아닙니다 @_@ , 재귀로 이루어집니다. 현재 어떤 부분을 이해 못하고 계신 것인지 설명만으로는 알 수가 없어서, 코드의 실행을 실제로 하나하나 손으로 직접 계산해보시면 좋을 것 같습니다!
선생님 처음 들을 때는 이해가 가지 않았는데 복습을 하니 정말 쏙쏙 이해가 됩니다. 이렇게 좋은 강의 무료로 해주셔서 정말 감사합니다.
감사합니다
00:00
인성쌤 ㅜㅜㅠㅠ
def factorial(n):
if n == 0:
return 1
else:
return n* factorial(n-1)
print("4! =",factorial(4)) 라는 코드에서
n* factorial(n-1)
라는 코드 결과 값이 왜 n * (n-1)! 가 되는 지 잘 이해가 안 가요,,ㅠㅠ
너무 기본적인 거라 물어보는 것도 죄송한데 정말 짚고 넘어가지 않으면 안될 거 같아서 인터넷에서도 몇 번 찾아봤는데
잘 안 나와서요,,
n* factorial(n-1)
결과 값이랑
n* (n-1) 결과 값이랑 같아야 하는 거 아닌가요??ㅠㅠ 결과가 다르게 나와서 왜 이렇게 나오는지 궁금해요..
정말 여쭤보기도 죄송한 부분이지만 여쭤볼 곳이 마땅찮아서 ..ㅠㅠ죄송해요
`n - 1`과 `factorial(n-1)`이 코드 자체가 다르므로 같지 않습니다!
factorial(a) = a * factorial(a - 1)로 작동하므로
factorial (a - 1) = (a - 1) * factorial(a - 1 - 1)이 됩니다.
이게 계속 반복적으로 동작해서, 계속해서 파고 들어가게 됩니다!
공부 단계에서는 질문을 빨리 주실수록
공부 속도가 빨라지므로 죄송해하시지 마시고 막 물어봐주세요 'ㅁ' ...!
@@윤인성 print("감사합니다" * 100)...ㅠㅠㅠㅠ
@@윤인성 선생님 진도를 나가다가 결국 이 부분에서 이해가 안 간 상태로 진행하다 보니 재귀함수 자체에서 막혀버렸습니다..
응용도 잘 안되네요,..ㅠㅠ '반복 적으로 동작해서, 계속 파고 들어가게 됩니다!' 라는 부분이 잘 이해가 안 가요ㅠㅠㅠ
다른 코딩 수업에서 진행하신 부분 중에 테이블 나눠서 앉는 문제 설명하시면서 말씀하신 노드랑 엣지 사용하는 트리를 보여주시면서 이해시켜주시는 수업을 반복해서 몇 번이고 봤는데 이 재귀함수 알고리즘이 이해가 안 갑니다 ㅠㅠㅠㅠㅠㅠ 그냥 함수자체를 외워버릴까요,,?ㅠ
어떻게 나아갈지 모르겠습니다.. 무시하고 일단 진도 나가도 성격 상 확실히 짚고 넘어가지 않으면 안되는 타입이라.. 어떻게 이해를 하면 좋을까요..? 다음 강의 문제 부분에서
def flatten(data):
output = []
for i in data:
if type(i) == list:
output += flatten(i)
else:
output += [i]
return output
example = [[1,2,3],[4,[5,6]],7,[8,9]]
print("원본:",example)
print("변환:",flatten(example))
이 코드 중에서
output += flatten(i)
를 실행시키면 어떤 결과가 어떻게 도출됐는지 도저히 이해를 할 수 가 없습니다..흑흑
연말에 너무 죄송하지만 갑갑한 마음에 여쭤봅니다 선생님..ㅠㅠㅠㅠ 새해 복 많이 받으세요 항상 친절한 강의와 답변 감사드립니다!
@@강희원-i4h 넵 함수 자체를 외워버리는 것도 좋습니다.
재귀 함수가 알고리즘 대회에서 꽤 고급 스킬이고
+ 이게 실무에서도 "잘 못 쓰면 쓰지 말아라"라고 하는 금단의 위험한 스킬[?] 같은 것이라서
= 실무 분들도 많이들 잘 못 쓰고 안쓰려고 하는 편입니다.
따라서 일단 강의를 다 끝내고 다시 보시는 것도 추천드립니다!
새해복 많이 받으세요!!
@@윤인성 # f6
# f5 f4
# f4 f3 f3 f2
# f3 f2 f2 f1 f2 f1 f1
# f2 f1 f1 f1 f1
# f1
다 괜찮은데 피보나치 재귀함수가 도무지 이해가 안가서 책한권 다돌리고 다시 몇번을 봐도 이해가 안 가서 미칠지경이었는데
저런 식으로 이해 해보니까 이해가 갔네요 너무 하찮은 이해지만 진짜 해보고 눈물났습니다.. 수학을 못해서 뭔가 벽을 느낀거같고 함수만 나오면
이해하기가 어려워서 그만두고 싶었는데 이해가 조금은 된거같습니다.,ㅠ
감사합니다..
이게 참 여렵다고 느낄수 있는 내용이었는데요, 동영상 강의랑 직접쓰신 혼공파를 잘 곱씹으면서 하나하나 이해할수 있었습니다. 매번 수많은 질문에 답해주시는 것에 무한한 감사를 드립니다 ^^.
메모화를 이용한 피보나치수열 문제에서 f(5)=f(4)+f(3)
f(4)=f(3)+f(2)
f(3)=f(2)+f(1)
이처럼 하나하나 값을 알아야 구할수 있는데 코드 순서를 확인해 보니 f(3)를 메모에 추가하고 그 다음 f(4)를 메모에 추가하는 순서인데
이처럼 f(4),f(3)의 값을 따로따로 구한는게 아닌 작은 값부터 구하는 순 인가요?
호출은 큰 값에서 작은 값으로 내려가고
리턴은 작은 값에서 큰 값으로 돌아 올라오게 됩니다!
메모를 추가하는 과정은 리턴 시점에 이루어지므로 → 작은 값부터 구해 올라와지는 것처럼 보이게 됩니다!
그럼 f(4)+f(3) 에서 f(4)의 값을 구하기 위해 f(3)의 값을 구해dictionary에 저장 하고 옆에 +f(3)의 값은 이미 저장해 놨기 때문에 바로 꺼내어 계산하는 방식인가요?
@@shy-de7mb 넵!
@@윤인성 이제 다음강의를 들을수 있네요.
감사합니다.!!
재귀 함수가 여지껏 했던 것중에 제일 어려운거 같습니다 이해하는데 애먹었어요 ㅜㅜㅜ
선생님안녕하세요 혼자 복습중 궁금증이 생겨 질문드립니다.
while 반복문 공부중에서
1. i = 0
2. while i < 10:
3. i += 3
4. print(i)
------------------
PS C:\혼자공부하는파이썬> python ex01.py
3
6
9
12
왜 12가 나오는 걸까요? 10보다 작게 입력했는데. 이 부분이 궁금합니다. (+ 추가 '+='는 무슨 뜻인가요?)
a += b는 a = a + b를 의미합니다.
마지막 반복에서
(1) i의 초기값은 9입니다.
(2) 그래서 i < 10에 포함되므로 반복문 내부로 진입합니다.
(3) i += 3을 하므로 i는 12가 됩니다.
(4) print(i)하므로 12가 나옵니다.
(1) 이제 i는 12입니다.
(2) i < 10에 포함되지 않으므로 반복문을 벗어납니다.
해서 12는 출력이 됩니다!
def factorial_2(n):
if n == 0:
return 1
else:
return n * factorial_2(n-1)
print(factorial_2(10))
재귀함수 부분에서
else:
return n * factorial_2(n-1)
return n 은 10으로 고정이 되있고
factorial_2(n-1)의 n이 0이 되서 if 문으로 갈때까지 도는게 맞나요? 제가 잘 이해한건지 모르겠어서 질문드립니다
처음 return n이 다음과 같이 쭉 대체되며 계산됩니다![표기를 간단하게 하려고 연산자 우선순위 무시했습니다]
return n * factorial_2(n-1)
return n * n-1 * factorial_2(n-2)
return n * n-1 * n-2 * factorial_2(n-3) * .... * 0
@@윤인성 factorial_2(10-1), factorial_2(9-1), factorial_2(8-1),...(1-1) 이렇게 n의 수치가 줄어드는게 아니고
뒤에 -1, -2, -3...-10 으로 재귀될때마다 수치가 바뀌는건가요?
재귀 한번 할때마다 factorial_2(n-1-1) 이렇게 -1이 늘어나는건가요?
@@sangwoonoh7438
factorial(n)에서
n의 값이 그냥 계속 떨어질 뿐입니다.
이게 실질적으로 n으로서 계산되는게 아니라
10 들어가고, 9 들어가고, 8 들어가고 등으로 값이 들어가는거라
복잡하게 생각하지 마시고 그냥 값을 하나씩 넣어보면서 손으로 어떤 순서로 계산되는지 확인해보시기 바랍니다.
조기리턴 관련 질문입니다.
들여쓰기를 줄여 주기에 조기리턴을 이용한 코드가 요즘추세다 라고 하시는데
이게 어떻게 좋다는 의미 인지가 궁금합니다.
막연히 짐작하기에 혹시, 기계어 코드로 변환 될때 들여쓰기가 있는것과 아닌것의 코드 복잡도가 달라서 그런 걸까요?
항상 좋은 강의 감사합니다.
"들여쓰기가 줄어드는 것"이 장점입니다!
코드의 가독성이 좋아집니다.
현대 개발에서는 아주 성능이 크리티컬한 부분이 아닌 이상 코드의 성능보다 가독성을 중시합니다. 그래서 가독성이 좋아지는 것은 굉장히 큰 이득입니다!
사내 교육 시험 준비로 연습문제만 다시 듣습니다. 두번째 들으니 처음 들을때 놓쳤던 부분도 보이고 이해도 더 잘되네요. 그런데 혼자 코딩하려면 막막한게 일단 외워야할까요? 뭔가 응용은 안되고 이론만 아는 정체된 느낌이에요. 공부의 절대량이 부족한거겠죠? 나름 시간투자는 많이 했는데.. 뭔가 머릿속 코딩에 대한 전구가 안켜진 느낌.. 좋은 방법이 있을까요?
두 가지 이유 때문이라고 생각하는데요.
1. 지식의 문제
일반적으로 초중고대학학교 16년 동안 수학을 배우면, 이게 모두 단순한 "암기"처럼 느껴집니다. 하지만 "암기"를 하면서도 조금씩 계속해서 나아가고 있는 것은 분명합니다. 프로그래밍도 초기 단계에서는 오랜 기간 동안 그런 생각이 드십니다. 하지만 분명 계속해서 나아가고 있는 것입니다.
.
2. 방향성의 문제
공학 공부도 대학교까지는 진짜 모든걸 외우는데, 회사에서 과제를 받는 활용의 영역부터는 이게 암기의 영역이 아니게 됩니다. 프로그래밍도 실제로 해결해야하는 "답이 없는 과제"를 만나실 때부터 "내가 암기 이상의 것을 할 수 있었구나"하는 느낌을 받으실 수 있을 것이라 생각합니다!
.
사실 알고리즘 시험과 같은 영역은 활용의 부분이라고 보기 약간 애매해서[대학교 때에 공학 공식들 외우는 기분이라], 현재 공부에서는 그런 느낌을 받을 수 밖에 없을 것이라 생각합니다!
.
단순 공부와 함께 활용을 함께 진행하시면 약간 그런 느낌이 사라지리라 생각합니다!
@@윤인성 네 업무는 결과물이 나와야 하는 프로젝트라 이제 첫걸음을 내딛다보니 막막했는데 꾸준히 하는 수밖에 없겠네요. 답변 감사합니다. 용기내어 계속 해봐야겠어요.
@@윤인성답변 감사합니다. 좋은 책 꾸준히 출간해주세요~
재귀함수로 팩토리얼 구하기 소스코드 factorial_recursion.py 에서
if n==0: 에서 return 1이라고 해버리면 n!=0일때 n*factorial(n-1)을 내다가 결국 n==0일때 리턴값으로 1만 줘버리는거 아닌가요? ㅠ 헷갈리네요
재귀 함수는 직접 출력을 해보시는 것이 실행이 어떻게 되는지 이해하기가 쉽습니다.
1. 함수 정의 바로 아래에
print("factorial({})을 실행합니다".format(n))를 넣고
2. 리턴 부분의 return n * factorial(n - 1)을
temp = n * factorial(n - 1)
print("{n} * factorial({})의 계산 결과 = {}".format(n, n-1, temp))
return temp
라고 적어서 함수의 시작과 끝에 출력을 해보시게 하면
"아아 이게 이렇게 실행되는거구나!!"하고 흐름을 볼 수 있을 것입니다!
감사합니다^^
제가 질문을 올렸는데
자꾸 지워지는거 같은데
혹시 설정같은거 해놓으셨나요?
6일 전에 올리신 "실험"이라는 댓글 이후로는 올리신 댓글이 없는 것으로 나옵니다. 구글 자동 필터링에 걸린 것도 없습니다.
.
그 이전에 올리신 댓글 12개는 모두 정상적으로 올라가 있습니다.
안녕하세요 선생님! 코린이 입니다..책에 나와있는지 잘 모르겠지만 제가 해외에 있고 책을 현재 받아보기가 어려운 상황이라 부득이하게 영상으로만 보고 있어요. ㅠㅠ 팩토리얼(3:36)을 보다가 코드 순서를 정리해봤는데 이게 맞는지 궁금해서 댓글을 남기게 되었습니다. 저 6줄 안에 총 17번으로 코드가 읽히는 것이 맞나요? 맞다면 혹시 지정해준 함수 내부의 조건문이나 반복문이 길어지고 함수 속에 함수가 또 들어가고.. 그러면 결국 속도에 영향을 많이 줄까요? 코드가 달랑 6줄인데 17번이나 읽는다는게 왠지 비효율적으로 느껴져서요.. ㅠ_ㅠ 그리고... 이북 출간 생각 없으실까요...? ㅠ_ㅠ 이거 말고 다른 강의들도 책이랑 같이 보고 싶은데 배보다 배꼽이 더 커서 영상으로만 보고 있습니다ㅠㅠ
def factorial(n): #2 #6 #10 #14
if n == 0 : #15
return 1 #16
else : #3 #7 #11
return n * factorial(n-1) #4 #8 #12
print(factorial(3)) #1 #5 #9 #13 #17
현재 5,9,13,17이 순서가 약간 잘못되어 있습니다.
이걸 제거하고 12번부터 시작한다면[factorial이 기니까 f로 적었습니다]
12. 2 * f(1) 해야하네
14. f(1) 하자
15. n == 1이네
16. return 1하자
[그 상위에서 f(1)을 호츌했던 곳으로 리턴][#12]
17.return 2 * f(1)[=1]니까 2 리턴하자
[그 상위에서 return 3 * f(2)했었던 쪽으로 리턴][#8]
18. return 3 * f(2)[=6]이니까 6리턴하자
[그 상위에서 print(f(3)했었던 쪽으로 리턴][#1]
19. print(f(3)[=3]) 구했으니 3 출력하자
해서 돌아 나오게 됩니다.
17번 정도 실행은 큰 문제없습니다. 일반적으로 입력(현재 코드에서 3)이 들어갈 때 함수 흐름이 몇 번 실행되냐가 중요한데[알고리즘 배울 때 오더 표기(빅오 표기)를 배웁니다].
현재 코드는 f(3), f(2), f(1)로
입력 크기 3만큼 실행되는 코드라
실행 획수가 입력 크기 n과 비례합니다.
이건 시간적 관점에서는 좋은 알고리즘입니다.
[입력이 1억이어도 1억 번만 돌리면 되므로]
이 다음에 나오는 예제 중에 (메모화가 없는) 피보나치 수열은 함수가 한 번 실행 될 때 내부에서 두 개씩 타고 들어가야 해서 2^n과 비례하는 알고리즘이 됩니다. 이건 입력이 10이면 대충 1024번, 20이면 대충 1,048,576번 반복합니다[입력이 1억이면(...), 읽을 수도 없을 만큼 처리가 실행되어야 합니다].
이런게 비효율적인 알고리즘입니다!
@@윤인성 아! 저는 return을 하면 무조건 함수 밖으로 나간다고 생각했는데 아직 f(n)이 남아있는 상태에서는 당연히 함수 안을 도는거였네요! 생각해보니 함수 밖을 나가면 그것도 출력해야 하니 답이 하나가 아니라 여러줄로 나오고요. 깔끔하게 이해됐어요!! 시간 내 주셔서 이렇게 정성스럽게 답변 주셔서 정말 고맙습니다 :) 그리고.. 정가여도 좋으니 이북 출간 제발 고려해주세요 ㅠ_ㅠ 열심히 광고보며 보답하고 있지만 책도 꼭 구매하고 싶어요ㅠ_ㅠ 늘 좋은 강의 감사합니다!
함수는 재귀 호출하면
마트료시카 인형처럼 한 단계씩 들어갑니다.
5겹이면
return을 한다고 5겹을 한 번에 빠져 나오지 못하며
한 겹씩만 빠져나올 수 있습니다!
이북은 작년에 한국 인터넷에서 거대한 pdf 공유 사례가 발생해서 ㅠㅁㅜ [수 백 명이 수 백 권을 공유하는 카톡방 등이 생겨서], 당분간 힘들지 않을까 싶습니다 ㅠㅁㅜ
@@윤인성 답변 고맙습니다! + 그런 몰상식한 사람들이 있다니... 저작권 무서운 줄 모르고... ㅠㅠㅠㅠ 이쪽에서 받아볼 수 있는 방법을 찾아볼게요 ㅠ_ㅠ 늘 적게 일하시고 많이 버시기 바랍니당!
233쪽 재귀 함수로 구현한 피보나치 수열(2)에서 궁금한 점이 있어서 질문 드립니다! 21열을 작성하지 않고 19열까지만 작성하면 fibonacci(10)의 값이 출력되는데 21열을 작성하면 fibonacci(10)의 값이 출력되지 않고 21열만 출력되는 이유가 궁금합니다!
제가 질문의 의도를 정확하게 파악한 것인지 모르겠는데
화면에 무언가를 출력하려면 반드시 print() 함수를 사용하셔야 합니다.
20번째 줄과 21번째 줄에서 print() 함수로
"---"과
"fibonacci(10) 계산에 활용된 덧셈 횟수는 {}번입니다"를 출력하므로
이를 안 쓰면 이 두 줄이 출력되지 않습니다.
점점 잘생겨져보입니다.
강의 진행하면서 친구들이 끌고 가서 보톡스도 맞고 필러도 맞고 했었습니다[...]!
245쪽 확인문제 2번 이해하는데 너무오래걸렸네요.. 꾸역꾸역 암기하다보니까 깨달음을 얻으니 뿌듯하네요 ^^
전체 강의를 거의 다 들었는데요, 이 재귀함수가 가장 이해가 안 되네요 TT
사실 실무에서는 많이 사용되지 않아서[입사 시험에서는 보지만 😢], 일단 넘어가시고 + 개발에 조금 익숙해지면 알고리즘 대회 책들을 보며 그때 파보셔도 괜찮습니다!
교수님 강의 잘 듣고 있습니다.
return 키워드의 궁금한 점이 있습니다. 자료 없는 return은 만나는 순간 그 함수가 종료되는데
자료 있는 return 의 경우 어째서 for를 사용하지 않았는데도 계속 반복하는지 이해가 잘 안되네요.
예제)
def f(n):
if n == 1 or n == 2:
return 1
else:
return f(n-1) + f(n-2)
print(f(10))
위의 예제 경우 for가 없는데 여러번의 계산을 진행하는지 이해가 되지 않습니다.
함수 내에서 또 함수를 호출하기 때문에 반복처럼 동작합니다. 프로그래밍에서 반복을 만드는 것은 크게
- 반복문
- 재귀호출[지금 보여주신 코드]
로 구분할 수 있습니다!
@@윤인성 답변 감사합니다. 반복을 하기위해서는 for만 알고 있었는데 return으로도 할 수 있다니까... 쉽게 와 닿지 않네요 ㅋㅋㅋ 많은 연습이 필요할 것 같습니다.
return 으로 반복하는게 아니라 함수 내부에서 함수를 호출해서 반복되는 것입니다.
@@윤인성 함수 호출이란 개념을 다시 이해해야겠네요ㅎㅎㅎ 답변 감사합니다!!
선생님 질문 댓글은 처음인 것 같습니다.
피보나치 count 관련 질문입니다. 9:00
선생님이 적어주신 대로 실행을 시켜봤는데 count가 자꾸 0으로 출력이 됩니다.
어떻게 해야 count가 함수에 10을 넣었을 때 정상적으로 109가 나오나요...
전체 코드를 한번 올려주실 수 있을까요!
@@윤인성 헉 죄송합니다.
함수가 여러 개 중복되어 있어서 제가 이름을 바꿔서 썼었는데 실수를 해버렸었네여!!
선생님 메모화 파트를 공부중인데 이해가안되는게 있어서 질문드려요 ㅜㅜ
else:
output=fibo(n-1)+fibo(n-2)
dictionary[n]=output
return output
이구문을 통해서 예를들어 "n=3일 떄 dictionary에는 n=3일 때의 key값이 없으니까 dictionary[3]=output으로 딕셔너리에 key와 그 값이 추가된다" 라고 이해하면 되는건가요? 그리고 "그 n의 값들이 증가함에 따라 dictionary에 추가 되어 계산없이 사용이 가능하다 "라고 이해를 했는데 맞는지 궁금해서 글써봅니다... 조금 어려워지네요 ㅜㅜ
넵 맞습니다!
@@윤인성 감사합니다~
243쪽 확인 문제 1번을 이런식으로 data의 길이를 받아와서 range로 돌려서 풀면 안되는 이유가 궁금합니다.ㅠㅠ
def flatten(data):
output=[]
for i in range(len(data)):
if type(data[i])==list:
output=output+flatten(data)
else:
output.append(data[i])
return output
example=[[1,2,3],[4,[5,6]],7,[8,9]]
print=("원본:",example)
print=("변환:",flatten(example))
range로 돌리는 것은 문제가 없습니다!
중간에 flatten(data)를 flatten(data[i])로 바꿔주세요!
11:03 7행에 메모[n] = output 을 작성해주실때 "한번 계산했던 내용들이기 때문에"라고 언급해주셨고,
12:01 "이는 한번 계산했던 것은 더 계산하지 않고 그냥 메모했던 것을 다시 확인하기 때문"이라고 언급해주셨습니다.
실제로 메모[n] = output을 작성하거나 하지 않을 때, 속도 차이가 컸습니다.(메모화 여부로 판단됩니다.)
메모[n] = output을 작성함으로써 정확히 어떤 부분이 계산되지 않는지에 대한 개념을 조금 더 상세하게 듣고 싶습니다.
그냥 보이는대로 해당 if 조건문 아래가 실행 안 됩니다. 거시적으로 설명하면 "함수를 해당 매개변수로 계산한 결과"가 추가 계산되지 않습니다.
@@윤인성 감사합니다.
람다 부분까지 공부를 하다가 도저히 어려워서 책을 구매 후 복습 중에 있습니다 ㅠㅠ
6행에서 재귀함수를 다시 실행함으로써 그 결과 값이 7행을 통해, 1행에 추가되고
그로 인해 if 조건문 이하가 실행되지 않음을 깨닫는데에 시간이 소요되었습니다.
답변 감사합니다.
3일째 이해가 안되는게 있어서 질문드립니다.
243쪽 확인문제 1번에서 if 구문에서 output += flatten(item) 부분이 이해가 안됩니다. 제 생각에는 재귀함수인 flatten(item)만 써서 함수 호출하고 리스트 평탄화를 시켜서 else 구문으로
들어가게 되면 append 함수에 의해서 output에 리스트에 요소가 추가 된다고 생각합니다. output += 을 왜써야하는 지 모르겠습니다.
def flatten(data):
output = []
for item in data :
if type(item) == list:
output += flatten(item)
else :
output.append(item)
return output
example = [[1, 2, 3],[4, [5, 6]], 7, [8, 9]]
print("원본:", example)
print("변환:", flatten(example))
1. += 연산자는 마치 "리스트.extend()"처럼 동작합니다. 즉 여러 개의 요소를 추가합니다. 반면 "리스트.append()"는 하나의 요소만 추가합니다.
2. 함수는 실행 때마다 다른 변수 공간을 갖습니다.
따라서 재귀 함수의 각 실행 때마다 있는 output은 같은 대상이 아니라 모두 다른 대상입니다.
PS. 일반적으로 이 코드가 헷갈린 경우 여기 2번을 헷갈리는 분들이 많더라구요!
3. 그래서 다음 단계에서 만들어진 output을 이전 단계에서 합쳐주는 과정이 필요합니다!
안녕하세요! 메모를 쓴 경우는 한번 f(10)을 구하면, 그 밑에 f(9)와 f(8)을 다시 연산 할 필요가 없어서 과정이 간소화 되는게 맞게 이해를 한 것인지 질문 드립니다!
넵 그렇습니다!
궁금한게 있어서 질문드립니다! = 을 쓸 때와 == 를 쓸 때의 차이점을 모르겠습니다!
==는 결과가 불로 나오는 비교식에 쓰이는 연산자이고
=는 오른쪽 것을 왼쪽 변수에 할당하는 연산자입니다
@@윤인성 답변 감사드립니다!
팩토리얼 구할때
output *=이 이해가 잘 가지 않습니다. 무슨 의미인가요??
output = output * 의 줄임 형태입니다
그냥 이런 것이 있다는 생각을 가지고 들었네요 ㅠㅠ
강의를 여기까지 굉장히 빨리 들으셨는데,
여기까지가 한 학기 6개월 정도 과정이라서 느긋느긋 이해해보셔도 괜찮을 것 같습니다!
안녕하세요, format 관련 내용 질문있습니다.
counter = 0
def fibonacci(n):
global counter
counter += 1
if n == 1:
return 1
if n ==2:
return 1
else:
return fibonacci(n-1)+ fibonacci(n-2)
print(fibonacci(4))
print("{} {}".format(counter, fibonacci(4)) )
이렇게 작성하면 counter값이 제대로 출력 되는데, print(fibonacci(4))
을 삭제하고 출력하면 값이 0, 3 이렇게 출력됩니다. 이유가 뭔지 궁금해서 질문드립니다. 코로나 조심하세요!
전역 위치에 있는 counter를 활용하기 때문에,
한 번만 제대로 실행 결과를 확인할 수 있고,
두 번 실행하면 그 카운터가 계속 증가되어서 제대로된 값이 안 나옵니다...![확인 용으로 넣은 카운터]
따라서 두 번째 실행하기 전에 카운터를 0으로 초기화 해주셔야(counter = 0 을 현재 올려주신 코드 print() 함수들 사이에 넣어야), 카운터가 계속 증가되는 일 없이 출력됩니다.
윤인성 넵 감사합니다
안녕하세요 선생님! 이번 강의가 제 발목을 붙잡네요..ㅠㅡㅠ
memo = {1:1, 2:1}
def f(n) :
if n in memo :
return memo[n]
else :
output = f(n-1) + f(n-2)
memo[n] = output
return output
print(f(10))
이것 대신
memo = {1:1, 2:1}
def f(n) :
if n in memo :
return memo[n]
else :
memo[n] = f(n-1) + f(n-2)
return memo[n]
print(f(10))
이렇게 써도 상관 없을까요? 결과값은 똑같이 나오고 굳이 output을 지정해주고 다시 그걸 메모에 넣는 것이 크게 의미가 없는 것 같아서 output 을 만들어주는 대신 memo[n]에 함수(f(n-1)+f(n-2)) 를 바로 집어넣고 memo[n]을 리턴값으로 넣어 프린트해봤더니 과정도 똑같이 나오더라구요. 제 생각에 두번째 풀이도 별 문제 없는 것 같은데.. 혹시 output을 만들어주고 그 output을 memo[n]에 넣어 준 후 리턴값을 output 으로 지정하신 이유가 있을까요?
넵 큰 상관은 없습니다 'ㅁ'
위의 코드는 그냥 컴퓨터가 내부적으로
- 딕셔너리[키]를 할 때
이 키에 해당하는 값을 찾기 위해 약간의 시간을 더 투자하므로[배열이면 빠른데 딕셔너리는 약간 더 걸려서], 미리 다른 변수를 만들고 그걸 리턴하게 한 것입니다[memo[n] 횟수를 최대한 줄인 것].
return을 넣고 안넣고의 차이는 뭘까요?
def f(n):
if n == 1 or 2:
1
else :
f(n-1) + f(n-2) 이것과
def f(n):
if n == 1 or 2:
return 1
else :
return f(n-1) + f(n-2)
함수단원 들어가기 전까지는 return을 넣지 않고도 조건문이 출력 됐었는데 그건 함수'값'이 아니라 그런건가요?
Sangmin's TV 함수값이라고 말하시는게 정확하게 무엇인지 설명해주실 수 있을까요, 추가로 넣고 안 넣는 차이는 리턴으로 값 전달하냐 안 하나만으로도 엄청나게 정말 와장창 차이가 발생합니다.
@@윤인성 리턴함수를 배우기 전에는 return 값을 넣지 않아도 출력이 된 것 같은데 어느 순간 리턴값을 안넣으면 None이 되더라구요..
@@DailySangmin 화면에 출력을 하려면, 무조건 print() 함수를 사용해야 합니다...! 출력 자체는 리턴과 전혀 상관이 없습니다.
무엇을 출력해야 하는가의 무엇만 관계가 있습니다.
선생님~ 질문에 대한 대답을 항상 잘해주셔서 너무 감사합니다. 한가지 더 질문이 있는데, 교재 p.237에 메모화 해서 피보나치 수열 구하는 코드 중에 dictionary[n]=output을 꼭 써야 하나요? 이 부분이 메모화 같긴 한데...이해가 잘 되지 않습니다. 제 생각에는 딕셔너리에 메모된 값으로 리턴하는건데 else 구문 뒤에 왜 굳이 써야하는지 의문입니다. 이미 메모화가 된거가지고 쓰는데요....
그게 없으면 메모를 적는 과정이 없습니다![리턴은 메모를 읽을 뿐입니다]
@@윤인성 크 ,,감사합니다.
안녕하세요 선생님 ! 항상 영상 잘 보고 있습니다.
5-2 연습문제 1번을 도전하는 와중에 for 반복문이 제가 사용하기 더 편하다는걸 느끼고
def flatten(data):
output = []
for i in data:
if type(i) == list:
for n in i:
if type(n) == list:
output.extend(n)
elif type(n) == int:
output.append(n)
elif type(i) == int:
output.append(i)
return output
example = [[1, 2, 3], [4, [5, 6]], 7, [8, 9]]
print("원본:", example)
print("변환:", flatten(example))
이런 식으로 코드를 짜 봤더니 결과적으로 리스트를 평탄화 하는데는 성공했습니다.
그러나 생각해보니 리스트 안에 리스트가 다중으로 중첩될 경우 for 반복문보다는 재귀함수를 사용하는 것이 훨씬 더 편리하다는 생각이 들었는데요 ㅠㅠ
일반적으로 리스트 평탄화 할 때는 대부분 재귀함수를 사용하나요?
일반적으로 반복문과 재귀함수 두 가지를 모두 사용할 수 있을 때는 반복문을 사용합니다.
하지만 현재처럼 몇 번 중첩된지 모르는 경우에는 재귀 함수를 사용해야 합니다![몇 단계까지 파고 들어갈지 모르므로]
예를 들어 윈도우에서 검색 등으로 파일을 찾으면
현재 예제에서 『리스트 = 폴더, 숫자 = 파일』처럼 만들면서
모든 파일을 뒤지며 찾게 되는데요.
몇 단계까지 파고 들어가야 할지 모르므로 재귀 함수로 만들어야 합니다!
그렇군요 알겠습니다 ! 답변 감사합니다!! ㅎㅎ
오늘도 잘 봤습니다.
인성님
앞으로의 계획에 대해 막막한 부분이 많은데 몇가지 부분에 대해서 조언 좀 부탁드려도 될까요.
어떤 계획인지 잘 모르겠지만 간단한 내용이라면 답변 드릴 수 있습니다...!
@@윤인성 예약관련 안드로이드 앱을 만들고 싶은데, 파이썬으론 힘들다면서 java 를 공부 해야한다고 하던데..
맞는 말인가요? ㅠㅠ 혹시 그렇다면 JAVA 를 공부하기 위해 인성님이 만드신 추천 교재나 커리가 있으실까요?
지금 전
첫파이썬, 혼공파로 파이썬을 이론 공부하고 있고.
html 과 css 는 그렇게 완벽하게 알지 않아도 된다고 해서 웹페이지 따라 만들기를 통해 공부 중인데.
제가 목표로 하는 앱을 만들기 위해서 어떤걸 어떻게 공부해야 할지 감이 잘 오질 않습니다..
근처에 학원에 java 관련 학원에 등록하려 했는데
커리가 웹컨텐츠 제작이지 앱만드는게 포커스는 아니라고 해서 또 이걸 어떻게 해야하나.. 싶어서
이렇게 장문의 질문 글 올립니다.
좋은 영상 항상 감사드리면서 이만 줄입니다
@@빛나리-p9m 안드로이드 개발은 기본적으로 프로그래밍 언어로 자바 또는 코틀린을 사용합니다. 저의 경우는 없습니다 ;ㅁ; [안드로이드는 너무 버전 업데이트가 많다보니 관리가 힘들어서 쓰지 않았습니다 ;ㅁ;]
HTML과 CSS의 경우는 "웹 개발"을 할 때에 의미 있는 공부입니다. 만약 안드로이드 앱을 만들고 싶으시다면, 전혀 의미가 없습니다(아주 없지는 않겠지만 거의 없습니다).
@@윤인성 답글 정말 감사드립니다.
학원에 다니면서 java 를 배우고 이력서에 NCS JAVA 과정 이수 한줄 쓰는게 나은지.
(학원에서 하는 JAVA 커리엔 또 HTML 이나 CSS 같은 걸로 몇주 할애하는거 같이 적혀있고)
바로 앱을 만들기 위해 독학으로 JAVA 나 코틀린 같은걸 공부 할지 고심이 많아서요 ㅠ_ㅠ
혹시 알고리즘 강의는 안하시나요?
넵! 일단 예정에는 없습니다!
[아주 먼 옛날에 찍었다가 + 질문 폭탄을 너무 많이 맞아서 = 본업에 영향을 줘서 다 내린 적이 있습니다 ;ㅁ; ...!]
안녕하세요? 좋은 강의 감사드립니다. 메모화가 계산의 초기값을 할당해주는데, 245쪽 2번 문제에서 메모화를 할 때 count를 넣어주는 원리에 대해 좀 더 자세히 설명해주실 수 있을까요?
해당 문제의 설명은 ruclips.net/video/594WmZdC_ts/видео.html 를 참고해주세요!
선생님 팩토리얼 두번째 구현에서
else:
return n * factorial_2(n-1)
로 재귀함수 말고
return n* (n-1)로 그냥 쓰면 안되나요...?!
그러면, 4를 넣었을 때 4 * 3이 리턴되고 끝납니다!
ㅜㅜㅜㅜ~~
좀 여러번 숙독을 해야 되겠네요
수고 하셨습니다.
감사 합니다.^^
안녕하세요! 강의 잘 보고 있습니다.
피보나치 수열의 메모화에 대한설명에서 질문이 있습니다.
메모[n] = output과정은 위에 선언해준 dictionary 메모에 n 값을 집어 넣어서 다음에 계산할 때 쉽게 불러오도록 하는 역할인가요?
넵! 그렇습니다!!
항상 답변해주셔서 감사합니다! 열심히 공부하겠습니다!
파이썬이 현존하는 언어중에 가장 배우기 쉬운 언어라던데 그래도 진도가 나갈수록 어려워지긴하는군요 씨플플이나 자바같은 언어들에 비하면 쉽긴하지만 ㅋ
사실 언어의 난이도 표현은 그냥 "한국어가 어미조사가 많아 제일 어렵데", "무슨 소리야 중국어 외울 글자가 얼마나 많은데", "프랑스어는 시제가 몇 개인데 까부냐"정도로 크게 의미없는 것이라 생각합니다 'ㅁ' ...!
PS. 결국 자유롭게 표현을 하려면 + 모든 언어가 어려워서[...]....
@@윤인성 요즘 스페인어 공부중인데 남성어 여성어 따로있고 동사단어들이 주어에 따라 형태가 달라지더라구요 유럽어는 영어이외에 배우는게 처음이라 당황;;
233쪽에서는 global counter를 작성해줘서 함수내에서 함수 외부의 변수를 참조할수 있게했는데 241쪽에 '3.14를 PI라는 변수로 설정한 상태' 부분에서는 함수 외부에 작성된 PI값을 global로 함수 내부에 작성해주지않았는데 코드가 문제없이 실행되는 이유가 궁금합니다.
약간 어려운 내용이고 + 사실 알아도 실수를 하는 부분이라
이전에 언급했던 것처럼 "오류가 뜰 때 global 키워드를 붙인다"가 제일 편한데요.
정확하게는 "global 키워드는 변수에 들어있는 값을 교체할 때" 사용하는 것입니다.
현재 상황에는 문제 없습니다.
강의 잘 들었습니다~~^^
2번째 팩토리얼 구현에서
def factorial_2(n):
if n==0:
return 1
else:
return n*factorial_2(n-1)
음수까지 가지 않는다는 조건이 필요 없는 건가요?
n-1하게 되면 결국 0까지 갈 것이고, factorial_2(0)이면 1을 반환할 테고 다음에는 factorial_2(-1)인데 그걸 통제하는 조건문이 없는지 궁금합니다~!!
0이면 if n == 0으로 들어가서 return 1을 하므로, else 부분은 실행되지 않아서 factorial(-1)은 호출되지 않습니다.
물론 처음 함수 실행 때 factorial(-1)을 해버리면 무한하게 감소하므로 입력이 음수인지 유효성을 검사하는 과정이 있으면 좋습니다!
으어 재귀너무 어려워요ㅠ 많이쓰이는 개념인가요? 실무에서
일반적인 개발에서는 그렇게까지 사용되지는 않으며, 사실 사용 되는 경우에도 이정도까지 복잡한 형태로 사용하는 경우는 많지 않습니다.
책의 문제로 나오는 폴더 순회하기 등의 고정적인 형태에 사용되는 경우가 많으므로, 일단 너무 어려우시면 넘어 갔다가 이후에 살펴 보시는 것도 추천드립니다.
236페이지 메모화 예제에서 15열에 dictionary[n] = output을 넣어야 할 이유가 무엇인가요?
제 생각에
이미 11열에 리턴값에 return dictionary[n]을 넣었고 딕셔너리 변수 선언 범위(1~2)를 넘으면 else 로 넘어가서 dictionary[n]을 output을 넣을 필요가 없지 않나요?
그 부분이 메모화입니다. 그 부분이 있기에 n in dictionary가 True가 되는 부분이 발생하고, 메모화된 데이터를 꺼낼 수 있는 것입니다.
안녕하세요 저자님 !!! 혹시 236p에 global 키워드 질문 좀 드려도 될까요?
new_list = [8,9]
def 반전(리스트):
new_list[0] = "전역변수 없이 바꿔짐.."
for i in range(len(리스트)):
new_list.append(리스트[-i-1])
반전([1,2,3])
print(new_list) ---> >>> ['전역변수 없이 바꿔짐..', 9, 3, 2, 1]
이렇게 global new_list를 함수에 선언 안했는데, 에러도 없이 인덱스[0] 값이 수정되거나 .append()도 사용되어지고..
new_list 변수를 어떻게 참조할 수 있는건가요?ㅜㅜㅜ
정확하게는 "변수에 들어 있는 것이 값이 아니라 레퍼런스(주소)인 경우에는 global 키워드를 사용하지 않아도 괜찮음"입니다. 숫자, 문자열, 불 등은 global을 사용해야 합니다. 책의 범위에서는 "레퍼런스"가 무엇인지 설명하는 것이 복잡하므로, "오류가 발생할 때 넣으세요"라고 했는데요.
레퍼런스는 "주소"라는 의미입니다. 이게 C 언어 같은 곳에서 학생들 멘탈을 터는 몇 주 짜리 과정이라 할 수 있는 포인터 비슷한 것이라 댓글로 자세하게 설명할 수는 없지만, 간단하게 구분할 수 있는 예를 보여드리면
a = 10
b = a
b += 10
print(a, b) # 10 20이 출력되어서, a와 b가 아예 다른 값이 됩니다.
a = []
b = a
b.append(10)
print(a, b) # [10] [10]을 출력합니다. 즉 a와 b가 지칭하는 대상이 같습니다. 이렇게 되는 변수들은 "리스트의 값 자체"가 들어있는 것이 아니라, "리스트의 주소를 나타내는 레퍼런스"가 들어있는 자료형입니다.
이런 레퍼런스 자료형은 global 키워드를 사용하지 않아도 내부에서 사용할 수 있습니다.
@@윤인성 아....... 저자님 너무나 감사합니다. 예시까지 너무 구체적으로 설명해주셔서 100%로는 아니지만, 레퍼런스 자료형이 내부에서 왜 사용이 가능한 지 충분히 이해했습니다.
늦은 시간에도 매번 질문 받아주시고 존경스럽습니다.
쌀쌀해졌는데 건강 유의하시고, 오늘도 좋은 밤 되시길 바라겠습니다ㅜㅜ :)
오타가 책에 있는 거 같습니다 피보나치 수열의 메모화 예제에서 책 237페이지에 2:2 라고 적혀있는데 2:1로 적혀있어야 맞지 않나요?
1:53부터 나오는 자막 (n-1) 뒤에 ! 가 빠졌습니다..
앗 감사합니다 😂
@@윤인성 강의 너무 잘 보고 있어요. 중독적으로 연강하게 되네요^^ 빨리 완강하고 싶습니다^^
혹시 오프라인 강의도 하시나요?
본업이 따로 있어서 오프라인 강의는 하지 않고 있습니다!
헉.. 저자님!! 답변주신대로 찾아보니까요!
그러면 "리스트의 주소를 나타내는 레퍼런스"가 들어있는 자료형은 mutable(list, set, dict) 객체 아이들이 있고,
이 아이들은 "id() 함수의 값이 같다." 라는 의미로 이해해도 괜찮을까요?
장호재 넵 'ㅁ' ...! 기본 자료형(작은 녀석들) 이외에는 전부 레퍼런스로 작용하는 경우가 많아서, 리스트 이외의 것도 그렇게 된다고 생각하셔도 됩니다.
@@윤인성네네네 감사합니다 ....!! (뿌잉///)
강의 잘 듣고 있습니다. 함수에서 기본매개변수와 키워드매개변수는 어떻게 다른가요?
그냥 사용하는 문법이 다릅니다. 함수를 만드는 사람의 자율에 달려있어서, 둘 다 알아두어야 여러 함수를 만들거나 사용할 수 있습니다.
안녕하세요 243p 문제에서 질문이 있습니다.
def flatten(data):
output=[]
for element in data:
if type(element) is not list:
output.append(element)
else:
flatten(element)
return output
example= [[1,2,3],[4, [5, 6]], 7, [8, 9]]
print(flatten(example))
코드를 이렇게 작성하면 결과가 7이 나오던데 어느 부분이 잘못된 걸까요?
항상 감사합니다
+= a과 append(a) 함수는 다릅니다!
+= a은 append([a])와 같습니다....!
더 자세한 내용들은 다른 댓글들을 참고해보시는걸 추천드립니다!
232 페이지 대로 했는데 실행이 안되요 무슨 문제일까요 error message도 안뜨고 커서만 떠요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ
죄송해요 발견했어요 죄소X10000
If n==1 or 2:(답은 or n==2이지만)라고 했더니 원하는 값이안나오는데 이런경우에는 해석이 어떻게되는건지 여쭤봐도 되겠습니까?
n==1이라는 녀석과 2라는 녀석이 먼저 각각 해석되고 합쳐집니다. 다만 2는 항상 True(이전에 언급한 0 빈문자열 등을 제외하면 모두 True가 되므로)가 됩니다. 하나가 True이므로 or 전체 결과는 항상 True가 됩니다.
혹시 count 라는 변수는 언제 사용하는건지 알수 있을까요?? 경우의 수를 구할때 쓰이는건가요?
그냥 이 문제를 풀기 위한 변수라서 그게 특별한 의미가 있지는 않습니다.
피보나치 메모화 예제 중에 마지막에 return ouput을 해주시는데 그러면 output = f(n-1) + f(n-2) 열로 돌아가는건가요?
안녕하세요 질문이 있습니다.
counter = 0
def fibonacci(n):
print("피보나치{}를 구합니다.".format(n))
global counter
counter += 1
위는 교재 233쪽인데, 이것 대신에
counter = 0
def fibonacci(n):
print("피보나치{}를 구합니다.".format(n))
counter
= 0
counter += 1
을 써도 프로그램이 잘 돌아가더라고요.(global counter 대신 counter = 0 으로 바꾸었습니다)
global로 변수를 받지 않고 저런 방법으로 받아오는 것에 어떤 원리가 있는 건지 궁금합니다.
감사합니다!
밖에 선언된 녀석을 받아오지 않고 그냥 내부에서 counter = 0이라는 새로운 변수를 기반으로 도는 것 뿐입니다.
@@윤인성 아.. 감사합니다!!
메모를 def 안에 넣어도 괜찮을까요??
안 됩니다 'ㅁ' ...! 넣어보신 뒤 출력해보시면 이유를 알 수 있을 것입니다.
강의 감사합니다
강의 내용이 너무 잘 이해됩니다. 감사합니다.
print 와 return 의 차이점은 무엇인가요?
print는 출력하는 것이고 return은 함수의 결과를 함수 밖으로 뺄 때 사용합니다.
메모 = {1:1, 2:1}
def f(x):
if x in 메모:
return 메모[x]
else:
output = f(x-1)+ f(x-2)
메모[x] = output
return output
print(f(150))
이 과정에서 f(x-1)+f(x-2) = output이라든지 output = 메모[x] 와 같이 순서를 바꿔적으면 오실행이 안되는 이유가 무엇일까요?
오른쪽의 것을 왼쪽에 할당하는 코드만 존재할 뿐, 왼쪽의 것을 오른쪽에 할당하는 코드는 없습니다. =은 프로그래밍에서 같다 기호가 아닙니다.
좋은 강의 감사합니다
어려워서 이부분은 일단 패스합니다. ㅠㅠ..
안녕하세요 항상 좋은 강의 감사합니다! p.236, 237 피보나치 수열 메모화에서 dictionary를 함수 내부에 넣어서 실행을 해보면 실행이 안되는데 dictionary를 함수 외부에 넣었을 때와 내부에 넣었을 때의 차이가 뭔가요? 왜 실행이 되지 않는 걸까요ㅠ
함수 내부에 선언한 변수는 함수가 끝날 때 사라집니다. 메모용 딕셔너리는 프로그램이 실행되는 내내 유지되야 하는 아이라서 밖에 두셔야 합니다.
답변 감사합니다. 그러면 메모화의 원래 역할이 재귀함수가 느리게 작동하는 것을 극복하기 위해서인데 이 코드에서 함수 내부에 딕셔너리를 선언했을 때 해당 역할을 못하기 때문에 결과가 느리게 출력되는 문제가 발생한 것인가요?? 16번 째 줄에 return output에서 코드에서 최종적으로 출력해야 하는 것은 어차피 output이여서 dictionary가 사라지는 것은 문제가 되지 않는다고 생각했습니다. 실행해봤을 때 결과가 출력이 아예 안되는게 아니라 느리게 되는 것을 확인해서 이런 의문이 들었습니다.
@@홍선아-n6k 정확하게 어떤 코드를 사용하신지 모르겠지만, 함수 맨 앞에 그냥 만들어주셨다면 아무 효과도 못하고 사라집니다. 내부에 선언하면 아무 의미가 없습니다[딕셔너리가 남지 않으므로].
직접 확인해보실 수 있는 방법은
- 1번 경우: 딕셔너리를 밖에 선언하고, 함수의 첫 번째 줄에서 딕셔너리를 print() 함수로 출력
- 2번 경우: 딕셔너리를 함수 첫 번째 줄에 선언하고, 그 아래에 print() 함수로 출력
해보고 확인해보시는 것입니다...!
안녕하세요! 11분에 나오는 메모이제이션 코드를 따라 작성해봤는데 1000 정도나 더 큰 수를 넣으면 에러가 뜨는데
왜 그런건지 궁금합니다 (약 900 정도까지는 값이 나와요)
아래는 코드와 에러에요
메모 = { 1: 1, 2: 1 }
def f(n):
if n in 메모:
return 메모[n]
else:
output = f(n-1) + f(n-2)
메모[n] = output
return output
print(f(1000))
Traceback (most recent call last):
File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 9, in
print(f(1000))
File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 6, in f
output = f(n-1) + f(n-2)
File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 6, in f
output = f(n-1) + f(n-2)
File "D:/동진/##@@#@심화수학/코드/메모이제이션.txt", line 6, in f
output = f(n-1) + f(n-2)
[Previous line repeated 991 more times]
RecursionError: maximum recursion depth exceeded
함수 재귀 호출이 너무 많아지면 파이썬 실행기가 "이거 뭔가 잘못된거 아냐?"하면서 그냥 강제로 종료시켜버립니다. 이 제한을 없애면 되는데 코드가 약간 길지만 책에 해결책이 적혀 있습니다![지금 외부 이동 중이라 😂]
@@윤인성 답변 감사합니다!! 사실 책 없이 강의 영상만 보고 있었는데ㅎㅎ 책 사서 봐야겠어요
좋은 강의 감사합니다!
혹시 하나만 더 여쭤봐도 되나요? 학교 과제로 피보나치 수열을 프로그래밍으로 표현하는 걸 해보고 있는데,
공부하다 보니 다이내믹 프로그래밍(Dynamic Programming) 이랑 메모이제이션(Memoization)이 같은 건지, 메모가 DP의 한 방법인건지 모르겠는데 알려주시면 감사하겠습니다!
@@따끈우동 다이나믹 프로그래밍을 할 때 활용할 수 있는 테크닉이 메모화라고 생각하는 것이 좋을 것 같습니다!