From 9c177aeb9efa70fa13e2a840c8ef667197c66199 Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Sat, 18 Jan 2025 17:03:27 +0900 Subject: [PATCH 01/11] Create git command.xlsx hello --- 03151_minsuje/hw/git command.xlsx | Bin 0 -> 13002 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 03151_minsuje/hw/git command.xlsx diff --git a/03151_minsuje/hw/git command.xlsx b/03151_minsuje/hw/git command.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..13c6ac7500676a3e104ef62585ff20e5723560cd GIT binary patch literal 13002 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 literal 0 HcmV?d00001 From c9e7c59defe40a47a37a1ce8681cbf135b6766c2 Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Mon, 20 Jan 2025 01:03:40 +0900 Subject: [PATCH 02/11] =?UTF-8?q?=ED=94=84=EB=A1=9C=EA=B7=B8=EB=9E=98?= =?UTF-8?q?=EB=A8=B8=EC=8A=A4=20=EC=BD=94=EB=94=A9=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=97=B0=EC=8A=B5=5F=EC=A4=91=EC=9A=94=ED=95=9C?= =?UTF-8?q?=EB=8F=84=EB=A1=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 주간 스터디 과제 올리기 우선 예제 4개는 문제 없이 동작까지 했으나 답안 제출 시 입력되는 값이 큰 케이스는 전부 시간초과로 실패했음. 추후 수정하여 올려볼 예정. --- .../python/code_test/important road/README.md | 9 + .../important road/image_data/ex1-1.png | Bin 0 -> 61024 bytes .../important road/image_data/ex1-2.png | Bin 0 -> 61381 bytes .../code_test/important road/importantroad.py | 187 +++++++++++++++++ .../important road/importantroad2.py | 190 ++++++++++++++++++ .../important road/prepare2slove_problem.md | 123 ++++++++++++ 6 files changed, 509 insertions(+) create mode 100644 03151_minsuje/hw/python/code_test/important road/README.md create mode 100644 03151_minsuje/hw/python/code_test/important road/image_data/ex1-1.png create mode 100644 03151_minsuje/hw/python/code_test/important road/image_data/ex1-2.png create mode 100644 03151_minsuje/hw/python/code_test/important road/importantroad.py create mode 100644 03151_minsuje/hw/python/code_test/important road/importantroad2.py create mode 100644 03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md diff --git a/03151_minsuje/hw/python/code_test/important road/README.md b/03151_minsuje/hw/python/code_test/important road/README.md new file mode 100644 index 0000000..3221671 --- /dev/null +++ b/03151_minsuje/hw/python/code_test/important road/README.md @@ -0,0 +1,9 @@ +# 프로그래머스 테스트코드 : 중요한 로드 문제 풀기 +> 저는 프로그래머스에 있는 문제를 선택하여 진행하였습니다. +해당 문제풀이 및 작성 도중 필요한 문서까지 작성하였는데 +참고하셔도 좋고 참고 하지 않으셔도 좋습니다. +그럼 토요일 스터디에서 뵙겠습니다. +해당 문제에 대한 자세한 사항을 알고 싶으시다면 아래 링크를 참조해 주세요. + + +https://school.programmers.co.kr/learn/courses/30/lessons/214293 \ No newline at end of file diff --git a/03151_minsuje/hw/python/code_test/important road/image_data/ex1-1.png b/03151_minsuje/hw/python/code_test/important road/image_data/ex1-1.png new file mode 100644 index 0000000000000000000000000000000000000000..e9b070cc23b4515e1d5d338f555ff44147b1613f GIT binary patch literal 61024 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 literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/python/code_test/important road/image_data/ex1-2.png b/03151_minsuje/hw/python/code_test/important road/image_data/ex1-2.png new file mode 100644 index 0000000000000000000000000000000000000000..adc349098ad7c18473ce3e94b7e19b13e9d0ae33 GIT binary patch literal 61381 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 QCV)R`%Gyc=3Rk@T2S&SC#Q*>R literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/python/code_test/important road/importantroad.py b/03151_minsuje/hw/python/code_test/important road/importantroad.py new file mode 100644 index 0000000..e4f3d04 --- /dev/null +++ b/03151_minsuje/hw/python/code_test/important road/importantroad.py @@ -0,0 +1,187 @@ +'''중요한 도로 코드 작성 +작성 사유 : ROKEY 스터디 코드 리뷰용 코드 작성 +작성자 : 제민수 +진행하는곳 : ROKEY 3기 스터디 중 +작성 날짜 :2025.01.18~2025.01.19 +ver : 1.0ver +작성 언어 :python +이외 프로그램 작성 중 정리 문서는 prepare2slove_program 문서를 참조 한다. + - 코드 작성의 전반적인 방향성, 변수 기록 등등 참고 자료로 작성함. +''' + + +class ImportRoad(): + """ + n개의 이동 지점과 도로의 정보(도로의 길이, 교통량)를 입력받아 최단 거리를 계산 + 또한 계산된 최단 거리가가 교통량의 변화에 따라 최단 거리가 바뀌는 것을 찾아 최단거리에 + 영향을 주는 도로를 출력 하는 프로그램. + """ + #고정 변수 선언 + __MAX_LOCATION_NUM = 50000 + __MIN_LOCATION_NUM = 2 + __MAX_ROADS_LEN = 200000 + __MIN_U_POINT = 1 + __MIN_V_POINT = __MIN_U_POINT+1 + __MIN_ROAD_COST = 1 + __MAX_ROAD_COST = 10**9 + __MIN_TRAFFIC = 0 + __MAX_TRAFFIC = 10**9 + + ##### 생성자 최단 경로 자체는 필요 없으나 만드는 사람 입장에서 최단 경로도 확인 하고 싶을때가 있을거라 생각되서 추가함. + def __init__(self,location_num:int, roads:list): + '''초기화 + location_num : 이동 가능한 지점의 수 2보다 크고 50000보다 작음 + roads : 도로의 정보를 담은 리스트[[u 지점, v 지점, 도로의 이동 시간 비용, 도로의 트레픽],...] + 이외 고정 변수 혹은 내부에서 사용될 변수 선언 및 초기 맵 제작 함수 동작 + ''' + #입력 변수 + self.location_num = location_num + self.roads = roads + + #입력 변수에 따라 변하는 고정 변수 + self.__MIN_ROADS_LEN = location_num-1 + self.__MAX_V_POINT = location_num + self.__MAX_U_POINT = location_num-1 + + # 맵그리기용 빈 맵 생성 + self.road_map = {location:[] for location in range(1, self.location_num+1)} #1 부터 n까지 빈 리스트 생성 + + #맵 생성 + self.__map_maker() + + + ### 맵 그리기 함수 + def __map_maker(self): + '''맵그리기기(클래스 내부에서만 쓰는 함수) + 함수이름에 _를 두개 쓰면 외부에서 호출이 불가능 + ''' + self.road_map = {location:[] for location in range(1, self.location_num+1)} #다시 그릴때 초기화 되야함. + for u_point, v_point, road_cost, traffic in self.roads: + self.road_map[u_point].append((v_point, road_cost+traffic)) #도로 길이시간에 트래픽을 더함 + self.road_map[v_point].append((u_point,road_cost+traffic)) #양방향이므로 반대 포인트에서 오는것도 저장 + + + ### 최단 경로 찾기 함수 + def __shortest_path(self): + '''최단 시간의 경로(들) 찾기(클래스 내부에서만 쓰는 함수) + 현재의 최단 경로와 걸린 시간 값을 알아야 하나의 도로의 traffic이 변경 되었을때 최단 경로의 변화를 찾을 수 있다. + 현재 함수에서 다익스트라 알고리즘 흐름은 다음과 같다. + 초기 큐를 생성하고 큐의 요소가 빌때까지 아래내용을 반복한다. + 큐에서 가장 작은 누적 시간을 가진 값을 꺼내서 현재 지점으로 설정한다. + 현재 지점에 인접한 지점을 탐색 하고 그 지점을 큐에 추가한다. + + ''' + #다익스트라 알고리즘을 이용하여 최단 시간을 알아야 해서 경로의 최단시간만 알면 됨됨 + + #queue의 역할을 할 변수 location_info 작성-시간과 지역역 값을 확인하며 리스트에 튜플로 작성한 이유는 + + # 최단 시간 변수 + #shorest_time 에 location키의 벨류 값은 short_time의 최대값을 넣어야 최초 비교때 최솟 값을 넣을 수 있음 + #따라서 도로의 최소수(1-2-3-4-5이런식으로 하나씩만 연결됬고 모든 도로를 지나야 될때 이게 제일 큰값임임)*2*트레픽 최대값을 넣어줌. + shortest_time = {location: self.__MIN_ROADS_LEN*2*ImportRoad.__MAX_TRAFFIC for location in range(1, self.location_num + 1)} # 최단 시간 초기화 내부의 키를 location이라 칭한것은 해당 위치까지 가는 최단 시간을 찾는 것이기 때문 + shortest_time[1] = 0 #1번지점에서 1번지점 이동 시간은 0임 + + # 선언된 값 자체가 변경되면안됨. queue의 역활로서 삭제되거나 추가될 순 있어도 들어온 값 자체가 수정 되어서는 안됨 + location_info = [(0,1)] #시간, 지역 변수 초기화 최초엔 1번 위치에서 0시간소모 경로는 1만 통과 했으므로 + + #queue 역할을 하는 locationvector의 요소가 없을때 while문은 실행되지 않는다. + while location_info: + #location_info에서 가장 작은 누적 시간 찾기 + min_index_num = 0 #location_info에서 가장 작은 누적시간을 가진 index를 찾기위해 해당 인덱스 초기화 + for i in range(1,len(location_info)): + if(location_info[i][0]shortest_time[current_location]): + continue + + #현재와 인접한 노드를 탐색해서 queue즉 location_info에 새로운 경로를 추가해야 한다. + #새로운 지역 탐색 + for neighbor_location, move_cost in self.road_map[current_location]: + new_time = current_time+move_cost #새로운 경로의 시간 + #새로운 경로의 시간이 짧은경로 시간에 저장된 값보다 작으면 시간을 갱신해 주고 location_info에 새로운 경로 시간과 지역을 저장 + if new_time < shortest_time[neighbor_location]: + shortest_time[neighbor_location] = new_time + location_info.append((new_time, neighbor_location)) + #위와 같이 queue(location_info)에 저장된 값을 꺼내어 지역과 시간값을 근처 지역과 총걸린 시간을 더해가면서 반복하여 + #location_info에 더이상 새로운 이동경로 시간과 근처 지역에 대한 정보를 저장 하지 못하면 결국은 location_info의 요소는 모두 비어버리고 + #sortest_time에 location_num를 키값으로 넣으면 location의 마지막 번호 까지의 최단 시간을 불러 올수 있다. + return shortest_time[self.location_num] + #해당값을 통해 최초 시점 최단 시간과, 트레픽 변경으로 인한 최단 시간이 변경되는지 비교를 통해 도로 번호를 찾는 함수에 가져다 주면 + #목표 출력에 도달 한다. + + + ### 트레픽 변경시 최단 시간 변경에 영향을 주는 도로 출력 함수 + def find_affected_roads(self): + '''트레픽 변경에 따라 최단시간이 바귀는 도로 번호 찾기 함수 + __shortest_path를 이용하여 최초 최단 시간을 찾고 + for문을 통해 트레픽값을 0 과 __TRAFFIC_MAX값으로 변경한 도로정보를 수정하여 계산되어 나온 값이 최초 시간과 다르다면 + 해당 도로는 영향을 주는 도로로 저장하고 최종 적으로 찾은 모든 영향을 주는 도로를 return 하면 끝 + ''' + affected_roads = [] + #최초 최단 시간 + first_short_time = self.__shortest_path() + # 각도로의 트래픽을 0 또는 최대 값으로 변경하여 비교하여 최단 시간이 변경되면 해당 도로번호를 affected_roads에 저장한다. + # enumeraten으로 for문 리스트를 하면 키값으로 index를 생성할 수 있고 해당 index는 for문을 돌때 마다 1씩 증가한다. + for index_num,(u_point,v_point,road_cost,traffic) in enumerate(self.roads): + #traffic을 최소 값으로 변경 했을때 + self.roads[index_num][3] = ImportRoad.__MIN_TRAFFIC #traffic의 값을 최솟값으로 변경 + self.__map_maker() #변갱된 맵 적용 + update_short_time = self.__shortest_path() #변경된 최단 시간 값 저장 + + if first_short_time != update_short_time: #최초 최단 시간과 업데이트된 최단 시간이 다르면 영향을 주는 도로임 + affected_roads.append(index_num+1) #index_num+1이 도로의 번호임 index_num은 0부터 시작하는데 해당 자리가 1번 도로 에 관한거 같이 1씩 증가함 + + #traffic을 최대 값으로 변경 했을때 + self.roads[index_num][3] = ImportRoad.__MAX_TRAFFIC #traffic의 값을 최솟값으로 변경 + self.__map_maker() #변경된 맵 적용 + update_short_time = self.__shortest_path() #변경된 최단 시간 값 저장 + + if first_short_time != update_short_time: #최초 최단 시간과 업데이트된 최단 시간이 다르면 영향을 주는 도로임 + affected_roads.append(index_num+1) #index_num+1이 도로의 번호임 index_num은 0부터 시작하는데 해당 자리가 1번 도로 에 관한거 같이 1씩 증가함 + + self.roads[index_num][3] = traffic #기존의 값으로 변경해줘야 다음 도로 확인때 문제가 발생하지 않음. + affected_roads = list(set(affected_roads)) #중복 제거거 + #만약 경로에 영향을 미치는 도로가 없으면 affected_roads는 [-1]값을 가지고 반환 되야함 + if not affected_roads: + affected_roads.append(-1) + #이제 모든 과정을 마쳤으니 affected_roads를 반환하면 끝 + return affected_roads + +def solution(n, roads): + city = ImportRoad(n,roads) + answer = city.find_affected_roads() + return answer + + +roads_1 = [ + [1, 2, 10, 0], [2, 4, 8, 0], [1, 3, 9, 0], [3, 4, 9, 0], [3, 5, 10, 6], [2, 5, 10, 2], [4, 5, 2, 0] +] +n_1 = 5 + +roads_2 = [ + [1, 2, 10, 10], [2, 3, 10, 10], [3, 4, 10, 10] +] +n_2 = 4 + +roads_3 = [ + [1, 2, 5, 0], [2, 4, 5, 0], [1, 3, 5, 0], [3, 4, 5, 0] +] +n_3 = 4 + +roads_4 = [ + [1, 2, 5, 0], [2, 4, 5, 0], [1, 3, 5, 0], [3, 4, 5, 0], [1, 4, 5, 5] +] +n_4 = 4 + +# 결과 출력 +print(solution(n_1, roads_1)) + +print(solution(n_2, roads_2)) + +print(solution(n_3, roads_3)) + +print(solution(n_4, roads_4)) \ No newline at end of file diff --git a/03151_minsuje/hw/python/code_test/important road/importantroad2.py b/03151_minsuje/hw/python/code_test/important road/importantroad2.py new file mode 100644 index 0000000..1766a56 --- /dev/null +++ b/03151_minsuje/hw/python/code_test/important road/importantroad2.py @@ -0,0 +1,190 @@ +'''중요한 도로 코드 작성 +작성 사유 : ROKEY 스터디 코드 리뷰용 코드 작성 +작성자 : 제민수 +진행하는곳 : ROKEY 3기 스터디 중 +작성 날짜 :2025.01.18~2025.01.19 +ver : 2.0ver +작성 언어 :python +이외 프로그램 작성 중 정리 문서는 prepare2slove_program 문서를 참조 한다. + - 코드 작성의 전반적인 방향성, 변수 기록 등등 참고 자료로 작성함. + 버전 1은 일반 테스트 4개는 통과 하였으나 제출 및 풀이에서 시간 초과라는 결과와 실패 등이 포함되어 나왔다. + 이에 대한 문제를 해결해 보고자 2.0ver으로 관리 해보고자 한다. +''' + +## 아직 수정 못함함 + +class ImportRoad(): + """ + n개의 이동 지점과 도로의 정보(도로의 길이, 교통량)를 입력받아 최단 거리를 계산 + 또한 계산된 최단 거리가가 교통량의 변화에 따라 최단 거리가 바뀌는 것을 찾아 최단거리에 + 영향을 주는 도로를 출력 하는 프로그램. + """ + #고정 변수 선언 + __MAX_LOCATION_NUM = 50000 + __MIN_LOCATION_NUM = 2 + __MAX_ROADS_LEN = 200000 + __MIN_U_POINT = 1 + __MIN_V_POINT = __MIN_U_POINT+1 + __MIN_ROAD_COST = 1 + __MAX_ROAD_COST = 10**9 + __MIN_TRAFFIC = 0 + __MAX_TRAFFIC = 10**9 + + ##### 생성자 최단 경로 자체는 필요 없으나 만드는 사람 입장에서 최단 경로도 확인 하고 싶을때가 있을거라 생각되서 추가함. + def __init__(self,location_num:int, roads:list): + '''초기화 + location_num : 이동 가능한 지점의 수 2보다 크고 50000보다 작음 + roads : 도로의 정보를 담은 리스트[[u 지점, v 지점, 도로의 이동 시간 비용, 도로의 트레픽],...] + 이외 고정 변수 혹은 내부에서 사용될 변수 선언 및 초기 맵 제작 함수 동작 + ''' + #입력 변수 + self.location_num = location_num + self.roads = roads + + #입력 변수에 따라 변하는 고정 변수 + self.__MIN_ROADS_LEN = location_num-1 + self.__MAX_V_POINT = location_num + self.__MAX_U_POINT = location_num-1 + + # 맵그리기용 빈 맵 생성 + self.road_map = {location:[] for location in range(1, self.location_num+1)} #1 부터 n까지 빈 리스트 생성 + + #맵 생성 + self.__map_maker() + + + ### 맵 그리기 함수 + def __map_maker(self): + '''맵그리기기(클래스 내부에서만 쓰는 함수) + 함수이름에 _를 두개 쓰면 외부에서 호출이 불가능 + ''' + self.road_map = {location:[] for location in range(1, self.location_num+1)} #다시 그릴때 초기화 되야함. + for u_point, v_point, road_cost, traffic in self.roads: + self.road_map[u_point].append((v_point, road_cost+traffic)) #도로 길이시간에 트래픽을 더함 + self.road_map[v_point].append((u_point,road_cost+traffic)) #양방향이므로 반대 포인트에서 오는것도 저장 + + + ### 최단 경로 찾기 함수 + def __shortest_path(self): + '''최단 시간의 경로(들) 찾기(클래스 내부에서만 쓰는 함수) + 현재의 최단 경로와 걸린 시간 값을 알아야 하나의 도로의 traffic이 변경 되었을때 최단 경로의 변화를 찾을 수 있다. + 현재 함수에서 다익스트라 알고리즘 흐름은 다음과 같다. + 초기 큐를 생성하고 큐의 요소가 빌때까지 아래내용을 반복한다. + 큐에서 가장 작은 누적 시간을 가진 값을 꺼내서 현재 지점으로 설정한다. + 현재 지점에 인접한 지점을 탐색 하고 그 지점을 큐에 추가한다. + + ''' + #다익스트라 알고리즘을 이용하여 최단 시간을 알아야 해서 경로의 최단시간만 알면 됨됨 + + #queue의 역할을 할 변수 location_info 작성-시간과 지역역 값을 확인하며 리스트에 튜플로 작성한 이유는 + + # 최단 시간 변수 + #shorest_time 에 location키의 벨류 값은 short_time의 최대값을 넣어야 최초 비교때 최솟 값을 넣을 수 있음 + #따라서 도로의 최소수(1-2-3-4-5이런식으로 하나씩만 연결됬고 모든 도로를 지나야 될때 이게 제일 큰값임임)*2*트레픽 최대값을 넣어줌. + shortest_time = {location: self.__MIN_ROADS_LEN*2*ImportRoad.__MAX_TRAFFIC for location in range(1, self.location_num + 1)} # 최단 시간 초기화 내부의 키를 location이라 칭한것은 해당 위치까지 가는 최단 시간을 찾는 것이기 때문 + shortest_time[1] = 0 #1번지점에서 1번지점 이동 시간은 0임 + + # 선언된 값 자체가 변경되면안됨. queue의 역활로서 삭제되거나 추가될 순 있어도 들어온 값 자체가 수정 되어서는 안됨 + location_info = [(0,1)] #시간, 지역 변수 초기화 최초엔 1번 위치에서 0시간소모 경로는 1만 통과 했으므로 + + #queue 역할을 하는 locationvector의 요소가 없을때 while문은 실행되지 않는다. + while location_info: + #location_info에서 가장 작은 누적 시간 찾기 + min_index_num = 0 #location_info에서 가장 작은 누적시간을 가진 index를 찾기위해 해당 인덱스 초기화 + for i in range(1,len(location_info)): + if(location_info[i][0]shortest_time[current_location]): + continue + + #현재와 인접한 노드를 탐색해서 queue즉 location_info에 새로운 경로를 추가해야 한다. + #새로운 지역 탐색 + for neighbor_location, move_cost in self.road_map[current_location]: + new_time = current_time+move_cost #새로운 경로의 시간 + #새로운 경로의 시간이 짧은경로 시간에 저장된 값보다 작으면 시간을 갱신해 주고 location_info에 새로운 경로 시간과 지역을 저장 + if new_time < shortest_time[neighbor_location]: + shortest_time[neighbor_location] = new_time + location_info.append((new_time, neighbor_location)) + #위와 같이 queue(location_info)에 저장된 값을 꺼내어 지역과 시간값을 근처 지역과 총걸린 시간을 더해가면서 반복하여 + #location_info에 더이상 새로운 이동경로 시간과 근처 지역에 대한 정보를 저장 하지 못하면 결국은 location_info의 요소는 모두 비어버리고 + #sortest_time에 location_num를 키값으로 넣으면 location의 마지막 번호 까지의 최단 시간을 불러 올수 있다. + return shortest_time[self.location_num] + #해당값을 통해 최초 시점 최단 시간과, 트레픽 변경으로 인한 최단 시간이 변경되는지 비교를 통해 도로 번호를 찾는 함수에 가져다 주면 + #목표 출력에 도달 한다. + + + ### 트레픽 변경시 최단 시간 변경에 영향을 주는 도로 출력 함수 + def find_affected_roads(self): + '''트레픽 변경에 따라 최단시간이 바귀는 도로 번호 찾기 함수 + __shortest_path를 이용하여 최초 최단 시간을 찾고 + for문을 통해 트레픽값을 0 과 __TRAFFIC_MAX값으로 변경한 도로정보를 수정하여 계산되어 나온 값이 최초 시간과 다르다면 + 해당 도로는 영향을 주는 도로로 저장하고 최종 적으로 찾은 모든 영향을 주는 도로를 return 하면 끝 + ''' + affected_roads = [] + #최초 최단 시간 + first_short_time = self.__shortest_path() + # 각도로의 트래픽을 0 또는 최대 값으로 변경하여 비교하여 최단 시간이 변경되면 해당 도로번호를 affected_roads에 저장한다. + # enumeraten으로 for문 리스트를 하면 키값으로 index를 생성할 수 있고 해당 index는 for문을 돌때 마다 1씩 증가한다. + for index_num,(u_point,v_point,road_cost,traffic) in enumerate(self.roads): + #traffic을 최소 값으로 변경 했을때 + self.roads[index_num][3] = ImportRoad.__MIN_TRAFFIC #traffic의 값을 최솟값으로 변경 + self.__map_maker() #변갱된 맵 적용 + update_short_time = self.__shortest_path() #변경된 최단 시간 값 저장 + + if first_short_time != update_short_time: #최초 최단 시간과 업데이트된 최단 시간이 다르면 영향을 주는 도로임 + affected_roads.append(index_num+1) #index_num+1이 도로의 번호임 index_num은 0부터 시작하는데 해당 자리가 1번 도로 에 관한거 같이 1씩 증가함 + + #traffic을 최대 값으로 변경 했을때 + self.roads[index_num][3] = ImportRoad.__MAX_TRAFFIC #traffic의 값을 최솟값으로 변경 + self.__map_maker() #변경된 맵 적용 + update_short_time = self.__shortest_path() #변경된 최단 시간 값 저장 + + if first_short_time != update_short_time: #최초 최단 시간과 업데이트된 최단 시간이 다르면 영향을 주는 도로임 + affected_roads.append(index_num+1) #index_num+1이 도로의 번호임 index_num은 0부터 시작하는데 해당 자리가 1번 도로 에 관한거 같이 1씩 증가함 + + self.roads[index_num][3] = traffic #기존의 값으로 변경해줘야 다음 도로 확인때 문제가 발생하지 않음. + affected_roads = list(set(affected_roads)) #중복 제거거 + #만약 경로에 영향을 미치는 도로가 없으면 affected_roads는 [-1]값을 가지고 반환 되야함 + if not affected_roads: + affected_roads.append(-1) + #이제 모든 과정을 마쳤으니 affected_roads를 반환하면 끝 + return affected_roads + +def solution(n, roads): + city = ImportRoad(n,roads) + answer = city.find_affected_roads() + return answer + + +roads_1 = [ + [1, 2, 10, 0], [2, 4, 8, 0], [1, 3, 9, 0], [3, 4, 9, 0], [3, 5, 10, 6], [2, 5, 10, 2], [4, 5, 2, 0] +] +n_1 = 5 + +roads_2 = [ + [1, 2, 10, 10], [2, 3, 10, 10], [3, 4, 10, 10] +] +n_2 = 4 + +roads_3 = [ + [1, 2, 5, 0], [2, 4, 5, 0], [1, 3, 5, 0], [3, 4, 5, 0] +] +n_3 = 4 + +roads_4 = [ + [1, 2, 5, 0], [2, 4, 5, 0], [1, 3, 5, 0], [3, 4, 5, 0], [1, 4, 5, 5] +] +n_4 = 4 + +# 결과 출력 +print(solution(n_1, roads_1)) + +print(solution(n_2, roads_2)) + +print(solution(n_3, roads_3)) + +print(solution(n_4, roads_4)) \ No newline at end of file diff --git a/03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md b/03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md new file mode 100644 index 0000000..c421a6e --- /dev/null +++ b/03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md @@ -0,0 +1,123 @@ +# 프로그래머스 코딩 테스트 : 중요한 도로 문제 + +- 작성자 : 제민수(ROKEY 3기생 DR-05131) +- 작성 기간 : 2025-01-18~(진행중) +- 버전 관리 : 1.2.1 ver +- 0.x 프로그램 실행 안됨 테스트 및 코딩 작성 +- 1.1.x 프로그램 실행 됨(4가지 예시의 테스트 케이스는 통과 했으나, 제출시 시간초과 case가 많음.) +- 1.2.x 1.0ver의 문제점을 기타에서 code 수정에 대해 관리 할 예정 +- +## 📜목차 + +## [개요](#개요) +- [작성의 목적](#작성의-목적) +- [중요한 도로 문제의 목적](#중요한-도로-문제의-목적) + +## [프로그램](#프로그램) +- [문제에서 사용할 변수 이름](#문제에서-사용할-변수-이름) +- [제한사항](#제한사항) +- [문제 요구사항 정리](#문제-요구사항-정리) +- [입출력 정리](#입출력-정리) + +## [기타](#기타) + + +## 개요 + ### 작성의 목적 +- ROKEY 3기 프로그램 진행에서 스터디 그룹에서 코딩 리뷰 및 학습 내용 공유를 위함. +- 스터디 피드백 내용 정리 + - 추가예정 +- 해당 문서는 ROKEY 3기생 DR-03151제민수가 작성 하였으며, 문서 및 파일은 직접 수정하지 않는다. + + ### 중요한 도로 문제의 목적 +- 도시의 이동 지점 및 차량 도로에 대한 정보를 이용하여 최단 경로를 찾으며, 도로의 트레픽 값이 하나 변경된다 가정 했을때 현재의 최단 경로가 변경 될때 영향을 주는 도로의 번호를 찾는 것이 목적이다. + +## 프로그램 + +### 문제에서 사용할 변수 이름 +- 도시 내의 n개의 지점 location_num +- 도로의 수 m road_num-> len(roads)으로 대체. +- *추가 roads(2차원 정수 배열)[[U1,V1,L1,T1],[U2,V2,2L,T2], ... ] +- 도로의 길이 L road_cost **roads의 최소 개수랑 나중에 이름이 헷깔릴거같아서 lenth 에서 cost로 수정 +- 교통량 t traffic + +### 제한사항 +- 2<= n <= 50,000 + - 1번 지점이 출발지, n번 지점이 목적지 +- n-1<= roads의 길이 = m <=200,000 + - road[i] 는 i+1번 도로에 대한 정보를 담고 있으며 [U, V, L, T] 형태의 길이가 4인 1차원 정수 배열이다. + - u번 지점, v번 지점을 연결하는 길이L, 교통량 T인 도로를 의미함 + - 1<=U 최단 경로 보단 최단 시간에 영향을 주는 도로를 찾는 것 이기때문에 굳이 사용자가 알 필요 없다 판단하여 그렇게 함. +- [x] 트레픽 변경에 따른 최단 시간 변경 되는 도로 번호 찾는 함수 작성 + + +### importantroad.py 2.0ver 예상 문제 및 코드 수정 후 결과 +시간 초과라는 문제점이 발견됨. 이에 예측 되는 문제점들을 하나씩 수정해볼 예정 +>- 최대 n,m일 경우 너무 큰 맵 생성이 여러번 반복되고, 많은__shortest_path를 호출하게됨 +> - [ ] 변경되는 index의 트레픽 값만 map update를 진행할 것. +> - [ ] shortest_path이 많고 +> +>- chat GPT에 의하면 다익스트라 알고리즘 구현도 비효율적으로 탐색한다고함..... +> - [ ] 알고리즘 수정 해보자........ \ No newline at end of file From b7cd6562c844f3dff267f0c9d68f9b967255722b Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Sat, 25 Jan 2025 11:59:15 +0900 Subject: [PATCH 03/11] Edit file location and write homework MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 다른분들 숙제 보고 한것 제출 합니다. --- 03117_bae/main.py | 7 -- ...\354\247\200\354\230\210\354\235\200.docx" | Bin 41677 -> 0 bytes .../python/code_test/important road/README.md | 9 -- .../hw/{ => week1(git)}/git command.xlsx | Bin .../CCTV_project/CCTV_minsuje/solution.py | 0 .../__pycache__/video_player.cpython-312.pyc | Bin 0 -> 3436 bytes .../CCTV_minsuje/src/recorder/video_player.py | 64 ++++++++++++ .../src/recorder/video_recorder.py | 24 +++++ .../src/webcam/webcam_selecter.py | 57 +++++++++++ .../src/webcam/webcam_streamer.py | 69 +++++++++++++ .../week2(p)/CCTV_project/README_project.md | 46 +++++++++ .../CCTV_project/minsuje_cctv_project.md | 81 +++++++++++++++ .../hw/week2(p)/important road/README.md | 13 +++ .../important road/image_data/ex1-1.png | Bin .../important road/image_data/ex1-2.png | Bin .../important road/importantroad.py | 0 .../important road/importantroad2.py | 8 +- .../important road/prepare2slove_problem.md | 31 +++--- 03151_minsuje/hw/week2(p)/king/King.md | 76 ++++++++++++++ .../__pycache__/chess_board.cpython-312.pyc | Bin 0 -> 3585 bytes 03151_minsuje/hw/week2(p)/king/chess_board.py | 81 +++++++++++++++ .../hw/week2(p)/king/king_move_program.py | 14 +++ .../account_manager.cpython-312.pyc | Bin 0 -> 3125 bytes .../__pycache__/file_reader.cpython-312.pyc | Bin 0 -> 1584 bytes .../__pycache__/gui_control.cpython-312.pyc | Bin 0 -> 190 bytes .../__pycache__/gui_screens.cpython-312.pyc | Bin 0 -> 6520 bytes .../account_manager.cpython-312.pyc | Bin 0 -> 3145 bytes .../__pycache__/file_reader.cpython-312.pyc | Bin 0 -> 1592 bytes .../__pycache__/gui_screens.cpython-312.pyc | Bin 0 -> 6576 bytes .../week2(p)/study_2week_kimQ/src/account.txt | 6 ++ .../study_2week_kimQ/src/account_manager.py | 47 +++++++++ .../study_2week_kimQ/src/file_reader.py | 26 +++++ .../study_2week_kimQ/src/gui_screens.py | 95 +++++++++++++++++ .../study_2week_kimQ/study_2week_kimQ.md | 96 ++++++++++++++++++ .../study_2week_kimQ/study_2week_minA.py | 12 +++ .../study_week2_Q_ji/study_week2_A_jeminsu.py | 6 ++ .../study_week2_Q_ji/study_week2_Q_ji.md | 41 ++++++++ .../study_week2_jwLee/study_week2_jwLee_Q.md | 44 ++++++++ .../study_week2_minsuje_A.py | 12 +++ README.md | 2 - Readme_ji.md | 1 - 41 files changed, 929 insertions(+), 39 deletions(-) delete mode 100644 03117_bae/main.py delete mode 100644 "03122_Ji/\354\212\244\355\204\260\353\224\224 1\354\243\274\354\260\250_\354\247\200\354\230\210\354\235\200.docx" delete mode 100644 03151_minsuje/hw/python/code_test/important road/README.md rename 03151_minsuje/hw/{ => week1(git)}/git command.xlsx (100%) create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/solution.py create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/__pycache__/video_player.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_player.py create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_recorder.py create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_selecter.py create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/README_project.md create mode 100644 03151_minsuje/hw/week2(p)/CCTV_project/minsuje_cctv_project.md create mode 100644 03151_minsuje/hw/week2(p)/important road/README.md rename 03151_minsuje/hw/{python/code_test => week2(p)}/important road/image_data/ex1-1.png (100%) rename 03151_minsuje/hw/{python/code_test => week2(p)}/important road/image_data/ex1-2.png (100%) rename 03151_minsuje/hw/{python/code_test => week2(p)}/important road/importantroad.py (100%) rename 03151_minsuje/hw/{python/code_test => week2(p)}/important road/importantroad2.py (97%) rename 03151_minsuje/hw/{python/code_test => week2(p)}/important road/prepare2slove_problem.md (89%) create mode 100644 03151_minsuje/hw/week2(p)/king/King.md create mode 100644 03151_minsuje/hw/week2(p)/king/__pycache__/chess_board.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/king/chess_board.py create mode 100644 03151_minsuje/hw/week2(p)/king/king_move_program.py create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/account_manager.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/file_reader.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/gui_control.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/gui_screens.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/account_manager.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/file_reader.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/gui_screens.cpython-312.pyc create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/account.txt create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/account_manager.py create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/file_reader.py create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/src/gui_screens.py create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_kimQ.md create mode 100644 03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_minA.py create mode 100644 03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py create mode 100644 03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_Q_ji.md create mode 100644 03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_jwLee_Q.md create mode 100644 03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_minsuje_A.py delete mode 100644 README.md delete mode 100644 Readme_ji.md diff --git a/03117_bae/main.py b/03117_bae/main.py deleted file mode 100644 index a9d5247..0000000 --- a/03117_bae/main.py +++ /dev/null @@ -1,7 +0,0 @@ -x = 2.4 -dkdkdk = 3.4 -c = x + dkdkdk -# 주석 -# 아무거나 -# 추가 아무거나 -# 설명 \ No newline at end of file diff --git "a/03122_Ji/\354\212\244\355\204\260\353\224\224 1\354\243\274\354\260\250_\354\247\200\354\230\210\354\235\200.docx" "b/03122_Ji/\354\212\244\355\204\260\353\224\224 1\354\243\274\354\260\250_\354\247\200\354\230\210\354\235\200.docx" deleted file mode 100644 index 4ce2a7a934bea7f63eea50d0abc8372ed16fc112..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41677 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 저는 프로그래머스에 있는 문제를 선택하여 진행하였습니다. -해당 문제풀이 및 작성 도중 필요한 문서까지 작성하였는데 -참고하셔도 좋고 참고 하지 않으셔도 좋습니다. -그럼 토요일 스터디에서 뵙겠습니다. -해당 문제에 대한 자세한 사항을 알고 싶으시다면 아래 링크를 참조해 주세요. - - -https://school.programmers.co.kr/learn/courses/30/lessons/214293 \ No newline at end of file diff --git a/03151_minsuje/hw/git command.xlsx b/03151_minsuje/hw/week1(git)/git command.xlsx similarity index 100% rename from 03151_minsuje/hw/git command.xlsx rename to 03151_minsuje/hw/week1(git)/git command.xlsx diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/solution.py b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/solution.py new file mode 100644 index 0000000..e69de29 diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/__pycache__/video_player.cpython-312.pyc b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/__pycache__/video_player.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb6c7eb8452ade322cd4a2d4818b04e60d338261 GIT binary patch literal 3436 zcmb7GZ%iE55r2EPcP!k(9bil_2Jbl-Seo92q(OpEl#1ACz#&m&B`T%bUTzn-^KpB5 zZ;$I;a77iG@=t=O#t^xc2zWMFcPpc978x`!q7Ma6tU^bDAWG05jtv55y zIM8cIb}S&-dCOsGjyuwf$lj;ISlF7fC{q*;dw|(Q3L0l*H13d@1vKuYYmBq96R1mO zfx2ZE(5kdstTH_BL}W#MD;7#CIBYLNSEIjl!gDwV1e{~$kOZ7HWCT)4+mwnfB5)bL zQA=}7f%~6QTRT{kMj|_wA;SZ~x8EE+`xBsVM2Lbz@5L1Iu<-ngy)X4jGm$t+MwQ@n zDwtA~i!XF1(qeFU_`*9<0;^FatXYDsMsPTYm9UCs1qZ`nZB{Bua`2qU8qS%-4}e^p z1)>58%|=9*!B0kFiWHJ%tPo;Ug+mD~i4~)MmL^9^Kz1Z;8Y>~$sEH6$j>M-7ZzvX1 zQ;IB2s(2=(kDmXR-@cF8QQ2+LqB{HdlVbe~*_XoBP~tuLmoY`~ux)Y>o0e z+FIsq&i0XdBUUAYFu(Wbg}uv{3tKmY2dk@v?XL>k3qoP@cHzoxp>XZepArwS{FpuluZB!3VDRJc& z2|SbuRAN_6C~?WcIkgN7#?){qMuq|D^I~RAc(AomSlKRI`}N++;@--Q z0bwjDg2fZED?lnC%O4e%|77V0ESf)X`%zuOyCwEgq}X( z=T>IDkEAfu`jq_Azmls!Ad~-aBVXg)hS4u%y>H}B-w3cd@8~_ge&^ULU$=bi*=abR zfQa>?*1>uZ1?cp=2y+i;%!`;Tbk3o9a(Qj&f7^>X!v1{ z9|F^TH)=KO%{_mQ?(fa|d%rxU_rIR)e?8|PvFZ`W>s))5YuCAsEZ4Eibz*wj9s{pg zlG*{L6t+>&cy!?RVg87+6fKpYvW0!PCP4oZbICEsKq)8{Be?{82F1^5(AlkVR5^l% z=&(CDgDP}ON8YxE=IOK#l+0!z64`YTE(e&C-B2P*YVq19#K)}C2%l2Upj05SYAi|7 zSVr^SueJl3IujEDy$ZY+3SYcWkNf@qP(n-3IgvB*XknD4y%4v-JZ=YKxFa)UT1^>M zsZc~4RnkU1R$@wsDA0U~n#5s+h)xrnh7&8A;hMzd<1d&X#m~Y*ndVAhR=}JdZju5r zkMea5YwEI^Z)yAe$xlw|Ej`(mp1Up2EsZP=uQ&ar@%TMo)6VhEoUbeIYXVr-`qoC4 zMs@&~O*uYj0($L(r4P1xSAKb&1vK7t-0}A0Pj{`em%U)I-+}WaF50#(;qu-oN? z#{oxSWc5H`9=#tO4KsY===rC?4**jF-BBIThAC{ULv$u-=P2)M;o3S>I4JhF3)g=a zI5#G`D)z9dxJA|u*2@afu$ul+EcR|BE~_bmDU7VEjI}}E2RYMLxj~O@GHpSG*4BCS zSL+gy_juO^mk0B_Z|(fjd7T%sypZEh-{U+w*OuklcDYke$?X+b>VM2_-~XRm-1-EY zQpVx;#Zj5(wByKJ)AlM9ZhQ>wgyx#Ha&6XUsOeHD7MWEHHmXMAkEYhBA)1=7dR*ps zWroZ1ec%Wg0#cb;-Q&OG@n4tq&cSTwpx${l+j%zE`5I(f=TB$((>mXk<-2xyao>r$ ze$4E6{ARMpM2=n*X$zJlqehZuR5=M3V9DSm>HTCVW_`g8@H>2l5_&i>1puage1^Nu%8lhjRDHh q!frJ!ZqV{-2)_(-v>Fk(iJ*Na!!X~Xns1TspYE5Ko&yBLH2W{sRVBdy literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_player.py b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_player.py new file mode 100644 index 0000000..3ec9494 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_player.py @@ -0,0 +1,64 @@ +import cv2 #opencv +import threading #thread 분할 (webcam streamming 중에 반복문으로 프레임을 읽어와서 보여줘야하는데 다른작업도 해야해서 들고옴) + + +class VideoPlayer: + def __init__(self): + self.file_address = 'C:/ROKEY/ROMiserables/ROMiserables/03151_minsuje/hw/week2(py)/CCTV_project/CCTV_minsuje/src/recorder/cctv_recorded/' + self.capture = None + self.video_play_thread = None + self.is_playing = False + self.allowed_formats = ['mp4', 'mkv', 'mov','avi'] + + def open_video_file(self, file_name): + """비디오 파일을 열어 재생하는 함수.""" + # 파일 형식 확인 + if not any(file_name.endswith(fmt) for fmt in self.allowed_formats): + print(f"지원되지 않는 파일 형식입니다: {file_name}") + return + + # 비디오 파일 읽기 없으면 return + self.capture = cv2.VideoCapture(self.file_address+file_name) + if not self.capture.isOpened(): + print("비디오 파일을 열 수 없습니다.") + return + + # 재생중 플래그 및 쓰래드 시작 + self.is_playing = True + self.video_play_thread = threading.Thread(target=self._play_video) + self.video_play_thread.start() + + def _play_video(self): + while self.is_playing: + ret, frame = self.capture.read() + if not ret: + print("비디오 끝.") + break + + # 비디오 피드를 화면에 표시 + cv2.imshow('Video Playback', frame) + + # 'ESC'를 눌러 종료 + if cv2.waitKey(1) & 0xFF == 27: # ESC 키 코드 + self.is_playing = False + break + self.release_resources() + + def release_resources(self): + """비디오 자원 해제.""" + self.is_playing = False + if self.capture: + self.capture.release() + cv2.destroyAllWindows() + + def stop_video(self): + """비디오 재생 중지.""" + self.is_playing = False + if self.video_play_thread and self.video_play_thread.is_alive(): + self.video_play_thread.join() + +# play_cam = VideoPlayer() +# play_cam.open_video_file("") +# play_cam._play_video() +# play_cam.release_resources() +# play_cam.stop_video() \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_recorder.py b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_recorder.py new file mode 100644 index 0000000..2eb0a43 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/recorder/video_recorder.py @@ -0,0 +1,24 @@ +import cv2 +import datetime + +class VideoRecorder(): + def __init__(self): + self.path_record_adress = "C:/ROKEY/ROMiserables/ROMiserables/03151_minsuje/hw/week2(py)/CCTV_project/CCTV_minsuje/src/recorder/cctv_recorded/" + self.recording = None + + def open_video_record(self, frame_size): + timestamp = datetime.now().strftime('%Y%m%d_%H%M%S') + file_name = f"{self.path_record_adress}CCTV_{timestamp}.avi" + fourcc = cv2.VideoWriter_fourcc(*'XVID') + self.out = cv2.VideoWriter(str(file_name), fourcc, 20.0, frame_size) + print(f"녹화 시작: {file_name}") + + def on_air_recording(self,frame): + if self.recording: + self.recording.write(frame) + + def stop_recording(self): + if self.out: + self.out.release() + self.out = None + print("녹화 중지 및 저장.") \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_selecter.py b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_selecter.py new file mode 100644 index 0000000..0e9b976 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_selecter.py @@ -0,0 +1,57 @@ +import cv2 +class WebCamSelecter(): + def __init__(self): + self.cam = None + self.selected_cam = None + self.cam_list = [] + self.cam_name = {} + self.find_cam_list() + + # 카메라를 찾을때 window 11에서만 그럴진 모르겠지만 장치가 한번 이상 인식되면 계속 남아서 연결할수 있게 뜨는데 실제로 연결 안되있으면 error를 반환하긴함 + # 지금 이컴퓨터에 전에 다른 웹캠을 연결 한적있는데 그게 1,2번으로 잡혀 있고, 연결되어있지 않아서 error가 뜸 동작은 함함 + def find_cam_list(self): + index = 0 # 웹카메라는 노트북의 경우 0번이 노트북 카메라고 나머지가 1~n의 번호로 불러올수있음 + f_cam_list = [] + while(True): + self.cam = cv2.VideoCapture(index) + ret, frame = self.cam.read() # ret은 카메라 상태가 동작가능하면true, 불가능하면 false 프래임은 현재 프레임을 받아옴 + if(not ret): + break # 더 이상 읽어올 카메라 없음. + self.cam_list.append(index) # 캠의 번호만 저장하는게 프로그램에 덜무리감감 + self.cam.release() # 카메라 메모리 해제 cam에는 더이상 카메라 정보를 받지 않음 + self.cam_name[index] = ' ' + index +=1 + + def select_cam(self,cam_num=0): + self.selected_cam = self.cam_list[cam_num] + + def name_set(self,cam_num:int, name:str): + if len(name) <2: + raise Exception("카메라 이름의 문자는 길이가 1보다 커야합니다.") + if name in self.cam_name.values(): + raise Exception(f"이미 '{name}'라는 카메라 이름이 존재합니다.") + self.cam_name[cam_num] = name + + def rename(self,last_name,new_name): + if len(new_name) <2: + raise Exception("카메라 이름의 문자는 길이가 1보다 커야합니다.") + if new_name in self.cam_name.values(): + raise Exception(f"이미 '{new_name}'라는 이름이 존재합니다.") + for index, name in self.cam_name.items(): + if(last_name==name): + self.cam_name[index] = new_name + + def name2index(self,name:str): + for index, cam_name in self.cam_name.items(): + if cam_name==name: + return int(index) + + +# webcam = WebCamSelecter() +# webcam.find_cam_list() +# print(webcam.cam_name) +# webcam.name_set(0,"노트북카메라") +# webcam.name_set(1,"엘가토 웹캠") +# webcam.name_set(2,"모르겠음 웹캠") +# print(webcam.cam_name) +# print(webcam.name2index("엘가토 웹캠")) diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py new file mode 100644 index 0000000..a35302e --- /dev/null +++ b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py @@ -0,0 +1,69 @@ +import cv2 #opencv +import threading #thread 분할 (webcam streamming 중에 반복문으로 프레임을 읽어와서 보여줘야하는데 다른작업도 해야해서 들고옴) + +#from src.recorder.video_player import VideoRecorder + +class WebCamStreamer(): + def __init__(self,cam_num=0): # 노트북은 캠이 기본 탑재 되어있어서 그냥 아무것도 선택안하면 노트북 웹캠 자체그대로로 + self.selected_cam_number = cam_num + self.capture = None + self.stream_thread = None + self.is_streamming = False + #self.recorder = VideoRecorder() + + def open_cam(self): + self.capture = cv2.VideoCapture(self.selected_cam_number,cv2.CAP_DSHOW) + if not self.capture.isOpened(): # 열려있는지 확인 + raise Exception("카메라가 연결되지 않아 스트리밍을 할 수 없습니다.") + self.is_streamming = True #스트리밍 상태가 True가 되야 스트리밍 함수 내부에 while로 돌릴수 있음. + self.stream_thread = threading.Thread(target=self.cam_streamming) #쓰레드 분할 타겟 스트림 함수 + self.stream_thread.start() #스트림 스래드 활성화 + + def cam_streamming(self): + while self.is_streamming: + ret, frame = self.capture.read() #정보를 읽어와서 + if not ret: #상태가 False이면 읽어올수 없는 상태임 + print("프레임을 읽을 수 없습니다. 다시 시도합니다....") + continue + # frame은 하나의 이미지임 그래서 cv2의 이미지를 읽어오는 imshow함수 사용 + cv2.imshow("streamming_On_Air...",frame) + # cv.waitkey는 입력 키의 값을 나타내는 정수를 반환하는데 + # 비트 마스크 0xFF로 받은 키 값의 하위 8비트만 확인한다 + # 27번은 esc키의 입력값이고 해당 값이 들어오면 스트리밍을 종료한다. + key = cv2.waitKey(1)&0xFF + if key==27: + break + # if key== ord('r'): + # if self.recorder.recording==False: + # video_frame_size = (int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)), + # int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))) + # self.recorder.open_video_record(video_frame_size) + # self.is_streamming = True + # else: + # self.recorder.stop_recording() + # self.is_recording = False + # print("녹화 중지!") + self.close_stream_resources() + # if self.recorder.recording: + # self.recorder.stop_recording() + # self.is_recording = False + # print("녹화 중지!") + + def close_ALL_resources(self): + self.close_stream_resources() + self.close_thread_resources() + + def close_thread_resources(self): + if self.stream_thread and self.stream_thread.is_alive(): + self.stream_thread.join() # 스레드가 종료될 때까지 기다림 + + def close_stream_resources(self): + if self.capture: + self.capture.release() # 연결 해제 + cv2.destroyAllWindows() # opencv로 연 모든 윈도우창 닫기 + self.is_streamming = False + +play_cam = WebCamStreamer() +play_cam.open_cam() +play_cam.cam_streamming() +play_cam.close_ALL_resources() \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/README_project.md b/03151_minsuje/hw/week2(p)/CCTV_project/README_project.md new file mode 100644 index 0000000..4539470 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/CCTV_project/README_project.md @@ -0,0 +1,46 @@ +# CCTV 개발 프로젝트 +## 목적 +- 본 Rokey 커리큘럼내에 있는 딥러닝 맛보기 + +- 본 Rokey 커리큘럼내에 있는 OpenCV 맛보기 + - 딥러닝보다는 OpenCV사용에 조금 더 초점이 맞춰져 있음 + +## 절차(목차) +1. 가상환경 생성 + +2. opencv 라이브러리 설치 +3. webcam 열기 + - 강의를 위해 사용중인 webcam을 기준으로 제작 + - 만일 webcam 없다면, 사용할만한 영상 제공 +4. webcam 영상 저장 +5. 영상 내 도형 그리기 및 글자 입력(OpenCV 심화) +6. 딥러닝 알고리즘 사용을 위한 환경 설정(cuda 또는 필수 라이브러리 설치) (**중요**) + - 본 프로젝트 담당자의 노트북을 성능을 기준으로 설치할 예정 + - 개인 노트북의 성능을 기준으로 설치할 것 +7. webcam 영상에 딥러닝 알고리즘 적용 + - 본 프로젝트에서는 학습 및 알고리즘 설명을 제외 + - 간단한 설명만 추가 예정 +8. tracking 알고리즘 적용 + - 딥러닝 알고리즘과 동일하게 간단한 정의만 설명 예정 +9. people counting 알고리즘 적용 + + + +## 내용 +### 1. 가상환경 생성 + +### 2. OpenCV 라이브러리 설치 + +### 3. Webcam 열기 +### 4. Webcam 영상 저장 +### 5. 이미지내 선 및 도형 그리기 및 글자 입력(OpenCV 심화) + +### 6. 딥러닝 알고리즘 사용을 위한 cuda 설치 및 환경 셋팅 + +### 7. webcam 영상에 딥러닝 알고리즘 적용 + +### 8. tracking 알고리즘 적용 + +### 9. people counting 알고리즘 적용 + + diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/minsuje_cctv_project.md b/03151_minsuje/hw/week2(p)/CCTV_project/minsuje_cctv_project.md new file mode 100644 index 0000000..8542649 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/CCTV_project/minsuje_cctv_project.md @@ -0,0 +1,81 @@ +# 배재성님의 CCTV 프로젝트 + +- 작성자 : 제민수(ROKEY 3기생 DR-05131) +- 작성 기간 : 2025-01-22~(진행중) +- 버전 관리 : 1.2.1 ver +- 0.1.x 1주차 웹캠 열기까지 할 예정 + + +- +## 📜목차 + +- [개요](#개요) + [작성의 목적](#작성의-목적) + [CCTV 목적](CCTV-목적) + +- [프로그램](#프로그램) + +- [기타](#기타) +__________________________ +________________________ + +## 개요 + ### 작성의 목적 +- ROKEY 3기 프로그램 진행에서 스터디 그룹에서 코딩 리뷰 및 학습 내용 공유를 위함. +- 스터디 피드백 내용 정리 + - 추가예정 +- 해당 문서는 ROKEY 3기생 DR-03151제민수가 작성 하였으며, 문서 및 파일은 직접 수정하지 않는다. + + ### CCTV 목적 +- 본 Rokey 커리큘럼내에 있는 딥러닝 맛보기 + +- 본 Rokey 커리큘럼내에 있는 OpenCV 맛보기 + - 딥러닝보다는 OpenCV사용에 조금 더 초점이 맞춰져 있음 + +___이라고 함_________________________________________________________________________ +- 영상 읽고 저장 및 영상 내에 도형 및 글자 입력.(????) +- 영상 내에 사람 트레킹 딥러닝 알고리즘 작성 및 사람 카운팅 +_______________________ +_____________ +## 프로그램 + +### 프로젝트 진행 순서 +1. 가상환경 생성 + +2. opencv 라이브러리 설치 +3. webcam 열기 + - 강의를 위해 사용중인 webcam을 기준으로 제작 + - 만일 webcam 없다면, 사용할만한 영상 제공 +4. webcam 영상 저장 +5. 영상 내 도형 그리기 및 글자 입력(OpenCV 심화) +6. 딥러닝 알고리즘 사용을 위한 환경 설정(cuda 또는 필수 라이브러리 설치) (**중요**) + - 본 프로젝트 담당자의 노트북을 성능을 기준으로 설치할 예정 + - 개인 노트북의 성능을 기준으로 설치할 것 +7. webcam 영상에 딥러닝 알고리즘 적용 + - 본 프로젝트에서는 학습 및 알고리즘 설명을 제외 + - 간단한 설명만 추가 예정 +8. tracking 알고리즘 적용 + - 딥러닝 알고리즘과 동일하게 간단한 정의만 설명 예정 +9. people counting 알고리즘 적용 + + ### 입출력 정리 + #### 입력 + - webcam data + #### 출력 + - people counting num + +### 필수 사용 라이브러리 및 프로그램램 +- opencv +- cuda (????????????????????????) + +## 기타 + +### 문제 풀이 진행 순서 및 주의 사항(막쓰고 수정예졍) + #### 진행 순서 + + #### 주의 사항 + 1. 제한사항을 꼭 코드작성시 적용 할것. + 2. 함수 작성시''''''' 을 이용하여 설명을 꼭 작성 할것 + + +### 체크리스트 diff --git a/03151_minsuje/hw/week2(p)/important road/README.md b/03151_minsuje/hw/week2(p)/important road/README.md new file mode 100644 index 0000000..eda30cc --- /dev/null +++ b/03151_minsuje/hw/week2(p)/important road/README.md @@ -0,0 +1,13 @@ +# 프로그래머스 테스트코드 : 중요한 로드 문제 풀기 +> 저는 프로그래머스에 있는 문제를 선택하여 진행하였습니다. +해당 문제풀이 및 작성 도중 필요한 문서까지 작성하였는데 +참고하셔도 좋고 참고 하지 않으셔도 좋습니다. +그럼 토요일 스터디에서 뵙겠습니다. +해당 문제에 대한 자세한 사항을 알고 싶으시다면 아래 링크를 참조해 주세요. + + +https://school.programmers.co.kr/learn/courses/30/lessons/214293 + +예제 코드는 성공 했는데 아무래도 제출에는 입력되는 량이 커서 그런지.. 시간 초과가 뜨네요... +토요일까지 수정 해보고자는 하는데.... 될진 모르겠습니다. 최대한 수정해서 올려보겠습니다 우선 초안부터 올리겠습니다 다른분들도 문제 풀어는 봐야 되니까요. +우선 어려운문제로 해봤는데 다음에는 스택과 큐 같은 기초 알고리즘 문제를 선택해봐야 겠어요. \ No newline at end of file diff --git a/03151_minsuje/hw/python/code_test/important road/image_data/ex1-1.png b/03151_minsuje/hw/week2(p)/important road/image_data/ex1-1.png similarity index 100% rename from 03151_minsuje/hw/python/code_test/important road/image_data/ex1-1.png rename to 03151_minsuje/hw/week2(p)/important road/image_data/ex1-1.png diff --git a/03151_minsuje/hw/python/code_test/important road/image_data/ex1-2.png b/03151_minsuje/hw/week2(p)/important road/image_data/ex1-2.png similarity index 100% rename from 03151_minsuje/hw/python/code_test/important road/image_data/ex1-2.png rename to 03151_minsuje/hw/week2(p)/important road/image_data/ex1-2.png diff --git a/03151_minsuje/hw/python/code_test/important road/importantroad.py b/03151_minsuje/hw/week2(p)/important road/importantroad.py similarity index 100% rename from 03151_minsuje/hw/python/code_test/important road/importantroad.py rename to 03151_minsuje/hw/week2(p)/important road/importantroad.py diff --git a/03151_minsuje/hw/python/code_test/important road/importantroad2.py b/03151_minsuje/hw/week2(p)/important road/importantroad2.py similarity index 97% rename from 03151_minsuje/hw/python/code_test/important road/importantroad2.py rename to 03151_minsuje/hw/week2(p)/important road/importantroad2.py index 1766a56..8eec099 100644 --- a/03151_minsuje/hw/python/code_test/important road/importantroad2.py +++ b/03151_minsuje/hw/week2(p)/important road/importantroad2.py @@ -2,7 +2,7 @@ 작성 사유 : ROKEY 스터디 코드 리뷰용 코드 작성 작성자 : 제민수 진행하는곳 : ROKEY 3기 스터디 중 -작성 날짜 :2025.01.18~2025.01.19 +작성 날짜 :2025.01.19~ ver : 2.0ver 작성 언어 :python 이외 프로그램 작성 중 정리 문서는 prepare2slove_program 문서를 참조 한다. @@ -74,13 +74,13 @@ def __shortest_path(self): 현재 지점에 인접한 지점을 탐색 하고 그 지점을 큐에 추가한다. ''' - #다익스트라 알고리즘을 이용하여 최단 시간을 알아야 해서 경로의 최단시간만 알면 됨됨 + #다익스트라 알고리즘을 이용하여 최단 시간을 알아야 해서 경로의 최단시간만 알면 됨 - #queue의 역할을 할 변수 location_info 작성-시간과 지역역 값을 확인하며 리스트에 튜플로 작성한 이유는 + #queue의 역할을 할 변수 location_info 작성-시간과 지역 값을 확인하며 리스트에 튜플로 작성한 이유는 임의로 변경 하면 안되기때문 # 최단 시간 변수 #shorest_time 에 location키의 벨류 값은 short_time의 최대값을 넣어야 최초 비교때 최솟 값을 넣을 수 있음 - #따라서 도로의 최소수(1-2-3-4-5이런식으로 하나씩만 연결됬고 모든 도로를 지나야 될때 이게 제일 큰값임임)*2*트레픽 최대값을 넣어줌. + #따라서 도로의 최소수(1-2-3-4-5이런식으로 하나씩만 연결됬고 모든 도로를 지나야 될때 이게 제일 큰값임)*2*트레픽 최대값을 넣어줌. shortest_time = {location: self.__MIN_ROADS_LEN*2*ImportRoad.__MAX_TRAFFIC for location in range(1, self.location_num + 1)} # 최단 시간 초기화 내부의 키를 location이라 칭한것은 해당 위치까지 가는 최단 시간을 찾는 것이기 때문 shortest_time[1] = 0 #1번지점에서 1번지점 이동 시간은 0임 diff --git a/03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md b/03151_minsuje/hw/week2(p)/important road/prepare2slove_problem.md similarity index 89% rename from 03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md rename to 03151_minsuje/hw/week2(p)/important road/prepare2slove_problem.md index c421a6e..a542d14 100644 --- a/03151_minsuje/hw/python/code_test/important road/prepare2slove_problem.md +++ b/03151_minsuje/hw/week2(p)/important road/prepare2slove_problem.md @@ -9,17 +9,17 @@ - ## 📜목차 -## [개요](#개요) -- [작성의 목적](#작성의-목적) -- [중요한 도로 문제의 목적](#중요한-도로-문제의-목적) - -## [프로그램](#프로그램) -- [문제에서 사용할 변수 이름](#문제에서-사용할-변수-이름) -- [제한사항](#제한사항) -- [문제 요구사항 정리](#문제-요구사항-정리) -- [입출력 정리](#입출력-정리) +- [개요](#개요) + [작성의 목적](#작성의-목적) + [중요한 도로 문제의 목적](#중요한-도로-문제의-목적) -## [기타](#기타) +- [프로그램](#프로그램) + [문제에서 사용할 변수 이름](#문제에서-사용할-변수-이름) + [제한사항](#제한사항) + [문제 요구사항 정리](#문제-요구사항-정리) + [입출력 정리](#입출력-정리) + +- [기타](#기타) ## 개요 @@ -56,10 +56,10 @@ ### 문제 요구사항 정리 - 도시의 지점은 각각 숫자로 표기하며 항상 1번 지점이 출발지 n번 지점이 목적지 이다. - 선분에 표기된 것은 [#도로 번호] 길이/교통량을 의미한다. -![ex-1](./image_data/ex1-1.png) +![ex-1](./image_data/ex1-1.png) - 목적지에 도착하기 까지 가장 빠른 예상 소요 시간은 1-2-4-5와 같이 이동 했을때 20 분이다. - 여기서 7번 도로의 교통 량이 3 증가 한다고 가정한 그림은 아래와 같다. - ![ex-2](./image_data/ex1-2.png) + ![ex-2](./image_data/ex1-2.png) 목적지에 도착하기 까지 가장 빠른 소요 시간은 1-2-5로 이동하여 22이다. 모든 도로의 교통량 정보를 실시간으로 업데이트 하는 것은 비효율 적이다. 한도로의 교통량이 변했을때 가장 빠른 예상 소요 시간이 변 할 수 있는 도로 (5,7)에 대해서만 실시간으로 교통량 정보를 업데이트 해햐 한다. @@ -84,12 +84,11 @@ #### 진행 순서 1. 우선 지도를 그려야한다. - 주어지는 n(지점의 개수)와 roads의 정보를 통해 이동 맵을 그려야함 - 2. 최단 거리를 찾아야한다. + 2. 최단 시간을 찾는 함수 작성성. - 다 익스트라 최단 경로 알고리즘을 이용하자(학습해야함) - - 그려진 이동 맵을 통해 최단 거리를 찾아야 한다. - - 단 최단 거리가 여러개 일 경우 여러개 모두 값으로 저장해야 한다. + - 그려진 이동 맵을 통해 최단 시간을 찾는다 3. 결과값 출력. - -찾은 최단 거리가 교통량 변경에 따라 바뀌는 도로를 찾아 출력해야함. + -찾은 최단 시간이 교통량 변경에 따라 바뀌는 도로를 찾아 출력해야함. #### 주의 사항 1. 제한사항을 꼭 코드작성시 적용 할것. 2. 함수 작성시''''''' 을 이용하여 설명을 꼭 작성 할것 diff --git a/03151_minsuje/hw/week2(p)/king/King.md b/03151_minsuje/hw/week2(p)/king/King.md new file mode 100644 index 0000000..c27b53c --- /dev/null +++ b/03151_minsuje/hw/week2(p)/king/King.md @@ -0,0 +1,76 @@ +https://www.acmicpc.net/problem/1063 +# 백준 코드문제 1063번 킹킹 + +- 작성자 : 제민수(ROKEY 3기생 DR-05131) +- 작성 기간 : 2025-01-22~(진행중) +- 버전 관리 : 0.1 ver +- 0.x 프로그램 실행 안됨 문서 작성중 +- 1.x 프로그램 실행 됨 +- +## 📜목차 + +- [개요](#개요) + [작성의 목적](#작성의-목적) + [킹 문제의 목적](#킹-문제의-목적) + +- [프로그램](#프로그램) + +- [기타](#기타) + + +## 개요 + ### 작성의 목적 +- ROKEY 3기 프로그램 진행에서 스터디 그룹에서 코딩 리뷰 및 학습 내용 공유를 위함. +- 스터디 피드백 내용 정리 + - 추가예정 +- 해당 문서는 ROKEY 3기생 DR-03151제민수가 작성 하였으며, 문서 및 파일은 직접 수정하지 않는다. + + ### 킹 문제의 목적 +- 도시의 이동 지점 및 차량 도로에 대한 정보를 이용하여 최단 경로를 찾으며, 도로의 트레픽 값이 하나 변경된다 가정 했을때 현재의 최단 경로가 변경 될때 영향을 주는 도로의 번호를 찾는 것이 목적이다. + +## 프로그램 + +### 문제에서 사용할 변수 이름 + +### 제한사항 +- 주어지는 움직이는 횟수 N은 50보다 작거나 같음. +- 체스판의 크기는 8x8 y축 1~8, x축 A~H +- 킹하나 있음. +- 돌도 하나 있음. +- 움직이는 정보는 8가지중 하나 + - R 한칸 오른쪽 + - L한칸 왼쪽 + - B 한칸 아래 + - T 한칸 위 + - RT 오른쪽 위 대각선 + - LT 왼쪽 위 대각선 + - RB 오른쪽 아래 대각선 + - LB 왼쪽 아래 대각선 + + +### 문제 요구사항 정리 +- 8x8 체스판에 돌하나와 킹 하나가 있다. +- 킹은 8방향으로 한칸씩 이동 가능하고, 사용자는 입력받은 데이터를 통해 움직이는 킹과, 특수하게 움직이는 돌의 마지막 위치를 반환하면 됨. +- 돌의 경우 킹이 돌위치로 이동해야할때 킹의 이동방향과 같은 벡터로 한칸만 이동하면된다. + + ### 입출력 정리 + #### 입력 + - 첫째 줄에 킹의 위치, 돌의 위치,움직이는 횟수 N + - 둘째줄 부터 N개의 줄에는 킹이 어떻게 움직여야하는지 주어짐 + - N은 50보다 작거나 같은 자연수 + #### 출력 + - 첫줄에 킹의 마지막 위치 둘째줄에 돌의 마지막 위치 출력 + +## 기타 + +### 문제 풀이 진행 순서 및 주의 사항(막쓰고 수정예졍) + #### 진행 순서 + 1. 각각의 위치 좌표를 계산 하기 편하게 좌표평면 값으로 변환 0~7,0~7 + 2. 명령어에 대해 이동 방식을 정함. + 3. 이동 방법에 대한 함수 작성(범위 벗어남 확인 벗어나려하면 명령어 무시) + 4. 완료된 위치 좌표 반환 후 출력력 + + #### 주의 사항 + 1. 제한사항을 꼭 코드작성시 적용 할것. + 2. 함수 작성시''''''' 을 이용하여 설명을 꼭 작성 할것 + diff --git a/03151_minsuje/hw/week2(p)/king/__pycache__/chess_board.cpython-312.pyc b/03151_minsuje/hw/week2(p)/king/__pycache__/chess_board.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59d64414d3f65cf57b43579868a44f0dabbff62a GIT binary patch literal 3585 zcmaJ@Z%kX)6~FI28*GQnV4K=BqII^ zA-S^8yZ4-P|GeM(opbI#4jwcRXv_Z$Uj6Dvg!~H!YSZL8yEf>A2uscqflL#DdBkQd zJ!Fivb1u~%pGjzQH%ZmL4$r7^r-^+<)wWzs(Li4{y9CJ zOZ7ULxg<01$V`XKT$b5O@P7xN9q{bvvX{vQ!6Uj|evi*9$rXTr)9-V7yn_3NtU*v@ zEq!BIr@oG?8TS3oZP&;e$vt#M)~U$J`aCqE1x_U4mqOtGd(qX_d+FB~e)&GgcRi9@ z?E7%YE$tmNA9wuR;T-mOrI7)5Z~tiTsM|f*(s*sm-isUbx{#U950RS3u8qk$C!Epa zcRI(-1=Rr*7QfM&+{+(xQvHZ1ii zOMSF|-SRWg={G@BeI!+VBs#WU?EsBo)5gQ&;Fhl9j{cVZlLNc3JaOfD3_<-ToDGtoxBI^@by9Y)R@`#6vK555mZ5itst; zAi}+X|0Fxf72{fjT0Y~9gTIRRT{6J}=AgMt770PsFw9)^V| zn24mSUliX2g^Hw>MwR$u^r-`}7fZQPS?IU0fQCdXmQGq^|izG!aRP<|XK0R#zG8VsEg6uM={E5w#2v z*g-(q%eq(wHD=JDCx-;s&$An}4519gl2C-}pPwq9C6tHLIbLqZr+DS-1m?tYCMM1kAk2$S5^f(!_4g4fA}bTapt3MjV)0}jEl7| zmpwQguUa|{WThgDaX!Xjc0MO~K?{r}1E4HzXUGQ+fX572@xUc*f@YCP7Oa{Q6AW`X z25LNh4`lUA{AdnB=Bs{JAa1}Hi$qB)B6czfB=`Y!A3y2bAQ{ur`l(Y>}g6) zrFqGzG-?FHsUj2LRdg4?n?WACnV5!*agZUO!jX&k7oAe>eUT1A4y5%M$e8~0b7gTF zI2BIc3@dZXz{fC@Y53&}bj}wExfssOLwco2m8RFlMEXvI&JL>VeFb@!M*mp9TKBkO)&H!0Z8X*VcG7w_aBjNupKhlfqE0!$OeppBet?=2I ze4`Q$wDFA%?T&_{d_#w$!EVp<&(4WQ;P6?#QK~VNY7#<`ORER3y8T$OJoE-RZYyHb z9!nQYk(xjNttv>RWy8p)jC|Dcux6=d-S}4Q@lK;q&$lyPZzi;B*fAgpncaS2&&5NBV}c77aecaiEqOp_hfrnT&}mTQmin98+|9g_xn6*g_%ZflwL0+XGMbGqydom;Y~toudw dXs1MsBDyld_MBrF=09vV!(3o?2z}7C{tvQX(XRji literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/king/chess_board.py b/03151_minsuje/hw/week2(p)/king/chess_board.py new file mode 100644 index 0000000..301e329 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/king/chess_board.py @@ -0,0 +1,81 @@ +class ChessBoard: + def __init__(self, king_pos, stone_pos, commands): + ''' + 초기화 함수 + - king_pos: 왕의 초기 위치 + - stone_pos: 돌의 초기 위치 + - commands: 명령리스트트 + ''' + # 명령어 좌표 이동동 + self.directions = { + 'R': (0, 1), # 오른쪽 (y축 증가) + 'L': (0, -1), # 왼쪽 (y축 감소) + 'B': (1, 0), # 아래쪽 (x축 증가) + 'T': (-1, 0), # 위쪽 (x축 감소) + 'RT': (-1, 1), # 오른쪽 위 대각선 + 'LT': (-1, -1), # 왼쪽 위 대각선 + 'RB': (1, 1), # 오른쪽 아래 대각선 + 'LB': (1, -1) # 왼쪽 아래 대각선 + } + + # 초기 위치 정보 변환하여 저장 및 명령어 저장 + self.king = self.pos_to_index(king_pos) + self.stone = self.pos_to_index(stone_pos) + self.commands = commands + # 초기화 후 내부에서 바로 결과 내는게 더 맞다고 생각들어서함. + self.move() + + def pos_to_index(self, pos): + ''' + 문자열 위치를 좌표 평면으로 변환 + ''' + col, row = pos[0], pos[1] # pos에서 열과 행을 분리 + # 행은 1부터 시작되므로, 배열에서는 row - 1로 변환 + # 열은 'A'의 ASCII 값에서 빼서 0부터 시작하는 숫자로 변환 + return (int(row) - 1, ord(col) - ord('A')) + + def index_to_pos(self, index): + ''' + 좌표 평면위치를 문자열 위치로 변환 + ''' + row, col = index # 인덱스에서 행과 열을 분리 + # 행은 1부터 시작되고, 배열은 0에서 시작 됨으로row+1 + # 열은 'A'의 ASCII 값에서 빼서 0부터 했으니 반대로 'A'를 더해서 ASCII로 변환환 + return f"{chr(col + ord('A'))}{row + 1}" + + def is_within_bounds(self, pos): + ''' + 주어진 좌표가 체스판의 범위 내에 있는지 확인하는 함수 + ''' + return 0 <= pos[0] < 8 and 0 <= pos[1] < 8 + + def move(self): + ''' + 저장된 명령어들을 하나씩 처리리 + 명령에 의해 좌표를 이동 하되 범위내에 있는지 확인하며 벗어났으면 무시하고 넘김김 + ''' + for command in self.commands: + move = self.directions[command] + # 명령에 의한 king의 새로운 좌표 위치 저장 + new_king = (self.king[0] + move[0], self.king[1] + move[1]) + # king이 좌표를 벗어 나면 + if not self.is_within_bounds(new_king): + continue # 다음명령으로 감 + # 새로운 king의 좌표가 stone의 좌표와 같으면 + if new_king == self.stone: + # stone은 king의 이동과 같은 방향으로 같은 크기로 이동 + new_stone = (self.stone[0] + move[0], self.stone[1] + move[1]) + # stone이 좌표를 벗어 났으면 + if not self.is_within_bounds(new_stone): + continue # 다음명령으로감 + # stone의 위치 업데이트 + self.stone = new_stone + # king의 위치 업데이트 + self.king = new_king + + def get_positions(self): + ''' + 문자열 위치 좌표로 king과 stone 위치 반환. + ''' + # 왕과 돌의 좌표를 문자로 변환하여 반환 + return self.index_to_pos(self.king), self.index_to_pos(self.stone) \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/king/king_move_program.py b/03151_minsuje/hw/week2(p)/king/king_move_program.py new file mode 100644 index 0000000..f34f6d3 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/king/king_move_program.py @@ -0,0 +1,14 @@ +from chess_board import ChessBoard + + +# 입력 받기 +king_pos, stone_pos, n = input().split() +n = int(n) +commands = [input().strip() for _ in range(n)] +# 게임 초기화 및 실행 +game = ChessBoard(king_pos, stone_pos, commands) +king_final, stone_final = game.get_positions() + +# 결과 출력 +print(king_final) +print(stone_final) \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/account_manager.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/account_manager.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..89bc4197d1c0c17d7247921146d9eb4b910b1b4b GIT binary patch literal 3125 zcmcgu-%s0C6ux#6Fiq05P_>lN;?im(vAzTCbLZP<&%E{y*fzh& z3+(v-FXlfSJ$|h57}Mtuic$~X**(}f$n(ARH3MOHrx=pBFjJ2mOs~K1t8Q}o_st!<^bL$aW9w=l-gSzvyN>~l~=Bo*UII!%jHL6)@#mn7(_k- z+f2*iR|}3f3T4N7ve=lR2${&8LvBKP3H)mhqT1{vtzKKurXQxG3+misIz2X~O+VJ+ z6IyhNR&P(KA58&db{$xOXE|O_ocKQrZITc$^F;h=TCjr^C@{m7o0gfkA2>qX31$TS z;;LA6)yS@zWmoMIRVz5bo3}>H0i7eSLg$~>2%It54$)?t&)`BJ;5R8927fvc)n@L} z1tFld*%57K4wxmlV2ZMRQ1FNN?8=1_a0+-8Ig3}EB71QoW(y2?qYgZG7Z`wnDqE$h zWvY6%;ZDo#mLI5N1`@dyfLEp?u>u{VT6&1+j#s$VYB+UUk{4SYcmtttr1#F zyszDSsNP+KXZ6k)jc3iy(Q6AM>gZg0GMP!Sg?`5&r7lrt5P^Y5@4}{C!VqT*ZevyE zf^HIVfllS%&y&koD)dHu+Cteq}g}sbsxRA_TW+aW)4Z8Vr7$F1e04Y`nSv^)X%@! zLTb`D4l#{|Ltye*YYX&u`Gdo|Hj!2LR^jMtV04Zq8a{5h)gs$#Fh}jK@s=wsiE`Oq zy>zfawl^;B{NCQ2Dyz#KnQfNso`o7b@Je&+^myBqwnUBWIJk7EQFfe2Id-f%_REg_ zD-JqU*7(G+BR62#abod+>^KSk`GF_(jnF-%`S zC&87IQ5+2Oo&@Erj|li+*RMf(Sqm6O0bkLQNKb2AldRZ_4csu79lceqCXB25W zj7|MB%4w@#-|w_}jd?iQP3pH1eWu_6$3{wp@){r1D%8OM-a@ey%x@NgAbv!pzgyje L_Zb{QM!LTNK8R^2 literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/file_reader.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/file_reader.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fc8597030a90bfa811c81b5861f7674dc51c9969 GIT binary patch literal 1584 zcma)6&2Jl35TCan{=z14;*=nfG?X^20ogdgQi&oYi-v|Yb(_#jf-7t5-H>(s#lE#R zj_l$}NKMs9xauLP0Aa+1Dwq5L9Ow;+ivxw4Z4OABa!ZIrq@0*%d*h}=h<)05^JZq> z&Tr=T-cKHn3-AfusC*pd0sdqQ>#?=)^I2sil@~K%_o)Myb&}MWnt)CuHX++JuesH zL(C9gP}5UEDUrzLGkQQ@)Jk|MauE-_D=0?xT_15CJ;>ny$SjAk zwlBFNV4R&m6adTL7*@svitr&kUvy?`mE93FiDr^Fw^<>!8TxGo+|QYgoJ6US z)nv0{PEu2f9G7%mN#}H`H6m=Lkj*I>)A{}flVkC#k!$0oNOeuk;gn0My2+=|%c~jP zFPM&28>mU-2grZ*ApYLM&nVo8-H|hr17zNBX-#M*z=8#&0)@Q zO_5|p3*-u>hpBNZ4ecfTEvqdppeRGV!&@HTa(Y(OweH8xzN+`BuV?u}-PgN1ac|=O z|lv2@kMeRO^e(Ycq<^act)+3-k>Au;#W3{f_Qq*9!I&t zzX(^b=w^#*42;I^B8@@QSQAX*@(Y@qEj?^0sz@|yiiU;?db*gWn|U00yb&@|S}_G# z(xpT8XeXHW#l{EiCikO}HJW~eq72XWx86Vab>>0lxBkGL=<;|)uDd;-U%Yd%vRFx0 zN%eGfY4g-j?bYFp(8jge$feEjWbN(CKTg+tSATU+?ecIk*y!mKXWyo??|?E8_uh&4 z_(wi5(r5QOOfE~CScIIU&zm-7QKfit8WC^iAg!B#i$$uV?$HJ_}t9A;?k_tn2hq6^3>F9BaMPe&6whn(v-@0BalFRc4ls1 vOnPZ%d~$wXNl|`|UP0w84x8Nkl+v73yCPPgZHz!%3}Sp_W@Kb6Vg|AR1`#q& literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/gui_screens.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/__pycache__/gui_screens.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dbc85b1f7d4df1eaaa3fd97a49986e2e5a99ac0 GIT binary patch literal 6520 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 Oc9iG$Z*W8n*?#~gjjlfc literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/account_manager.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/account_manager.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..85e4c37f1a522c584e4a0f15592b84458b038522 GIT binary patch literal 3145 zcmcgu-%s0C6ux#6Fik>Qs9H*C>r%84+NG32(P%*Gv}u|uT6KLIVzRv0g+LOR9T$R9 ziLIHGQYxrcnp6TtrLiuf)95daY5fBx?FA1eB5RW>Z4WDUq^UgYhxV{@?Ia{Y&9;|a zDJR$Wo_p-`-S2$&ervaHL(u+`CVS46BJ>k}$TV}hvrz|~7~&8|_>iCIA_zpH*AYiX z5NBE-4X-XTWOiDf;s+<8STA^eJR|Td#|s|A!LVs>v~dKUV~9sx1c$mvu9PDpM3)K2 z>@ssEuolh?wuG~QEe(}8DW&|B$1@-Wf}L!D?SZ(NSU587o8Y(M1`|VJB8(X587++Z z@LWM#NI!#THc|*Bh%-);Ql@|ZARFve?7jh(V_4(WqC#bQPEs+8yzhcQK^zfBpy@w( zPh0n!XHUQO7T8X&$P4T{K3>d!Xgq$b(aQH9-hg7!~m=X~70oC<8N6 zQ;=TXUg*H@0Jl-}v!i;=Q7=2{R~!w?RD)0sqj|aEck29j1v>wf8}J3=SI`#Hcn~N= zI7#U+OsC=zZT2o*G<8~=8`Wm#fmKH0TA8YyYrfNdyZw9Wn1Mtt`*CJE606WLDy0v4h3z5|h!7DbidBwCgvg*J zvl3Trn0z(Mj0|4jWzO+}dVY>qNf_$@HBAEknV>oUVFK4S%z;i7whS9#Z_1q8Bn+o^ zIhxrR?edHkxu>%fxT$`zL~FMn!p5bh;_BE9TAPaC;Tt!!*$>pKQT6J_E~x`Y$c*bw z(FJXGQoA)uYw`EAn-A5yOYp4T8K?28xp{hhaa0|fPfaD#A-2%(IE2*Y=`5ODG!u%%v+^Y(ay2~r_ljf&aR%L-``(#uCF zbNBE8et1ym7-=jhA`g__CIek=-++hpi5;%&ie30icZ2x_{XUA8D_Rr1bKGQe%zfP* z>qzwev4J`Cesv8YHA6@JDxyN}_oJ!!5|lcv=|}+_bZP=1{#2ce176w`$ie>y4(l5P zM5^HPa#0cX!oYvW1BVf6u-OMjY6G(+=^RoNPhG%b3WoC4vg$8N|Eh&JqKnKJ+W3!24k15Uy`kL$x3(9v3t#NKz1BhbsS7q zp8vs7A!D|zRJ5)-T9cJ;6b_tya3KS%ds(mzll}GJdx$G3>Px1TDOYDEILDEOX`R73Nwe?N>ppUC{lTNu%^Z?G#mXkV04BFy z^lzDstDk+nh18^R9AX*^bzt&YYw->AcmpFl3&^UE9>Ct$z~~%}H-FTAt6jF%V~$!K z6YW>p<5jY?cKJ}VY;9TE@tw6TS$Q;fX0A=Px)$s4#LI2bS0_5JbjIst+o9#U7TI

yAqVMJ|h4NjBAiy)&ho6z*n;b(!(0pBz*h|*x=n0vA#vn z21#08dPb3!!`L)EqwJQZjs13u+gOLa@g>&;w@dv_qOTWRFuWO9q1?u2bqI|xfj3gD X0Q0MfAc!B)-rvkl!u<@6A|vSEAF^)= literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/file_reader.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/file_reader.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b2fc0bc6a908ebcb756b7ee364e8535d3a4b01e GIT binary patch literal 1592 zcma)6&2Jk;6o0c{{=g=2vME6#X((-41F~^~r4mI*77Yz)nl_=A1cSABH)I`uv9p%r z$S$db)Kraxs~(aH5Jp_6a>*aSf!>g~I8dnB=77X0w}ePUiiE@)+Z#6}LhNYYym>P_ z`+o2DoB7e}bpt+s=gJ>V@c@6Yf&EBLXRnOTDyX26B+P)y%@7R|g1xNOCmb!`_B66i z8b0mhKoc~g^6Ok95{4Pkg}bt5#|Wsxr!XU_B3eg*yaXYjB+n6;27+y+eSx2bJn>80 zY?Fz_58fIIPF=Y)GL81KPBlaMFsad_gVzQ_;ZQ84r)e&s1?Td?yr#_$oXZycL2BmI zLTrEqV)J@xGDwYhP>IJgxwIKD7fg%fu~1 zN~B0G!24qWC9cRN#KuNX+V$q(xB{x2UBD7=y6mrtyd72f`E!6JS_u_-Rd^m3n9sCU zsUnLUu9d#vih%1JEIN$u%D4bXLA}`-6DY#F@O0r>tXX>JghdRCyt>T_vCYtLGvI#C za%L4u^BF_6+GZ6!si`r=G__RLq(*&(WC@w9mbP4PzcW4(yBfJRYKhb|^elGSq;6V# z5@&fmZTbbv*`$G5WY!XrdRnu@tYVmyGVS%@bD+eBqIL4ow#Yv^I6{7OE+0K4Kl(KJ zQ6xV)i+RTkO;I%?kS$nV=Em$)jOXyztiH5>W(jI-zNOJEmv=>9>wM_ysrVktUCS40 za`)=kow2*)kL3PMxxYexmS0&O*=p-3hi@;gP2T?G_r5a~fUXn!Jh*#z+QB0)UD@}w`~&L4zuz5<1o#Jz7nlu*k@JrD zp%8JFo$I<#zei{F|A-X+OPVO)GXPO!vBZ`5A~{Z~MecLF9Z+68lULKPOA>wYOUafY zp5n8|$*%A((G_gTNfQPGW3W5PV9*Rkf<@eZ!SJx5mkmW7#YQbLZ=i!S9c-qP%{X&- zGo+Q2W(lfdDu)U(PO#Z$>mRg8?!_P@n!bl-37+J)*4zJ8`d<3i-oUMi<g$((n5xQGfALK2@^CU(=k$@QXVcYl zKpBWTZ$xDNfh$rRZ?iK?rzRN2+DPKNpK#E9tl2giD8X8-^I literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/gui_screens.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/gui_screens.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d994f51c90d070045014a36ab4a3e9e4f1aedaae GIT binary patch literal 6576 zcmeHLT}&L;6`t8Y4$EJbB`paC7K$+oHa7k*scqR{jALih*u+jL&S%UFE~$bO)0q>`ul5vhHc5sN08lBf2?0ZSIHRjE%sXJ-Fd|1|wk z)#gfb=H7GX+&lN4bH01e`F&ZLlfxoRUmIF2<+wjlBUNn4%F}~bxygx~$cMOo9^aM_ z7q;|Uc;Z<@*08PL#&Z_#1Si^NIMIIJVoLVgCwZ^q5jA{XUU!BiS@sV}7o!u{DnA+s zMB|azJN^jrSilr9DW7aS?ZwJXPBLcgw}|`<*KZXqNNu7Osh#HQcZhbRMWO>Kh($Xz83Ztr3Ku%uUn{lSP3mLhRs&|s8= zqC?0r8&#+me@qfm1DMJ3=vJK7K&Z@!RC{2%pY+Oq!<=@U z6R|MAyy~2joY&!tzlP%LGqaCBx%2qOt@WA3^`Bqwoac30Oqz&2BU@a%_lvK8ySRR5 zao)n-z_wl#h=$Q?#CRFDzW&Y3`s@wQ`X_hRXMW`^VkPv2{j~q06k^n`+s6EXQQdJY z9*adIdWAe5j0J{;SX3}PL$A&-a@}H{XXNuTsoKM;kTUw!sW-E%G|%S<1LP4TA9JhV z{25$@YgL+StLoaSY(JcUBN}w8(4BxD>Mg!ne62~VY*s6q=YIUKNjr8(E~{B6CP~oL#nXj6kMtOxhpM4)#nu) zw-EFcBcF^nuRL(R2pq%`+~tx7rKxXn^!(~`m*L!%c@tyvC3BbO&y8SF;d@31w|--0 z{m$oW*ROZ7YHTu6_`F58vgo+(2t-5iaO4p=?K5)!wJ&DY7Cv74^_9oB7CUvmm5@aq zj*hc8NwfyZBSYTGnu)OuiS9H9k;nXzXS8c;^Vbo5Jos9>`Z=P}BSKWK(|{UQOJcMe zx^0LBMcsZp5@VBkc^nVR2p;BwWVXlrvOFGTqSPvnc*<}PpiDcfL3@~InsHdICE+QRBa*(cqxVwq$L84biq;Vk+>I_~XxGT@S zV6g)8%)5E1|bzf$|a_JG>xG5w&fIpUWh>NbOF$#qss_n2C#wwJU2o|WnRgI zBG_L5CPvZ$dPdL)Z<1s290t5rUmqqf9MS|HqoUWUR}2S53|d1WGmMpu+c~Sl5jNQX z8OBsywhg2&?db!OY)~e%#=wxmxa^RQ>KZht&@fk}K*I{OZ$|(B*ha8J_>*2MJAyCc zqEL9v9_-GIEz)Z?&iMV<|Gf29t5B^$tqQfXeG1fK1pD8zUIQ))>bQZ{`@MoX&h_=q z7c87qtUOPWy(xud5Q*<>PSGV;X9`N5cVaY z+2EKPyF-N?E3k9(p3-g@d#YgNo9yXjOdJ-9R9>_{mn|q$Xiq6gkXJAGVLD+iis@ETz&@-oia!{+BBSN&K%qo1G8mn=8OZ`2 zQfHwKsS{9lFiDPwVlr)-2aB0Yph2cy%d&sN%e#;(pFx7Ua(`EIH>>Vu&E2ZHTbJG2 zuRuYb>vc27pt;&qSKD0g!tk=|$Q8#bRBAx?_**At&#l1r|358Gm3JALQcp60j_UkA zZY}E}La<`0^DU~8I@t*#y-4zOMPE$4k)^9#ggQwQXOSe8M(Wbs?W((d*}W^Nw0vGh zX?s=I-h~eqCzf5kSxQs3Y@ZukfqjP7eBLrjlN#ZqpgRR292MgsNf7i>LAVt6hs+*E z`6nYu#VA^2bd@qMSstnp;+m(BVZgMgdCnN$v`BI-MubjxnaEP!k-QGQC^j05#3W`$%ZAsu zF$>(D%3dea-$qj0n4SF)1v9^;!w<~W9%i(~bi= 3: #입력 받은 계정의 'failed_attempts'의 겂이 3 이상이면(틀린횟수 3회이상) + return "계정이 잠겼습니다." + if self.accounts[username]['password'] == password: # 비밀번호가 일치하면 + self.accounts[username]['failed_attempts'] = 0 # 비밀번호 틀린횟수 초기화 + self.save_accounts() #초기화된 틀린횟수 저장 + return "로그인에 성공했습니다." + else: #비밀번호가 틀렸을때 + self.accounts[username]['failed_attempts'] += 1 #비밀번호 틀린 횟수 1추가 + self.save_accounts() #틀린 횟수 저장. + return "비밀번호가 잘못되었습니다." \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/file_reader.py b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/file_reader.py new file mode 100644 index 0000000..e928395 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/file_reader.py @@ -0,0 +1,26 @@ +import os + +# 파일 경로 설정 +FILE_PATH = "C:/ROKEY/ROMiserables/ROMiserables/03151_minsuje/hw/week2(py)/study_2week_kimQ/src/account.txt" +#읽기 +def read_accounts(): + '''txt파일 내용 읽기''' + accounts = {} + with open(FILE_PATH, 'r') as f: + for line in f: # 한줄씩 확인함. + parts = line.strip().split(',') #,로 분리하며 띄어쓰기 없긴한데 없앴음. + if len(parts) == 3: #읽은 데이터가 3개가 아니면 잘못된 데이터 읽기 혹은 잘못된 데이터가 저장되어 있음.(현재 비밀번호에,가 들어가는데 들어가면 ㅇ 4개나옴) + accounts[parts[0]] = { #계정 아이디에 + 'password': parts[1], #비밀번호 + 'failed_attempts': int(parts[2]) #틀린횟수 + } + return accounts #읽어온 계정 반환환 +#쓰기 +def write_accounts(accounts): + '''txt파일 내용 쓰기 - 이미 있는 내용은 수정되고 없는 내용은 새로 써짐 + 한번에 다쓰는 식으로 했음 해당 부분만 수정하는게 아니라 통째로 수정함. + 차후 같은 내용의 이름이 있으면 수정 없으면 추가 하는식으로 수정하는것도 좋을지도 + ''' + with open(FILE_PATH, 'w') as f: + for username, data in accounts.items(): #입력된 데이터 분리 + f.write(f"{username},{data['password']},{data['failed_attempts']}\n") #데이터 가공및 저장 \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/gui_screens.py b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/gui_screens.py new file mode 100644 index 0000000..0cef3af --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/gui_screens.py @@ -0,0 +1,95 @@ +import tkinter as tk +from tkinter import messagebox +from src.account_manager import AccountManager + +class GUIScreens: + def __init__(self, root): + '''초기화''' + self.root = root + self.account_manager = AccountManager() + + # 화면 프레임 생성 + self.main_menu_frame = tk.Frame(root) + self.login_frame = tk.Frame(root) + self.create_account_frame = tk.Frame(root) + + # 화면 구성 + self.setup_main_menu() + self.setup_login_screen() + self.setup_create_account_screen() + + #로그인 할지 계정생성 할지 선택하는 페이즈 + def setup_main_menu(self): + '''메인메뉴 화면 세팅''' + tk.Label(self.main_menu_frame, text="선택하세요:").pack() + tk.Button(self.main_menu_frame, text="로그인", command=self.switch_to_login).pack() + tk.Button(self.main_menu_frame, text="계정 생성", command=self.switch_to_create_account).pack() + + #로그인 페이즈 + def setup_login_screen(self): + '''로그인 화면 세팅''' + tk.Label(self.login_frame, text="아이디:").grid(row=0, column=0) + self.username_entry = tk.Entry(self.login_frame) #빈 입력가능한 칸 생성 + self.username_entry.grid(row=0, column=1) + + tk.Label(self.login_frame, text="비밀번호:").grid(row=1, column=0) + self.password_entry = tk.Entry(self.login_frame, show="*") #빈 입력가능한 칸 생성 입력시 *로 표시됨됨 + self.password_entry.grid(row=1, column=1) + + tk.Button(self.login_frame, text="로그인", command=self.login).grid(row=2, column=0, columnspan=2) + #로그인 함수를 사용하여 계정 로그인 확인을 하고 실패 성공 유무 왜 실패하였는지에 대한 정보를 받아 메세지 박스로 띄움 + tk.Button(self.login_frame, text="메인 메뉴로", command=self.switch_to_main_menu).grid(row=3, column=0, columnspan=2) + #메인 메뉴 페이즈로 화면 전환. + + #계정생성 페이즈 + def setup_create_account_screen(self): + '''계정생성 화면 세팅''' + #로그인 페이즈와 비슷함 생성 버튼이 계정생성 함수를 실행 시킬 뿐임. + tk.Label(self.create_account_frame, text="아이디:").grid(row=0, column=0) + self.new_username_entry = tk.Entry(self.create_account_frame) + self.new_username_entry.grid(row=0, column=1) + + tk.Label(self.create_account_frame, text="비밀번호:").grid(row=1, column=0) + self.new_password_entry = tk.Entry(self.create_account_frame, show="*") + self.new_password_entry.grid(row=1, column=1) + + tk.Button(self.create_account_frame, text="생성", command=self.create_account).grid(row=2, column=0, columnspan=2) + tk.Button(self.create_account_frame, text="메인 메뉴로", command=self.switch_to_main_menu).grid(row=3, column=0, columnspan=2) + + def switch_to_main_menu(self): + '''메인메뉴로 화면 전환''' + #화면 전환시 기존 화면은 지우고 새로운 화면을 나타내는 것이 좋음 에러가 안생김. 아래 switch frame 모두 동일일 + self.hide_all_frames() + self.main_menu_frame.pack(expand=True) + + def switch_to_login(self): + '''로그인로 화면 전환''' + self.hide_all_frames() + self.login_frame.pack(expand=True) + + def switch_to_create_account(self): + '''계정생성으로 화면 전환''' + self.hide_all_frames() + self.create_account_frame.pack(expand=True) + + def hide_all_frames(self): + '''모든 화면 숨기기''' + self.main_menu_frame.pack_forget() + self.login_frame.pack_forget() + self.create_account_frame.pack_forget() + + def login(self): + '''화면에 입력 받은 데이터 계정 매니저의 로그인 함수로 넘김 -> 수행후 내용 retrun받아 메시지 박스 생성''' + username = self.username_entry.get() + password = self.password_entry.get() + #입력 받은 값을 login에 보내고 결과값을 받아 메시지 박스로 화면에 띄움 + result = self.account_manager.login(username, password) + messagebox.showinfo("Login", result) + + def create_account(self): + '''화면에 입력 받은 데이터 계정 매니저의 계정생성 함수로 넘김 -> 수행후 내용 retrun받아 메시지 박스 생성''' + username = self.new_username_entry.get() + password = self.new_password_entry.get() + #입력 받은 값을 create_account에 보내고 결과값을 받아 메시지 박스로 화면에 띄움 + result = self.account_manager.create_account(username, password) + messagebox.showinfo("Create Account", result) \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_kimQ.md b/03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_kimQ.md new file mode 100644 index 0000000..8095386 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_kimQ.md @@ -0,0 +1,96 @@ +# 김서희님의 로그인 프로그램 + +- 작성자 : 제민수(ROKEY 3기생 DR-05131) +- 작성 기간 : 2025-01-22~(진행중) +- 버전 관리 : 1.1 ver +- 0.x 프로그램 작성중 +- 1.x 프로그램 1차 작성 완료(프로그램 동작작) +## 📜목차 + +- [개요](#개요) + [작성의 목적](#작성의-목적) + [로그인 프로그램 목적](로그인-프로그램-목적) + +- [프로그램](#프로그램) + +- [기타](#기타) + +## 개요 + ### 작성의 목적 + - ROKEY 3기 프로그램 진행에서 스터디 그룹에서 코딩 리뷰 및 학습 내용 공유를 위함. + - 스터디 피드백 내용 정리 + - 추가예정 + - 해당 문서는 ROKEY 3기생 DR-03151제민수가 작성 하였으며, 문서 및 파일은 직접 수정하지 않는다. + + ### 로그인 프로그램 목적 + - 고정된 비밀번호를 check()를 정의하여 틀렸는지 제대로 입력 했는지 판별 한다. + - 판별된 데이터가 3번이상 틀렸을경우 문자를 출력한다. + + ### 프로그램 수정 + - > 최초 화면에서 로그인, 계정 생성 중 무엇을 할지 입력받는다. + - > 입력받은 것이 어느 페이즈 인지 확인 후 해당 페이즈로 넘어간다. + - > 로그인 시 아이디와 비밀번호를 입력받고 판별 한다. 단 계정 당 3번이상 틀렸을시 3회 이상 틀렸습니다. 계정이 잠깁니다.를 띄우고 해당 계정으로 더 이상 로그인 할수 없게 하며 로그인 시도시 로그인이 불가능 합니다 를 띄운다. + - > 로그인 시 옳은 아이디와 비밀 번호를 입력 하면, 로그인 되었음을 화면에 표시하고 프로그램을 종료한다. + - > 계정.txt 를 미리 만들고 임의의 아이디와 비밀 번호를 입력 해둔다. + - > 계정 생성시 아이디와 비밀번호를 입력 받고 아이디 입력 받을 때 이미 존재하는 아이디 일 경우 이미존재한다 알리고 다시 입력 받는다. + - > 계정 생성시 완성된 아이디와 비밀번호를 입력 받으면 계정.txt에 추가해 주고 바로 로그인 페이즈로 넘어간다. + - 수정 내용의 설정 : 외주로 로그인 프로그램을 받았으며, 로그인하는 것과 계정 생성 업무를 받았다. 로그인 3회 실패시 인증을 받고 다시 로그인 가능 하게 해달라 하였고 인증파트는 다른 사람이 작업을 진행 하므로 로그인, 계정 생성, 계정 잠금 업무만 진행하고자 한다. (로그인 이후 역시 다른 사람이 하는것.) + +## 프로그램 + +### 프로그램 설명 +- 로그인 시에 아이디를 검사하는 함수 check()를 작성해서 테스트하라. +- check가 한 번 호출 될 때마다 비밀번호를 질문하고 일치여부를 확인한다. +- 비밀번호는 숫자 1234로 고정되어있다고 가정한다. +- check가 3번 이상 호출되고 아이디가 일치하지 않으면 check()는 "Account has exceed allowed number of login attempts."메시지를 출력한다. +### 변경한 프로그램 +- 최초 화면에서 로그인, 계정생성을 선택하고 해당 페이즈로 넘긴다. +- 계정.txt를 미리 생성 해두며, 해당 txt는 [아이디,비밀번호,올바르지않은 접속시도] 3가지 정보를 가지고 있어야 하며 ,로 구분하고 한 아이디가 입력 되어 있으면 다른 아이디는 다음 줄에 생성 되어 있어야 한다. +- 계정 생성 + - 계정 생성페이즈를 입력 받아 들어오면, 아이디를 우선 입력 받고 해당 아이디가 계정.txt에 이미 존재하는지 확인 후 존재 하면 이미 존재하는 아이디임을 알린다. + - 아이디를 입력받고 문제가 없으면, 비밀번호를 입력 받고 숫자와 영어 문자로 입력되었는지 확인 하고 아닐시 아이디는 숫자와 영어문자만 입력 되어야 함을 알린다. (영어만 입력 받으면 숫자가 필요하다는 식으로도 알린다. 반대로 숫자만 입력시 영어 문자 필요하다 알리고 대소문자는 구분한다.) + - 아이디와 비밀번호가 문제가 없을시 txt에 추가하고, 로그인 페이즈로 넘어간다. +- 로그인 + - 로그인 페이즈로 넘어오면 아이디와 비밀번호를 입력 받으며,txt와 비교하여 존재하고 알맞는지 확인 후 틀렸을 시 틀림을 알리고 txt에 바르지 않은 접속 시도 횟수를 올린다 재입력을 받는다. + - 틀림 횟수가 3번 이상인 계정은 비밀 번호가 맞는 것을 입력 받아도 계정이 잠겼습니다를 표시한다. + - 로그인 완료시 로그인을 완료 했음을 알리고 txt의 올바르지 않은 접속 시도 카운트를 0으로 바꾼다. + + ### 입출력 정리 + #### 입력 + - id, password + #### 출력 + - 최초 화면, 로그인화면, 계정 생성 화면 + - 계정 생성 관련 str + - 로그인 관련 str + +### 프로그램 구조 + - study_2week_minA.py 에서 tk를 통해 초기 설정만 하고 src파일 내부에 gui 및 txt 파일읽기, account 관리 py 파일을 만들어 main을 간략화 함. + - gui_screens.py는 GUIScreens 클래스로 구성 되어 있다. + - 초기화로 GUI입력으로 인해 동작을 할 AccountManager()를 초기화 하여 선언하고 각각의 프레임을 생성 하고, 화면 구성을 한다. + - 각각의 화면 구성은 setup_화면이름으로 정의한 함수를 사용한다. + - setup_main_menu 로그인과 계정 생성을 선택 핧수 있는 버튼 선택하라는 txt lable으로 구성하고 각각의 버튼은 loing과 create_account로 이동하도록 command=로 각 함수를 부른다. + - setup_login_screen은 "아이디:" 아래 "비밀번호:"를 라벨로 나타내고, 각 옆에 Entry를 이용해 아이디와 비밀 번호를 입력 받는데 비밀번호는 '*'로 표시되게 한다. 또한 로그인 버튼과 메인 메뉴로 가는 버튼을 만들고 로그인 버튼은 login함수를 부르고 메인 메뉴로 버튼은 메인메뉴로 switch하는 함수를 부른다. + - setup_create_account_screen은 login과 같이 아이디와 비밀 번호를 입력 받고 생성을 누르면 create_acount함수를 부르고 메인 메뉴로 버튼은 메인베뉴로switch하는 함수를 부른다. + - switch_to 함수로각각의 메뉴 프레임으로 변경 하는 함수를 만들며 pack(expand=True)로 중앙 정렬을 한다. + - hide_all_frames함수를 작성하여 .pack_forget()함수를 활용하여 모두 숨김 상태로 되게 하고, switch_to_함수에서 사용하여 화면이 바뀔때 서로 영향을 주지 않도록 한다. + - login 화면에 입력된 값을 읽어와 account_manager함수에 입력한다. 나온 결과를 messagebox로 띄운다. + - create_account화면에 입력된 값을 읽어와 account_manager함수에 입력한다. 나온 결과를 messagebox로 띄운다. +- acoount_manger는 AccountManger 클래스로 구성되어 있다. + - 초기화에서서 계정에 대한 정보를 읽어옴. + - load_accounts 함수로 file_reader를 이용하여 데이터 읽어 옴 + - 계정 데이터 파일 저장 Save_accounts 역시 file_reader를 이용하여 새로 생긴 데이터 작성 + - 새로운 계정 생성create_account + - 아이디, 비밀번호를 입력 받음 + - 아이디 이미존재, 아이디는 숫자와 영어만 입력, 비밀번호는 숫자와 영어가 포함되어야함 을 확인하여 문자열로 반환 만약 모두 만족하고 넘어간다면 accounts 에 추가하고, 3번째 데이터인 failed_attempts를 0으로 입력하고고 계정을 저장하고 계정이 생성됬음을 반환한다. + - 계정의 데이터 형식은 accounts[username] = {'password':pasword,'failed_attepts':?}이다.(?는 0~3의 숫자임) + - login 로그인 처리 + - 아이디 존재유무, 계정의 잠김(accounts에 3번째가 failedatteps 3 이상)유무, 비밀번호 일치 + - 비밀번호 비 일치시 3번째 데이터 1추가 한후 저장 하고 비밀번호 틀림 반환 + - 비밀번호 일치시 3번째 데이터 0으로 변경하고 저장 후 로그인 성공 반환 +- flie_reader + - 파일 경로 및 읽고, 쓰기 작성 + - 모두 with를 사용하여 쓰고 바로 닫음 + - read_accounts를 가공하는데 입력 값을 ,로 나누고 데이터의 수가 3개면 데이터 0번은 아이디, 1번은 password, 번은 틀림 횟수로 저장한다. + - write_accounts는(accounts)데이터를 입력받아 이름,비밀번호,틀림횟수\n의 데이터를 가공하여 저장. +## 기타 +- 뭔가 더 이쁘게 계정 생성 및 로그인 관련 데이터 생성및 GUI 꾸미는 것을 할수 있을 거같긴한데.. 다른것 해보고 다되면 수정해서 올려보겠습니다. \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_minA.py b/03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_minA.py new file mode 100644 index 0000000..19153b3 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_2week_kimQ/study_2week_minA.py @@ -0,0 +1,12 @@ +import tkinter as tk +from src.gui_screens import GUIScreens + +#if __name__ == "__main__": 하면 분리된 py.가 잘못된 연결을 안하도록 할 수 있다고 함. 안해도 잘되서 안씀 +root = tk.Tk() +root.title("Account Management") +root.geometry("300x150") +#위는 잘알꺼같아서 안씀 아래는 음 root로 gui를 열어서 제어는 app으로 연결하여 가능하다는 정도. GUI가보면 애초에 root 입력 받게 되어있음. +app = GUIScreens(root) #root 입력 안하면 연결안되서 제어 못함. +app.switch_to_main_menu() #시작 화면은 메인 메뉴 화면이라서 먼저 부름. + +root.mainloop() \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py b/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py new file mode 100644 index 0000000..27c6054 --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py @@ -0,0 +1,6 @@ +def solution(s): + if(len(s)==4 or len(s)==6): + answer = s.isdigit() + else: + answer = False + return answer \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_Q_ji.md b/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_Q_ji.md new file mode 100644 index 0000000..656e32e --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_Q_ji.md @@ -0,0 +1,41 @@ +# 지예은님 문제 + +- 작성자 : 제민수(ROKEY 3기생 DR-05131) +- 작성 기간 : 2025-01-22~(진행중) +- 버전 관리 : 1.1 ver +- 0.x 프로그램 작성중 +- 1.x 프로그램 1차 작성 완료(프로그램 동작작) +## 📜목차 + +- [개요](#개요) + +- [프로그램](#프로그램) + +- [기타](#기타) + +## 개요 + ### 작성의 목적 + - ROKEY 3기 프로그램 진행에서 스터디 그룹에서 코딩 리뷰 및 학습 내용 공유를 위함. + - 스터디 피드백 내용 정리 + - 추가예정 + - 해당 문서는 ROKEY 3기생 DR-03151제민수가 작성 하였으며, 문서 및 파일은 직접 수정하지 않는다. + + ### 문제의 목적 + - 문자열 다루기 기본 + - 문자열 s의 길이가 4 혹은 6이고, 숫자로만 구성돼있는지 확인해주는 함수, solution을 완성하세요. 예를 들어 s가 "a234"이면 False를 리턴하고 "1234"라면 True를 리턴하면 됩니다. + +## 프로그램 + +### 제한 사항 +- 문자열의 길이는 1이상 길이는 8이하인 문자열 입니다. +- 문자열은 영문 알파벳 대소문자 또는 0부터 9까지 숫자로 이루어 져 있습니다. +### 프로그램 설명 +- + + ### 입출력 정리 + #### 입력 + - "a234", "1234" + #### 출력 + - false, true + +## 기타 diff --git a/03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_jwLee_Q.md b/03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_jwLee_Q.md new file mode 100644 index 0000000..f26d54e --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_jwLee_Q.md @@ -0,0 +1,44 @@ +# 하샤드 수 + +- 작성자 : 제민수(ROKEY 3기생 DR-05131) +- 작성 기간 : 2025-01-23~(진행중) +- 버전 관리 : 1.1 ver +- 0.x 프로그램 작성중 +- 1.x 프로그램 1차 작성 완료(프로그램 동작작) +## 📜목차 + +- [개요](#개요) + +- [프로그램](#프로그램) + +- [기타](#기타) + +## 개요 + ### 작성의 목적 + - ROKEY 3기 프로그램 진행에서 스터디 그룹에서 코딩 리뷰 및 학습 내용 공유를 위함. + - 스터디 피드백 내용 정리 + - 추가예정 + - 해당 문서는 ROKEY 3기생 DR-03151제민수가 작성 하였으며, 문서 및 파일은 직접 수정하지 않는다. + + ### 문제의 목적 + - 하샤드 수 학습 + +## 프로그램 + +### 제한 사항 +- x는 1 이상, 10000 이하인 정수입니다. +### 프로그램 설명 +- 양의 정수 x가 하샤드 수이려면 x의 자릿수의 합으로 x가 나누어져야 합니다. +- 예를 들어 18의 자릿수 합은 1+8=9이고, 18은 9로 나누어 떨어지므로 18은 하샤드 수입니다. +- 자연수 x를 입력받아 x가 하샤드 수인지 아닌지 검사하는 함수, solution을 완성해주세요. + + ### 입출력 정리 + #### 입력 + - 10,12,11,13 + #### 출력 + - ture,ture, false, false + +## 기타 + + +# https://school.programmers.co.kr/learn/courses/30/lessons/12947 \ No newline at end of file diff --git a/03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_minsuje_A.py b/03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_minsuje_A.py new file mode 100644 index 0000000..f82cf1e --- /dev/null +++ b/03151_minsuje/hw/week2(p)/study_week2_jwLee/study_week2_minsuje_A.py @@ -0,0 +1,12 @@ +def is_harshad_num(x): + if not 1<=x<=10000: #범위 확인 + return + sum_digits = 0 #자리수 합을 구할 변수 초기화 + strxs = str(x) #x를 문자화 해서 문자열 각각을 int로 변환 하고 자리수의 합을 구함. + for strx in strxs: + sum_digits+= strx + return x%sum_digits==0 #x를 자리수의 합으로 나누어 나머지가 0이면 하샤드수수 + +def solution(x): + answer = is_harshad_num(x) + return answer \ No newline at end of file diff --git a/README.md b/README.md deleted file mode 100644 index 789112f..0000000 --- a/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# ROMiserables -- 로기 스터디 diff --git a/Readme_ji.md b/Readme_ji.md deleted file mode 100644 index 45b983b..0000000 --- a/Readme_ji.md +++ /dev/null @@ -1 +0,0 @@ -hi From 42282f225419ff1e90ae37c3599d3292f7b2377b Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Wed, 29 Jan 2025 11:00:42 +0900 Subject: [PATCH 04/11] =?UTF-8?q?3=EC=A3=BC=EC=B0=A8=20=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/webcam/webcam_streamer.py | 3 +- .../week2(p)/important road/importantroad.py | 2 - .../account_manager.cpython-312.pyc | Bin 3145 -> 3197 bytes .../__pycache__/file_reader.cpython-312.pyc | Bin 1592 -> 1747 bytes .../__pycache__/gui_screens.cpython-312.pyc | Bin 6576 -> 7106 bytes .../week2(p)/study_2week_kimQ/src/account.txt | 1 + .../study_2week_kimQ/src/file_reader.py | 2 +- .../week2(p)/study_week2_Q_ji/Untitled-1.py | 101 +++ .../hw/week3(p)/python_Q/lamdaA.ipynb | 704 ++++++++++++++++++ 03151_minsuje/hw/week3(p)/python_Q/pythonQ.md | 0 10 files changed, 809 insertions(+), 4 deletions(-) create mode 100644 03151_minsuje/hw/week2(p)/study_week2_Q_ji/Untitled-1.py create mode 100644 03151_minsuje/hw/week3(p)/python_Q/lamdaA.ipynb create mode 100644 03151_minsuje/hw/week3(p)/python_Q/pythonQ.md diff --git a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py index a35302e..52a1183 100644 --- a/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py +++ b/03151_minsuje/hw/week2(p)/CCTV_project/CCTV_minsuje/src/webcam/webcam_streamer.py @@ -1,7 +1,8 @@ import cv2 #opencv import threading #thread 분할 (webcam streamming 중에 반복문으로 프레임을 읽어와서 보여줘야하는데 다른작업도 해야해서 들고옴) +os sys -#from src.recorder.video_player import VideoRecorder +from recorder.video_player import VideoRecorder class WebCamStreamer(): def __init__(self,cam_num=0): # 노트북은 캠이 기본 탑재 되어있어서 그냥 아무것도 선택안하면 노트북 웹캠 자체그대로로 diff --git a/03151_minsuje/hw/week2(p)/important road/importantroad.py b/03151_minsuje/hw/week2(p)/important road/importantroad.py index e4f3d04..d8a7196 100644 --- a/03151_minsuje/hw/week2(p)/important road/importantroad.py +++ b/03151_minsuje/hw/week2(p)/important road/importantroad.py @@ -83,7 +83,6 @@ def __shortest_path(self): # 선언된 값 자체가 변경되면안됨. queue의 역활로서 삭제되거나 추가될 순 있어도 들어온 값 자체가 수정 되어서는 안됨 location_info = [(0,1)] #시간, 지역 변수 초기화 최초엔 1번 위치에서 0시간소모 경로는 1만 통과 했으므로 - #queue 역할을 하는 locationvector의 요소가 없을때 while문은 실행되지 않는다. while location_info: #location_info에서 가장 작은 누적 시간 찾기 @@ -94,7 +93,6 @@ def __shortest_path(self): #가장 작은 누적 시간을 가진 튜플을 현재 시간과 현재 지점으로 저장하고 큐에서 제거 current_time , current_location = location_info.pop(min_index_num) #pop은 내장 함수로 해당 인덱스의 값을 리턴하고 변수 내부에서 해당 인덱스 삭제를 함. # 만약 self.shortest_time[curret_location]에 저장된 값이 current_time보다 작으면 아래 동작을 수행 할 필요가 없음 - # 같은 경우는 다른 경로 일 수도 있으니 할 이유는 있음. if(current_time>shortest_time[current_location]): continue diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/account_manager.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/account_manager.cpython-312.pyc index 85e4c37f1a522c584e4a0f15592b84458b038522..b5a3dbea4e4421fbf2463e2ebbb9672470feef6b 100644 GIT binary patch delta 621 zcmZ8eO=uHQ5PtJ^H~aQ&v$fH*Yqx02TQ38#aj%& z!cHbs5{Cuh7`dUqN4y9ozT|r;OC==U))v6VJ?%9A!|;j7p{KvlNs*-#*`$cd5_{g$ z9iEvYKjH+1!jN(rf27W&Jj#SKc*?xv8KGj1%`1`LYHwVNHNU+X9#r=NduA5$_}M%U z>sS%Zad+muTkg5#w{GQ@em9K|#H>6^18uX>PA2}{iN!k5LC~`JMp&q6hwzJVlQU~2 z=QtduhXP(FBnE?KC?@wetpcbhr&}eth##yf6ws2#Nli^&%4nfb0+W>_Qjg+}tmcc9 zj2;tgvHpKj`(n0_?_?LR+w%vK=A`eKqAB4sdv0pL!Ke;W+?XE-Zqx?SF>3oq9QJ_LD7(wVz`Y&^Gj)VXJ delta 659 zcmX|8O=uHQ5Pq|}$^ImpwxM8tj7=nn(Imuz2(};vuN8W&kgz1%+L~_lZ30Ge=)r?X zg@!p)#2&l|5l?!sXTgIgf}$V`f+r8AhmstGqTsyU#)0?oy?OJ^%zpbf@h%a2Z<+?9 z_|x85T~d3odPWjgicyhZm)UF?8f;l=s13LWz3t2u&5JG6>zi$-wP-oks?F9@$udIq2X`STd88+G5|5r|&D9jXI*>XC3no@n)pXzCC*XEA3Ve>2w)T_|Iie?ukF7Ox?)rC*vP>A@x#c9*Pw{?a` zS{fKSdI~H0l+TiQU8fStd6Lz#%_>8(!g#)8ZTMwQWg_2 zx`~OJl_+8oJh-&6M5qVBn@2sAcoBLsGYiFd6@0Tv5WyMt@!tF1+wXfb)0y}Zxbis= z@FQ5W_0sKI9)xyyFj~UU=^p{7f+Qs2I0_?42xG~mp|Bu{U|m@pbpPO`p*xX>pXMLo zIpa9qaeF1$MnDM8_|gXfO|7KtLV=lEgx+nlr!B(F5510MoDOl=svS3v7edChr0?v6P*l&iaFv@z4p;Jh~83CgOgkfhrE3O5U!NIZgW&A%z z!vaQf0;t>cZHKVuI=xpK>S3lzm|kV|GA&kn8+F1eYyY4*!d7+qqDI*LCTkS^1eRT{ z(RH0wiiGB0F~i~wEN`;f7B93P>&z@bQJd!96S}F=O^r4RLmInWh4S7y#AS`C?xj>Lp>*9D z85}^SII@=`-n0^vm!pYTSCpcus3Jm=pPRg&qmxd)f9s=6WOeXG=YMG zJtPcbk6tBs^3p^9fgpk&boC}Z2p*(42tuK6nubDWm~Y6Q*LEgej01F@$+Q+FvqtV;&;RTQ}OIxUtZgeSvXj`#|oJd(hbp(F+mf~4}Y+i_~DQ2Ul%d_|8oq3pNoQq z0zywh=s^kXmY|zAMOsr&Q(mcsRhjTeP(YO@y5g&2p2MuV<)e>u8}c1N6RsRj4O>f} z?1Zh#zT8|}tSu*2Sg**M?A!Xp# z;M`f@Rk5jW+ue*>(PpF7Xjjfs6BmxRRr%_lIk~;Z=XpDQZ-6`Y({gdRH)>!B@5hOs SIJpPukY5*PjPLw4PyGg+gmQ=g diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/gui_screens.cpython-312.pyc b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/__pycache__/gui_screens.cpython-312.pyc index d994f51c90d070045014a36ab4a3e9e4f1aedaae..fb0a9dc6c7019e23c126b13997ec39eaf4813d01 100644 GIT binary patch delta 1771 zcmbVMUu;ul6u-B(x9hswwOvcs&AELrb-j*_O=gusrnn&fAp?d!;7eD#yRA@K^0f_Q zFKe)vPB77Ys|>eljTly*O4i^^c+nRhd@wv|s)Rl8pu4w`RE@+3;yJg0bWCHyP4mmm zIlbriJHPXNr?~T*=bFE>S}hzr*KU0{b+_ee^Ps`O%Z6klgtSs-eYIG*IL}@(6s%^5 z#0>z1{5{U@8g{cG;UK@Zk``|8+e~spvK?}2VP4Cv0;+Q*0$-|y64BDDmGfuWQL&%* zu#DL07?m3+a+bvd!MBwNmDn}$1xE|k=dnI@0#X|@nYtu5MvnocxZ7;dG|g{ezX@$C zKR11E7_iCqWGkf9&z9D|Tm{~ZjDI4BmQ8E9k~%-{r>*QlqrbHcf)u6xioFyB`XmOP zV!t%Xwo%!l3!@zvv$8JBAm7OjTZm&T1nR}v*%`|=>2Zv@Kr@OfT7Kkjv$>{SbrNS$ zB9g7Iq_uojdnc!*uWnRHyO9gqpeTqwfzX5CMUWAm21uF!Y6W!pbUSAH5OyF80BqFX z%yDLp4r1~d=Co~xR$jEZ+&&CE+>e7Dv-R4sTD)EF=MNLt*tGJw&Ba4IUpr2Z3$ihZ z{nk$yjDOHfK3%!E@J4|zo0QWhgVBjmSt#44!xKs%7>NWXY4C&+rxJ2wl}!SCEb8dC z??wUGe2TjR0<7#)$JQGEEb{9o?EbJflhZx$CGgT=WUwOqD_0j}X4?0^`Rb7nRg`GF zKYl8l2u%kPu|Om?6^`zOd>oHOid!>FKbSjim^)au<*}NQF;qezTR&56>H7cafpPqY z9>T_)Ug>4X-)Cj-I=g}Giu3v*yo~xGzp|{d`~$l)%WyT}H!2%-SIbQ&gQ4Sr$rznd z61CoS!iNVv%$8hT((B0eJOFgazIFM4>z+%SHONA84x+V-t6lhjXrG)_^Is6PxTxh) zM18*qm#LC2l3MRXy?jYMm(lVmEw@1Gu3>gr%PgQFYItW(aBiBNLyI9Tkg@92>xNlUN>rez=t6k9|OSly|zU_v2#L!nqQnm|KvesmwgE(F~WKfa+M6ps_#4-hv35O`{9)z9v= zc1lMvaRdMz@OsdJLmn9%nDO-bT@a@>1UrHQLEjp9aVSC1ZLV&Cs}ljy5`jvG!kl^YVr z!_kC7sfCTSdG{T}%C++FRyOZB5t~Rxlwpbkgk1$23*e5x^ZZYo>n7KElk5M>_!iIm JsvM&J?LTO`N5TLA delta 1280 zcmZvcOH30{6o%(^I;9NLmckUupk=@ZjMV}HMaoM;6irAqDofLpGPGzPOau}pj}8_Vd~ybtH!04#Ak?7AaG8rUzsY4e@qwav$Ap6EAh zqP(_JUVr*&bu~i$>}_?VQGpO!MES^Z@^4SI2kNN-Y*Rd^6(2b27e#^d7 z+>~l%0^VD_i{r2?(Q6thIrPPO*guUgc~WyTAev6cW@$X58x*&c1`ZO(iiH5{l6{ST zw+dYv*!U8+?UdNbx>l=Fh@-<0)p$AzKh%vlP*jCXK|xV(I+vWwhT;8>ARDefV##U$ z%9#svpj;~p${kW!)VKn`dS4sc$u>LW@35*yv1-9RZk`8q%sLNHegLM^^9bzU zDnE!LEKes87XXGGpu%Ha#z9uA1f+|YxC+2}5e4f_D;m_hs{|u>AI(cky*R2vn8#1W zQ7gjSWwTeTSmbB}MrF3AD1DL;tOR%=O)8=&jN2-HQJ4hUgwBf7201`)#mNg@711u7 z`XbqdFl}IGn`KhNrkXp>T}CNO4@M>DP$oB%PwOKT{o-fE!29}{CxpD= 문자자 + self.now_board = chessboard_n2a[self.now[0]] + str(self.now[1]) + return self.now_board + + def move(self, moving_cmd): # 체스말 이동 + for i in range(2): + self.now[i] += move[moving_cmd][i] + if self.now[i] > 8 or self.now[i] < 1: # 체스판의 범위를 넘으면 False 반환환 + return False + return True + + def move_back(self, moving_cmd): # 커맨드 반대로 되돌아가는 함수 + for i in range(2): + self.now[i] -= move[moving_cmd][i] + +first = input('킹의 위치, 돌의 위치, 움직이는 횟수를 입력하시오:').split() # 한줄에 입력받은 문자열을 나눠서 리스트에 저장장 + +king = Chessmen(first[0]) # king 객체 초기 위치(문자열) 주며 초기화화 +dol = Chessmen(first[1]) # dol 객체 초기 위치(문자열) 주며 초기화화 +n = int(first[2]) # 반복횟수 숫자로 저장장 + +def move_chessman(cmd): # 킹 이동 및 돌과 겹치면 돌 이동, 체스판을 넘어가면면 다시 원래 자리로 돌아가게 하는 함수 + king_next = king.move(cmd) # 킹 이동동 + if king_next == False: # 킹 이동이 체스판 범위를 넘음 + king.move_back(cmd) # 킹 움직임 번복 + return + + if king.now == dol.now: # 킹과 돌의 위치가 같다 + dol_next = dol.move(cmd) # 돌을 킹이 움직인 방향으로 움직임 + + if dol_next == False: # 돌이 체스판 벗어남 + king.move_back(cmd) # 킹과 돌 원래 자리로 돌아감 + dol.move_back(cmd) + return + + +for i in range(n): # 입력받은 수만큼 킹 이동 함수 반복복 + moving_cmd = input() # 반복하는 횟수만큼 커맨드 입력받음 + move_chessman(moving_cmd) + +print(f'킹의 마지막 위치: {king.where()}') +print(f'돌의 마지막 위치: {dol.where()}') +for i in range(2): + print(i) \ No newline at end of file diff --git a/03151_minsuje/hw/week3(p)/python_Q/lamdaA.ipynb b/03151_minsuje/hw/week3(p)/python_Q/lamdaA.ipynb new file mode 100644 index 0000000..521e810 --- /dev/null +++ b/03151_minsuje/hw/week3(p)/python_Q/lamdaA.ipynb @@ -0,0 +1,704 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 두 숫자를 더하는 람다 함수 작성하기\n", + "```python\n", + "# 입력: (3, 5)\n", + "# 출력: 8\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "8\n" + ] + } + ], + "source": [ + "sum_num = lambda x, y : x+y\n", + "print(sum_num(3,5))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. 리스트의 각 요소를 제곱하는 람다 함수 사용\n", + "```python\n", + "numbers = [1, 2, 3, 4]\n", + "# 출력: [1, 4, 9, 16]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 4, 9, 16]\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3, 4] ##\n", + "square_num = lambda x : x**2\n", + "square_nubers = list(map(square_num, numbers))\n", + "print(square_nubers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 3. 문자열 길이를 반환하는 람다 함수 작성\n", + "```python\n", + "words = [\"hello\", \"world\"]\n", + "# 출력: [5, 5]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 5]\n" + ] + } + ], + "source": [ + "words = [\"hello\",\"world\"]\n", + "len_str = lambda x : len(x)\n", + "words_len = list(map(len_str,words))\n", + "print(words_len)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 4. 짝수 필터링\n", + "```python\n", + "numbers = [1, 2, 3, 4, 5, 6]\n", + "# 출력: [2, 4, 6]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6]\n", + "[2, 4, 6]\n" + ] + } + ], + "source": [ + "numbers = [1,2,3,4,5,6] ##\n", + "even_num = lambda x: x if x%2==0 else None #람다 if 문은 else 필수구나..\n", + "even_numbers = list(map(even_num, numbers))\n", + "even_numbers = [x for x in even_numbers if x is not None] #컴프리 헨션 \n", + "#or\n", + "even_numbers2 = list(filter(lambda x: x % 2 == 0, numbers))\n", + "print(even_numbers)\n", + "print(even_numbers2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 5. 리스트의 최대값 찾기\n", + "```python\n", + "numbers = [10, 20, 30, 40]\n", + "# 출력: 40\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "40\n", + "40\n" + ] + } + ], + "source": [ + "numbers = [10, 20, 30, 40]\n", + "max_num = lambda x: max(x)\n", + "max_number = max_num(numbers)\n", + "#or\n", + "from functools import reduce ##리스트의 첫 두 요소를 비교한 뒤, 그 결과를 다음 요소와 계속 비교\n", + "max_number2 = reduce(lambda a,b: a if a>b else b, numbers)\n", + "\n", + "print(max_number)\n", + "print(max_number2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 6. 단어를 알파벳 순서로 정렬하기\n", + "```python\n", + "words = [\"banana\", \"apple\", \"cherry\"]\n", + "# 출력: [\"apple\", \"banana\", \"cherry\"]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['apple', 'banana', 'cherry']\n" + ] + } + ], + "source": [ + "words = [\"banana\", \"apple\", \"cherry\"] ##\n", + "ASC_words = lambda x : sorted(x)\n", + "new_words = ASC_words(words)\n", + "print(new_words)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 7. 리스트의 요소를 두 배로 만드는 람다 함수\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: [2, 4, 6]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4, 6]\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3]\n", + "double_num = lambda x : 2*x\n", + "double_numbers = list(map(double_num, numbers))\n", + "print(double_numbers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 8. 특정 조건에 따라 값 필터링\n", + "```python\n", + "numbers = [5, 10, 15, 20]\n", + "# 조건: 10 이상인 숫자만\n", + "# 출력: [10, 15, 20]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[10, 15, 20]\n" + ] + } + ], + "source": [ + "numbers = [5,10,15,20]\n", + "num_if = list(filter(lambda x: x>=10, numbers))\n", + "print(num_if)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 9. 문자열 리스트를 대문자로 변환\n", + "```python\n", + "words = [\"python\", \"lambda\"]\n", + "# 출력: [\"PYTHON\", \"LAMBDA\"]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['PYTHON', 'LAMBDA']\n", + "['python', 'lambda']\n" + ] + } + ], + "source": [ + "words = [\"python\", \"lambda\"] ##\n", + "upper_words = lambda x : x.upper()\n", + "lower_words = lambda x : x.lower()\n", + "new_words = list(map(upper_words, words))\n", + "print(new_words)\n", + "print(list(map(lower_words,new_words)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 10. 람다와 map을 사용해 리스트의 제곱근 계산\n", + "```python\n", + "numbers = [4, 9, 16]\n", + "# 출력: [2.0, 3.0, 4.0]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2.0, 3.0, 4.0]\n", + "[2.0, 3.0, 4.0]\n" + ] + } + ], + "source": [ + "numbers = [4, 9, 16] ##\n", + "root_nummbers = list(map(lambda x : x**(1/2),numbers))\n", + "#or\n", + "from math import sqrt\n", + "root_nummbers2 = list(map(lambda x: sqrt(x), numbers))\n", + "print(root_nummbers)\n", + "print(root_nummbers2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 11. 리스트 내 특정 단어 포함 여부 확인\n", + "```python\n", + "words = [\"hello\", \"world\"]\n", + "# 조건: 'w'가 포함된 단어\n", + "# 출력: [\"world\"]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['world', 'wolf', 'aws']\n" + ] + } + ], + "source": [ + "words = [\"hello\", \"world\",'wolf','aws'] ##\n", + "find_w_words = list(filter(lambda x: 'w' in x,words))\n", + "print(find_w_words)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 12. 람다와 reduce를 사용해 리스트의 곱 계산\n", + "```python\n", + "numbers = [1, 2, 3, 4]\n", + "# 출력: 24\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "24\n" + ] + } + ], + "source": [ + "from functools import reduce\n", + "numbers = [1,2,3,4]\n", + "multiplication_number = reduce(lambda a,b : a*b, numbers)\n", + "print(multiplication_number)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 13. 리스트의 짝수 요소를 제곱\n", + "```python\n", + "numbers = [1, 2, 3, 4, 5]\n", + "# 출력: [4, 16]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[4, 16]\n", + "[4, 16]\n", + "[4, 16]\n" + ] + } + ], + "source": [ + "numbers = [1,2,3,4,5] ##\n", + "even_square = lambda x : x**2 if x%2==0 else None\n", + "even_sque = list(map(even_square, numbers))\n", + "even_sque = [x for x in even_sque if x is not None]\n", + "#or\n", + "even_square1 = list(filter(lambda x: x % 2 == 0, numbers))\n", + "even_sque1 = list(map(lambda x : x**2, even_square1))\n", + "#or\n", + "even_sque2 = list(map(lambda x: x**2, filter(lambda x : x%2==0,numbers)))\n", + "print(even_sque)\n", + "print(even_sque1)\n", + "print(even_sque2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 14. 두 리스트의 합 생성\n", + "```python\n", + "list1 = [1, 2, 3]\n", + "list2 = [4, 5, 6]\n", + "# 출력: [5, 7, 9]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[5, 7, 9]\n" + ] + } + ], + "source": [ + "list1 = [1, 2, 3]\n", + "list2 = [4, 5, 6]\n", + "list_sum = list(map(lambda a,b : a+b,list1,list2))\n", + "print(list_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 15. 이름과 나이를 튜플로 정렬\n", + "```python\n", + "people = [(\"Alice\", 30), (\"Bob\", 25), (\"Charlie\", 35)]\n", + "# 나이 순으로 정렬\n", + "# 출력: [(\"Bob\", 25), (\"Alice\", 30), (\"Charlie\", 35)]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[('Bob', 25), ('Alice', 30), ('Charlie', 35)]\n", + "[('Alice', 30), ('Bob', 25), ('Charlie', 35)]\n" + ] + } + ], + "source": [ + "people = [(\"Alice\", 30), (\"Bob\", 25), (\"Charlie\", 35)]\n", + "sorted_age_people = sorted(people,key = lambda x : x[1])\n", + "print(sorted_age_people)\n", + "sorted_name_people = sorted(sorted_age_people,key = lambda x : x[0])\n", + "print(sorted_name_people)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 16. 두 문자열을 결합하는 람다 함수 작성\n", + "```python\n", + "# 입력: (\"hello\", \"world\")\n", + "# 출력: \"hello world\"\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hello world\n" + ] + } + ], + "source": [ + "first_word = 'hello'\n", + "second_word = 'world'\n", + "sum_word = lambda a,b: a+' '+b\n", + "print(sum_word(input(),input()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 17. 리스트에서 짝수의 합 계산\n", + "```python\n", + "numbers = [1, 2, 3, 4, 5, 6]\n", + "# 출력: 12\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 51, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "12\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3, 4, 5, 6]\n", + "from functools import reduce\n", + "\n", + "even_num_sum = reduce(lambda a,b :a+b, list(filter(lambda x: x%2==0,numbers)))\n", + "print(even_num_sum)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 18. 문자열의 첫 글자를 반환\n", + "```python\n", + "words = [\"apple\", \"banana\"]\n", + "# 출력: [\"a\", \"b\"]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['a', 'b']\n", + "['Apple', 'Banana']\n" + ] + } + ], + "source": [ + "words = [\"apple\", \"banana\"]\n", + "\n", + "changed_words = list(map(lambda x : x[0],words))\n", + "print(changed_words)\n", + "#응용 첫 글자만 대문자 만들기\n", + "changed_words1 = list(map(lambda x : x[0].upper() + x[1:] ,words))\n", + "print(changed_words1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "### 19. 리스트의 요소를 문자열로 변환\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: [\"1\", \"2\", \"3\"]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['1', '2', '3']\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3]\n", + "\n", + "string_numbers = list(map(lambda x : str(x),numbers))\n", + "print(string_numbers)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 20. 특정 길이 이상의 단어 필터링\n", + "```python\n", + "words = [\"python\", \"is\", \"awesome\"]\n", + "# 조건: 길이 3 이상\n", + "# 출력: [\"python\", \"awesome\"]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['python', 'awesome']\n" + ] + } + ], + "source": [ + "words = [\"python\", \"is\", \"awesome\"]\n", + "thr_len_words = list(filter(lambda x : len(x)>=3 ,words))\n", + "print(thr_len_words)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/03151_minsuje/hw/week3(p)/python_Q/pythonQ.md b/03151_minsuje/hw/week3(p)/python_Q/pythonQ.md new file mode 100644 index 0000000..e69de29 From d574b5b96bcad200c6924f100338874abc8de25a Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Wed, 29 Jan 2025 11:02:44 +0900 Subject: [PATCH 05/11] Update pythonQ.md --- 03151_minsuje/hw/week3(p)/python_Q/pythonQ.md | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/03151_minsuje/hw/week3(p)/python_Q/pythonQ.md b/03151_minsuje/hw/week3(p)/python_Q/pythonQ.md index e69de29..11367f3 100644 --- a/03151_minsuje/hw/week3(p)/python_Q/pythonQ.md +++ b/03151_minsuje/hw/week3(p)/python_Q/pythonQ.md @@ -0,0 +1,132 @@ +# Python 기초 심화 문제 모음 + +아래는 Python의 lambda에 관련된된 20개씩의 문제를 구성하였습니다. + +--- + +## 람다 함수 문제 + +### 1. 두 숫자를 더하는 람다 함수 작성하기 +```python +# 입력: (3, 5) +# 출력: 8 +``` + +### 2. 리스트의 각 요소를 제곱하는 람다 함수 사용 +```python +numbers = [1, 2, 3, 4] +# 출력: [1, 4, 9, 16] +``` + +### 3. 문자열 길이를 반환하는 람다 함수 작성 +```python +words = ["hello", "world"] +# 출력: [5, 5] +``` + +### 4. 짝수 필터링 +```python +numbers = [1, 2, 3, 4, 5, 6] +# 출력: [2, 4, 6] +``` + +### 5. 리스트의 최대값 찾기 +```python +numbers = [10, 20, 30, 40] +# 출력: 40 +``` + +### 6. 단어를 알파벳 순서로 정렬하기 +```python +words = ["banana", "apple", "cherry"] +# 출력: ["apple", "banana", "cherry"] +``` + +### 7. 리스트의 요소를 두 배로 만드는 람다 함수 +```python +numbers = [1, 2, 3] +# 출력: [2, 4, 6] +``` + +### 8. 특정 조건에 따라 값 필터링 +```python +numbers = [5, 10, 15, 20] +# 조건: 10 이상인 숫자만 +# 출력: [10, 15, 20] +``` + +### 9. 문자열 리스트를 대문자로 변환 +```python +words = ["python", "lambda"] +# 출력: ["PYTHON", "LAMBDA"] +``` + +### 10. 람다와 map을 사용해 리스트의 제곱근 계산 +```python +numbers = [4, 9, 16] +# 출력: [2.0, 3.0, 4.0] +``` + +### 11. 리스트 내 특정 단어 포함 여부 확인 +```python +words = ["hello", "world"] +# 조건: 'w'가 포함된 단어 +# 출력: ["world"] +``` + +### 12. 람다와 reduce를 사용해 리스트의 곱 계산 +```python +numbers = [1, 2, 3, 4] +# 출력: 24 +``` + +### 13. 리스트의 짝수 요소를 제곱 +```python +numbers = [1, 2, 3, 4, 5] +# 출력: [4, 16] +``` + +### 14. 두 리스트의 합 생성 +```python +list1 = [1, 2, 3] +list2 = [4, 5, 6] +# 출력: [5, 7, 9] +``` + +### 15. 이름과 나이를 튜플로 정렬 +```python +people = [("Alice", 30), ("Bob", 25), ("Charlie", 35)] +# 나이 순으로 정렬 +# 출력: [("Bob", 25), ("Alice", 30), ("Charlie", 35)] +``` + +### 16. 두 문자열을 결합하는 람다 함수 작성 +```python +# 입력: ("hello", "world") +# 출력: "hello world" +``` + +### 17. 리스트에서 짝수의 합 계산 +```python +numbers = [1, 2, 3, 4, 5, 6] +# 출력: 12 +``` + +### 18. 문자열의 첫 글자를 반환 +```python +words = ["apple", "banana"] +# 출력: ["a", "b"] +``` + +### 19. 리스트의 요소를 문자열로 변환 +```python +numbers = [1, 2, 3] +# 출력: ["1", "2", "3"] +``` + +### 20. 특정 길이 이상의 단어 필터링 +```python +words = ["python", "is", "awesome"] +# 조건: 길이 3 이상 +# 출력: ["python", "awesome"] +``` From 06c1426690ec2e0953b3e3903176858ecc892691 Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Mon, 3 Feb 2025 09:49:58 +0900 Subject: [PATCH 06/11] =?UTF-8?q?4=EC=A3=BC=EC=B0=A8=20=EC=8A=A4=ED=84=B0?= =?UTF-8?q?=EB=94=94=20=EA=B3=BC=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 4주차 스터디 --- .../study_3week_kimQ/study_3week_kimQ.py | 48 ++ .../study_3week_kimQ/study_3wwek_kimA.py | 8 + .../study_week3_A_jwlee.py | 62 ++ .../study_week3_Q_jwlee.py | 11 + .../study_week3_A_seok/study_week3_A_seok.py | 0 .../study_week3_Q_ji/study_week3_A_ji_1.py | 70 ++ .../study_week3_Q_ji/study_week3_A_ji_2.py | 68 ++ .../study_week3_Q_ji/study_week3_A_ji_3.py | 29 + .../study_week3_Q_ji/study_week3_Q_ji.py | 110 +++ ...in_functions_and_regular_expressions.ipynb | 747 ++++++++++++++++++ .../hw/week4(p)/python_Q_min/python_Q.md | 249 ++++++ 11 files changed, 1402 insertions(+) create mode 100644 03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3week_kimQ.py create mode 100644 03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3wwek_kimA.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_A_jwlee.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_Q_jwlee.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_1.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_2.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_3.py create mode 100644 03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_Q_ji.py create mode 100644 03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb create mode 100644 03151_minsuje/hw/week4(p)/python_Q_min/python_Q.md diff --git a/03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3week_kimQ.py b/03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3week_kimQ.py new file mode 100644 index 0000000..551730f --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3week_kimQ.py @@ -0,0 +1,48 @@ +from tkinter import * + +tk=Tk() + +tk.title("order beverage") +tk.geometry("300x400") + +menu={'coffee':3500,'latte':4000,'smoothie':5000,'tea':3000} + +selected_quantity={} + +total_quantity=IntVar() #store selected beverage quantity +total_price=IntVar() #store selected beverage price #tkinter widget-data value sync +total_quantity.set(0) #initial value=0(no select beverage) +total_price.set(0) + +def show_order(item): #when user press the button(beverage), call this function + total_quantity.set(total_quantity.get()+1) #get now quantity, and update +1 + total_price.set(total_price.get()+menu[item]) #get now price, and update with selected beverage price (menu[item]==bring selceted beverage's price) + ostring.set(f"Total items: {total_quantity.get()} | Total price: {total_price.get()}won") #store ostring with updated values + +#ostring.set()method: update total qauntity and price +#total_quantity.get()=bring now total quantity +#total_price.get()=bring now total price + +def order_exit(): + print("Order program exit") + exit() + +ostring=StringVar() +ostring.set("Total items: 0 | Total price: 0 won") #default message + +olabel=Label(tk,textvariable=ostring) #when ostirng update,label1 value update too +olabel.pack(side="bottom") + +obtn1=Button(tk,text="coffee",width=10,height=1,command=lambda: show_order("coffee")) +obtn2=Button(tk,text="latte",width=10,height=1,command=lambda: show_order("latte")) +obtn3=Button(tk,text="smoothie",width=10,height=1,command=lambda:show_order("smoothie")) +obtn4=Button(tk,text="tea",width=10,height=1,command=lambda:show_order("tea")) +obtn5=Button(tk,text="exit",width=10,height=1,command=order_exit) + +obtn1.pack(side="top") +obtn2.pack(side="top") +obtn3.pack(side="top") +obtn4.pack(side="top") +obtn5.pack(side="top") + +tk.mainloop() \ No newline at end of file diff --git a/03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3wwek_kimA.py b/03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3wwek_kimA.py new file mode 100644 index 0000000..9bf3bcc --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_3week_kimQ/study_3wwek_kimA.py @@ -0,0 +1,8 @@ +# 음료 주문 프로그램 + +# menu={'coffee':3500,'latte':4000,'smoothie':5000,'tea':3000} + +# 해당 딕셔너리를 활용하여 음료 주문을 하는 GUI프로그램을 생성한다. +# 창 제목은 음료 주문 프로그램이라고 작성한다. +# exit버튼을 누르면 터미널에 음료 주문 프로그램을 종료했다는 문구와 함께 프로그램 창을 종료시킨다. +# 창에는 메뉴판에 있는 메뉴명을 기재하며 각 메뉴 버튼을 누르면 하단에 총 금액과 총 가격에 반영되도록 이벤트를 설정한다. \ No newline at end of file diff --git a/03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_A_jwlee.py b/03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_A_jwlee.py new file mode 100644 index 0000000..1e1c747 --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_A_jwlee.py @@ -0,0 +1,62 @@ +# 행렬의 덧셈은 행과 열의 크기가 같은 두 행렬의 같은 행, 같은 열의 값을 서로 더한 결과가 됩니다. +# 2개의 행렬 arr1과 arr2를 입력받아, 행렬 덧셈의 결과를 반환하는 함수, solution을 완성해주세요. + +# 제한 조건 +# 행렬 arr1, arr2의 행과 열의 길이는 500을 넘지 않습니다. +# 입출력 예 +# arr1 = [[[1, 2], [2, 3]], [[1], [2]]] +# arr2 = [[[3, 4], [5, 6]], [[3], [4]]] +# return [[[4, 6], [7, 9]], [[4], [6]]] + + +# # 풀이 + +# 1. 2차원 배열 + +def solution(arr1, arr2): + result = [] + for row in range(len(arr1)): # 행 반복 + new_row = [] + for col in range(len(arr1[0])): # 열 반복 + new_row.append(arr1[row][col] + arr2[row][col]) # 한 행 완성, result에 추가 + result.append(new_row) + return result + +arr1 = [[1, 2], [2, 3]] +arr2 = [[3, 4], [5, 6]] + +print(solution(arr1, arr2)) + + + +# 2. lambda 와 map 함수를 사용(gpt 활용) +def solution(arr1, arr2): + # map과 lambda를 사용해 2차원 배열의 요소를 더함 + return list(map(lambda row1, row2: list(map(lambda x, y: x + y, row1, row2)), arr1, arr2)) + +# 테스트 +arr1 = [[1, 2], [2, 3]] +arr2 = [[3, 4], [5, 6]] + +print(solution(arr1, arr2)) # 출력: [[4, 6], [7, 9]] + + + +# 3. 3차원배열 (구현 실패) + +# def solution(arr1, arr2): +# result = [] +# for i in range(len(arr1)): # 3차원 배열의 층 반복 +# two_d=[] # 2차원 배열 합 +# for row in range(len(arr1[i])): # 행 반복 +# row_list = [] +# for col in range(len(arr1[i][row])): # 열 반복 +# row_list.append(arr1[i][row][col] + arr2[i][row][col]) # 한 행 완성, result에 추가 +# two_d.append(row_list) +# result.append(row_list) +# return result + +# arr1 = [[[1, 2], [2, 3]], [[1], [2]]] +# arr2 = [[[3, 4], [5, 6]], [[3], [4]]] + +# print(solution(arr1, arr2)) \ No newline at end of file diff --git a/03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_Q_jwlee.py b/03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_Q_jwlee.py new file mode 100644 index 0000000..d65ee86 --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_week3_A_jwlee/study_week3_Q_jwlee.py @@ -0,0 +1,11 @@ +# 1번 - lambda와 map 함수 활용 + +# 행렬의 덧셈은 행과 열의 크기가 같은 두 행렬의 같은 행, 같은 열의 값을 서로 더한 결과가 됩니다. +# 2개의 행렬 arr1과 arr2를 입력받아, 행렬 덧셈의 결과를 반환하는 함수, solution을 완성해주세요. + +# 제한 조건 +# 행렬 arr1, arr2의 행과 열의 길이는 500을 넘지 않습니다. +# 입출력 예 +# arr1 arr2 return +# [[1,2],[2,3]] [[3,4],[5,6]] [[4,6],[7,9]] +# [[1],[2]] [[3],[4]] [[4],[6]] \ No newline at end of file diff --git a/03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py b/03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py new file mode 100644 index 0000000..e69de29 diff --git a/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_1.py b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_1.py new file mode 100644 index 0000000..78d77b5 --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_1.py @@ -0,0 +1,70 @@ + +# 1. 문제 설명 +'''네오와 프로도가 숫자놀이를 하고 있습니다. +네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다. +다음은 숫자의 일부 자릿수를 영단어로 바꾸는 예시입니다. + +1478 → "one4seveneight" +234567 → "23four5six7" +10203 → "1zerotwozero3" + +이렇게 숫자의 일부 자릿수가 영단어로 바뀌어졌거나, 혹은 바뀌지 않고 그대로인 문자열 s가 매개변수로 주어집니다. s가 의미하는 원래 숫자를 return 하도록 solution 함수를 완성해주세요. +참고로 각 숫자에 대응되는 영단어는 다음 표와 같습니다. + +숫자 영단어 +0 zero +1 one +2 two +3 three +4 four +5 five +6 six +7 seven +8 eight +9 nine + +제한사항 +1 ≤ s의 길이 ≤ 50 +s가 "zero" 또는 "0"으로 시작하는 경우는 주어지지 않습니다. +return 값이 1 이상 2,000,000,000 이하의 정수가 되는 올바른 입력만 s로 주어집니다. + +입출력 예 +s result +"one4seveneight" 1478 +"23four5six7" 234567 +"2three45sixseven" 234567 +"123" 123 +입출력 예 설명 +입출력 예 #1 + +문제 예시와 같습니다. +입출력 예 #2 + +문제 예시와 같습니다. +입출력 예 #3 + +"three"는 3, "six"는 6, "seven"은 7에 대응되기 때문에 정답은 입출력 예 #2와 같은 234567이 됩니다. +입출력 예 #2와 #3과 같이 같은 정답을 가리키는 문자열이 여러 가지가 나올 수 있습니다. +입출력 예 #4 + +s에는 영단어로 바뀐 부분이 없습니다. + +제한시간 안내 +정확성 테스트 : 10초 +''' +import re +numbers=['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine'] + +def solution(s): + for idx, num in enumerate(numbers): # numbers 리스트와 인덱스를 같이 처리(0,1,2,3...) + p = re.compile(num) # numbers 요소를 비교로 설정정 + if p.search(s): # 문자열 처음부터 끝까지 검색해서 존재하면면 + s= s.replace(num,str(idx)) # 문자열에서 numbers요소 부분을을 그 인덱스를 문자열화 한것으로 대체 + return int(s) # '숫자'로 대체한한 문자열을 정수형으로 변환하여 반환환 + + +# 테스트 예시 +print(solution("one4seveneight")) # 1478 +print(solution("23four5six7")) # 234567 +print(solution("2three45sixseven")) # 234567 +print(solution("123")) # 123 diff --git a/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_2.py b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_2.py new file mode 100644 index 0000000..752c978 --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_2.py @@ -0,0 +1,68 @@ +# 2. 문제 설명 +''' +문자열 s가 입력되었을 때 다음 규칙을 따라서 이 문자열을 여러 문자열로 분해하려고 합니다. + +- 먼저 첫 글자를 읽습니다. 이 글자를 x라고 합시다. +- 이제 이 문자열을 왼쪽에서 오른쪽으로 읽어나가면서, x와 x가 아닌 다른 글자들이 나온 횟수를 각각 셉니다. + 처음으로 두 횟수가 같아지는 순간 멈추고, 지금까지 읽은 문자열을 분리합니다. +- s에서 분리한 문자열을 빼고 남은 부분에 대해서 이 과정을 반복합니다. 남은 부분이 없다면 종료합니다. +- 만약 두 횟수가 다른 상태에서 더 이상 읽을 글자가 없다면, 역시 지금까지 읽은 문자열을 분리하고, 종료합니다. + +문자열 s가 매개변수로 주어질 때, 위 과정과 같이 문자열들로 분해하고, 분해한 문자열의 개수를 return 하는 함수 solution을 완성하세요. + +제한사항 +1 ≤ s의 길이 ≤ 10,000 +s는 영어 소문자로만 이루어져 있습니다. + +입출력 예 + s result +"banana" 3 +"abracadabra" 6 +"aaabbaccccabba" 3 + +입출력 예 설명 +입출력 예 #1 +s="banana"인 경우 ba - na - na와 같이 분해됩니다. + +입출력 예 #2 +s="abracadabra"인 경우 ab - ra - ca - da - br - a와 같이 분해됩니다. + +입출력 예 #3 +s="aaabbaccccabba"인 경우 aaabbacc - ccab - ba와 같이 분해됩니다. +''' +from collections import deque + +def solution(s): + dq = deque(s) + count = 0 # 몇 개의 부분으로 분해되었는지 저장하는 변수수 + + while dq: + if len(dq) == 1: # 문자열이 처음부터 한글자거나, 한글자만 남았을 때 + count += 1 + + x = dq.popleft() # 첫번째 요소를 x에 저장(덱에서 삭제제) + count_x = 1 # x 개수를 저장할 변수 초기화 (처음 하나가 있으니 1) + count_a = 0 # x와 다른 문자 개수를 저장할 변수 초기화화 + + while dq: + if x == dq[0]: # 그 다음요소가 x와 같으면면 + count_x += 1 # x 개수 +1 + dq.popleft() # 그리고 검사한 요소는 삭제제 + else: + count_a += 1 # 그 다음요소가 x와 다르면면 a에 +1 + dq.popleft() # 그리고 검사한 요소 삭제 + + if count_x == count_a: # 검사 후 x와 다른문자의 개수가 같으면 + count += 1 # count 변수에 +1 하고 내부 반복문 탈출출 + break + elif len(dq) == 0: # 만약 개수가 다른데 문자열을 다 확인했다면 + count += 1 # count 변수에 +1 하여 한덩어리임을 저장장 + return count + +print(solution("banana")) +print(solution("abracadabra")) +print(solution("aaabbaccccabba")) +from collections import deque +dq = deque([1, 2, 3]) +dq.appendleft(0) +print(dq) diff --git a/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_3.py b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_3.py new file mode 100644 index 0000000..85ce31f --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_A_ji_3.py @@ -0,0 +1,29 @@ + +# 3. 문제 설명 +''' +문자열 s에는 공백으로 구분된 숫자들이 저장되어 있습니다. +str에 나타나는 숫자 중 최소값과 최대값을 찾아 이를 "(최소값) (최대값)"형태의 문자열을 반환하는 함수, solution을 완성하세요. +예를들어 s가 "1 2 3 4"라면 "1 4"를 리턴하고, "-1 -2 -3 -4"라면 "-4 -1"을 리턴하면 됩니다. + +제한 조건 +s에는 둘 이상의 정수가 공백으로 구분되어 있습니다. + +입출력 예 +s return +"1 2 3 4" "1 4" +"-1 -2 -3 -4" "-4 -1" +"-1 -1" "-1 -1" +''' +def solution(s): + nums = s.split() # 공백을 기준으로 나눠 리스트로 저장장 + nums = list(map(lambda x: int(x), nums)) # 리스트 내부 문자열숫자를 정수로 변환환 + max_num = max(nums) + min_num = min(nums) + result_list = [min_num, max_num] # 최소값, 최대값을 차례대로 결과 리스트에 저장 + result_list = list(map(lambda x: str(x), result_list)) # 내부 요소를 문자열숫자로 변환 + result = " ".join(result_list) # 공백을 기준으로 하나의 문자열로 저장 + return result + +print(solution("1 2 3 4")) +print(solution("-1 -2 -3 -4")) +print(solution("-1 1")) \ No newline at end of file diff --git a/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_Q_ji.py b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_Q_ji.py new file mode 100644 index 0000000..5c23d3e --- /dev/null +++ b/03151_minsuje/hw/week3(p)/study_week3_Q_ji/study_week3_Q_ji.py @@ -0,0 +1,110 @@ +''' +총 3문제 +1. https://school.programmers.co.kr/learn/courses/30/lessons/81301 +2. https://school.programmers.co.kr/learn/courses/30/lessons/140108 +3. https://school.programmers.co.kr/learn/courses/30/lessons/12939 + +''' + +# 1. 문제 설명 +'''네오와 프로도가 숫자놀이를 하고 있습니다. +네오가 프로도에게 숫자를 건넬 때 일부 자릿수를 영단어로 바꾼 카드를 건네주면 프로도는 원래 숫자를 찾는 게임입니다. +다음은 숫자의 일부 자릿수를 영단어로 바꾸는 예시입니다. + +1478 → "one4seveneight" +234567 → "23four5six7" +10203 → "1zerotwozero3" + +이렇게 숫자의 일부 자릿수가 영단어로 바뀌어졌거나, 혹은 바뀌지 않고 그대로인 문자열 s가 매개변수로 주어집니다. s가 의미하는 원래 숫자를 return 하도록 solution 함수를 완성해주세요. +참고로 각 숫자에 대응되는 영단어는 다음 표와 같습니다. + +숫자 영단어 +0 zero +1 one +2 two +3 three +4 four +5 five +6 six +7 seven +8 eight +9 nine + +제한사항 +1 ≤ s의 길이 ≤ 50 +s가 "zero" 또는 "0"으로 시작하는 경우는 주어지지 않습니다. +return 값이 1 이상 2,000,000,000 이하의 정수가 되는 올바른 입력만 s로 주어집니다. + +입출력 예 +s result +"one4seveneight" 1478 +"23four5six7" 234567 +"2three45sixseven" 234567 +"123" 123 +입출력 예 설명 +입출력 예 #1 + +문제 예시와 같습니다. +입출력 예 #2 + +문제 예시와 같습니다. +입출력 예 #3 + +"three"는 3, "six"는 6, "seven"은 7에 대응되기 때문에 정답은 입출력 예 #2와 같은 234567이 됩니다. +입출력 예 #2와 #3과 같이 같은 정답을 가리키는 문자열이 여러 가지가 나올 수 있습니다. +입출력 예 #4 + +s에는 영단어로 바뀐 부분이 없습니다. + +제한시간 안내 +정확성 테스트 : 10초 +''' + +# 2. 문제 설명 +''' +문자열 s가 입력되었을 때 다음 규칙을 따라서 이 문자열을 여러 문자열로 분해하려고 합니다. + +- 먼저 첫 글자를 읽습니다. 이 글자를 x라고 합시다. +- 이제 이 문자열을 왼쪽에서 오른쪽으로 읽어나가면서, x와 x가 아닌 다른 글자들이 나온 횟수를 각각 셉니다. + 처음으로 두 횟수가 같아지는 순간 멈추고, 지금까지 읽은 문자열을 분리합니다. +- s에서 분리한 문자열을 빼고 남은 부분에 대해서 이 과정을 반복합니다. 남은 부분이 없다면 종료합니다. +- 만약 두 횟수가 다른 상태에서 더 이상 읽을 글자가 없다면, 역시 지금까지 읽은 문자열을 분리하고, 종료합니다. + +문자열 s가 매개변수로 주어질 때, 위 과정과 같이 문자열들로 분해하고, 분해한 문자열의 개수를 return 하는 함수 solution을 완성하세요. + +제한사항 +1 ≤ s의 길이 ≤ 10,000 +s는 영어 소문자로만 이루어져 있습니다. + +입출력 예 + s result +"banana" 3 +"abracadabra" 6 +"aaabbaccccabba" 3 + +입출력 예 설명 +입출력 예 #1 +s="banana"인 경우 ba - na - na와 같이 분해됩니다. + +입출력 예 #2 +s="abracadabra"인 경우 ab - ra - ca - da - br - a와 같이 분해됩니다. + +입출력 예 #3 +s="aaabbaccccabba"인 경우 aaabbacc - ccab - ba와 같이 분해됩니다. +''' + +# 3. 문제 설명 +''' +문자열 s에는 공백으로 구분된 숫자들이 저장되어 있습니다. +str에 나타나는 숫자 중 최소값과 최대값을 찾아 이를 "(최소값) (최대값)"형태의 문자열을 반환하는 함수, solution을 완성하세요. +예를들어 s가 "1 2 3 4"라면 "1 4"를 리턴하고, "-1 -2 -3 -4"라면 "-4 -1"을 리턴하면 됩니다. + +제한 조건 +s에는 둘 이상의 정수가 공백으로 구분되어 있습니다. + +입출력 예 +s return +"1 2 3 4" "1 4" +"-1 -2 -3 -4" "-4 -1" +"-1 -1" "-1 -1" +''' \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb b/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb new file mode 100644 index 0000000..800020e --- /dev/null +++ b/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb @@ -0,0 +1,747 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 내장 함수 문제" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. abs 함수 사용하기\n", + "```python\n", + "# 입력: -5\n", + "# 출력: 5\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. all 함수로 리스트 검사하기\n", + "```python\n", + "numbers = [True, True, False]\n", + "# 출력: False\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. any 함수로 값 존재 여부 확인\n", + "```python\n", + "numbers = [0, 0, 1]\n", + "# 출력: True\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4. enumerate 함수로 인덱스와 값 출력\n", + "```python\n", + "words = [\"a\", \"b\", \"c\"]\n", + "# 출력: [(0, \"a\"), (1, \"b\"), (2, \"c\")]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5. filter 함수로 짝수 필터링\n", + "```python\n", + "numbers = [1, 2, 3, 4, 5]\n", + "# 출력: [2, 4]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 6. len 함수로 리스트 길이 확인\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: 3\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7. max 함수로 최대값 찾기\n", + "```python\n", + "numbers = [10, 20, 30]\n", + "# 출력: 30\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 8. min 함수로 최소값 찾기\n", + "```python\n", + "numbers = [10, 20, 30]\n", + "# 출력: 10\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 9. map 함수로 리스트 요소 제곱\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: [1, 4, 9]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 10. pow 함수로 제곱 계산\n", + "```python\n", + "# 입력: 2, 3\n", + "# 출력: 8\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 11. range 함수로 숫자 생성\n", + "```python\n", + "# 입력: range(5)\n", + "# 출력: [0, 1, 2, 3, 4]\n", + "```\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 12. reversed 함수로 리스트 뒤집기\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: [3, 2, 1]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 13. round 함수로 소수점 반올림\n", + "```python\n", + "# 입력: 3.14159, 2\n", + "# 출력: 3.14\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 14. sorted 함수로 정렬하기\n", + "```python\n", + "numbers = [3, 1, 2]\n", + "# 출력: [1, 2, 3]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 15. sum 함수로 리스트 합 계산\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: 6\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 16. type 함수로 데이터 타입 확인\n", + "```python\n", + "value = 42\n", + "# 출력: \n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 17. zip 함수로 리스트 병합\n", + "```python\n", + "list1 = [1, 2, 3]\n", + "list2 = [\"a\", \"b\", \"c\"]\n", + "# 출력: [(1, \"a\"), (2, \"b\"), (3, \"c\")]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 18. eval 함수로 문자열 표현식 계산\n", + "```python\n", + "expression = \"2 + 3 * 4\"\n", + "# 출력: 14\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 19. chr 함수로 아스키 코드 문자 반환\n", + "```python\n", + "# 입력: 97\n", + "# 출력: 'a'\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 20. ord 함수로 문자 아스키 코드 반환\n", + "```python\n", + "# 입력: 'a'\n", + "# 출력: 97\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 정규 표현식 문제" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1. 문자열에서 모든 이메일 주소 찾기\n", + "```python\n", + "text = \"Contact us at info@example.com or support@domain.org\"\n", + "# 출력: ['info@example.com', 'support@domain.org']\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2. all 함수로 리스트 검사하기\n", + "```python\n", + "numbers = [True, True, False]\n", + "# 출력: False\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3. any 함수로 값 존재 여부 확인\n", + "```python\n", + "numbers = [0, 0, 1]\n", + "# 출력: True\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4. enumerate 함수로 인덱스와 값 출력\n", + "```python\n", + "words = [\"a\", \"b\", \"c\"]\n", + "# 출력: [(0, \"a\"), (1, \"b\"), (2, \"c\")]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 5. filter 함수로 짝수 필터링\n", + "```python\n", + "numbers = [1, 2, 3, 4, 5]\n", + "# 출력: [2, 4]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 6. len 함수로 리스트 길이 확인\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: 3\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7. max 함수로 최대값 찾기\n", + "```python\n", + "numbers = [10, 20, 30]\n", + "# 출력: 30\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 8. min 함수로 최소값 찾기\n", + "```python\n", + "numbers = [10, 20, 30]\n", + "# 출력: 10\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 9. map 함수로 리스트 요소 제곱\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: [1, 4, 9]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 10. pow 함수로 제곱 계산\n", + "```python\n", + "# 입력: 2, 3\n", + "# 출력: 8\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 11. range 함수로 숫자 생성\n", + "```python\n", + "# 입력: range(5)\n", + "# 출력: [0, 1, 2, 3, 4]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 12. reversed 함수로 리스트 뒤집기\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: [3, 2, 1]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 13. round 함수로 소수점 반올림\n", + "```python\n", + "# 입력: 3.14159, 2\n", + "# 출력: 3.14\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 14. sorted 함수로 정렬하기\n", + "```python\n", + "numbers = [3, 1, 2]\n", + "# 출력: [1, 2, 3]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 15. sum 함수로 리스트 합 계산\n", + "```python\n", + "numbers = [1, 2, 3]\n", + "# 출력: 6\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 16. type 함수로 데이터 타입 확인\n", + "```python\n", + "value = 42\n", + "# 출력: \n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 17. zip 함수로 리스트 병합\n", + "```python\n", + "list1 = [1, 2, 3]\n", + "list2 = [\"a\", \"b\", \"c\"]\n", + "# 출력: [(1, \"a\"), (2, \"b\"), (3, \"c\")]\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 18. eval 함수로 문자열 표현식 계산\n", + "```python\n", + "expression = \"2 + 3 * 4\"\n", + "# 출력: 14\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 19. chr 함수로 아스키 코드 문자 반환\n", + "```python\n", + "# 입력: 97\n", + "# 출력: 'a'\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 20. ord 함수로 문자 아스키 코드 반환\n", + "```python\n", + "# 입력: 'a'\n", + "# 출력: 97\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/03151_minsuje/hw/week4(p)/python_Q_min/python_Q.md b/03151_minsuje/hw/week4(p)/python_Q_min/python_Q.md new file mode 100644 index 0000000..9239c78 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/python_Q_min/python_Q.md @@ -0,0 +1,249 @@ +## 내장 함수 문제 + +### 1. abs 함수 사용하기 +```python +# 입력: -5 +# 출력: 5 +``` + +### 2. all 함수로 리스트 검사하기 +```python +numbers = [True, True, False] +# 출력: False +``` + +### 3. any 함수로 값 존재 여부 확인 +```python +numbers = [0, 0, 1] +# 출력: True +``` + +### 4. enumerate 함수로 인덱스와 값 출력 +```python +words = ["a", "b", "c"] +# 출력: [(0, "a"), (1, "b"), (2, "c")] +``` + +### 5. filter 함수로 짝수 필터링 +```python +numbers = [1, 2, 3, 4, 5] +# 출력: [2, 4] +``` + +### 6. len 함수로 리스트 길이 확인 +```python +numbers = [1, 2, 3] +# 출력: 3 +``` + +### 7. max 함수로 최대값 찾기 +```python +numbers = [10, 20, 30] +# 출력: 30 +``` + +### 8. min 함수로 최소값 찾기 +```python +numbers = [10, 20, 30] +# 출력: 10 +``` + +### 9. map 함수로 리스트 요소 제곱 +```python +numbers = [1, 2, 3] +# 출력: [1, 4, 9] +``` + +### 10. pow 함수로 제곱 계산 +```python +# 입력: 2, 3 +# 출력: 8 +``` + +### 11. range 함수로 숫자 생성 +```python +# 입력: range(5) +# 출력: [0, 1, 2, 3, 4] +``` + +### 12. reversed 함수로 리스트 뒤집기 +```python +numbers = [1, 2, 3] +# 출력: [3, 2, 1] +``` + +### 13. round 함수로 소수점 반올림 +```python +# 입력: 3.14159, 2 +# 출력: 3.14 +``` + +### 14. sorted 함수로 정렬하기 +```python +numbers = [3, 1, 2] +# 출력: [1, 2, 3] +``` + +### 15. sum 함수로 리스트 합 계산 +```python +numbers = [1, 2, 3] +# 출력: 6 +``` + +### 16. type 함수로 데이터 타입 확인 +```python +value = 42 +# 출력: +``` + +### 17. zip 함수로 리스트 병합 +```python +list1 = [1, 2, 3] +list2 = ["a", "b", "c"] +# 출력: [(1, "a"), (2, "b"), (3, "c")] +``` + +### 18. eval 함수로 문자열 표현식 계산 +```python +expression = "2 + 3 * 4" +# 출력: 14 +``` + +### 19. chr 함수로 아스키 코드 문자 반환 +```python +# 입력: 97 +# 출력: 'a' +``` + +### 20. ord 함수로 문자 아스키 코드 반환 +```python +# 입력: 'a' +# 출력: 97 +``` +## 정규 표현식 문제 + +### 1. 문자열에서 모든 이메일 주소 찾기 +```python +text = "Contact us at info@example.com or support@domain.org" +# 출력: ['info@example.com', 'support@domain.org'] +``` + +### 2. 특정 패턴으로 시작하는 단어 추출 +```python +text = "apple banana cherry date" +pattern = r"^a" +# 출력: ['apple'] +``` + +### 3. 전화번호 형식 검사 +```python +phone = "123-456-7890" +# 출력: True (형식이 올바른 경우) +``` + +### 4. 문자열에서 숫자만 추출 +```python +text = "Order 123 items for $45.67" +# 출력: ['123', '45', '67'] +``` + +### 5. 공백으로 구분된 단어의 개수 세기 +```python +text = "This is a test sentence." +# 출력: 5 +``` + +### 6. HTML 태그 제거하기 +```python +html = "

This is a paragraph.

" +# 출력: 'This is a paragraph.' +``` + +### 7. 특정 단어 포함 여부 확인 +```python +text = "Python is fun" +word = "fun" +# 출력: True +``` + +### 8. 날짜 형식 변환 +```python +date = "2025-01-27" +# 출력: '27-01-2025' +``` + +### 9. 소문자와 대문자 교체 +```python +text = "Hello World" +# 출력: 'hELLO wORLD' +``` + +### 10. IP 주소 형식 검사 +```python +ip = "192.168.1.1" +# 출력: True (형식이 올바른 경우) +``` + +### 11. 문자열에서 모든 URL 추출 +```python +text = "Visit https://example.com or http://test.org for info." +# 출력: ['https://example.com', 'http://test.org'] +``` + +### 12. 특정 패턴의 단어 치환 +```python +text = "I love cats and dogs" +pattern = r"cats" +replacement = "pets" +# 출력: 'I love pets and dogs' +``` + +### 13. 문자열에서 연속된 공백 제거 +```python +text = "This is a test." +# 출력: 'This is a test.' +``` + +### 14. 특정 문자열이 파일 경로인지 검사 +```python +path = "/user/home/test.txt" +# 출력: True (파일 경로가 올바른 경우) +``` + +### 15. 영어 단어만 추출하기 +```python +text = "123abc!@#def456" +# 출력: ['abc', 'def'] +``` + +### 16. 특정 접미사로 끝나는 단어 찾기 +```python +text = "running swimming jumping" +pattern = r"ing" +# 출력: ['running', 'swimming', 'jumping'] +``` + +### 17. 문자열에서 중복된 단어 제거 +```python +text = "this this is is a test test" +# 출력: 'this is a test' +``` + +### 18. 문자열에서 특수 문자 제거 +```python +text = "Hello!@#$%^&*()" +# 출력: 'Hello' +``` + +### 19. 특정 길이의 단어만 추출 +```python +text = "cat bat mat" +length = 3 +# 출력: ['cat', 'bat', 'mat'] +``` + +### 20. 파일 확장자 추출 +```python +filename = "document.pdf" +# 출력: 'pdf' +``` \ No newline at end of file From aecdeb2b0ea8bd457588f896e2e64519bb6e16fe Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Mon, 3 Feb 2025 12:50:12 +0900 Subject: [PATCH 07/11] =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=9E=98=EB=AA=BB?= =?UTF-8?q?=EC=98=AC=EB=A0=A4=EC=84=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 중간까진 풀이 있음 --- ...in_functions_and_regular_expressions.ipynb | 830 ++++++++++++++---- 1 file changed, 654 insertions(+), 176 deletions(-) diff --git a/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb b/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb index 800020e..f8e2e8c 100644 --- a/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb +++ b/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb @@ -11,7 +11,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 1. abs 함수 사용하기\n", + "### 1. 절대값 함수 사용하기\n", "```python\n", "# 입력: -5\n", "# 출력: 5\n", @@ -20,10 +20,23 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "5" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "abs(-5) ##" + ] }, { "cell_type": "markdown", @@ -33,15 +46,34 @@ "```python\n", "numbers = [True, True, False]\n", "# 출력: False\n", - "```" + "```\n", + "all은 받은 값들이 모두 참 일때만 True 0또는 false가 하나라도 끼여있으면 false" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "False\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "numbers = [True, True, False] \n", + "print(all(numbers))\n", + "## test\n", + "numbers1 = [1,2,3,4,5,6,7,8,'test',1<2,2+3==5]\n", + "print(all(numbers1))\n", + "numbers2 = [0,1,2,3,4,5,6,7,8,'test',1<2,2+3==5]\n", + "print(all(numbers2))" + ] }, { "cell_type": "markdown", @@ -56,10 +88,34 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 84, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n", + "True\n", + "False\n", + "True\n" + ] + } + ], + "source": [ + "numbers = [0, 0, 1]\n", + "print(any(numbers))\n", + "## test\n", + "numbers1 = [0,False, 1>2,10==9]\n", + "print(any(numbers1))\n", + "numbers2 = [0,False, True]\n", + "print(any(numbers2))\n", + "numbers3 = [0,False, None]\n", + "print(any(numbers3))\n", + "numbers4 = [0,False, \"sadasd\"]\n", + "print(any(numbers4))" + ] }, { "cell_type": "markdown", @@ -74,10 +130,24 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(0, 'a'), (1, 'b'), (2, 'c')]\n" + ] + } + ], + "source": [ + "words = [\"a\",\"b\",\"c\"] ##\n", + "answer = []\n", + "for index,word in enumerate(words):\n", + " answer.append((index,word))\n", + "print(answer)" + ] }, { "cell_type": "markdown", @@ -92,10 +162,22 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 86, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[2, 4]\n" + ] + } + ], + "source": [ + "numbers = [1,2,3,4,5]\n", + "even_numbers = list(filter(lambda x : x%2==0,numbers))\n", + "print(even_numbers)" + ] }, { "cell_type": "markdown", @@ -110,10 +192,21 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 87, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3]\n", + "print(len(numbers))" + ] }, { "cell_type": "markdown", @@ -128,10 +221,21 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 88, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "30\n" + ] + } + ], + "source": [ + "numbers = [10,20,30]\n", + "print(max(numbers))" + ] }, { "cell_type": "markdown", @@ -146,10 +250,21 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 89, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10\n" + ] + } + ], + "source": [ + "numbers = [10,20,30]\n", + "print(min(numbers))" + ] }, { "cell_type": "markdown", @@ -164,16 +279,28 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 4, 9]\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3]\n", + "square_numbers = list(map(lambda x: x**2,numbers))\n", + "print(square_numbers)" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 10. pow 함수로 제곱 계산\n", + "### 10. pow 함수로 제곱 계산 ##\n", "```python\n", "# 입력: 2, 3\n", "# 출력: 8\n", @@ -182,10 +309,22 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 4, 9]\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3] ##\n", + "square_numbers = list(map(lambda x: pow(x,2),numbers))\n", + "print(square_numbers)" + ] }, { "cell_type": "markdown", @@ -193,17 +332,45 @@ "source": [ "### 11. range 함수로 숫자 생성\n", "```python\n", - "# 입력: range(5)\n", + "# 입력: range(5) revarse\n", "# 출력: [0, 1, 2, 3, 4]\n", - "```\n" + "```\n", + "\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[0, 1, 2, 3, 4]\n", + "range(0, 5)\n", + "range(0, 5)\n", + "range(0, 5)\n", + "range(0, 5, 2)\n", + "[2, 4, 8, 16, 32, 64, 128, 256]\n" + ] + } + ], + "source": [ + "print(list(range(5)))\n", + "print(range(5))\n", + "print(range(0,5))\n", + "print(range(0,5,1))\n", + "print(range(0,5,2))\n", + "#아래 같이 표현하고 숫자들을 만들어도 됨.\n", + "a,r,n = 1,2,10\n", + "nums = []\n", + "num = a\n", + "for _ in range(1,n-1):\n", + " num=num*r\n", + " nums.append(num)\n", + "print(nums)" + ] }, { "cell_type": "markdown", @@ -218,28 +385,76 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 93, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[3, 2, 1]\n", + "['hello', 3, 2, True, 1]\n", + "('hello', 3, 2, True, 1)\n", + "[(4, 'World'), (2, False), (True, 2), ('hello', 1)]\n" + ] + } + ], + "source": [ + "numbers = [1, 2, 3]\n", + "print(list(reversed(numbers)))\n", + "numbers = [1,True, 2, 3,\"hello\"]\n", + "print(list(reversed(numbers)))\n", + "numbers = (1,True, 2, 3,\"hello\")\n", + "print(tuple(reversed(numbers)))\n", + "numbers = {\"hello\":1, True:2, 2:False,4:\"World\"}\n", + "print(list(reversed(numbers.items())))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 13. round 함수로 소수점 반올림\n", + "### 13. round 함수로 소수점 반올림##\n", "```python\n", "# 입력: 3.14159, 2\n", "# 출력: 3.14\n", - "```" + "```\n", + "반올림은 round() 함수, 올림은 ceil() 함수, 내림은 floor() \n", + "올림과 내림은 math 모듈듈에 내장되어 있음" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 94, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.14\n", + "1240125129600000.0\n", + "4\n", + "1240125129593469\n", + "3\n", + "1240125129593468\n" + ] + } + ], + "source": [ + "from math import ceil ##\n", + "from math import floor\n", + "\n", + "Circumference = 3.141596\n", + "\n", + "number = 1240125129593468.7675656\n", + "print(round(Circumference,2))\n", + "print(round(number,-5))\n", + "print(ceil(Circumference))\n", + "print(ceil(number))\n", + "print(floor(Circumference))\n", + "print(floor(number))\n" + ] }, { "cell_type": "markdown", @@ -254,10 +469,23 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 95, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[3, 2, 1]\n", + "[1, 2, 3]\n" + ] + } + ], + "source": [ + "numbers = [3, 1, 2]\n", + "print(sorted(numbers,reverse=True))\n", + "print(sorted(numbers))" + ] }, { "cell_type": "markdown", @@ -272,10 +500,21 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 96, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6\n" + ] + } + ], + "source": [ + "numbers = [1,2,3]\n", + "print(sum(numbers))" + ] }, { "cell_type": "markdown", @@ -290,16 +529,62 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 97, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "value = 42\n", + "print(type(value))\n", + "value = True\n", + "print(type(value))\n", + "value = []\n", + "print(type(value))\n", + "value = {}\n", + "print(type(value))\n", + "value = ()\n", + "print(type(value))\n", + "value = 124.124\n", + "print(type(value))\n", + "value = \"sdfadf\"\n", + "print(type(value))\n", + "value = \"s\"\n", + "print(type(value))\n", + "value = 's'\n", + "print(type(value))\n", + "value = 's14515'\n", + "print(type(value))\n", + "value = map(lambda x: x,[1,2,3])\n", + "print(type(value))\n", + "value = filter(lambda x: x%2==0,[1,2,3,4,5])\n", + "print(type(value))\n", + "print(type(type(value)))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 17. zip 함수로 리스트 병합\n", + "### 17. zip 함수로 리스트 병합 \n", "```python\n", "list1 = [1, 2, 3]\n", "list2 = [\"a\", \"b\", \"c\"]\n", @@ -309,10 +594,32 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 145, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n", + "(1, 2, 3) ('a', 'b', 'c') (True, False, None) (('A', 12), ('B', 23), ('c', 25))\n", + "{1: 'e', 2: 'b', 3: 'c'}\n" + ] + } + ], + "source": [ + "list1 = [1, 2, 3]\n", + "list2 = [\"a\", \"b\", \"c\"]\n", + "tuple1 = (True,False,None)\n", + "dict1 = {'A':12,'B':23,'c':25}\n", + "zip1 = zip(list1,list2,tuple1,dict1.items())\n", + "l1,l2,t1,d1 = zip(*zip1)\n", + "print(list(zip1))\n", + "print(l1,l2,t1,d1)\n", + "list1 = [1,1,1, 2, 3]\n", + "list2 = [\"a\",\"d\",\"e\", \"b\", \"c\"]\n", + "print(dict(zip(list1,list2)))" + ] }, { "cell_type": "markdown", @@ -327,10 +634,30 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 146, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "14\n", + "5\n", + "14\n", + "35\n" + ] + } + ], + "source": [ + "expression = \"2 + 3 * 4\" ##\n", + "print(eval(expression))\n", + "x = lambda x : pow(x,3)\n", + "y = lambda y : y*2\n", + "values = {1:2,2:3,3:4}\n", + "for a,b in values.items():\n", + " expression = f\"{x(a)}+{y(b)}\"\n", + " print(eval(expression))" + ] }, { "cell_type": "markdown", @@ -345,10 +672,33 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 147, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a\n", + "a\n", + "b\n", + "c\n", + "d\n", + "e\n", + "f\n", + "g\n", + "h\n", + "i\n", + "j\n" + ] + } + ], + "source": [ + "print(chr(97))\n", + "for i in range(10):\n", + " a = chr(97+i)\n", + " print(a)" + ] }, { "cell_type": "markdown", @@ -363,10 +713,20 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 148, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "97\n" + ] + } + ], + "source": [ + "print(ord('a'))" + ] }, { "cell_type": "markdown", @@ -388,127 +748,228 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 155, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['info@example.com', 'support@domain.org']\n", + "['info@example.com', 'support@domain.org']\n" + ] + } + ], + "source": [ + "import re ##\n", + "text = \"Contact us at info@example.com or support@domain.org\"\n", + "email_pattern = r\"\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b\"\n", + "email_pattern2 = r\"\\b\\w+@\\w+\\.\\w{2,}\\b\"\n", + "email_match = re.findall(email_pattern,text)\n", + "email_match2 = re.findall(email_pattern2,text)\n", + "print(email_match)\n", + "print(email_match2)\n" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 2. all 함수로 리스트 검사하기\n", + "### 2. 특정 패턴으로 시작하는 단어 추출\n", "```python\n", - "numbers = [True, True, False]\n", - "# 출력: False\n", + "text = \"apple banana cherry date\"\n", + "pattern = r\"^a\"\n", + "# 출력: ['apple']\n", "```" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 162, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "apple\n" + ] + } + ], + "source": [ + "text = \"apple banana cherry date\"\n", + "pattern = r\"^a\\w+\\b\"\n", + "print(re.search(pattern,text).group())" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 3. any 함수로 값 존재 여부 확인\n", + "### 3. 전화번호 형식 검사\n", "```python\n", - "numbers = [0, 0, 1]\n", - "# 출력: True\n", + "phone = \"123-456-7890\"\n", + "# 출력: True (형식이 올바른 경우)\n", "```" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 172, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "phone = \"123-456-7890\" ##\n", + "phone_number_pattern = r\"\\d{2,3}-\\d{3,4}-\\d{4}\"\n", + "if re.search(phone_number_pattern,phone):\n", + " print(True)\n", + "else:\n", + " print(False)" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 4. enumerate 함수로 인덱스와 값 출력\n", + "### 4. 문자열에서 숫자만 추출\n", "```python\n", - "words = [\"a\", \"b\", \"c\"]\n", - "# 출력: [(0, \"a\"), (1, \"b\"), (2, \"c\")]\n", + "text = \"Order 123 items for $45.67\"\n", + "# 출력: ['123', '45', '67']\n", "```" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 175, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['123', '45', '67']\n" + ] + } + ], + "source": [ + "text = \"Order 123 items for $45.67\"\n", + "number_pattern = r\"\\d+\\d\"\n", + "print(re.findall(number_pattern,text))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 5. filter 함수로 짝수 필터링\n", + "### 5. 공백으로 구분된 단어의 개수 세기\n", "```python\n", - "numbers = [1, 2, 3, 4, 5]\n", - "# 출력: [2, 4]\n", - "```" + "text = \"This is a test sentence.\"\n", + "# 출력: 5\n", + "```\n" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 181, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n", + "5\n" + ] + } + ], + "source": [ + "text = \"This is a test sentence.\" ##\n", + "print(len(text.split(\" \")))\n", + "word_pattern = r\"\\b\\w+\\b\"\n", + "print(len(re.findall(word_pattern,text)))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 6. len 함수로 리스트 길이 확인\n", + "### 6. HTML 태그 제거하기\n", "```python\n", - "numbers = [1, 2, 3]\n", - "# 출력: 3\n", + "html = \"

This is a paragraph.

\"\n", + "# 출력: 'This is a paragraph.'\n", "```" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 188, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is a paragraph.\n" + ] + } + ], + "source": [ + "html = \"

This is a paragraph.

\"\n", + "html_pattern = r\"<+[a-zA-Z/]+>\"\n", + "print(re.sub(html_pattern,\"\",html))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 7. max 함수로 최대값 찾기\n", + "### 7. 특정 단어 포함 여부 확인\n", "```python\n", - "numbers = [10, 20, 30]\n", - "# 출력: 30\n", + "text = \"Python is fun\"\n", + "word = \"fun\"\n", + "# 출력: True\n", "```" ] }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] + "execution_count": 195, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "text = \"Python is fun\"\n", + "word = \"fun\"\n", + "isword = re.search(word,text)\n", + "if isword:\n", + " print(True)\n", + "else:\n", + " print(False)" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "### 8. min 함수로 최소값 찾기\n", + "### 8. 날짜 형식 변환\n", "```python\n", - "numbers = [10, 20, 30]\n", - "# 출력: 10\n", + "date = \"2025-01-27\"\n", + "# 출력: '27-01-2025'\n", "```" ] }, @@ -523,10 +984,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 9. map 함수로 리스트 요소 제곱\n", + "### 9. 소문자와 대문자 교체\n", "```python\n", - "numbers = [1, 2, 3]\n", - "# 출력: [1, 4, 9]\n", + "text = \"Hello World\"\n", + "# 출력: 'hELLO wORLD'\n", "```" ] }, @@ -541,10 +1002,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 10. pow 함수로 제곱 계산\n", + "### 10. IP 주소 형식 검사\n", "```python\n", - "# 입력: 2, 3\n", - "# 출력: 8\n", + "ip = \"192.168.1.1\"\n", + "# 출력: True (형식이 올바른 경우)\n", "```" ] }, @@ -559,10 +1020,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 11. range 함수로 숫자 생성\n", + "### 11. 문자열에서 모든 URL 추출\n", "```python\n", - "# 입력: range(5)\n", - "# 출력: [0, 1, 2, 3, 4]\n", + "text = \"Visit https://example.com or http://test.org for info.\"\n", + "# 출력: ['https://example.com', 'http://test.org']\n", "```" ] }, @@ -577,10 +1038,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 12. reversed 함수로 리스트 뒤집기\n", + "### 12. 특정 패턴의 단어 치환\n", "```python\n", - "numbers = [1, 2, 3]\n", - "# 출력: [3, 2, 1]\n", + "text = \"I love cats and dogs\"\n", + "pattern = r\"cats\"\n", + "replacement = \"pets\"\n", + "# 출력: 'I love pets and dogs'\n", "```" ] }, @@ -595,10 +1058,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 13. round 함수로 소수점 반올림\n", + "### 13. 문자열에서 연속된 공백 제거\n", "```python\n", - "# 입력: 3.14159, 2\n", - "# 출력: 3.14\n", + "text = \"This is a test.\"\n", + "# 출력: 'This is a test.'\n", "```" ] }, @@ -613,10 +1076,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 14. sorted 함수로 정렬하기\n", + "### 14. 특정 문자열이 파일 경로인지 검사\n", "```python\n", - "numbers = [3, 1, 2]\n", - "# 출력: [1, 2, 3]\n", + "path = \"/user/home/test.txt\"\n", + "# 출력: True (파일 경로가 올바른 경우)\n", "```" ] }, @@ -631,10 +1094,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 15. sum 함수로 리스트 합 계산\n", + "### 15. 영어 단어만 추출하기\n", "```python\n", - "numbers = [1, 2, 3]\n", - "# 출력: 6\n", + "text = \"123abc!@#def456\"\n", + "# 출력: ['abc', 'def']\n", "```" ] }, @@ -649,10 +1112,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 16. type 함수로 데이터 타입 확인\n", + "### 16. 특정 접미사로 끝나는 단어 찾기\n", "```python\n", - "value = 42\n", - "# 출력: \n", + "text = \"running swimming jumping\"\n", + "pattern = r\"ing\"\n", + "# 출력: ['running', 'swimming', 'jumping']\n", "```" ] }, @@ -667,11 +1131,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 17. zip 함수로 리스트 병합\n", + "### 17. 문자열에서 중복된 단어 제거\n", "```python\n", - "list1 = [1, 2, 3]\n", - "list2 = [\"a\", \"b\", \"c\"]\n", - "# 출력: [(1, \"a\"), (2, \"b\"), (3, \"c\")]\n", + "text = \"this this is is a test test\"\n", + "# 출력: 'this is a test'\n", "```" ] }, @@ -686,10 +1149,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 18. eval 함수로 문자열 표현식 계산\n", + "### 18. 문자열에서 특수 문자 제거\n", "```python\n", - "expression = \"2 + 3 * 4\"\n", - "# 출력: 14\n", + "text = \"Hello!@#$%^&*()\"\n", + "# 출력: 'Hello'\n", "```" ] }, @@ -704,10 +1167,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 19. chr 함수로 아스키 코드 문자 반환\n", + "### 19. 특정 길이의 단어만 추출\n", "```python\n", - "# 입력: 97\n", - "# 출력: 'a'\n", + "text = \"cat bat mat\"\n", + "length = 3\n", + "# 출력: ['cat', 'bat', 'mat']\n", "```" ] }, @@ -722,10 +1186,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 20. ord 함수로 문자 아스키 코드 반환\n", + "### 20. 파일 확장자 추출\n", "```python\n", - "# 입력: 'a'\n", - "# 출력: 97\n", + "filename = \"document.pdf\"\n", + "# 출력: 'pdf'\n", "```" ] }, @@ -738,8 +1202,22 @@ } ], "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, "language_info": { - "name": "python" + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.8" } }, "nbformat": 4, From fbc9746f28b382ce8a9b908ad374ba9bd0dc1b49 Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Mon, 10 Feb 2025 12:09:01 +0900 Subject: [PATCH 08/11] =?UTF-8?q?4=EC=A3=BC=EC=B0=A8=20=EB=8B=A4=EB=A5=B8?= =?UTF-8?q?=EB=B6=84=EB=93=A4=20=ED=92=80=EC=9D=B4=20=EB=B0=8F=205?= =?UTF-8?q?=EC=A3=BC=EC=B0=A8=20=EB=AC=B8=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 5주차 문제 추가 --- 03151_minsuje/hw/week2(p)/king/chess_board.py | 2 +- .../week2(p)/study_2week_kimQ/src/account.txt | 1 - .../study_week2_Q_ji/study_week2_A_jeminsu.py | 4 +- .../study_week3_A_seok/study_week3_A_seok.py | 26 ++ ...in_functions_and_regular_expressions.ipynb | 316 +++++++++++++----- .../study_kim_4week_Q/study_kim_4week_A.py | 42 +++ .../study_kim_4week_Q/study_kim_4week_Q.md | 15 + .../study_week4_Q_jwlee/study_week4_A.py | 10 + .../study_week4_Q_jwlee.md | 17 + .../study_week4_Q_seok/study_week4_A._seok.py | 95 ++++++ .../study_week4_Q_seok/study_week4_Q_seok.py | 89 +++++ .../week4(p)/study_week4_ji_Q/study_369_A..py | 26 ++ .../study_chage_number_star.py | 17 + .../study_week4_ji_Q/study_week4_ji_Q.md | 38 +++ .../__pycache__/logistics.cpython-312.pyc | Bin 0 -> 2816 bytes .../__pycache__/turtle_gui.cpython-312.pyc | Bin 0 -> 3259 bytes 03151_minsuje/hw/week5_p/logistics.py | 43 +++ 03151_minsuje/hw/week5_p/python_A.py | 27 ++ 03151_minsuje/hw/week5_p/python_Q.md | 47 +++ 03151_minsuje/hw/week5_p/turtle_gui.py | 53 +++ 20 files changed, 789 insertions(+), 79 deletions(-) create mode 100644 03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_A.py create mode 100644 03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_Q.md create mode 100644 03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_A.py create mode 100644 03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_Q_jwlee.md create mode 100644 03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_A._seok.py create mode 100644 03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_Q_seok.py create mode 100644 03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_369_A..py create mode 100644 03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_chage_number_star.py create mode 100644 03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_week4_ji_Q.md create mode 100644 03151_minsuje/hw/week5_p/__pycache__/logistics.cpython-312.pyc create mode 100644 03151_minsuje/hw/week5_p/__pycache__/turtle_gui.cpython-312.pyc create mode 100644 03151_minsuje/hw/week5_p/logistics.py create mode 100644 03151_minsuje/hw/week5_p/python_A.py create mode 100644 03151_minsuje/hw/week5_p/python_Q.md create mode 100644 03151_minsuje/hw/week5_p/turtle_gui.py diff --git a/03151_minsuje/hw/week2(p)/king/chess_board.py b/03151_minsuje/hw/week2(p)/king/chess_board.py index 301e329..4a26df7 100644 --- a/03151_minsuje/hw/week2(p)/king/chess_board.py +++ b/03151_minsuje/hw/week2(p)/king/chess_board.py @@ -24,7 +24,7 @@ def __init__(self, king_pos, stone_pos, commands): self.commands = commands # 초기화 후 내부에서 바로 결과 내는게 더 맞다고 생각들어서함. self.move() - + def pos_to_index(self, pos): ''' 문자열 위치를 좌표 평면으로 변환 diff --git a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/account.txt b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/account.txt index 18749af..b45b1fd 100644 --- a/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/account.txt +++ b/03151_minsuje/hw/week2(p)/study_2week_kimQ/src/account.txt @@ -4,4 +4,3 @@ DR03122Ji,yeyeye03122,1 DR03142seok,seeok03142,0 DR03119kim,kim03119,0 03135jwLee,lee03135,0 -dirkfhem,dist0486,3 diff --git a/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py b/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py index 27c6054..74abdb2 100644 --- a/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py +++ b/03151_minsuje/hw/week2(p)/study_week2_Q_ji/study_week2_A_jeminsu.py @@ -2,5 +2,5 @@ def solution(s): if(len(s)==4 or len(s)==6): answer = s.isdigit() else: - answer = False - return answer \ No newline at end of file + answer = False + return answer diff --git a/03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py b/03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py index e69de29..9f879ef 100644 --- a/03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py +++ b/03151_minsuje/hw/week3(p)/study_week3_A_seok/study_week3_A_seok.py @@ -0,0 +1,26 @@ +def solution(bridge_length, weight, truck_weights): + answer = 0 # 경과 시간 + total_weight = 0 # 현재 다리 위 트럭 무게의 합 + bridge = [] + for _ in range(bridge_length): + bridge.append(0) # 다리 길이만큼 0으로 채워진 큐 + + while bridge: # 다리가 빌 동안 반복 + answer += 1 # 경과 시간을 1초씩 증가가 + exited_truck = bridge.pop(0) # 다리에서 빠져나간 트럭 + total_weight -= exited_truck # 빠져나간 트럭의 무게를 현재 무게에서 뺀다. + if truck_weights: # 만약 대기 트럭이 있고, + if total_weight + truck_weights[0] <= weight: # 트럭의 무게를 견딜 수 있다면, + new_truck = truck_weights.pop(0) + bridge.append(new_truck) # 새 트럭이 다리에 오르고, + total_weight += new_truck # 현재 무게에 올라라온 트럭의 무게를 더한다. + else: + bridge.append(0) # 트럭이 못 올라오면 빈 공간을 유지한다. + return answer + + +bridge_length = int(input("bridge_length: ")) +weight = int(input("weight: ")) +truck_weights = list(map(int, input("truck_weights: ").split())) +answer = solution(bridge_length, weight, truck_weights) +print(f"{answer}초 소요") \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb b/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb index f8e2e8c..bec4f1d 100644 --- a/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb +++ b/03151_minsuje/hw/week4(p)/python_Q_min/built_in_functions_and_regular_expressions.ipynb @@ -20,7 +20,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 287, "metadata": {}, "outputs": [ { @@ -29,7 +29,7 @@ "5" ] }, - "execution_count": 1, + "execution_count": 287, "metadata": {}, "output_type": "execute_result" } @@ -52,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 288, "metadata": {}, "outputs": [ { @@ -88,7 +88,7 @@ }, { "cell_type": "code", - "execution_count": 84, + "execution_count": 289, "metadata": {}, "outputs": [ { @@ -130,7 +130,7 @@ }, { "cell_type": "code", - "execution_count": 85, + "execution_count": 290, "metadata": {}, "outputs": [ { @@ -162,7 +162,7 @@ }, { "cell_type": "code", - "execution_count": 86, + "execution_count": 291, "metadata": {}, "outputs": [ { @@ -192,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 87, + "execution_count": 292, "metadata": {}, "outputs": [ { @@ -221,7 +221,7 @@ }, { "cell_type": "code", - "execution_count": 88, + "execution_count": 293, "metadata": {}, "outputs": [ { @@ -250,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 89, + "execution_count": 294, "metadata": {}, "outputs": [ { @@ -279,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 90, + "execution_count": 295, "metadata": {}, "outputs": [ { @@ -309,7 +309,7 @@ }, { "cell_type": "code", - "execution_count": 91, + "execution_count": 296, "metadata": {}, "outputs": [ { @@ -340,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 92, + "execution_count": 297, "metadata": {}, "outputs": [ { @@ -385,7 +385,7 @@ }, { "cell_type": "code", - "execution_count": 93, + "execution_count": 298, "metadata": {}, "outputs": [ { @@ -425,7 +425,7 @@ }, { "cell_type": "code", - "execution_count": 94, + "execution_count": 299, "metadata": {}, "outputs": [ { @@ -469,7 +469,7 @@ }, { "cell_type": "code", - "execution_count": 95, + "execution_count": 300, "metadata": {}, "outputs": [ { @@ -500,7 +500,7 @@ }, { "cell_type": "code", - "execution_count": 96, + "execution_count": 301, "metadata": {}, "outputs": [ { @@ -529,7 +529,7 @@ }, { "cell_type": "code", - "execution_count": 97, + "execution_count": 302, "metadata": {}, "outputs": [ { @@ -594,7 +594,7 @@ }, { "cell_type": "code", - "execution_count": 145, + "execution_count": 703, "metadata": {}, "outputs": [ { @@ -602,7 +602,7 @@ "output_type": "stream", "text": [ "[]\n", - "(1, 2, 3) ('a', 'b', 'c') (True, False, None) (('A', 12), ('B', 23), ('c', 25))\n", + "(1, 2, 3) ('a', 'b', 'c') (True, False, None) {'A': 12, 'B': 23, 'c': 25}\n", "{1: 'e', 2: 'b', 3: 'c'}\n" ] } @@ -615,7 +615,7 @@ "zip1 = zip(list1,list2,tuple1,dict1.items())\n", "l1,l2,t1,d1 = zip(*zip1)\n", "print(list(zip1))\n", - "print(l1,l2,t1,d1)\n", + "print(l1,l2,t1,dict(d1))\n", "list1 = [1,1,1, 2, 3]\n", "list2 = [\"a\",\"d\",\"e\", \"b\", \"c\"]\n", "print(dict(zip(list1,list2)))" @@ -634,7 +634,7 @@ }, { "cell_type": "code", - "execution_count": 146, + "execution_count": 704, "metadata": {}, "outputs": [ { @@ -672,7 +672,7 @@ }, { "cell_type": "code", - "execution_count": 147, + "execution_count": 705, "metadata": {}, "outputs": [ { @@ -713,7 +713,7 @@ }, { "cell_type": "code", - "execution_count": 148, + "execution_count": 706, "metadata": {}, "outputs": [ { @@ -748,7 +748,7 @@ }, { "cell_type": "code", - "execution_count": 155, + "execution_count": 707, "metadata": {}, "outputs": [ { @@ -785,7 +785,7 @@ }, { "cell_type": "code", - "execution_count": 162, + "execution_count": 708, "metadata": {}, "outputs": [ { @@ -815,7 +815,7 @@ }, { "cell_type": "code", - "execution_count": 172, + "execution_count": 709, "metadata": {}, "outputs": [ { @@ -848,7 +848,7 @@ }, { "cell_type": "code", - "execution_count": 175, + "execution_count": 710, "metadata": {}, "outputs": [ { @@ -878,7 +878,7 @@ }, { "cell_type": "code", - "execution_count": 181, + "execution_count": 711, "metadata": {}, "outputs": [ { @@ -910,7 +910,7 @@ }, { "cell_type": "code", - "execution_count": 188, + "execution_count": 712, "metadata": {}, "outputs": [ { @@ -941,7 +941,7 @@ }, { "cell_type": "code", - "execution_count": 195, + "execution_count": 713, "metadata": {}, "outputs": [ { @@ -975,10 +975,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 714, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "27-01-2025\n" + ] + } + ], + "source": [ + "\n", + "date = \"2025-01-27\"\n", + "reverse_date = re.sub(r\"([1-9]\\d{3})-([0-1]?[0-9])-([0-3]?[0-9])\",r\"\\3-\\2-\\1\",date)\n", + "print(reverse_date)" + ] }, { "cell_type": "markdown", @@ -986,17 +999,29 @@ "source": [ "### 9. 소문자와 대문자 교체\n", "```python\n", - "text = \"Hello World\"\n", + "text = \"Hello World!\"\n", "# 출력: 'hELLO wORLD'\n", "```" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 715, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "hELLO wORLD\n" + ] + } + ], + "source": [ + "text = \"Hello World\"\n", + "upper_lower_chaage_text = re.sub(r\"\\w\",lambda x : x.group().upper() if x.group().islower() else x.group().lower(),text)\n", + "print(upper_lower_chaage_text)" + ] }, { "cell_type": "markdown", @@ -1011,10 +1036,26 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 903, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "ip = \"192.168.1.1\" ##\n", + "ip_pattern = r'^((25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])\\.){3}(25[0-5]|2[0-4][0-9]|1?[0-9]?[0-9])$'\n", + " #0~255 +. 3번 반복후 .없는 0~255 시작과 끝 확인인\n", + "if re.search(ip_pattern,ip):\n", + " print (True)\n", + "else :\n", + " print (False)" + ] }, { "cell_type": "markdown", @@ -1029,10 +1070,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 904, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['https://example.com', 'http://test.org']\n" + ] + } + ], + "source": [ + "text = \"Visit https://example.com or http://test.org for info.\"\n", + "URL_pattern = r\"http+\\w*://\\w+\\w.\\w{2,3}\"\n", + "print(re.findall(URL_pattern,text))" + ] }, { "cell_type": "markdown", @@ -1049,10 +1102,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 905, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I love pets and dogs\n" + ] + } + ], + "source": [ + "\n", + "text = \"I love cats and dogs\"\n", + "pattern = r\"cats\"\n", + "replacement = \"pets\"\n", + "print(re.sub(pattern,replacement,text))" + ] }, { "cell_type": "markdown", @@ -1067,10 +1134,23 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 906, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "This is a test.\n" + ] + } + ], + "source": [ + "text = \"This is a test.\"\n", + "pattern = r\" + \"\n", + "replacement = r\" \"\n", + "print(re.sub(pattern,replacement,text))" + ] }, { "cell_type": "markdown", @@ -1085,10 +1165,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 907, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "path = \"/user/home/test.txt\" #####\n", + "if re.search(r'\\/([a-zA-Z0-9_.]+\\.[a-zA-Z0-9]+)$',path):\n", + " print(True)\n", + "else:\n", + " print(False)" + ] }, { "cell_type": "markdown", @@ -1103,10 +1197,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 908, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['abc', 'def']\n" + ] + } + ], + "source": [ + "text = \"123abc!@#def456\"\n", + "pattern = r\"[a-zA-Z]+[a-zA-Z]\"\n", + "print(re.findall(pattern,text))" + ] }, { "cell_type": "markdown", @@ -1122,10 +1228,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 909, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['running', 'swimming', 'jumping']\n" + ] + } + ], + "source": [ + "text = \"running swimming jumping\"\n", + "pattern = r\"\\w+ing\\b\"\n", + "print(re.findall(pattern,text))" + ] }, { "cell_type": "markdown", @@ -1140,10 +1258,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 910, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "this is a test\n" + ] + } + ], + "source": [ + "text = \"this this is is a test test\" ## 괄호 하면 \\1\\2등으로 부를수있음음\n", + "print(re.sub(r\"\\b(\\w+)\\s+\\1\\b\",r\"\\1\",text))" + ] }, { "cell_type": "markdown", @@ -1151,17 +1280,29 @@ "source": [ "### 18. 문자열에서 특수 문자 제거\n", "```python\n", - "text = \"Hello!@#$%^&*()\"\n", - "# 출력: 'Hello'\n", + "text = \"Hello!@#$%^&*()fdfd\"\n", + "# 출력: 'Hellofdfd'\n", "```" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 911, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hello\n" + ] + } + ], + "source": [ + "text = \"Hello!@#$%^&*()\"\n", + "pattern = r\"[^a-zA-Z]+[^a-zA-Z]\"\n", + "print(re.sub(pattern,'',text))" + ] }, { "cell_type": "markdown", @@ -1177,28 +1318,53 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 914, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['cat', 'bat', 'mat']\n", + "['cat', 'bat', 'mat']\n", + "['cat', 'bat', 'mat']\n" + ] + } + ], + "source": [ + "text = \"cat bat mat\"\n", + "print(list(filter(lambda x : len(x)==3,text.split(\" \"))))\n", + "print(re.findall(r\"\\b[a-zA-Z][a-zA-Z][a-zA-Z]\\b\",text))\n", + "print(re.findall(r\"\\b[a-zA-Z]{3}\\b\",text))" + ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 20. 파일 확장자 추출\n", - "```python\n", + "python\n", "filename = \"document.pdf\"\n", - "# 출력: 'pdf'\n", - "```" + "# 출력: 'pdf'" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 915, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pdf\n" + ] + } + ], + "source": [ + "filename = \"docume.nt.pdf\" ##\n", + "print(re.search(r'\\.([a-zA-Z0-9]+)$',filename).group(1))" + ] } ], "metadata": { diff --git a/03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_A.py b/03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_A.py new file mode 100644 index 0000000..df64e3b --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_A.py @@ -0,0 +1,42 @@ +def solution(N): + pow = 1 + while pow * 2 <= N: + pow *= 2 + if pow == N: + return pow + return (N - pow) * 2 #N%pow = (N-pow) *2 마지막 숫자자 +# N = int(input()) +# print(solution(N)) +print(solution(2)) +print(solution(4)) +print(solution(6)) +print(solution(8)) +print(solution(10)) +print(solution(12)) +print(solution(14)) +print(solution(500000)) +#스텍으로 처리해도 되겠다 싶었지만 2의 배수가 너무 눈에뜀 +#아래에 서술 하겠음 + +#1~n까지 과정을 하다보면 홀수가 다 제거됨 +#단 n이 홀수 이면 n,2,4,6,8,10....이런식으로감 + +# 2,4,6,8,10,12,14,16을 일일이 구하기도 했음 규칙 찾으려고 +#위에 짝수를 한건 홀수랑 짝수랑 애매 해서 일딴 짝수 아무거나 한거거 + +#일딴 2**x이랑 마지막 남는게 관련 있겠다 싶음 (2**x는 편의상 쓴거고 n보다 작은 2의 x승) +#그래서 냅따 2**x이 나오는거 아닌가 답 넣었으나 오답 +#-> 이건 2,4,4,8 이렇게 나와서 했던건데 더해보니 4,8,12,16 이런식으로 나와서 아니구나 했음 + + +#여기서 냅다 n-2**x를 해보았음 딱 정답의 절반이었음 물론 2 4 8 16 같은 애들은 적용 안되니 따로 if문으로 빼야겠네? 싶었음 + +#이제 홀수도 확인해봐야 했음 위에 짝수에서 나온 결과를 한번 같이 해봄 (n-2**x)*2 직접 세서 했음 그러니 맞는걸 확인하고 +#바로 위에 식을 세움 + +#스텍으로 처리하면 쉬우나 단점이 스택은 결국 위에 식에 비해 과정을 많이해야함. +# 수가 작으면 스텍이 조금더 유리 할 수 있겠으나 수가 커지면 커질수록 스텍은 모든 과정을 반복해야 겠지만 +# 위의 식은 수가 커질수록 유리함 과정을 생략해버리니까 스텍으로 작성도 했지만 둘중엔 위에가 더 좋은 식이다 생각해서 이거만 남겨둠 +# -끝- + +# ps.수학좋아하는데 읽어보면서 수학 냄새가 나서 너무 좋았습니다 오랫만에 재밌는 문제를 푼거 같아요. 감사합니다. \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_Q.md b/03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_Q.md new file mode 100644 index 0000000..468c224 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_kim_4week_Q/study_kim_4week_Q.md @@ -0,0 +1,15 @@ +# N장의 카드가 있다. 각각의 카드는 차례로 1부터 N까지의 번호가 붙어 있으며, 1번 카드가 제일 위에, N번 카드가 제일 아래인 상태로 순서대로 카드가 놓여 있다. + +# 이제 다음과 같은 동작을 카드가 한 장 남을 때까지 반복하게 된다. 우선, 제일 위에 있는 카드를 바닥에 버린다. 그 다음, 제일 위에 있는 카드를 제일 아래에 있는 카드 밑으로 옮긴다. + +# 예를 들어 N=4인 경우를 생각해 보자. 카드는 제일 위에서부터 1234 의 순서로 놓여있다. 1을 버리면 234가 남는다. 여기서 2를 제일 아래로 옮기면 342가 된다. 3을 버리면 42가 되고, 4를 밑으로 옮기면 24가 된다. 마지막으로 2를 버리고 나면, 남는 카드는 4가 된다. + +# N이 주어졌을 때, 제일 마지막에 남게 되는 카드를 구하는 프로그램을 작성하시오. + +# 입력 +# 첫째 줄에 정수 N(1 ≤ N ≤ 500,000)이 주어진다. + +# 출력 +# 첫째 줄에 남게 되는 카드의 번호를 출력한다. + +# https://www.acmicpc.net/problem/2164 \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_A.py b/03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_A.py new file mode 100644 index 0000000..8074318 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_A.py @@ -0,0 +1,10 @@ +def solution(arry): + answer = [arry[0]] + for index in range(1,len(arry),1): + if arry[index]!=arry[index-1]: + answer.append(arry[index]) + return answer +arry = [1,1,3,3,0,1,1] +arry2 = [4,4,4,3,3] +print(solution(arry)) +print(solution(arry2)) \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_Q_jwlee.md b/03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_Q_jwlee.md new file mode 100644 index 0000000..3d01709 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_Q_jwlee/study_week4_Q_jwlee.md @@ -0,0 +1,17 @@ +# 배열 arr가 주어집니다. 배열 arr의 각 원소는 숫자 0부터 9까지로 이루어져 있습니다. +# 이때, 배열 arr에서 연속적으로 나타나는 숫자는 하나만 남기고 전부 제거하려고 합니다. +# 단, 제거된 후 남은 수들을 반환할 때는 배열 arr의 원소들의 순서를 유지해야 합니다. + +# 예를 들면, +# arr = [1, 1, 3, 3, 0, 1, 1] 이면 [1, 3, 0, 1] 을 return 합니다. +# arr = [4, 4, 4, 3, 3] 이면 [4, 3] 을 return 합니다. +# 배열 arr에서 연속적으로 나타나는 숫자는 제거하고 남은 수들을 return 하는 solution 함수를 완성해 주세요. + +# 제한사항 +# 배열 arr의 크기 : 1,000,000 이하의 자연수 +# 배열 arr의 원소의 크기 : 0보다 크거나 같고 9보다 작거나 같은 정수 + +# 입출력 예 +# arr answer +# [1,1,3,3,0,1,1] [1,3,0,1] +# [4,4,4,3,3] [4,3] \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_A._seok.py b/03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_A._seok.py new file mode 100644 index 0000000..fc39d89 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_A._seok.py @@ -0,0 +1,95 @@ +def solution(numbers,target): + if (sum(numbers)+target)%2==1: + return 0 + sum_target = int((sum(numbers)+target)/2) + # 1 1 1 1 1 + dp = {0: 1} + for num in numbers: + for sub_sum in range(sum_target, num - 1, -1): #4 1 + dp[sub_sum] = dp.get(sub_sum, 0) + dp.get(sub_sum - num, 0) + print(sub_sum,end =" : ") + print(dp[sub_sum]) + + print(dp) + return dp.get(sum_target, 0) + + +print(solution([1,1,1,1,1],3)) +print(solution([4, 1, 2, 1],4)) +# 2**len(numbers)의 경우의 수를 가진 합 +# 2의 2**20 이거만 해도 경우의 수가 너어어무 많아서 이건 아니다 싶음. + +# 수로 하다가 머리 빠질거 같아서 문자로함 +# a,b,c,d,e와 타겟이 있다고 치자 +# 그중에 a+b-c-d-e=target(numbers)+targ이 성립 한다면 뭔가의 양의값 = (전체값의 핪+ 타겟)/2 +# 2(a+b)=sumet이 성립된다. 이건 아예 안되는놈 빼는 경우로 써먹을수 있겠다. +# 왜냐하면 뭐가 됬든 첫 식이 성립 한다 쳤을때 (sum(numbers)+target)%2를 했을때 나머지가 1이면 애초에 성립되지 않는 식이된다. +# 좌측식이 a+b 든 a 든 뭐든 간에 위의 조건이 안맞으면 수학적으로 되지 않으므로 애초에 과정을 할 필요 없이 개수 0 이라고 해도 맞다. + +# 그럼 다시 보자 x = (sum(numbers)+target)/2는 조건에 성립하는 식이다. 그럼 이제 x에 들어가는 합을 찾으면 좀 더 쉽지 않을까...? +# 일딴 빼기의 경우가 다 사라졌다. 충분히 줄어 들었지만 여기서 하나더 생각 할 수 있다 +# 이제 일반적인 경우의 수에서 (sum(numbers)+target)/2보다 커지는 순간 더이상 계산할 이유가 없다 작거나 같을때 계속 다음 동작을 하면되는 것이다. +# 여기서 또 막힘..ㅎ 막힌 이유.... 6개에 120개인데 물론 합이 넘어가는걸 안빼긴함 여튼 그래도 많아보여서.... 의미가 없어 보임... 대강 합이 타겟넘어간다? 넘겨! 하기엔.... 이것도 사실 비효율적 이라고 보는게 결국 넘어가는거까지 확인을 하니까까...... +# 그래서 gpt씨에게 물어봄 +# DP 동적 계획 법이란게 있다고 하네요.... 한번 구한 값을 계속 활용 해서 여러번 반복 안한다고 해요... +# 이해하고 쓴건 아니고 동작 방식에 대해서 정도만 이해한 상태로 작성 했습니다 감안 부탁드립니다. + +# 우선 딕셔너리를 통해서 진행하는데 모든 수의 합이 0인 경우는 아무것도 선택안한 상태 밖에 없어서 1이고 초기 값을 입력한것 입니다. +# 우선 모든 number의 수를 대입해서 확인은 해야겠죠? 그래서 for문을 저렇게 활용 했습니다. +# 이제 타겟 부터 현재 선택된 수에 대해 탐색을 시작하는데 정순으로 올라가면 시작값이 뒤에 값에 영향을 줘서 반대로 역순으로 가면 시작값이 영향을 전혀 못줍니다. +# 첫과정에서 sub_sum이란 키값에 sub_sumdml 제일 작은수 즉 num에 1이란 값이 들어갑니다. 이제 이 이후에 영향을 주게 되겠죠. +# 여기서 왜 1이 들어가느냐 하면 get(x,0)은 딕셔너리 x키값에 value값이 존재하면 해당 값을 반환 하고 아니면 ,뒤의 값 즉 0을 반환 합니다. + +# 그럼 두번째 과정에서는 num의 키에 1이 추가되고 첫번째 과정에서 1이 들어갔던 키값을 부르는 곳 거기서 또 1이 추가 되겠죠? +# 이걸 반복해서 모든 과정을 거치고, sumtarget에 값을 확인해보면 합쳤을때 해당 키값에 도달 할수 있다면 1이 추가 됩니다. 만약 비었다면 get함수에 의해 0을 반환 하구요. +# + + + + +## 아래식은 제가 defaultdict이 잘 이해가 안되서 고대로 나둬봅니다. +# from collections import defaultdict + +# def solution(numbers, target): +# total_sum = sum(numbers) + +# # target을 만들 수 없는 경우 (S + target이 홀수인 경우) +# if (total_sum + target) % 2 == 1: +# return 0 + +# target_sum = (total_sum + target) // 2 + +# # DP 방식으로 부분집합 합의 개수 찾기 +# dp = defaultdict(int) +# dp[0] = 1 # 합이 0이 되는 경우의 수는 1 (아무것도 선택하지 않은 경우) + +# for num in numbers: +# for sub_sum in range(target_sum, num - 1, -1): +# dp[sub_sum] += dp[sub_sum - num] + +# return dp[target_sum] + +# # 예제 테스트 +# print(solution([1, 1, 1, 1, 1], 3)) # 5 +# print(solution([4, 1, 2, 1], 4)) # 2 + + +## 참고 시간 비교용 +# 테스트 1 〉 통과 (2.60ms, 10.3MB) +# 테스트 2 〉 통과 (2.48ms, 10.2MB) +# 테스트 3 〉 통과 (1.02ms, 10.3MB) +# 테스트 4 〉 통과 (1.29ms, 10.1MB) +# 테스트 5 〉 통과 (1.25ms, 10.1MB) +# 테스트 6 〉 통과 (1.42ms, 10.4MB) +# 테스트 7 〉 통과 (0.50ms, 10.3MB) +# 테스트 8 〉 통과 (1.10ms, 10.1MB) + +#우석님꺼 +# 테스트 1 〉 통과 (630.08ms, 10.2MB) +# 테스트 2 〉 통과 (514.51ms, 10.3MB) +# 테스트 3 〉 통과 (0.49ms, 10.2MB) +# 테스트 4 〉 통과 (1.90ms, 10.1MB) +# 테스트 5 〉 통과 (14.85ms, 10.3MB) +# 테스트 6 〉 통과 (1.95ms, 10.1MB) +# 테스트 7 〉 통과 (0.63ms, 10.3MB) +# 테스트 8 〉 통과 (3.84ms, 10.1MB) \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_Q_seok.py b/03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_Q_seok.py new file mode 100644 index 0000000..ef1efd0 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_Q_seok/study_week4_Q_seok.py @@ -0,0 +1,89 @@ +# https://school.programmers.co.kr/learn/courses/30/lessons/43165 +''' +문제 설명 +n개의 음이 아닌 정수들이 있습니다. 이 정수들을 순서를 바꾸지 않고 적절히 더하거나 빼서 타겟 넘버를 만들려고 합니다. 예를 들어 [1, 1, 1, 1, 1]로 숫자 3을 만들려면 다음 다섯 방법을 쓸 수 있습니다. + +-1+1+1+1+1 = 3 ++1-1+1+1+1 = 3 ++1+1-1+1+1 = 3 ++1+1+1-1+1 = 3 ++1+1+1+1-1 = 3 + +사용할 수 있는 숫자가 담긴 배열 numbers, 타겟 넘버 target이 매개변수로 주어질 때 숫자를 적절히 더하고 빼서 타겟 넘버를 만드는 방법의 수를 return 하도록 solution 함수를 작성해주세요. + +제한사항 + - 주어지는 숫자의 개수는 2개 이상 20개 이하입니다. + - 각 숫자는 1 이상 50 이하인 자연수입니다. + - 타겟 넘버는 1 이상 1000 이하인 자연수입니다. + +입출력 예 + numbers target return + [1, 1, 1, 1, 1] 3 5 + [4, 1, 2, 1] 4 2 + +입출력 예 설명 + +입출력 예 #1 + - 문제 예시와 같습니다. + +입출력 예 #2 + +4+1-2+1 = 4 + +4-1+2-1 = 4 + 총 2가지 방법이 있으므로, 2를 return 합니다. +''' +#------------------------------------------------------------------------------------------------------------------------------------------------------------------ +''' +예제분석 + - 위의 예제 중 두번째 [4, 1, 2, 1]의 정수들을 더하거나 뺏을 때 분기점이 나뉩니다. + - 이걸 이진트리로 표현하면 다음과 같습니다. (왼쪽은 덧셈, 오른쪽은 뺄셈으로 가정합니다.) + + 0 + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + +4 -4 + / \ / \ + / \ / \ + / \ / \ + / \ / \ + +1 -1 +1 -1 + / \ / \ / \ / \ + +2 -2 +2 -2 +2 -2 +2 -2 + /\ /\ /\ /\ /\ /\ /\ /\ ++1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 +1 -1 + + - 이를 계산하면 + + 0 + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + / \ + 4 -4 + / \ / \ + / \ / \ + / \ / \ + / \ / \ + 5 3 -3 -5 + / \ / \ / \ / \ + 7 3 5 1 -1 -5 -3 -7 + /\ /\ /\ /\ /\ /\ /\ /\ + 8 6 4 2 6 4 2 0 0 -2 -4 -6 -2 -4 -6 -8 + + - [4, 1, 2, 1]... 모든 정수를 소모하였을때, 4가 나오는 경우의 수가 2가지임을 알 수 있습니다. +''' \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_369_A..py b/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_369_A..py new file mode 100644 index 0000000..d86ee0e --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_369_A..py @@ -0,0 +1,26 @@ +# 제한사항 +# 1 ≤ order ≤ 1,000,000 +# 입출력 예 +# order result +# 3 1 +# 29423 2 +# 입출력 예 설명 +# 입출력 예 #1 + +# 3은 3이 1개 있으므로 1을 출력합니다. +# 입출력 예 #2 + +# 29423은 3이 1개, 9가 1개 있으므로 2를 출력합니다. +import re + +max_order = 1000000 +min_order = 1 + +def solution(s): + answer = sum(map(lambda x : x in '369',str(s))) + return answer + +for i in range(1,40): + +print(solution(29423)) +print(solution(312993)) \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_chage_number_star.py b/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_chage_number_star.py new file mode 100644 index 0000000..01e6334 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_chage_number_star.py @@ -0,0 +1,17 @@ +''' +문제 설명 +프로그래머스 모바일은 개인정보 보호를 위해 고지서를 보낼 때 고객들의 전화번호의 일부를 가립니다. +전화번호가 문자열 phone_number로 주어졌을 때, 전화번호의 뒷 4자리를 제외한 나머지 숫자를 전부 *으로 가린 문자열을 리턴하는 함수, solution을 완성해주세요. + +제한 조건 +phone_number는 길이 4 이상, 20이하인 문자열입니다. +입출력 예 +phone_number return +"01033334444" "*******4444" +"027778888" "*****8888" +''' +def solution(phone_number): + return "*"*(len(phone_number)-4) + phone_number[-4:] + +print(solution('01033334444')) +print(solution('027778888')) \ No newline at end of file diff --git a/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_week4_ji_Q.md b/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_week4_ji_Q.md new file mode 100644 index 0000000..818d863 --- /dev/null +++ b/03151_minsuje/hw/week4(p)/study_week4_ji_Q/study_week4_ji_Q.md @@ -0,0 +1,38 @@ +# 1. https://school.programmers.co.kr/learn/courses/30/lessons/120891 +''' +문제 설명 +머쓱이는 친구들과 369게임을 하고 있습니다. +369게임은 1부터 숫자를 하나씩 대며 3, 6, 9가 들어가는 숫자는 +숫자 대신 3, 6, 9의 개수만큼 박수를 치는 게임입니다. +머쓱이가 말해야하는 숫자 order가 매개변수로 주어질 때, +머쓱이가 쳐야할 박수 횟수를 return 하도록 solution 함수를 완성해보세요. + +제한사항 +1 ≤ order ≤ 1,000,000 +입출력 예 +order result +3 1 +29423 2 +입출력 예 설명 +입출력 예 #1 + +3은 3이 1개 있으므로 1을 출력합니다. +입출력 예 #2 + +29423은 3이 1개, 9가 1개 있으므로 2를 출력합니다. +''' + + +# 2. https://school.programmers.co.kr/learn/courses/30/lessons/12948 +''' +문제 설명 +프로그래머스 모바일은 개인정보 보호를 위해 고지서를 보낼 때 고객들의 전화번호의 일부를 가립니다. +전화번호가 문자열 phone_number로 주어졌을 때, 전화번호의 뒷 4자리를 제외한 나머지 숫자를 전부 *으로 가린 문자열을 리턴하는 함수, solution을 완성해주세요. + +제한 조건 +phone_number는 길이 4 이상, 20이하인 문자열입니다. +입출력 예 +phone_number return +"01033334444" "*******4444" +"027778888" "*****8888" +''' \ No newline at end of file diff --git a/03151_minsuje/hw/week5_p/__pycache__/logistics.cpython-312.pyc b/03151_minsuje/hw/week5_p/__pycache__/logistics.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c41abe73db46d4075878618f3c22514724fd146 GIT binary patch literal 2816 zcmb6bOH3PA@a=lnHXj3tF*uG%NF->M2nYq*h|s2qNK!S0qzye3nXHU=4L0`L*|ozb zM#>=vBO%qOQNU^?J5{ARq6ey0D!DW{wrZu~K*Q=Kl~VPT8wrOhy|nXoy>_5fRY$vT zX5O1OZ+3off3(@k5da^)Gpbq;`kgQaFa=_(3y1|IAb|>@AxgvakO?pyV#4eYOCcJa zLxSlB5||}g-!){OqB!;`VFow~vx0afF8cH}eJlu~tw!J%kf^C1q6JoF8TJu%U^_CwyLF2q$`Ymo;>o-Q2^u(3j1%^IsQn?VJu461|$Dz?Yq5-4aj=n`HkSh7t{i$Y0;P=?%>^b+|p z0I;G=rwAQ%7<36IXk!=1Rv7dDB5Qg{w$hLtg*bjjJXHKjfr0&djr9@^x=XY{fuz%* zOSl)vDa5e@XE_?P0Z9-ivBeh&#lw=qF&zE$F94Z@1Zd)&0<9sLd@@JtG;z})SB=Y* zm{*SRQap^yff^Nc+7^n829#L9r|^(0m{rESQ4yQu$b?J+f$6A#%lf=A?^)R!7BMS( zrBM-EuLhJrj2Haa>IdWaXhgwgT`Q;{2jOy|n0J^7gd#qU!Hgn?{4#M9wv}uc5oKIi zv<^6hBvB*4pKtqmJnvsPf969N`vZz7dq+Z|vYk2B+0os>hXaxl4~m|#3D1Nmj(77> zPw~szqEpz)^8pD==BMko7e$+~Kyq677>4Ue-Pe?4=BiZJD}buihL$9=Zgr`Rts9M< zd3dZ1FmFxO-gG~9x-ymN%IpW~8H+$AEIxXY9(RGJ8ql&!dmRT`AjHiQ1a^*t9oB6- ziVd-Jcwxs$ZO3WQx=Z^{SQ1t}i9jO?)|7S|6wL0@O#P;-#F{XylJwXC!MYt2z?M#u zskvDJuDJiVlQdSSFTY zOEeMOt|+;l4BN{@CU=ued@S3^KrRhz_C}+kByeSV39<0Q5En5uiK!{fM7^;w zObe6nPGMFOC-_MnO)2DpAPrUnt;Dcp#IIce({(%gV_}|{q*OswK$X=v7Hc!Ev@09? zV*2)UHndvbxmwq?R@0qif2*>qu7jD@bn7SWv*%~eB;QM3Np(G`u1W1licp)^=C3`d zI;__3PgOi|9muqQ+CFbi(W%qwfrD8(Eo4t+M{f6};wg5s9Mw8f@pXIiqL3L&k3F4K-Ij|li@C&_yH`DNa*@f{(zc?8rd)5{d0cfiXbnA{6SLB?uoAy7 zu1KqI^ygpeUu_!r#d%@Vf%dmNx1s9V&BLgsR%;dp z9wKxl&tHjqL;8x`0HRt;liPs0gESp_qa)owCIfjD(%EjHExL?tdtS$|hqfwfS^Y#! zhO=OE)GG;IMJ81P!HtLEs-vYSu7H1qP~o>v&oWJOCy13!!`5Ei!Z&5O6cFin3Q4O? a6Gc&vko^(b`zvbrgK4H}pCcHwoqq!m;!()} literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week5_p/__pycache__/turtle_gui.cpython-312.pyc b/03151_minsuje/hw/week5_p/__pycache__/turtle_gui.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5111f2a0fc0e4ead04b4e7118ad6972c22ef80b7 GIT binary patch literal 3259 zcma)8OK%%T67C+(kVEmI7fG3lACjHe8pk#)dmSXUlfa2Li@;eW-o<7SLBW9HjHHn% zlIkHNOQ3)pbdUf6CV>EAE{S|uC~yur2G~Eaz@BJRk;+Dvn#NLTCN9 z&gcY;fmLe;bc|xP3YiVNy7ztLs1*EWBi^{HdGm`zp<_yr$8v>f!z>wDQ-w@$$(+d) zbsk`a1s=*4a^<nU!+7I$bs{6&Jazsz%-@ zsp?W+E1#F#F$sTj6vXG`rxWK_#il&CJ9Kep=xPK0kSmp0oqt@ne96W@Ipb1Nm6)ms?_FAAq?LPLF#pQr+SJC!ZRy=2@ zZBOx|c9lS-1*10Go};$j{$baBN9Upbg()Eo6PkE$gbl*KxF*MyBVwwE3&XCg>mOPh=dcIubA~FsSK}Rbr za=IzM^t3lsEp6Pd-QPI1 zdTTE^SpUP3^ls{|b2ZZfcGGSGVRL_g~&i3~qc-`(QJ*ofz3orgxI( z8p(58bZc}=Y$Pv!*ZVkm#Wfk&PAE?u^MPhUf!I4e!;PNdX3v?u^vU}CSI4Ti(0Hsi zwt1zQIO{t0Z6{uSCXvC@zXVC|z(#ki`-h(4=VwStc@`jj!@ry*;chDrf8Ul*Fhu@X z*3W;)%~%EpA3@gqdUY32U?Zl>XCG0**C|SQK;+@@lXzS2* zcTWkRPaI2u)5|*Eo9#hY9Sy9jq+G2 z!>09;nlH~y>I~2c{SuE)8Gxa=!e_emnBn1;%FbaJAZ@}F6z4&hm}MJLC@oa+xD6vW z#L_YEDsP{`2bQ@C0$`RtwcBfA3 zqubFFQ1Amo&w?ZzbKVJ7VYj^#u*R*r{uUH}U3aQ#jY5Sv)!xS7exyJgY~K0$?gZqg zLroL3K*yM!-V~0nQ!~Z|z@qVw7cXAeH6vLC0tXH3TV$ue*shFW&=hJ_h6x_TK1Qox zmioQ3Ydr$-3Ff@R-0c6gex@m(bb9M?R3dAU>bv#6rhFWG_B+hVuOish43B1b?&ULc zx~lRn6>3f^!%I-*QB|EUXL9xo>&A6PP+UcUW&91X0@)mn%)wA#l1;psSIBcglG4w6 z2Beb*SHe>IASFs^+XW33(N09T^$51XWJP)d47})EzG*M(Ep`JYFgs=v#IpdU^hXl= R4|(~&;wVi&Cm<}h{{dL^Ra5`~ literal 0 HcmV?d00001 diff --git a/03151_minsuje/hw/week5_p/logistics.py b/03151_minsuje/hw/week5_p/logistics.py new file mode 100644 index 0000000..2c3ff2f --- /dev/null +++ b/03151_minsuje/hw/week5_p/logistics.py @@ -0,0 +1,43 @@ +import pandas as pd +import numpy as np +from collections import deque + +class map_Directions(): + def __init__(self,logistics_map, target_number=None, start_number=2): + self.start_num = start_number + self.target_num = target_number + self.logistics_map = logistics_map + self.row,self.columns = logistics_map.shape #맵의 크기를 튜플 값으로 받음 shape는 np의 객체 속성이라 따로 함수가 아님... 튜플로 크기 반환해줌 + self.visit_df = pd.DataFrame(False, index=range(self.row),columns=range(self.columns)) + self.target = self.find_pos(target_number) + self.start = self.find_pos(start_number) + self.directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] + self.visit_df.iloc[self.start] = True #시작점 설정 + + def find_pos(self, number): + for i in range(self.row): + for j in range(self.columns): + if self.logistics_map[i,j] == number: + return (i,j) + + def bfs_map(self): + queue = deque([((self.start), [self.start])]) #현재 위치, 경로 초기화 + + while queue: + (x,y), path = queue.popleft() + + if(x,y) == self.target: + return path + + for dx, dy in self.directions: + new_x, new_y =x+dx, y+dy + + #맵크기를 벗어 나지 않고 + #맵에 길과 시작지점, 타겟지점에 있는지 확인 + #그리고 이미 방문 한 곳이 아니면 + if 0<= new_x - 10×10 크기의 물류창고 맵이 주어진다. +> - 시작 위치(2)는 왼쪽 상단 모서리 (0,0)이며, 특정 제품(3~18)까지 이동 후 다시 원래 위치로 돌아와야 한다. +> - 제품(3~18)은 장애물로 간주되며, 터틀은 이를 피해서 이동해야 한다. +> - BFS 또는 DFS를 사용하여 최단 경로를 탐색한다. +> - Turtle Graphics를 이용해 창고 맵을 그리고, 터틀이 이동하는 경로를 시각화한다. +>>맵 구조 +>>- 2 0 0 0 0 0 0 0 0 0 +>> 0 3 0 4 0 5 0 6 0 0 +>> 0 0 0 0 7 0 0 8 0 0 +>> 0 9 0 10 0 11 0 12 0 0 +>> 0 0 0 0 13 0 0 0 14 0 +>> 0 15 0 16 0 17 0 18 0 0 +>> 0 0 0 0 0 0 0 0 0 0 +>- 2: 시작 위치 (0,0) +>- 3~18: 제품 (이동 불가) +>- 0: 이동 가능 +## 요구 사항 +- 주어진 맵을 numpy 배열로 저장하고 pandas 데이터프레임으로 변환한다. +- BFS 또는 DFS를 이용하여 특정 제품(예: 10)에 도달하는 최단 경로를 찾는다. +- 제품 위치를 피해서 이동해야 한다. +- 제품에 도달한 후 다시 원래 위치(0,0)로 돌아오는 최단 경로를 찾는다. +- Turtle Graphics를 활용하여 이동 경로를 시각화한다. + +### 시간 되시는분들만 아래 문제도 해보세용 시험이라 최대한 이전 수업 내용 모든걸 담은 문제를 만들어보려고 2개로 나눠서 만들어 보았습니다. + +- 참고로 gpt로 만들어서 저희 수업내용이 제대로 포함되어 있는지 확인을 못했습니다. +- 그점 참고하시고 배우지 않은 부분은 건너뛰시거나 배운 내용으로 변경하여 해주시면 될것 같습니다. + +# 문제 2: Seaborn 데이터셋을 활용한 통계 분석 및 시각화 +- 사용 라이브러리: numpy, statsmodels, SciPy, Seaborn, matplotlib + +## 문제 설명 +- Seaborn에서 제공하는 'tips' 데이터셋을 이용하여 통계 분석을 수행한다. +- 데이터의 기본 통계를 확인하고, 특정 변수 간 관계를 분석한다. +- statsmodels를 사용해 'total_bill'과 'tip' 간의 회귀 분석을 수행한다. +- SciPy를 이용해 정규성 검정을 진행한다. +- Seaborn과 matplotlib을 활용해 데이터 분포를 시각화한다. +## 요구 사항 +- Seaborn의 'tips' 데이터셋을 불러온다. +- 데이터의 기본 통계를 출력한다. +- 'total_bill'과 'tip'의 상관관계를 statsmodels를 사용하여 분석한다. +- SciPy를 활용하여 'tip'의 정규성 검정을 수행한다. +- matplotlib과 Seaborn을 사용하여 데이터 분포 및 관계를 시각화한다. \ No newline at end of file diff --git a/03151_minsuje/hw/week5_p/turtle_gui.py b/03151_minsuje/hw/week5_p/turtle_gui.py new file mode 100644 index 0000000..0d40776 --- /dev/null +++ b/03151_minsuje/hw/week5_p/turtle_gui.py @@ -0,0 +1,53 @@ +import turtle +from logistics import map_Directions + +class draw_path(): + def __init__(self,logistics_map): + + self.logistics_map = logistics_map + self.row,self.columns = logistics_map.shape + self.draw_map() + self.goto_zreo() + + + def draw_map(self): + turtle.speed(0) + turtle.hideturtle() + + for i in range(self.row): + for j in range(self.columns): + x,y = j*20 -100, 100- i*20 #그림은 +x -y인데 값은 x,y여서 변환 + + turtle.penup() + turtle.goto(x,y) + turtle.pendown() + + if self.logistics_map[i, j] == 2: # 시작 위치 + turtle.color("blue") + elif self.logistics_map[i, j] >= 3: # 제품 위치 + turtle.color("white") + else: + turtle.color("black") + turtle.begin_fill() + for _ in range(4): + turtle.forward(20) + turtle.right(90) + turtle.end_fill() + turtle.color("black") + + def draw_move_path(self,color, target_number=None,start=2): + find_move_path = map_Directions(self.logistics_map,target_number,start) + move_path = find_move_path.bfs_map() + turtle.speed(2) + turtle.pensize(2) + turtle.color(color) + for (i, j) in move_path: + x, y = j * 20 - 90, 90 - i * 20 # 좌표 변환 + turtle.goto(x, y) + self.goto_zreo() + + def goto_zreo(self): + turtle.setup(300, 300) + turtle.penup() + turtle.goto(-90, 90) # 시작 위치 설정 + turtle.pendown() \ No newline at end of file From 0109ff32b164886e254fdcb6afdceb9e2956aa15 Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Mon, 10 Feb 2025 12:18:54 +0900 Subject: [PATCH 09/11] =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EC=95=BD=EA=B0=84?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 03151_minsuje/hw/week5_p/python_Q.md | 54 +++++++++++++--------------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/03151_minsuje/hw/week5_p/python_Q.md b/03151_minsuje/hw/week5_p/python_Q.md index 2a7a7d6..429b45b 100644 --- a/03151_minsuje/hw/week5_p/python_Q.md +++ b/03151_minsuje/hw/week5_p/python_Q.md @@ -2,19 +2,21 @@ - 사용 라이브러리: Turtle Graphics, BFS/DFS, pandas, numpy ## 문제 설명 -> - 10×10 크기의 물류창고 맵이 주어진다. +> - 맵구조 라는 맵이 주어진다. > - 시작 위치(2)는 왼쪽 상단 모서리 (0,0)이며, 특정 제품(3~18)까지 이동 후 다시 원래 위치로 돌아와야 한다. -> - 제품(3~18)은 장애물로 간주되며, 터틀은 이를 피해서 이동해야 한다. +> - 제품(3~18)은 장애물로 간주되며, 터틀은 이를 피해서 이동해야 한다.(0은 이동 가능) > - BFS 또는 DFS를 사용하여 최단 경로를 탐색한다. > - Turtle Graphics를 이용해 창고 맵을 그리고, 터틀이 이동하는 경로를 시각화한다. ->>맵 구조 ->>- 2 0 0 0 0 0 0 0 0 0 ->> 0 3 0 4 0 5 0 6 0 0 ->> 0 0 0 0 7 0 0 8 0 0 ->> 0 9 0 10 0 11 0 12 0 0 ->> 0 0 0 0 13 0 0 0 14 0 ->> 0 15 0 16 0 17 0 18 0 0 ->> 0 0 0 0 0 0 0 0 0 0 +>>맵 구조(아래에 좀더 이쁘게 [[ ],[ ],[ ]]한거 확인 하고 쓰셔요. 요구사항 아래에 있음) + ``` + 2 0 0 0 0 0 0 0 0 0 + 0 3 0 4 0 5 0 6 0 0 + 0 0 0 0 7 0 0 8 0 0 + 0 9 0 10 0 11 0 12 0 0 + 0 0 0 0 13 0 0 0 14 0 + 0 15 0 16 0 17 0 18 0 0 + 0 0 0 0 0 0 0 0 0 0 + ``` >- 2: 시작 위치 (0,0) >- 3~18: 제품 (이동 불가) >- 0: 이동 가능 @@ -25,23 +27,15 @@ - 제품에 도달한 후 다시 원래 위치(0,0)로 돌아오는 최단 경로를 찾는다. - Turtle Graphics를 활용하여 이동 경로를 시각화한다. -### 시간 되시는분들만 아래 문제도 해보세용 시험이라 최대한 이전 수업 내용 모든걸 담은 문제를 만들어보려고 2개로 나눠서 만들어 보았습니다. - -- 참고로 gpt로 만들어서 저희 수업내용이 제대로 포함되어 있는지 확인을 못했습니다. -- 그점 참고하시고 배우지 않은 부분은 건너뛰시거나 배운 내용으로 변경하여 해주시면 될것 같습니다. - -# 문제 2: Seaborn 데이터셋을 활용한 통계 분석 및 시각화 -- 사용 라이브러리: numpy, statsmodels, SciPy, Seaborn, matplotlib - -## 문제 설명 -- Seaborn에서 제공하는 'tips' 데이터셋을 이용하여 통계 분석을 수행한다. -- 데이터의 기본 통계를 확인하고, 특정 변수 간 관계를 분석한다. -- statsmodels를 사용해 'total_bill'과 'tip' 간의 회귀 분석을 수행한다. -- SciPy를 이용해 정규성 검정을 진행한다. -- Seaborn과 matplotlib을 활용해 데이터 분포를 시각화한다. -## 요구 사항 -- Seaborn의 'tips' 데이터셋을 불러온다. -- 데이터의 기본 통계를 출력한다. -- 'total_bill'과 'tip'의 상관관계를 statsmodels를 사용하여 분석한다. -- SciPy를 활용하여 'tip'의 정규성 검정을 수행한다. -- matplotlib과 Seaborn을 사용하여 데이터 분포 및 관계를 시각화한다. \ No newline at end of file +## 맵구조 아래 꺼 활용하실분들은 활용 하세용 +``` +([ + [ 2, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [ 0, 3, 0, 4, 0, 5, 0, 6, 0, 0], + [ 0, 0, 0, 0, 7, 0, 0, 8, 0, 0], + [ 0, 9, 0, 10, 0, 11, 0, 12, 0, 0], + [ 0, 0, 0, 0, 13, 0, 0, 0, 14, 0], + [ 0, 15, 0, 16, 0, 17, 0, 18, 0, 0], + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] +]) +``` \ No newline at end of file From 35a0aafb74f720ad9f0215ff27d887d46a20cf4e Mon Sep 17 00:00:00 2001 From: 03151_minsuje Date: Tue, 18 Feb 2025 21:55:53 +0900 Subject: [PATCH 10/11] upload_Q&A --- .../__pycache__/logistics.cpython-312.pyc | Bin 2816 -> 2817 bytes .../__pycache__/turtle_gui.cpython-312.pyc | Bin 3259 -> 3260 bytes .../hw/{week5_p => week5(p)}/logistics.py | 0 .../hw/{week5_p => week5(p)}/python_A.py | 0 .../hw/{week5_p => week5(p)}/python_Q.md | 0 .../hw/{week5_p => week5(p)}/turtle_gui.py | 0 03151_minsuje/hw/week6(p)/python_A.py | 69 ++++++++++++++++++ 03151_minsuje/hw/week6(p)/python_Q.md | 21 ++++++ 03151_minsuje/hw/week6(p)/test.py | 26 +++++++ 9 files changed, 116 insertions(+) rename 03151_minsuje/hw/{week5_p => week5(p)}/__pycache__/logistics.cpython-312.pyc (89%) rename 03151_minsuje/hw/{week5_p => week5(p)}/__pycache__/turtle_gui.cpython-312.pyc (86%) rename 03151_minsuje/hw/{week5_p => week5(p)}/logistics.py (100%) rename 03151_minsuje/hw/{week5_p => week5(p)}/python_A.py (100%) rename 03151_minsuje/hw/{week5_p => week5(p)}/python_Q.md (100%) rename 03151_minsuje/hw/{week5_p => week5(p)}/turtle_gui.py (100%) create mode 100644 03151_minsuje/hw/week6(p)/python_A.py create mode 100644 03151_minsuje/hw/week6(p)/python_Q.md create mode 100644 03151_minsuje/hw/week6(p)/test.py diff --git a/03151_minsuje/hw/week5_p/__pycache__/logistics.cpython-312.pyc b/03151_minsuje/hw/week5(p)/__pycache__/logistics.cpython-312.pyc similarity index 89% rename from 03151_minsuje/hw/week5_p/__pycache__/logistics.cpython-312.pyc rename to 03151_minsuje/hw/week5(p)/__pycache__/logistics.cpython-312.pyc index 3c41abe73db46d4075878618f3c22514724fd146..fa56ee2378ce91222584a60596f34e6acbc4860f 100644 GIT binary patch delta 34 ocmZn=YZT);&CAQh00e*YH*zI2GkQ+WW42`0DA3%zk~y3m0F(>}yZ`_I delta 33 ncmZn^YY^i)&CAQh00i;58@ZC189gTFF Date: Sat, 22 Feb 2025 19:45:46 +0900 Subject: [PATCH 11/11] . . --- 03151_minsuje/hw/week6(p)/py_A_ji.py | 34 ++++++++ 03151_minsuje/hw/week6(p)/py_A_jwlee.py | 21 +++++ 03151_minsuje/hw/week6(p)/py_A_kim.py | 33 ++++++++ 03151_minsuje/hw/week6(p)/py_A_seok.py | 69 ++++++++++++++++ 03151_minsuje/hw/week6(p)/py_Q_ji.py | 70 +++++++++++++++++ 03151_minsuje/hw/week6(p)/py_Q_jwlee.py | 26 ++++++ 03151_minsuje/hw/week6(p)/py_Q_kim.py | 34 ++++++++ 03151_minsuje/hw/week6(p)/py_Q_seok.py | 100 ++++++++++++++++++++++++ 03151_minsuje/hw/week6(p)/test1.py | 13 +++ 9 files changed, 400 insertions(+) create mode 100644 03151_minsuje/hw/week6(p)/py_A_ji.py create mode 100644 03151_minsuje/hw/week6(p)/py_A_jwlee.py create mode 100644 03151_minsuje/hw/week6(p)/py_A_kim.py create mode 100644 03151_minsuje/hw/week6(p)/py_A_seok.py create mode 100644 03151_minsuje/hw/week6(p)/py_Q_ji.py create mode 100644 03151_minsuje/hw/week6(p)/py_Q_jwlee.py create mode 100644 03151_minsuje/hw/week6(p)/py_Q_kim.py create mode 100644 03151_minsuje/hw/week6(p)/py_Q_seok.py create mode 100644 03151_minsuje/hw/week6(p)/test1.py diff --git a/03151_minsuje/hw/week6(p)/py_A_ji.py b/03151_minsuje/hw/week6(p)/py_A_ji.py new file mode 100644 index 0000000..e603188 --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_A_ji.py @@ -0,0 +1,34 @@ +from collections import defaultdict + +def solution(id_list, report, k): + report = set(report) # 중복 신고 제거 + reports_by_user = defaultdict(set) # 각 유저가 신고한 ID 저장 + reported_count = defaultdict(int) # 각 유저가 신고당한 횟수 저장 + + # 신고 데이터 처리 + for r in report: + reporter, reported = r.split() + if reported not in reports_by_user[reporter]: # 중복 신고 방지 + reports_by_user[reporter].add(reported) + reported_count[reported] += 1 + + # 정지된 유저 목록 + banned_users = {user for user, count in reported_count.items() if count >= k} + + # 결과 메일 개수 계산 + result = [] + for user in id_list: + result.append(len(reports_by_user[user] & banned_users)) + + return result + +# 테스트 예시 +id_list1 = ["muzi", "frodo", "apeach", "neo"] +report1 = ["muzi frodo", "apeach frodo", "frodo neo", "muzi neo", "apeach muzi"] +k1 = 2 +print(solution(id_list1, report1, k1)) # [2, 1, 1, 0] + +id_list2 = ["con", "ryan"] +report2 = ["ryan con", "ryan con", "ryan con", "ryan con"] +k2 = 3 +print(solution(id_list2, report2, k2)) # [0, 0] diff --git a/03151_minsuje/hw/week6(p)/py_A_jwlee.py b/03151_minsuje/hw/week6(p)/py_A_jwlee.py new file mode 100644 index 0000000..f04c2bb --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_A_jwlee.py @@ -0,0 +1,21 @@ +import torch +def make_diagonally_symmetric_matrix(n): + matrix = torch.arange(1, n+1).repeat(n, 1) #1,2,3,4,5,6,7,8...n을 모든행에 입력 + res_matrix=torch.triu(matrix) + torch.tril(matrix.T, diagonal=-1) + #torch.triu(matrix) 대각선 포함 윗쪽 형태 유지 및 아래 0 + #torch.tril(matrix.T, diagonal=-1) 대각선 기준 뒤집고 행렬 대각선 미포함 유지 및 위는 0 + # 원하는 매트릭스 완성. + return res_matrix + +def Conver_onerow_matrix(matrix_n): + matrix = make_diagonally_symmetric_matrix(matrix_n) + one_row=matrix.view(-1) + return one_row + +def soulution(n,left,right): + array = Conver_onerow_matrix(n) + list_array = array.tolist() + return list_array[left:right+1] + +print(soulution(3,2,5)) +print(soulution(4,7,14)) \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/py_A_kim.py b/03151_minsuje/hw/week6(p)/py_A_kim.py new file mode 100644 index 0000000..986fdbb --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_A_kim.py @@ -0,0 +1,33 @@ +def count_num_pow(num: int): + count = 0 + while num % 2 == 0: # 2로 나눌 수 있을 때까지 나누기 + num //= 2 + count += 1 + return num, count + +def Collatz_def(num: int) -> int: + count = 0 + + if num == 1: + return 0 # 이미 1이면 0 반환 + + num, step_count = count_num_pow(num) # 2의 거듭제곱 처리 + count += step_count # count 갱신 + + while num != 1: + if num % 2 == 0: + num, step_count = count_num_pow(num) + count+=step_count + else: + num = (3 * num + 1) // 2 # 3n+1 후 바로 //2 적용하여 최적화 + count += 2 # 두 단계 줄였으므로 추가 + + if count >= 500: + return -1 # 500번 초과 시 -1 반환 + + return count + +print(Collatz_def(6)) +print(Collatz_def(16)) +print(Collatz_def(626331)) +print(Collatz_def(12412591235012358120581058105)) \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/py_A_seok.py b/03151_minsuje/hw/week6(p)/py_A_seok.py new file mode 100644 index 0000000..5849d56 --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_A_seok.py @@ -0,0 +1,69 @@ +import numpy as np +# 보드 를 넘파이로 하면 쉽긴 하겠다 생각함. +# board = np.array([ +# ['.','.','.'], +# ['.','.','.'], +# ['.','.','.'] +# ]) +''' +조건 1. "." 빈칸, "O","X"만 올수 있다. +조건 2. "O"가 선공 +조건 3. 승리 후 게임 진행 불가능 +''' +class TicTacToeValidator: + def __init__(self, board): + self.set_board(board) + + def set_board(self, board): + self.board = np.array([[c for c in row] for row in board]) + + # "O"가 "X"의 개수와 같거나 1개 더 많으면 정상 아니면 비정상 + def validate_counts(self): + o_count = np.count_nonzero(self.board == 'O') + x_count = np.count_nonzero(self.board == 'X') + return o_count == x_count or o_count == x_count + 1 + + # 승리자 확인 + def check_winner(self, player): + # 행과 열 검사 + for i in range(3): + if np.all(self.board[i, :] == player) or np.all(self.board[:, i] == player): + return True + # 대각선 검사 np.all(np.diag(self.board) 대각선이 X의 값이니? np.fliplr(self.board)대칭시킴 + if np.all(np.diag(self.board) == player) or np.all(np.diag(np.fliplr(self.board)) == player): + return True + return False + + #조건을 충족하는지 확인 + def is_valid(self): + if not self.validate_counts(): + return 0 + + o_wins = self.check_winner('O') + x_wins = self.check_winner('X') + + if o_wins and x_wins: + return 0 # 둘 다 승리 상태면 잘못된 게임 상태 + if o_wins and np.count_nonzero(self.board == 'O') != np.count_nonzero(self.board == 'X') + 1: + return 0 # O가 이겼는데 개수 조건이 맞지 않음(O가 이기면 O가 X보다 1개 더 많이 되어있음 만약 X가 미리 이겼으면 이전 조건에 이미 클리어) + if x_wins and np.count_nonzero(self.board == 'O') != np.count_nonzero(self.board == 'X'): + return 0 # X가 이겼는데 개수 조건이 맞지 않음(X가 이기면 X가 O랑 개수가 같음 만약 O도 이긴건 위의 조건에 이미 클리어) + + return 1 # 유효한 게임 상태 + +# 테스트 예시 +board = ["O.X", ".O.", "..X"] +validator = TicTacToeValidator(board) +print(validator.is_valid()) + +board = ["OOO", "...", "XXX"] +validator = TicTacToeValidator(board) +print(validator.is_valid()) + +board = ["...", ".X.", "..."] +validator = TicTacToeValidator(board) +print(validator.is_valid()) + +board = ["...", "...", "..."] +validator = TicTacToeValidator(board) +print(validator.is_valid()) \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/py_Q_ji.py b/03151_minsuje/hw/week6(p)/py_Q_ji.py new file mode 100644 index 0000000..27929a0 --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_Q_ji.py @@ -0,0 +1,70 @@ +# https://school.programmers.co.kr/learn/courses/30/lessons/92334 +''' +문제 설명 +신입사원 무지는 게시판 불량 이용자를 신고하고 처리 결과를 메일로 발송하는 시스템을 개발하려 합니다. 무지가 개발하려는 시스템은 다음과 같습니다. + +각 유저는 한 번에 한 명의 유저를 신고할 수 있습니다. +신고 횟수에 제한은 없습니다. 서로 다른 유저를 계속해서 신고할 수 있습니다. +한 유저를 여러 번 신고할 수도 있지만, 동일한 유저에 대한 신고 횟수는 1회로 처리됩니다. +k번 이상 신고된 유저는 게시판 이용이 정지되며, 해당 유저를 신고한 모든 유저에게 정지 사실을 메일로 발송합니다. +유저가 신고한 모든 내용을 취합하여 마지막에 한꺼번에 게시판 이용 정지를 시키면서 정지 메일을 발송합니다. +다음은 전체 유저 목록이 ["muzi", "frodo", "apeach", "neo"]이고, k = 2(즉, 2번 이상 신고당하면 이용 정지)인 경우의 예시입니다. + +유저 ID 유저가 신고한 ID 설명 +"muzi" "frodo" "muzi"가 "frodo"를 신고했습니다. +"apeach" "frodo" "apeach"가 "frodo"를 신고했습니다. +"frodo" "neo" "frodo"가 "neo"를 신고했습니다. +"muzi" "neo" "muzi"가 "neo"를 신고했습니다. +"apeach" "muzi" "apeach"가 "muzi"를 신고했습니다. + +각 유저별로 신고당한 횟수는 다음과 같습니다. + +유저 ID 신고당한 횟수 +"muzi" 1 +"frodo" 2 +"apeach" 0 +"neo" 2 +위 예시에서는 2번 이상 신고당한 "frodo"와 "neo"의 게시판 이용이 정지됩니다. 이때, 각 유저별로 신고한 아이디와 정지된 아이디를 정리하면 다음과 같습니다. + +유저 ID 유저가 신고한 ID 정지된 ID +"muzi" ["frodo", "neo"] ["frodo", "neo"] +"frodo" ["neo"] ["neo"] +"apeach" ["muzi", "frodo"] ["frodo"] +"neo" 없음 없음 +따라서 "muzi"는 처리 결과 메일을 2회, "frodo"와 "apeach"는 각각 처리 결과 메일을 1회 받게 됩니다. + +이용자의 ID가 담긴 문자열 배열 id_list, 각 이용자가 신고한 이용자의 ID 정보가 담긴 문자열 배열 report, 정지 기준이 되는 신고 횟수 k가 매개변수로 주어질 때, +각 유저별로 처리 결과 메일을 받은 횟수를 배열에 담아 return 하도록 solution 함수를 완성해주세요. + +제한사항 +2 ≤ id_list의 길이 ≤ 1,000 +1 ≤ id_list의 원소 길이 ≤ 10 +id_list의 원소는 이용자의 id를 나타내는 문자열이며 알파벳 소문자로만 이루어져 있습니다. +id_list에는 같은 아이디가 중복해서 들어있지 않습니다. +1 ≤ report의 길이 ≤ 200,000 +3 ≤ report의 원소 길이 ≤ 21 + +report의 원소는 "이용자id 신고한id"형태의 문자열입니다. +예를 들어 "muzi frodo"의 경우 "muzi"가 "frodo"를 신고했다는 의미입니다. +id는 알파벳 소문자로만 이루어져 있습니다. +이용자id와 신고한id는 공백(스페이스)하나로 구분되어 있습니다. +자기 자신을 신고하는 경우는 없습니다. + +1 ≤ k ≤ 200, k는 자연수입니다. +return 하는 배열은 id_list에 담긴 id 순서대로 각 유저가 받은 결과 메일 수를 담으면 됩니다. + +입출력 예 +id_list report k result +["muzi", "frodo", "apeach", "neo"] ["muzi frodo","apeach frodo","frodo neo","muzi neo","apeach muzi"] 2 [2,1,1,0] +["con", "ryan"] ["ryan con", "ryan con", "ryan con", "ryan con"] 3 [0,0] + +입출력 예 설명 +입출력 예 #1 + +문제의 예시와 같습니다. + +입출력 예 #2 + +"ryan"이 "con"을 4번 신고했으나, 주어진 조건에 따라 한 유저가 같은 유저를 여러 번 신고한 경우는 신고 횟수 1회로 처리합니다. 따라서 "con"은 1회 신고당했습니다. +3번 이상 신고당한 이용자는 없으며, "con"과 "ryan"은 결과 메일을 받지 않습니다. 따라서 [0, 0]을 return 합니다. +''' \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/py_Q_jwlee.py b/03151_minsuje/hw/week6(p)/py_Q_jwlee.py new file mode 100644 index 0000000..165e3aa --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_Q_jwlee.py @@ -0,0 +1,26 @@ +# 정수 n, left, right가 주어집니다. 다음 과정을 거쳐서 1차원 배열을 만들고자 합니다. + +# 1. n행 n열 크기의 비어있는 2차원 배열을 만듭니다. +# 2. i = 1, 2, 3, ..., n에 대해서, 다음 과정을 반복합니다. +# - 1행 1열부터 i행 i열까지의 영역 내의 모든 빈 칸을 숫자 i로 채웁니다. +# 3. 1행, 2행, ..., n행을 잘라내어 모두 이어붙인 새로운 1차원 배열을 만듭니다. +# 4. 새로운 1차원 배열을 arr이라 할 때, arr[left], arr[left+1], ..., arr[right]만 남기고 나머지는 지웁니다. + + +# 정수 n, left, right가 매개변수로 주어집니다. 주어진 과정대로 만들어진 1차원 배열을 return 하도록 solution 함수를 완성해주세요. + +# 제한사항 +# 1 ≤ n ≤ 107 +# 0 ≤ left ≤ right < n2 +# right - left < 105 + + +# 입출력 예 +# n left right result +# 3 2 5 [3,2,2,3] +# 4 7 14 [4,3,3,3,4,4,4,4] + + + + +# https://school.programmers.co.kr/learn/courses/30/lessons/87390 \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/py_Q_kim.py b/03151_minsuje/hw/week6(p)/py_Q_kim.py new file mode 100644 index 0000000..357e176 --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_Q_kim.py @@ -0,0 +1,34 @@ +# 문제 설명 +# 1937년 Collatz란 사람에 의해 제기된 이 추측은, 주어진 수가 1이 될 때까지 다음 작업을 반복하면, 모든 수를 1로 만들 수 있다는 추측입니다. 작업은 다음과 같습니다. + +# 1-1. 입력된 수가 짝수라면 2로 나눕니다. +# 1-2. 입력된 수가 홀수라면 3을 곱하고 1을 더합니다. +# 2. 결과로 나온 수에 같은 작업을 1이 될 때까지 반복합니다. +# 예를 들어, 주어진 수가 6이라면 6 → 3 → 10 → 5 → 16 → 8 → 4 → 2 → 1 이 되어 총 8번 만에 1이 됩니다. 위 작업을 몇 번이나 반복해야 하는지 반환하는 함수, solution을 완성해 주세요. 단, 주어진 수가 1인 경우에는 0을, 작업을 500번 반복할 때까지 1이 되지 않는다면 –1을 반환해 주세요. + +# 제한 사항 +# 입력된 수, num은 1 이상 8,000,000 미만인 정수입니다. +# 입출력 예 +# n result +# 6 8 +# 16 4 +# 626331 -1 +# 입출력 예 설명 +# 입출력 예 #1 +# 문제의 설명과 같습니다. + +# 입출력 예 #2 +# 16 → 8 → 4 → 2 → 1 이 되어 총 4번 만에 1이 됩니다. + +# 입출력 예 #3 +# 626331은 500번을 시도해도 1이 되지 못하므로 -1을 리턴해야 합니다. + +# ※ 공지 - 2022년 6월 10일 다음과 같이 지문이 일부 수정되었습니다. + +# 주어진 수가 1인 경우에 대한 조건 추가 + + + + + +#https://school.programmers.co.kr/learn/courses/30/lessons/12943 \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/py_Q_seok.py b/03151_minsuje/hw/week6(p)/py_Q_seok.py new file mode 100644 index 0000000..8878ddc --- /dev/null +++ b/03151_minsuje/hw/week6(p)/py_Q_seok.py @@ -0,0 +1,100 @@ +# https://school.programmers.co.kr/learn/courses/30/lessons/160585?language=c +"""------------------------------------------------------------------------------------------------------------------------------------------------------------------ + +문제 설명 + +틱택토는 두 사람이 하는 게임으로 처음에 3x3의 빈칸으로 이루어진 게임판에 선공이 "O", 후공이 "X"를 번갈아가면서 빈칸에 표시하는 게임입니다. +가로, 세로, 대각선으로 3개가 같은 표시가 만들어지면 같은 표시를 만든 사람이 승리하고 게임이 종료되며 9칸이 모두 차서 더 이상 표시를 할 수 없는 경우에는 무승부로 게임이 종료됩니다. +할 일이 없어 한가한 머쓱이는 두 사람이 하는 게임인 틱택토를 다음과 같이 혼자서 하려고 합니다. + + - 혼자서 선공과 후공을 둘 다 맡는다. + + - 틱택토 게임을 시작한 후 "O"와 "X"를 혼자서 번갈아 가면서 표시를 하면서 진행한다. + +틱택토는 단순한 규칙으로 게임이 금방 끝나기에 머쓱이는 한 게임이 종료되면 다시 3x3 빈칸을 그린 뒤 다시 게임을 반복했습니다. +그렇게 틱택토 수 십 판을 했더니 머쓱이는 게임 도중에 다음과 같이 규칙을 어기는 실수를 했을 수도 있습니다. + + - "O"를 표시할 차례인데 "X"를 표시하거나 반대로 "X"를 표시할 차례인데 "O"를 표시한다. + + - 선공이나 후공이 승리해서 게임이 종료되었음에도 그 게임을 진행한다. + +게임 도중 게임판을 본 어느 순간 머쓱이는 본인이 실수를 했는지 의문이 생겼습니다. +혼자서 틱택토를 했기에 게임하는 과정을 지켜본 사람이 없어 이를 알 수는 없습니다. +그러나 게임판만 봤을 때 실제로 틱택토 규칙을 지켜서 진행했을 때 나올 수 있는 상황인지는 판단할 수 있을 것 같고 문제가 없다면 게임을 이어서 하려고 합니다. + +머쓱이가 혼자서 게임을 진행하다 의문이 생긴 틱택토 게임판의 정보를 담고 있는 문자열 배열 board가 매개변수로 주어질 때, +이 게임판이 규칙을 지켜서 틱택토를 진행했을 때 나올 수 있는 게임 상황이면 1을 아니라면 0을 return 하는 solution 함수를 작성해 주세요. + +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +제한 사항 + + - board의 길이 = board[i]의 길이 = 3 + + - board의 원소는 모두 "O", "X", "."으로만 이루어져 있습니다. + + - board[i][j]는 i + 1행 j + 1열에 해당하는 칸의 상태를 나타냅니다. + + - "."은 빈칸을, "O"와 "X"는 해당 문자로 칸이 표시되어 있다는 의미입니다. + +--------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +입출력 예 + +board result +["O.X", ".O.", "..X"] 1 +["OOO", "...", "XXX"] 0 +["...", ".X.", "..."] 0 +["...", "...", "..."] 1 + + + +입출력 예 #1 + +예제 1번의 게임판은 다음과 같습니다. + +O.X +.O. +..X + +선공 후공이 번갈아가면서 다음과 같이 놓았을 때 이러한 게임판이 나올 수 있습니다. + +1행 1열 → 1행 3열 → 2행 2열 → 3행 3열 +1행 1열 → 3행 3열 → 2행 2열 → 1행 3열 +2행 2열 → 1행 3열 → 1행 1열 → 3행 3열 +2행 2열 → 3행 3열 → 1행 1열 → 1행 3열 + +물론 위와 다르게 머쓱이가 2행 2열에 O, 3행 3열에 X, 1행 3열에 X, 1행 1열에 O 순서로 표시를 해서 실수를 했을 가능성도 있지만 +"실수를 했을 가능성이 있는가"를 묻는 게 아닌 "이 게임판이 규칙을 지켜서 진행한 틱택토에서 나올 수 있는 상황인가"를 묻는 문제라는 것에 유의해주세요. 따라서 1을 return 합니다. + + + +입출력 예 #2 + +예제 2번의 게임판은 다음과 같습니다. + +OOO +... +XXX + +규칙을 지켜서 진행한 틱택토라면 선공과 후공이 번갈아가면서 각각 1행, 3행 중 두 칸씩에 표시를 한 뒤 5번째 차례에 선공이 1행에 가로로 3개의 O를 완성했을 때 종료되므로 +적어도 머쓱이가 게임이 종료된 후에도 계속 진행하는 실수를 했다는 것을 추론해 볼 수 있고, 정상적인 틱택토에서는 이러한 상황이 나올 수 없습니다. 따라서 0을 return 합니다. + + + +입출력 예 #3 + +예제 3번은 2행 2열에만 X가 표시가 되어있습니다. 선공 O 표시가 없이 X만 있으므로 머쓱이가 O를 표시해야 할 때 X를 표시하는 실수를 했다는 것을 추론해 볼 수 있고, +규칙을 지켜서 진행했을 때는 이러한 상황이 나올 수 없습니다. 따라서 0을 return 합니다. + + + +입출력 예 #4 + +예제 4번은 빈 3x3 게임판입니다. 선공이 아직 빈칸에 표시하기 전에 이러한 상황이 나올 수 있습니다. 따라서 1을 return 합니다. + +------------------------------------------------------------------------------------------------------------------------------------------------------------------""" + +def solution(board): + answer = -1 + return answer \ No newline at end of file diff --git a/03151_minsuje/hw/week6(p)/test1.py b/03151_minsuje/hw/week6(p)/test1.py new file mode 100644 index 0000000..9b828a8 --- /dev/null +++ b/03151_minsuje/hw/week6(p)/test1.py @@ -0,0 +1,13 @@ +import pandas as pd + +def data_conversion(reports): + a =[] + b =[] + for report in reports: + a = list(set(report.split())) + b.append(a) + return(b) +id_list = ["muzi", "frodo", "apeach", "neo"] +report = ["muzi frodo muzi","apeach frodo","frodo neo","muzi neo","apeach muzi"] +report_data = pd.DataFrame(index=id_list,columns=data_conversion(report)) +print(report_data) \ No newline at end of file