<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>TraceofLight</title><description>게임 개발, 그래픽스 프로그래밍, 데이터베이스 엔지니어링을 기록하는 TraceofLight의 기술 아카이브입니다.</description><link>https://www.traceoflight.dev/</link><language>ko</language><atom:link href="https://www.traceoflight.dev/ko/rss.xml" rel="self" type="application/rss+xml"/><lastBuildDate>Wed, 06 May 2026 01:18:04 GMT</lastBuildDate><item><title>Unity Roadshow 2026 배운 내용 정리</title><link>https://www.traceoflight.dev/ko/blog/unity-roadshow-2026/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/unity-roadshow-2026/</guid><description>Unity Roadshow 행사 가서 배운 내용들 간단 기록</description><pubDate>Sun, 19 Apr 2026 13:17:51 GMT</pubDate><content:encoded>&lt;h2&gt;메모리 사전 지식&lt;/h2&gt;
&lt;h3&gt;기본 내용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;우리는 가상 메모리 (Virtual Memory, 이하 VM) 를 사용하며, 물리 메모리를 직접적으로 컨트롤하지 않는다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VM은 페이지로 구성되어 있으며, OS마다 상이할 수 있음&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Window / Linux 4kb&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IOS, MacOS, Android 16kb&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;페이지에 대응하는 물리 메모리의 프레임 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메모리 압박 수준에 따라서 가상 메모리를 물리 메모리에 병합한다&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Page Fault&lt;/h3&gt;
&lt;p&gt;물리 메모리에 로드되지 않은 페이지가 필요한 경우를 Page Fault라고 함&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Clean Page: 원본 데이터가 변하지 않은 Page, OS에서 언제든 해지할 수 있고 회수가 쉬움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dirty Page: 응용 프로그램이 새로 작성하거나 수정한 정보를 가진 페이지, 메모리에서 바로 내릴 수 없다&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Memory Footprint&lt;/p&gt;
&lt;p&gt;실질적인 메모리 압박을 표현하는 지표이며, 전체 더티 페이지 크기를 합산한 결과&lt;/p&gt;
&lt;p&gt;Memory Footprint != 물리 메모리 사용량, 상주 메모리 사용량&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;메모리 관리법 (Windows vs Linux)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;예약: 물리 메모리를 사용하지 않고 가상 메모리만 할당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;커밋: 실제 가상 메모리만큼의 물리 프레임을 할당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;디커밋: 예약 공간을 유지하면서 물리 프레임을 해제하는 것&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Windows: 명시적인 API 제공 (virtual alloc, virtual free)&lt;/p&gt;
&lt;p&gt;UNIX Like: 예약과 커밋이 명시적 분리가 없음&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;mmap 호출은 암시적으로 메모리를 예약한다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;페이지 바로 접근 시 지연 커밋이 발생&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;명시적 API 없으며, 디커밋은 힌트로 동작한다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OS가 언제 페이지를 회수할지 결정함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Unity GC에서의 처리&lt;/h2&gt;
&lt;h3&gt;Managed Heap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C# 메모리 할당은 전부 여기서 이루어짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Garbage Collector 가 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Unity Profiler에서 GC.Alloc으로 표기&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Garbage Collector&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;주기적으로 유효한 참조가 존재하지 않는 Object를 Heap에서 수집&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GC를 수행해도 가상 메모리 총 사용량은 줄어들지 않음&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;수집한 오브젝트 공간도 OS 기준으로는 Dirty&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Segment&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;연속된 페이지들의 모음을 Segment라 정의&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Managed Heap은 Raw Page가 아닌 Segment 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;한 Segment에 여러 Object들이 할당될 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이를 할당하고 푼 뒤, 내부적으로 미사용 중인 상황이 있지만 RAM 사용으로 표기 (Dirty이므로)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;대부분은 전혀 문제가 없고 곧 재사용된다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;너무 오래 비어있는 케이스는 상주 메모리를 낭비하는 것이기 때문에 간헐적으로 Unity GC가 처리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unity GC가 하는 일&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;리맵핑 전략을 사용함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GC가 다수 실행된 뒤, Old Empty Segment들에 대해 Drop 후 같은 크기의 New Segment를 할당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows Remap 전략: Segment 해제 없이 Decommit (명시적 처리가 되기 때문)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UNIX Like Remap 전략: munmap &amp;amp; mmap을 통한 Remap ((Hot Page 효과로 캐시 적중률이 높음)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이를 통해서 상주 메모리를 줄일 수 있다는 장점이 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;GC.Collect 여러 번 실행하면 안되는 이유&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;세그먼트 릴리즈를 강제로 실행하지 말 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Collect 비싸고, 앱 프리징될 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;의도 자체가 오랫동안 비어있는 세그먼트의 디커밋&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;잠깐 빈 세그먼트 디커밋은 의도와 다름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;강제로 디커밋 시 성능 개선은 없고 CPU 비용만 발생&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;어차피 다음 프레임에 재사용되는 세그먼트도 디커밋되는 상황이 유발&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Managed Heap의 VM 사용량은 커지기만 하고 절대 줄지 않음&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Heap은 커지기만 하고 줄어들지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boehm GC의 원래 특징&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;가상 메모리 할당량을 Trim할 이유가 없음&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;큰 가상 메모리 != 큰 물리 메모리 사용량&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;세그먼트 어차피 재사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;게임 오브젝트들 매 프레임 자주 생성 및 파괴됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;오브젝트가 파괴될 때마다 세그먼트를 줄이는 것은 CPU 성능만 낭비됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Unity Boehm GC&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Unity의 Incremental Boehm GC는 보수적인 GC (Conservative GC)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이는 유니티가 과거 작성한 C# 코드를 C++로 변환하는 작업을 지원하는 IL2CPP을 제공하면서주로 사용하게 되었음&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IL2CPP을 통해 다양한 환경에 대한 지원을 가져갈 수 있게 되었으나, C#과 달리 메모리 GC가 자동화되지 않았기 때문에 오픈소스 GC인 Boehm GC를 사용했던 것으로 보임&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;성능보다 안정성이 중심으로, 포인터 &amp;quot;처럼&amp;quot; 보이는 모든 값을 참조로 간주&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GC 도중 오브젝트의 위치를 변경하지 않음 -&amp;gt; 컴팩팅이 없고, 메모리 파편화에 취약&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Compaction에 대해&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;메모리 파편화 해소에 유리한 메모리 압축 작업. 사용하지 않는 공간을 전부 비워내어 재정렬&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;정확한 참조 정보가 필요하기 때문에 보수적인 GC에서는 불가능함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;오브젝트의 위치를 옮기는 데에는 비용이 발생 (Stop The World + 실제 이동)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;CoreCLR GC&lt;/h3&gt;
&lt;p&gt;CoreCLR GC는 Precise GC로 메모리 스택 및 레지스터에 있는 값 중 어떤 것이 레퍼런스인지 정확하게 알고 있는 방식의 GC임&lt;/p&gt;
&lt;p&gt;그리고 .NET 은 CoreCLR을 코어 엔진으로 사용하고 있음 (CLR: Common Language Runtime)&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;CoreCLR이 지원하는 점&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CoreCLR GC&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JIT 컴파일러&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Excecption Control&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;misc...&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 CoreCLR GC (이하 닷넷 GC) 는 세대 기반 메모리 관리 방식을 사용함&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Heap을 3개 세대로 나누어 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0세대: 방금 생성된 새로운 객체 위주, 빈번하고 빠른 GC가 발생 (대부분 여기서 객체가 죽게 됨)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;1세대: 0세대에서 살아남은 객체들이 이동하는 Buffer 역할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2세대: 오랫동안 살아남은 무거운 객체가 존재하는 곳, GC가 이곳을 정리하는 것은 비용 소모가 큰 편&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LOH: 아주 큰 객체는 이 공간으로 배치&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;프로모션 과정에서 메모리 Compaction을 처리하게 되면서 단편화를 줄일 수 있음&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;LOH의 경우 STW가 길어지기 때문에 오래 전에는 Compaction 하지 않았지만 지금은 명시적으로 옵션화해서 처리하고 있다고 함&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;전환의 가치?&lt;/h3&gt;
&lt;p&gt;기본적으로 Unity가 .NET으로 넘어가면서 발생하는 부수 효과로 GC가 바뀌는 것이며, GC가 메인은 아니라는 점을 이야기했음. 그러나 가치를 찾아보자면...&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Compation이 지원 가능하므로, 메모리 파편화가 줄어듬&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GC 비용을 예측 가능하게 만들 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>컨테이너 환경에 대한 간단 메모</title><link>https://www.traceoflight.dev/ko/blog/difference-btw-container-vm/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/difference-btw-container-vm/</guid><description>컨테이너와 VM의 차이 외 기타 배운 점 기록</description><pubDate>Thu, 02 Apr 2026 06:58:20 GMT</pubDate><content:encoded>&lt;h3&gt;&lt;strong&gt;컨테이너 구동 원리&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;호스트 os의 커널을 공유하면서 프로세스처럼 격리하는 방식&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;그렇다면 커널 호환이 안된다면?&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;당연히 실행되지 않는 것이 정상, 그러나 mac, window 등에서 가동이 가능한 이유는 아예 vm layer가 추가되기 때문&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;윈도우에 docker desktop 설치 시 wsl2 설치하라고 하는 이유. MS의 리눅스 VM을 설치해야 해당 레이어 기반 컨테이너 작동이 수월하기 때문으로 보임.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;커널 버전에서 문제가 발생하더라도 크래시가 발생할 수 있음 (버전 차이로 인해 존재하지 않는 기능을 사용 시도하는 등)&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;결론&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;커널 타입 일치해야 하고, 기능 지원에서 문제가 없어야 하며, cpu 아키텍쳐가 일치해야 컨테이너 가동 가능&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;VM&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Hypervisor를 사용한 독립 실행, 커널을 따로 사용함. bare-metal / hosted 방식이 있고, 우리가 쓰는 건 대체로 호스트형, OS 위에 하이퍼바이저가 올라가기 때문에 성능 손실이 있음&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;볼륨 바인딩&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;데이터 영속성을 지키기 위해 사용, 호스트 머신의 특정 디렉토리를 마운팅하는 방식으로 처리됨. 리눅스 네이티브에서는 vfs에 직접 기록하는 방식이며 다른 os들의 경우는 내부 가상 네트워크를 태우는 방식으로 상대적으로 느릴 수 있음.&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;윈도우에서 chmod 무시하는 이유&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;윈도우에서는 ACL (Access Control List) 를 활용한 권한 관리 진행, chmod 방식을 이해하지 못함.&lt;/p&gt;
</content:encoded></item><item><title>크래프톤 정글 게임테크랩 수료 후기</title><link>https://www.traceoflight.dev/ko/blog/jungle-gametech-lab-review/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/jungle-gametech-lab-review/</guid><description>크래프톤 정글 게임테크랩 2기를 수료한 이야기</description><pubDate>Thu, 26 Mar 2026 18:02:12 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;p&gt;일단 수료 이후 속세에서의 삶을 반 년 정도 미뤄뒀다보니, 언제 후기를 적어야 할지를 좀 고민했던 거 같다.&lt;/p&gt;
&lt;p&gt;그래도 일단 기억이 좀 흐릿해지기 전에는 기록해둬야 할 거 같아서 지금 남겨둔다.&lt;/p&gt;
&lt;p&gt;아마 이 글을 보는 사람이라면 한창 고민 중일 것이라 생각해서 상단 미디어에 설명회 다시 보기도 첨부해두었다.&lt;/p&gt;
&lt;h2&gt;입과 전 고민&lt;/h2&gt;
&lt;p&gt;일단 입과를 선뜻 바로 택할 수는 없었다. 2025년 하반기에 뭘 하고 있을지에 대한 플랜이 여럿 있었으니까.&lt;/p&gt;
&lt;p&gt;그럼에도 입과한 이유는 이것들이 대체적으로는 잘 안 풀렸고, 그나마 고를 수 있는 선택지 중에 꽤 괜찮았다고 생각했기 때문이다.&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/240d3d9a-5133-45d9-a584-df6d6f8dc511-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;몇 번의 면접을 보면서 좋은 결과로 이끌어내진 못했다보니, 부족한 경험들을 어떻게 채워야 할지에 대한 고민이 항상 있었다.&lt;/p&gt;
&lt;p&gt;상용화된 리얼 타임 3D 엔진을 만져본 경험이 전무했다보니, 내부 로직은 커녕 전체적인 기능에 대한 설명도 할 수 없었다.&lt;/p&gt;
&lt;p&gt;그렇기 때문에 AI와 싸워가면서 짜낸 지식들을 가지고 면접관 앞에 섰지만, 수박 겉핥기에 불과한 설명만 늘어놓을 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;지금 와서 생각해보면, 해당 답변들을 면접관이 들으면서 어떤 생각을 했을까하는 생각에 굉장히 부끄러운 마음이 든다.&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;당시에 해당 과정을 입과하는 것에 대한 리스크로 2가지 정도를 고려했다.&lt;/p&gt;
&lt;p&gt;앞선 기수가 딱 1기뿐이었고, 수료도 하기 전이라서 어떤 과정인지, 어떤 성과가 있을지 전혀 짐작하지 못하는 상황이었다.&lt;/p&gt;
&lt;p&gt;또한, 2기는 하반기에 진행될 예정이었고, 염두에 두고 있던 게임 회사들은 대체로 하반기에 공채나 채용형 인턴 모집을 진행하다보니 이런 시도를 포기해야 한다는 점도 리스크라고 생각했다.&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;저울질 끝에 입과를 결정했다. 지금 생각해보면 입과에 설명회를 들으러 간 것이 꽤 영향을 미쳤던 것 같다.&lt;/p&gt;
&lt;p&gt;정글 과정 중 게임랩도 있었기 때문에 과정을 들어야 할지, 듣는다면 어떤 과정을 신청해야 할지를 고민하고 있었는데, 설명회를 다녀온 뒤 말끔하게 결심이 섰었다.&lt;/p&gt;
&lt;h2&gt;과정에 대해&lt;/h2&gt;
&lt;p&gt;수료한지 얼마 지나지 않아 어떤 결과로 이어질지는 모르겠으나, 지금까지는 굉장히 만족스러운 경험이었다고 생각하고 있다.&lt;/p&gt;
&lt;p&gt;과정 내에서 어떤 일을 하는지, 어떤 상황에 처하는지는 코치님들의 말씀을 인용하자면 &amp;quot;정글러들의 재미를 반감시킬 수 있기 때문에&amp;quot; 여기에 따로 적진 않을 것이다.&lt;/p&gt;
&lt;p&gt;다만, 테크랩은 쉽지 않은 과정이라고는 단언할 수 있다. 다른 작업의 병행은 거의 불가능할 것이고, 과정 기간 내내 강의실에서 불이 꺼지는 일이 거의 없다.&lt;/p&gt;
&lt;p&gt;이러한 과정 속에서 인상적인 경험 속에 지식이 자리잡게 되고 상용 리얼 타임 3D 엔진에 대한 이해도도 높아지게 된다고 보면 될 것 같다.&lt;/p&gt;
&lt;h2&gt;그래서 어떤 사람이 와야 하는가?&lt;/h2&gt;
&lt;p&gt;설명회 내용을 가져와서 보는 게 제일 직관적일 거 같다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/2572851e-3357-4318-803f-1cac3e951f91-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이것들에 대해서 좀 더 잘 알고 싶은 사람들이라면 와야 한다고 생각한다. 이것들에 대한 이해도가 많이 늘게 된다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/b21999e7-643c-4d5f-bfbf-f3c801e197f3-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이건 안 다룬다고 했지만, 사실 여기서 그래픽스와 개발환경 일부에 대해서 궁금한 사람들은 테크랩 수강을 고민해볼 필요가 있다.&lt;/p&gt;
&lt;p&gt;수강하고 나면 사람에 따라 편차는 있지만 최소한 저것들에 대해 풍월을 읊으면서 간단한 티키타카 정도는 나눌 수 있는 사람이 된다.&lt;/p&gt;
&lt;h2&gt;마무리 소회&lt;/h2&gt;
&lt;p&gt;이제 모든 과정을 마무리하고 난 시점에선 굉장히 후련한 것도 사실이지만, 워낙 짧은 기간에 많은 경험을 하기 때문에 앞으로 정리해야 할 부분들도 많다.&lt;/p&gt;
&lt;p&gt;하지만 그것들을 모두 자신의 몫으로 소화하고 나면, 조금 더 성장한 개발자가 되어 있으리라 생각한다.&lt;/p&gt;
&lt;p&gt;AI 발전에 따른 업계 인력 축소 이야기도 계속 있지만 내가 할 수 있는 일을 하려고 한다.&lt;/p&gt;
&lt;p&gt;성장 가스라이팅이라는 이야기도 최근 많이 나오고 있는 상황이지만, 분명히 주변에서 계속 성장한 사람들에게 좋은 결과가 나타나는 것을 눈으로 보고 있기 때문에 아마도 한동안은 동력을 유지할 수 있을 거 같다.&lt;/p&gt;
</content:encoded></item><item><title>Windows / MacOS 통합 터미널 환경 구축</title><link>https://www.traceoflight.dev/ko/blog/cross-platform-terminal-setting/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/cross-platform-terminal-setting/</guid><description>Windows와 MacOS에서 전부 동작하는 크로스플랫폼 터미널 환경 구축 과정</description><pubDate>Thu, 26 Mar 2026 12:18:01 GMT</pubDate><content:encoded>&lt;h2&gt;들어가며&lt;/h2&gt;
&lt;br /&gt;
&lt;p&gt;최근에 맥북 에어를 업그레이드한 것으로 인해 환경을 다시 세팅할 필요성이 느껴졌다.&lt;/p&gt;
&lt;p&gt;m1 -&amp;gt; m5 성능적인 변화가 만족스럽긴 한데 기존에 사용하던 환경을 다시 맞춰주려고 하니까 손이 많이 가는 것을 확인했고, 이번 기회에 전체 과정을 문서화해서 편하게 다시 세팅할 수 있도록 규격화하고자 했다.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://blog.dnd.ac/settings-mac-terminal-2026/&quot;&gt;2026 Mac 터미널 완벽 세팅 (Ghostty + Starship + AI 코딩 환경)&lt;/a&gt;&lt;/h3&gt;
&lt;br /&gt;
&lt;p&gt;그 과정에서 인상깊게 본 문서는 해당 링크의 자료였는데, 깔끔하고 멋지게 잘 세팅해 둔 환경을 스크립트 자료로 남겨두셔서 많은 도움을 받았다.&lt;/p&gt;
&lt;p&gt;결론부터 이야기하자면 아래와 같은 형태로 터미널 환경을 구축할 수 있었다.&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;https://traceoflight.dev/media/image/f0670bf2-9240-4320-ad5e-6367803485d2-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;br /&gt;
&lt;p&gt;내부적으로는 Wezterm + Nushell + LazyVim를 큰 틀로 세팅하고 있다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.github.com/TraceofLight/global-terminal-settings&quot;&gt;Github 링크&lt;/a&gt; 에서 세팅 전체 가이드를 확인할 수 있고, 해당 가이드를 통해 Windows, MacOS에 동일한 환경을 구축할 수 있도록 만들어 두었다.&lt;/p&gt;
&lt;h2&gt;목표 설정&lt;/h2&gt;
&lt;br /&gt;
&lt;p&gt;해당 작업의 목표는 명확했는데&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Windows / MacOS에서 동일한 터미널 환경을 사용할 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LazyVim 기반의 편집기와 문제 없이 잘 작동할 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;기존 사용 환경과 크게 다르지 않을 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tmux와 같은 멀티플렉서 툴을 사용하기에 어려움이 없을 것&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;p&gt;이와 같은 목표를 달성하기 위해 작업을 진행해 보았다.&lt;/p&gt;
&lt;h2&gt;진행 과정&lt;/h2&gt;
&lt;br /&gt;
&lt;p&gt;일단 사용할 기술을 선택해야 했다. 일단 터미널 에뮬레이터는 GPU 가속 렌더링이 가능한 GUI를 가진 툴들이 요즘 트렌드고 실제로 이런 툴들이 각광받는 이유가 빠르고 데코레이션이 가능하다는 점 때문인데, 위에 안내한 링크처럼 터미널을 구축하기 위해서는 이런 요소가 필요했기 때문에 그들 중 Wezterm을 선택하게 되었다.&lt;/p&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Terminal Emulator&lt;/p&gt;
&lt;p&gt;일단 크로스플랫폼에서 동일한 UX를 제공해야 했기 때문에 생태계가 구축된 크로스플랫폼 터미널 에뮬레이터로는 Alacritty, Wezterm 정도가 있다고 생각했고, 미니멀함을 추구하는 알라크리티는 확장성이 부족하다고 느껴져서 Wezterm을 선택하게 되었다. 멀티플렉서를 탑재하고 있다는 점도 메리트 중 하나.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Shell&lt;/p&gt;
&lt;p&gt;양쪽에서 동일한 사용감을 보장해야 했기 때문에 일단 unix 명령어를 사용할 수 있는 환경으로 통합하고자 했고, 그 결과 윈도우에서는 bash, 맥OS에서는 zsh를 사용하기로 초기에 결정을 했었다. 그러나 몇 가지 문제가 있었고 결국 최종안으로는 Nushell 기반으로 통합하게 되었다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;LazyVim&lt;/p&gt;
&lt;p&gt;사실 이쪽은 이미 사용하던 툴들이 있었고, 문제 없이 대부분 환경에서 통합되었기 때문에 어렵지 않았다. 원래 SpaceVim을 사용했었지만, 이쪽은 이미 &lt;a href=&quot;https://wsdjeg.net/why-spacevim-is-archived/&quot;&gt;유지보수가 중단된 상황&lt;/a&gt;이었기 때문에 LazyVim으로 넘어온지 어느 정도 시간이 지난 데에다가 기본적으로는 IDE를 사용하고 있고, 부수적인 툴로 사용하기 때문에 스무스하게 설치가 진행되었던 것 같다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;문제 봉착&lt;/h2&gt;
&lt;p&gt;이 과정에서 몇 가지 문제가 존재했는데, 두 문제가 모두 nushell로 넘어간 것과 연관이 되어 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;윈도우에서는 bash가 체감이 될 정도로 너무 느림&lt;/p&gt;
&lt;p&gt;사실 이는 나중에 확인해보니 예정된 결말이었던 것 같다. 윈도우 환경 하에서는 POSIX 식 동작을 Windows에서 처리하기 위해 호환성 동작이 추가 레이어로 들어간다는 점을 확인할 수 있었다. 그래서 실제로 wsl2 환경으로 놓는 것도 고려했으나, 그건 결국 리눅스를 사용하는 것과 다르지 않기 때문에 배제했다.&lt;/p&gt;
&lt;p&gt;-&amp;gt; 이 문제를 해결하기 위한 tool로 nushell을 도입하게 되었다. unix 명령어와 호환되는 부분이 많다는 점, rust 기반으로 설계되어 어느 정도 성능도 보장되어 있다는 점, MacOS에도 동일한 환경 세팅이 가능하다는 점을 고려하였다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Windows의 nushell에서 navi 플러그인이 작동하지 않음&lt;/p&gt;
&lt;p&gt;navi는 터미널 명령어 치트시트 참고용 플러그인이다. 그렇게 활용하는 빈도는 많지 않지만 해당 툴의 기능이 아예 동작하지 않으면 곤란했기 때문에 여러 방법을 고민해봤다. 결국 navi를 포크해서 해당 문제를 해결한 뒤, 새로 빌드한 플러그인을 사용하는 것으로 조치했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;원인: 사용자 shell이 변경되어도, 내부에서는 bash 기반의 문법을 적용하게 되어 nushell 사용 시에 깨지는 상황&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;해결: 해당 부분을 shellscript를 통한 명령어로 처리하는 대신, 관련 의존성을 제거하기 위해 wget을 사용해야 하는 부분에서 rust http client를 사용하고, bash 사용해야 할 부분에서 pwsh를 사용하는 등 내부 helper가 bash에 의존하는 부분을 제거&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/TraceofLight/navi/tree/fix/nushell-usability&quot;&gt;세부 수정 내역&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;결론&lt;/h2&gt;
&lt;p&gt;개발자는 터미널을 사용할 일이 꽤 있고, 환경이 하나로 통합되면 사용하기 편한 건 당연한 일이다. 그렇기에 크로스플랫폼과 동일한 사용성을 지원하는 Jetbrains의 IDE들이 메리트가 있는 것 아닐까? 마찬가지로 터미널에 있어서도 본인이 추구하는 바가 다양한 환경에서 통일된 사용감을 유지하는 거라면 이런 방식을 사용해보는 것도 괜찮은 것 같다.&lt;/p&gt;
</content:encoded></item><item><title>std::variant &amp; std::visit</title><link>https://www.traceoflight.dev/ko/blog/variant-and-visit/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/variant-and-visit/</guid><description>c++17에 추가된 variant와 visit에 관한 내용 정리</description><pubDate>Mon, 28 Jul 2025 14:13:37 GMT</pubDate><content:encoded>&lt;h3&gt;기타 정보&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0088r3.html&quot;&gt;관련 문서&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;위 링크에 C++17부터 추가된 Variant와 왜 추가되었는지에 대한 내용이 있는데 간단하게 언급하자면 std::optional로 추가되었어야 할 내용을 boost에서 너무 오래 썼기 때문에 이렇게 오래 끌지 말고 빨리 올려버리자는 이야기를 하고 있다.&lt;/p&gt;
&lt;h3&gt;내부 구조&lt;/h3&gt;
&lt;h4&gt;1. Variant&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터 버퍼
템플릿 인자로 주어진 타입들 중 가장 크기가 큰 타입을 저장할 수 있는 충분한 크기의 메모리 공간으로 대체로 Union으로 구현되어 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;판별자
현재 데이터 버퍼에 어떤 타입의 객체가 저장되어 있는지를 나타내는 인덱스 또는 식별자로 이 판별자를 사용하는 것을 통해  std::variant는 타입 안전성을 보장할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;충분한 크기의 메모리 공간을 가지는 것을 통해서 variant 타입은 아래와 같은 행동이 가능하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;
	&lt;span class=&quot;hljs-keyword&quot;&gt;struct&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Tracer&lt;/span&gt;
	{
		std::string name;

		&lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;const&lt;/span&gt; std::string&amp;amp; n) : &lt;span class=&quot;hljs-built_in&quot;&gt;name&lt;/span&gt;(n)
		{
			std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;  [+] &amp;#x27;&amp;quot;&lt;/span&gt; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27; Tracer created (Constructor)\n&amp;quot;&lt;/span&gt;;
		}

		&lt;span class=&quot;hljs-comment&quot;&gt;// Copy Constructor&lt;/span&gt;
		&lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-type&quot;&gt;const&lt;/span&gt; Tracer&amp;amp; other) : &lt;span class=&quot;hljs-built_in&quot;&gt;name&lt;/span&gt;(other.name)
		{
			std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;  [*] &amp;#x27;&amp;quot;&lt;/span&gt; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27; Tracer copy-constructed (Copy Constructor)\n&amp;quot;&lt;/span&gt;;
		}

		~&lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;()
		{
			std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;  [-] &amp;#x27;&amp;quot;&lt;/span&gt; &amp;lt;&amp;lt; name &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;#x27; Tracer destroyed (Destructor)\n&amp;quot;&lt;/span&gt;;
		}
	};

	&lt;span class=&quot;hljs-comment&quot;&gt;// 1. Initialize the variant with a Tracer type.&lt;/span&gt;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;1. Initializing variant with Tracer(\&amp;quot;Apple\&amp;quot;).\n&amp;quot;&lt;/span&gt;;
	std::variant&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;, Tracer&amp;gt; var = &lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Apple&amp;quot;&lt;/span&gt;);
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;   Variant now holds Tracer(\&amp;quot;Apple\&amp;quot;).\n\n&amp;quot;&lt;/span&gt;;

	&lt;span class=&quot;hljs-comment&quot;&gt;// 2. Assign a value of a different type (int).&lt;/span&gt;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2. Assigning integer 100 to the variant.\n&amp;quot;&lt;/span&gt;;
	var = &lt;span class=&quot;hljs-number&quot;&gt;100&lt;/span&gt;;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;   Variant now holds integer 100.\n\n&amp;quot;&lt;/span&gt;;

	&lt;span class=&quot;hljs-comment&quot;&gt;// 3. Assign another Tracer type value again.&lt;/span&gt;
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;3. Assigning Tracer(\&amp;quot;Banana\&amp;quot;) to the variant.\n&amp;quot;&lt;/span&gt;;
	var = &lt;span class=&quot;hljs-built_in&quot;&gt;Tracer&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Banana&amp;quot;&lt;/span&gt;);
	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;   Variant now holds Tracer(\&amp;quot;Banana\&amp;quot;).\n\n&amp;quot;&lt;/span&gt;;

	std::cout &amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;4. main function is about to end.\n&amp;quot;&lt;/span&gt;;
	&lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이와 같은 코드를 실행시키면 아래와 같은 결과를 얻는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1. Initializing variant with Tracer(&amp;quot;Apple&amp;quot;).
  [+] &amp;#x27;Apple&amp;#x27; Tracer created (Constructor)
  [*] &amp;#x27;Apple&amp;#x27; Tracer copy-constructed (Copy Constructor)
  [-] &amp;#x27;Apple&amp;#x27; Tracer destroyed (Destructor)
   Variant now holds Tracer(&amp;quot;Apple&amp;quot;).

2. Assigning integer 100 to the variant.
  [-] &amp;#x27;Apple&amp;#x27; Tracer destroyed (Destructor)
   Variant now holds integer 100.

3. Assigning Tracer(&amp;quot;Banana&amp;quot;) to the variant.
  [+] &amp;#x27;Banana&amp;#x27; Tracer created (Constructor)
  [*] &amp;#x27;Banana&amp;#x27; Tracer copy-constructed (Copy Constructor)
  [-] &amp;#x27;Banana&amp;#x27; Tracer destroyed (Destructor)
   Variant now holds Tracer(&amp;quot;Banana&amp;quot;).

4. main function is about to end.
  [-] &amp;#x27;Banana&amp;#x27; Tracer destroyed (Destructor)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기존에 있던 값에 대한 소멸자가 먼저 호출되고, 스택에 임시 객체를 생성한 뒤 복사 생성한 값을 본인 메모리 버퍼로 가져오는 순서를 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;따라서, 가장 큰 크기의 클래스를 저장할 공간을 내부적으로 유니온으로 보유하게 되면 variant type이 어떤 게 들어오던지 문제 없이 사용이 가능하게 만들 수 있다!&lt;/p&gt;
&lt;h4&gt;2. Visit&lt;/h4&gt;
&lt;p&gt;이건 라이브러리마다 다르지만,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;함수 포인터 테이블&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch 문&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;크게 2가지 형태로 구분된다고 한다. 사실 구현 방식과 오버헤드, 컴파일러 최적화에 약간의 차이만 있을 뿐, 기본적으로 판별자를 보고 활성화된 Type에 따라 적절한 함수를 호출할 수 있도록 구현되어 있다고 보면 될 것 같다.&lt;/p&gt;
</content:encoded></item><item><title>[종만북] 02. 문제 해결 전략</title><link>https://www.traceoflight.dev/ko/blog/jongmanbook02/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/jongmanbook02/</guid><description>알고리즘 문제 해결 전략 2장의 내용 정리</description><pubDate>Wed, 18 Dec 2024 04:27:16 GMT</pubDate><content:encoded>&lt;h2&gt;문제 해결 과정&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;문제를 읽고 이해한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;문제를 익숙한 용어로 재정의한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;어떻게 풀지 계획을 세운다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;계획을 검증한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프로그램으로 구현한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;어떻게 풀었는지 돌아보고, 개선할 방법이 있는지 찾아본다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;1) 문제를 읽고 이해하기&lt;/h3&gt;
&lt;p&gt;문제를 잘못 읽는 실수를 범하지 않도록, 문제를 공격적으로 읽으면서 문제가 원하는 바를 완전히 이해하려는 노력이 필요하다. 사소한 제약 조건을 놓치게 되는 경우 풀 수 없게 되는 경우도 많으며, 대회에서는 작은 실수도 용납하지 않는 경우가 대부분이기 때문이다.&lt;/p&gt;
&lt;h3&gt;2) 재정의와 추상화&lt;/h3&gt;
&lt;p&gt;자신이 다루기 쉬운 개념을 사용하여, 문제를 자신의 언어로 풀어쓰는 것, 문제가 요구하는 바를 직관적으로 이해하기 위해서 필요한 과정이며 복잡한 과정일수록 더욱 중요하다.
문제의 본질을 어떤 방식으로 재구성하느냐에 따라서 같은 일을 하는 프로그램이라도 전혀 다르게 받아들여질 수 있다.
어려운 문제를 쉽게, 쉬운 문제를 어렵게 풀 수 있기 때문에 추상화가 프로그램이 나아갈 방향을 결정한다고 볼 수 있음&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;추상화: 현실세계의 개념을 우리가 다루기 쉬운 수학적 / 전산학적 개념으로 옮겨 표현하는 과정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3) 계획 세우기&lt;/h3&gt;
&lt;p&gt;문제를 어떤 식으로 해결할지 결정하고, 사용할 알고리즘과 자료구조를 선택하는 과정. 가장 중요한 과정이라고 할 수 있으며, 문제를 보고 바로 해결 방법이 떠오르지 않는 경우,  이 과정에서 가장 많은 고민을 하게 됨.&lt;/p&gt;
&lt;h3&gt;4) 계획 검증하기&lt;/h3&gt;
&lt;p&gt;구현을 시작하기 전에 계획을 검증하는 단계를 거쳐야 함. 이 과정에서 우리가 설계한 알고리즘이 모든 경우에 대해 요구 조건을 정확히 수행하는지 증명하고, 수행에 걸리는 시간과 사용하는 메모리가 문제의 제한 내에 들어가는지 확인해야 한다.&lt;/p&gt;
&lt;h3&gt;5) 계획 수행하기&lt;/h3&gt;
&lt;p&gt;구현에 있어서는 효율성과 정확성을 항상 챙길 것.&lt;/p&gt;
&lt;h3&gt;6) 회고하기&lt;/h3&gt;
&lt;p&gt;당장 직접적인 영향은 없지만 장기적으로 가장 큰 영향을 미치는 단계.
한 번 풀어봤던 문제를 다시 풀어보는 경우에 더 효율적인 알고리즘을 찾거나 간결한 코드의 작성이 가능해지기도 하며, 같은 알고리즘을 유도할 수 있는 더 직관적인 방법을 찾아낼 수도 있다.
효과적으로 회고를 수행하는 방법으로는 문제를 풀 때마다 자신의 경험을 기록으로 남기는 것이 제일 유효하다고 본다.&lt;/p&gt;
&lt;p&gt;접근 방식, 결정적인 깨달음, 오답 원인 등을 기록하는 것으로 실수를 줄이고 패턴화에 도움을 줄 수 있기도 함. 해결한 다른 사람의 코드를 확인하는 것으로 생각치 못했던 통찰을 얻을 수도 있음&lt;/p&gt;
&lt;p&gt;해결하지 못했을 경우에도 일정 시간이 지나면 다른 사람의 코드나 풀이를 참조하되 반드시 복기를 동반할 것&lt;/p&gt;
&lt;h2&gt;문제 해결 전략&lt;/h2&gt;
&lt;h3&gt;1) 직관과 체계적인 접근&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;비슷한 문제를 풀어본 적이 있는가?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;단순하게 풀어본 경험이 아닌 원리의 이해와 변형이 가능해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;단순한 방법에서 시작할 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;무식하게 풀 수 있을까? 에서 시작하는 가장 단순한 알고리즘을 만들고 최적화를 통해 구현하는 방식도 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;알고리즘 효율성의 기준선을 정할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;내가 문제를 푸는 과정을 수식화할 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;문제에 주어진 예제 등을 해결하면서 공식화&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;문제를 단순화할 수 없을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;주어진 문제의 좀 더 쉬운 변형판을 먼저 풀어보는 것&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;그림으로 그려볼 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;기하학적 도형이 더 직관적으로 받아들이기 좋음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;수식으로 표현할 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;평문 → 수식이 문제를 해결하는 데에 도움을 줄 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;문제를 분해할 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;더 다루기 쉬운 형태로 문제를 변형하는 방법 중에서 제약 조건을 분해하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;뒤에서부터 생각해서 문제를 풀 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;전형적인 예시: 사다리 게임&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;앞에서 모든 경로를 시도하는 것보다 도착지에서부터 역으로 타고 올라가는 것으로 횟수 줄이기 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;순서를 강제할 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;순서가 없는 문제에 순서를 강제하는 방식&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;예시: 하나의 변수에 대해 변형을 하거나, 하지 않거나 2가지 경우만 존재 / 순서가 상관이 없음 → 순서대로 변형할지 말지만 결정하는 케이스&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;특정 형태의 답만을 고려할 수 있을까?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;정규화 기법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;여러 가지 답들 중 형태가 다르지만 결과적으로는 동일한 것들을 그룹으로 묶고, 그룹 대표들만을 고려하는 방법&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[Effective C++] item 02</title><link>https://www.traceoflight.dev/ko/blog/effective-cpp-02/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/effective-cpp-02/</guid><description>#define을 쓰려거든 const, enum, inline을 떠올리자</description><pubDate>Tue, 12 Mar 2024 14:40:14 GMT</pubDate><content:encoded>&lt;h3&gt;#define보다 Const, Enum, Inline을 더 선호&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;전처리보다 컴파일러를 선호한다는 표현&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;#define FOO 1.024&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;위 케이스는 컴파일 전에 해당 문자열을 치환하는 전처리기&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;위의 FOO라는 심볼릭의 존재를 컴파일러가 알지 못한 채로 제거될 수 있어서 오류에도 상수로 표기될 수 있음, 따라서 이와 관련된 버그가 발생할 경우, 추적하는 데에 시간을 낭비하게 될 것&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;const double FOO = 1.024;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;해결책은 매크로를 상수로 대체하는 것이다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;위 상수는 컴파일러에서 확실히 관측할 수 있고 심볼 테이블에도 확실하게 입력된다. 또한, 전처리기를 통해 일괄적으로 대체된 경우 해당 객체의 복사본이 여럿 생성될 수 있지만 상수의 경우는 복사본이 하나 이상 생성되지 않는다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[Effective C++] item 01</title><link>https://www.traceoflight.dev/ko/blog/effective-cpp-01/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/effective-cpp-01/</guid><description>C++를 언어들의 연합체로 바라보는 안목은 필수</description><pubDate>Tue, 12 Mar 2024 14:01:04 GMT</pubDate><content:encoded>&lt;h3&gt;C++은 멀티 패러다임 프로그래밍 언어&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;처음에는 객체지향 기능이 추가된 C에서 시작&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;현재 절차형, 객체 지향형, 함수형, 제네릭, 메타 프로그래밍까지 지원&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;제네릭 프로그래밍: 데이터 형식에 구애받지 않도록, 하나의 값이 다양한 데이터 타입을 가질 수 있는 방향으로 재사용성을 극대화하는 프로그래밍 패러다임&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메타 프로그래밍: 자기 자신 혹은 다른 프로그램을 데이터로 취급하며 프로그램을 작성, 수정하는 것, 런타임에 수행해야 하는 작업의 일부를 컴파일 타임 동안 수행하는 방식을 말하기도 함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C++을 단일 언어가 아닌 언어의 연합으로 볼 필요가 있으며 각각의 룰에 맞춰줄  필요가 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C: 다양한 것들이 C에서 유래했으나 C++에서 더 좋은 접근방식을 제공하는 경우가 많아 좀 더 제한적이고 안전한 범위로 사용할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;객체지향 C++: 클래스가 존재하는 C++의 핵심, 객체 지향 설계가 가장 직접적으로 작용하는 부분&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Template C++: 자주 경험하는 부분은 아니며, 주류 C++ 과 거의 상호작용하지 않는다. TMP라는 강력한 패러다임을 탄생시킨 바가 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;STL: Template 라이브러리이지만 매우 특별한 케이스, STL을 사용할 때는 특정한 방식이 존재하며 반드시 그 규칙을 따라야만 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;위 하위 언어들 간의 전환이 발생한다면 전략을 변경하는 상황을 직면할 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;단일 규칙이 아닌 각기 고유 규칙을 보유한 하위 언어의 집합체라는 것을 이해한다면 C++이 더욱 알기 쉬울 것&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[Effective C++] 들어가며</title><link>https://www.traceoflight.dev/ko/blog/effective-cpp-00/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/effective-cpp-00/</guid><description>Effective C++ 공부를 시작하는 이야기</description><pubDate>Tue, 12 Mar 2024 12:45:19 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-fb3d40db998200c1-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;정말 오랜만에 스터디 관련 글을 올려보는 거 같다.&lt;/p&gt;
&lt;p&gt;모두 글로 다 옮겨적진 않았지만 현재 합격 후기를 적었던 회사와 비교하고 좀 더 괜찮을 거라고 생각한 회사에서 시스템 개발 쪽을 맡아서 진행하고 있다.&lt;/p&gt;
&lt;p&gt;사내에서 이 책에 대한 스터디 이야기가 나와서 공부하는 김에 기존에 사용하던 플랫폼을 활용해보는 것도 좋겠다고 생각했고 이에 따라 꾸준히 글을 남겨보려고 한다. 이 책에 대해 학습하는 것으로 좀 더 업무를 잘 해나가고 싶은데 아직까진 요원한 일인 거 같아 마음이 좀 쓰리다..&lt;/p&gt;
&lt;p&gt;글은 1개의 아이템마다 하나씩 정리해서 남겨둘 생각이다. 화이팅!&lt;/p&gt;
</content:encoded></item><item><title>42Seoul 라피신 후기</title><link>https://www.traceoflight.dev/ko/blog/42seoul-la-piscine/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/42seoul-la-piscine/</guid><description>42서울 라피신 10기 1차 과정에 참가한 후기</description><pubDate>Sat, 23 Sep 2023 17:19:05 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;취준을 진행하면서 올해 중순에 SSAFY가 종료를 앞두고 있던 시점, 혹시 준비하는 기간이 더 길어질까 우려하여 기업에 원서를 작성하는 동시에 다양한 부트캠프, 교육 과정에 대해서 알아보는 시간을 가졌었다.&lt;/p&gt;
&lt;p&gt;그 결과, 나에게 가장 잘 맞는 교육 과정은 42Seoul이라고 생각하여 지원을 하게 되었다.&lt;/p&gt;
&lt;p&gt;이유라면 여러 가지가 있었겠지만 그 중에서는 타 부트캠프 과정 대비 자율적인 학습 및 시간적인 유연성, 상대적으로 Low-Level의 언어를 다룬다는 점이 매력적으로 다가왔다.&lt;/p&gt;
&lt;h3&gt;라피신 과정 진행&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-1b1c639d3d343b20-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;체크인과 라피신을 성공적으로 신청한 뒤에 라피신 과정을 기다리던 도중, 몇몇 기업에 최종 합격 발표를 받게 되었다. 원래 과정 포기를 진행하려고 했지만, 현업에 있는 42 카뎃들의 이야기나 42 교육 과정을 고려했을 때 충분히 병행 가능하다고 판단하여, 초반에는 전력으로 진행하고 그 뒤에는 직장과 병행으로 진행하였다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-7a35603c5af347f5-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;42 과정에 관해서 알아본 사람들은 어느 정도 알고 있겠지만, 입과 진행 전에 라피신이라고 불리는 프리코스 과정이 있다. 이 과정이 상당히 혹독한 편인데..&lt;/p&gt;
&lt;p&gt;아마 베이스가 없는 비전공자라면 따라가기도 벅찰 것이고, 어느 정도 프로그래밍 지식이 있는 비전공자라면 열심히 한다면 소기의 성과를 거둘 것이라 생각한다. 전공자의 경우라면 다른 이유로 과정에 집중을 못했거나, 억까를 당하지 않는다면 본 과정 입과는 어렵지 않았을 것이라고 보고 있다.&lt;/p&gt;
&lt;p&gt;개인적인 생각이지만 42에서 진행하는 교육은 대학 과정과 유사성이 상당한지라 오히려 비전공자에게 더 좋을 수 있다고 생각한다. 대학에서 이미 관련 교육을 충실하게 수행했다면 전공자에게는 42에서 주는 지원금 + 기타 제도들을 제외하면 이점이 타 부트캠프에 비해 상대적으로 부족해보였다.&lt;/p&gt;
&lt;p&gt;본인이 입과를 고려하게 된 이유에는 지원금과 별개로 전공 지식의 부재를 채워줄 수 있는 좋은 교육 과정이라고 생각했기 때문이며 그러한 대전제가 취업을 했다고 해서 달라지지 않았기 때문에 라피신 과정을 끝까지 완주할 수 있었다.&lt;/p&gt;
&lt;p&gt;(당연하게도 취업 이후로는 지원금을 받을 수 없다..)&lt;/p&gt;
&lt;h3&gt;결과&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-881466acbebffd64-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;다행히도 좋은 결과를 얻어 이번 42Seoul 10기로 본 과정을 진행할 수 있게 되었다. 현재 회사에서 맡고 있는 직무와 비슷한 기술 스택을 사용하기 때문에 양쪽으로 좋은 선순환을 일으킬 수 있을 거 같아 기대가 된다.&lt;/p&gt;
&lt;h3&gt;Q &amp;amp; A&lt;/h3&gt;
&lt;p&gt;일반적으로 적당히 나올 수 있는 과정에 대한 질문을 답변해보자면,&lt;/p&gt;
&lt;h4&gt;1. 노 베이스 비전공자 합격 가능?&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;초기 기수는 몰라도 재도전이 가능해졌고, 정보가 많이 노출된 지금 시점에는 불가능에 가까움&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;2. 어떤 사람에게 해당 과정을 추천하고 싶은가?&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;아직 학부에 있을 기간이 많이 남은 전공생, 취업을 고려치 않고 기간을 길게 잡고 기반 지식을 쌓고자 하는 비전공자.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;3. 오기 전에 알면 좋은 것들?&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;C 언어의 기초적인 개념과 접했을 때 바로 이해가 어려울 수 있는 포인터 등 많이 알수록 좋음, 다들 Shell 사용법에 대해서 강조를 하는데 거기에 Git 사용법을 숙지하라는 조언을 추가적으로 더하고 싶다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;4. 과정 진행하면서 꼭 해보라고 하고 싶은 것?&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;개인적으로 첫 Rush 팀원들이 너무 좋은 사람들이었고, 끝까지 그 분들과 완주한 입장에서 다른 사람들과의 교류가 꼭 필요한 것은 아니지만 기회가 온다면 놓치지 않고 어울려주길.. 개발자는 코딩 못지 않게 커뮤니케이션 능력도 중요하다!&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[간단 용어 정리] File System</title><link>https://www.traceoflight.dev/ko/blog/file-system/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/file-system/</guid><description>File System 관련 업무에서 사용하는 용어 정리</description><pubDate>Thu, 14 Sep 2023 14:36:39 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;현재 맡은 업무에서 기반 용어들에 대해 지식이 조금 부족하다는 것을 느껴서 내친 김에 알고 있던 용어들까지 추가로 조사하여 간략하게 따로 정리해보는 시간을 갖기로 했다.&lt;/p&gt;
&lt;h3&gt;File Descriptor&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;리눅스, 유닉스 계열 시스템에서&lt;/li&gt;
&lt;li&gt;Process가 File을 다룰 때 사용하는 값의 일종&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;프로세스가 파일을 오픈할 때 커널이 해당 프로세서의 파일 디스크립터 숫자 중, 사용하지 않는 가장 작은 값을 할당하면, 이후 오픈된 파일에 시스템 콜을 사용하여 접근할 시, 디스크립터 값을 활용하여 파일을 지칭할 수 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;기본 할당 디스크립터&lt;/h4&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;표준 입력 (Standard Input)&lt;/li&gt;
&lt;li&gt;표준 출력 (Standard Output)&lt;/li&gt;
&lt;li&gt;표준 에러 (Standard Error)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Inode&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Index Node의 줄임말, 파일을 빠르게 찾기 위한 노드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;inode는 리눅스의 모든 파일에 인덱스를 부여하고 해당 파일에 대한 메타데이터를 보유하고 있는 노드이다. list 명령어를 통해 출력하는 메타데이터를 inode에서 보유하고 있다.&lt;/p&gt;
&lt;h3&gt;Symbolic Link&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;원본 파일의 inode를 가리키는 정보를 가진 파일&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;내부적으로 파일 접근은 inode 번호를 통해 액세스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;원본 파일에 대한 정보를 가지고 있지 않은 새로운 inode를 가짐&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;cf) Hard Link&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;새로운 inode를 가진 파일이 아닌 inode만 그대로 복사한 파일&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;진짜 복사와의 차이점은 data 기록이 복사와 달리 추가적으로 발생하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Block Device &amp;amp; Character Device&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터 전송 방식의 차이로 디바이스 분류&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Block: 블록이나 섹터 등의 정량 단위로 데이터 전송, IO 전송 속도가 빠름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Character: Byte 단위로 데이터 전송, IO 전송 속도가 다소 느릴 수 있지만 Application단에서 Buffering 제어를 통한 성능 차이가 존재&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Raw Device&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;파일 시스템이 set up 되지 않은 장치&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;OS 커널에 의해 버퍼링 되지 않으며, Device로부터 Data 직접 전송, 자체적인 캐싱 시스템을 가진 경우 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Disk IO 성능이 좋고, CPU 오버헤드가 적다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OS 파일 시스템 오버헤드를 피할 수 있고 OS 버퍼 사이즈를 줄일 수 있음.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;shared disk의 경우 시스템에 구성하면 동시 access가 불가능하여 raw device로 사용.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;IO Scheduler&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;디스크 I/O를 효율적으로 하기 위해 요청을 정렬, 병합하고 처리 순서를 결정하는 시스템의 일부.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;탐색 시간이 비싸서 같은 위치에 대한 요청을 병합하는 것이 효과적인 HDD와 같은 디바이스에 특히 유용하며 SSD에서는 효과가 반감된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;종류&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;noop: no-operation, 성능이 뛰어난 디스크에 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;cfq (completely fair queueing): 프로세스마다 IO 대기열 부여하고 최대한 균등하게 예약, 다량의 프로세스가 세세한 IO를 발생시킬 때 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;deadline: 한계점을 기준으로 가까울수록 우선 처리, 지연 시간에 대한 최적화, I/O 전부 균형적으로 처리하며 소수의 프로세스가 다수의 I/O를 발생시키는 환경에 적합&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;anticipacy: 향후 발생될 I/O 요청의 위치를 예측하고 가까운 위치에 존재하는 I/O 요청부터 처리하는 방식, 전통적인 HDD에서 사용하는 구조, 입출력을 모아서 처리하는 성질이 있어 지연 시간이 늘어질 가능성이 존재.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 9519, CPP] 졸려</title><link>https://www.traceoflight.dev/ko/blog/boj9519/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj9519/</guid><description>BOJ 9519, &quot;졸려&quot; 문제의 C++ 풀이</description><pubDate>Mon, 04 Sep 2023 14:32:38 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/9519&quot;&gt;BOJ 9519&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;구현, 문자열, 시뮬레이션&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;이 문제에 대해서는 처음에는 완전 탐색을 통한 풀이를 진행했다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;문자열의 길이를 먼저 측정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0 ~ 문자열의 길이만큼의 숫자 벡터를 할당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;문제 조건에 따라서 반복하여 뒤집기&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;횟수만큼 뒤집은 경우, 해당 해시값을 활용하여 역순 배치&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;원래 모습을 확인할 수 있다!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;여기서 제일 중요한 점은 문제 조건에 따라서 반복해서 뒤집는 것인데 반복해서 뒤집을 경우, 반드시 초기 배열과 동일하게 돌아오는 주기가 돌아온다는 점이 핵심이다.&lt;/p&gt;
&lt;p&gt;위 규칙을 찾은 이후 해당 부분을 세분화를 거치면&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;문자열의 길이를 먼저 측정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;0 ~ 문자열의 길이만큼의 숫자 벡터를 할당&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1회부터 (문자열의 길이 - 1) 회까지 주기를 체크&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전체 뒤집는 횟수를 주기로 나눈만큼 반복하여 해시 도출&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;횟수만큼 뒤집은 경우, 해당 해시값을 활용하여 역순 배치&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;원래 모습을 확인할 수 있다!&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;이렇게 된다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++)
    {
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;; j++)
        {
            temp = result.&lt;span class=&quot;hljs-built_in&quot;&gt;back&lt;/span&gt;();
            result.&lt;span class=&quot;hljs-built_in&quot;&gt;pop_back&lt;/span&gt;();
            result.&lt;span class=&quot;hljs-built_in&quot;&gt;insert&lt;/span&gt;(result.&lt;span class=&quot;hljs-built_in&quot;&gt;begin&lt;/span&gt;() + &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * j + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, temp);
        }

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start_vector == result)
		{
			cycle = i;
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		}
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;처음에는 위와 같이 배열을 직접 움직이는 방식으로 했는데 이렇게 될 경우 insert 이후의 배열이 전부 움직여야 해서 일종의 오버헤드가 발생하는 케이스라 시간이 조금 더 늘어나는 모습을 보였다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++)
    {
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt;();
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(target_length);
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length; j++)
        {
			&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!(j % &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
				temp_vector[j] = result[j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
			&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				temp_vector[j] = result[target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - (j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)];
        }

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start_vector == temp_vector)
		{
			cycle = i;
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		}
		&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
			result = temp_vector;
    }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;따라서 이후에는 위와 같은 방식을 활용해 배열을 미리 만들고, 값을 하나씩 집어넣는 방식을 활용하여 최대 배열의 길이만큼만 시간을 사용하도록 했다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 졸려&lt;/span&gt;

&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;namespace&lt;/span&gt; std;

&lt;span class=&quot;hljs-function&quot;&gt;vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;flicker_action&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; target_length, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; count)&lt;/span&gt;&lt;/span&gt;;

&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;
&lt;/span&gt;{
    ios_base::&lt;span class=&quot;hljs-built_in&quot;&gt;sync_with_stdio&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;);
    cin.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);
    cout.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);

    &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; flicker_number;
    string result_string, init_string;
    vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt;&amp;gt; string_vector;
    vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; idx_vector;

    cin &amp;gt;&amp;gt; flicker_number;
    cin.&lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;();
    &lt;span class=&quot;hljs-built_in&quot;&gt;getline&lt;/span&gt;(cin, result_string);

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;(); i++)
        string_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;push_back&lt;/span&gt;(result_string[i]);
    

    idx_vector = &lt;span class=&quot;hljs-built_in&quot;&gt;flicker_action&lt;/span&gt;(result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;(), flicker_number);
    init_string.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;());

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) result_string.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;(); i++)
        init_string[idx_vector[i]] = result_string[i];

    cout &amp;lt;&amp;lt; init_string &amp;lt;&amp;lt; endl;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;);
}

&lt;span class=&quot;hljs-function&quot;&gt;vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; &lt;span class=&quot;hljs-title&quot;&gt;flicker_action&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; target_length, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; count)&lt;/span&gt;
&lt;/span&gt;{
    vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt; result, temp_vector, start_vector;
	&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; cycle;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; target_length; i++)
        result.&lt;span class=&quot;hljs-built_in&quot;&gt;push_back&lt;/span&gt;(i);

	start_vector = result;
	cycle = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++)
    {
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt;();
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(target_length);
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length; j++)
        {
			&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!(j % &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
				temp_vector[j] = result[j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
			&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				temp_vector[j] = result[target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - (j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)];
        }

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start_vector == temp_vector)
		{
			cycle = i;
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		}
		&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
			result = temp_vector;
    }

	result = start_vector;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (count % cycle); i++)
    {
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;clear&lt;/span&gt;();
		temp_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;resize&lt;/span&gt;(target_length);
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; j = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; target_length; j++)
        {
			&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!(j % &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))
				temp_vector[j] = result[j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
			&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				temp_vector[j] = result[target_length - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; - (j / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)];
        }

		result = temp_vector;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (result);
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 4821, CPP] 페이지 세기</title><link>https://www.traceoflight.dev/ko/blog/boj4821/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj4821/</guid><description>BOJ 4821, &quot;페이지 세기&quot; 문제의 C++ 풀이</description><pubDate>Sat, 26 Aug 2023 15:04:16 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/4821&quot;&gt;BOJ 4821&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;구현, 문자열, 파싱&lt;/p&gt;
&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;최근 입사를 하게 되면서 상당히 바쁜 시간들이 이어지고 있다. 회사에 있다는 것 자체로도 부담을 느끼는 신입이기 때문에.. 한동안은 적응에 바쁠 것 같다! 그래도 꾸준히 여러 이야기들을 적으려고 기록하고 있어서 조만간 이야길 풀어낼 수 있으리라 본다.&lt;/p&gt;
&lt;p&gt;최근에 C에 대해서 학습할 수 있는 좋은 기회를 얻게 되었고, 가끔 Python이나 Java로 시간초과의 벽을 만날 때마다 아쉬운 점이 있어 이번 기회에 C++를 통해 문제 풀이를 진행해보고자 했다.&lt;/p&gt;
&lt;p&gt;얼마 되지 않는 동안 써본 경험상 구현에서 많은 부분이 손이 많이 가지만 그걸 속도가 보상한다는 느낌을 꽤 받는다. 숙달된다면 빠른 속도라는 장점만 가져갈 수 있을지...? 기대가 된다.&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;vector: 동적 배열 구조, 배열과 유사하지만 크기의 유동적인 변경이 가능하며 메모리 할당이 자동이라는 큰 장점이 있다!&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;npos: no position, 유효하지 않은 위치일 때를 체크하기 위한 인덱스 value&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;stringstream: 문자열을 스트림으로 다루기 위한 장치, 입출력과 같은 방식으로 다룰 수 있도록 하며 파싱에 자주 사용됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;기본적인 로직은 페이지 수 제한 전 범위를 커버할 수 있는 bool 배열을 만든 뒤, 들어온 페이지 범위를 모두 체크하고 마지막에 카운팅한 값을 출력하면 된다.&lt;/p&gt;
&lt;p&gt;다만, 문제에서 제시한 숫자 범위가 int를 넘어선 값으로 주어질 수 있어 그걸 컨트롤하기 위한 변수 설정이 필요하고, 범위가 역순으로 주어질 경우 체크하지 않는다는 예외항들에 대해서도 주목할 필요가 있다.&lt;/p&gt;
&lt;p&gt;이런 과정을 파이썬으로 해결할 때는 상당히 편했지만 C++로 하려니 코드가 엄청 길어지게 되었다..&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-cpp&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;// 페이지 세기&lt;/span&gt;

&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;vector&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;hljs-meta&quot;&gt;#&lt;span class=&quot;hljs-keyword&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;lt;sstream&amp;gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;namespace&lt;/span&gt; std;

&lt;span class=&quot;hljs-function&quot;&gt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;void&lt;/span&gt;)&lt;/span&gt;
&lt;/span&gt;{
	ios_base::&lt;span class=&quot;hljs-built_in&quot;&gt;sync_with_stdio&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;);
	cin.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);
	cout.&lt;span class=&quot;hljs-built_in&quot;&gt;tie&lt;/span&gt;(&lt;span class=&quot;hljs-literal&quot;&gt;NULL&lt;/span&gt;);

	&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;				total_page, seperator, start, end, result;
	string			temp, each_range;
	vector&amp;lt;string&amp;gt;	line_info;
	vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;bool&lt;/span&gt;&amp;gt;	print_info;
	vector&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;&amp;gt;		result_vector;

	&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;)
	{
		cin &amp;gt;&amp;gt; total_page;

		&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!total_page)
			&lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; ;
		&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
		{
			print_info.&lt;span class=&quot;hljs-built_in&quot;&gt;assign&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1001&lt;/span&gt;, &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;);
			cin.&lt;span class=&quot;hljs-built_in&quot;&gt;ignore&lt;/span&gt;();
			&lt;span class=&quot;hljs-built_in&quot;&gt;getline&lt;/span&gt;(cin, temp);
			&lt;span class=&quot;hljs-function&quot;&gt;stringstream &lt;span class=&quot;hljs-title&quot;&gt;range_stream&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(temp)&lt;/span&gt;&lt;/span&gt;;

			&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-built_in&quot;&gt;getline&lt;/span&gt;(range_stream, each_range, &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;,&amp;#x27;&lt;/span&gt;))
			{
				&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-&amp;#x27;&lt;/span&gt;) == string::npos)
				{
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;() &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; &amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range) &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)
						print_info[&lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range)] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
				}
				&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
				{
					seperator = each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;find&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;-&amp;#x27;&lt;/span&gt;);
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, seperator).&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;() &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;
						&amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, seperator)) &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)
						start = &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, seperator));
					&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
						start = &lt;span class=&quot;hljs-number&quot;&gt;1001&lt;/span&gt;;
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(seperator + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;()).&lt;span class=&quot;hljs-built_in&quot;&gt;length&lt;/span&gt;() &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt; 
						&amp;amp;&amp;amp; &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(seperator + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;())) &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1000&lt;/span&gt;)
						end = &lt;span class=&quot;hljs-built_in&quot;&gt;stoi&lt;/span&gt;(each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;substr&lt;/span&gt;(seperator + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, each_range.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;()));
					&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;
						end = &lt;span class=&quot;hljs-number&quot;&gt;1001&lt;/span&gt;;
					&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (start &amp;lt;= end)
					{
						&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = start; i &amp;lt;= end; i++)
						{
							&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i &amp;lt;= total_page)
								print_info[i] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
						}
					}
				}
			}

			result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
			&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt;= total_page; i++)
			{
				&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (print_info[i])
					result++;
			}
			result_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;push_back&lt;/span&gt;(result);
		}
	}

	&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; i = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) result_vector.&lt;span class=&quot;hljs-built_in&quot;&gt;size&lt;/span&gt;(); i++)
		cout &amp;lt;&amp;lt; result_vector[i] &amp;lt;&amp;lt; endl;

	&lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;);
}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>잡다한 Shell 기록 (3)</title><link>https://www.traceoflight.dev/ko/blog/shell-3/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/shell-3/</guid><description>Shell을 학습하는 여정, 3번째 이야기</description><pubDate>Tue, 25 Jul 2023 18:05:52 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;23-07-26 오기된 내용 수정
23-07-27 명령어 추가&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;BC&lt;/h3&gt;
&lt;p&gt;Basic Calculator의 약자, POSIX 표준에 따라 제공되며, 유닉스 기반 시스템에서 사용할 수 있는 계산기이다.&lt;/p&gt;
&lt;p&gt;특징적인 부분으로는&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;스택 기반의 구조를 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;후위 표기법 (Reverse Polish notation) 을 지원&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;2 + 3&amp;#x27;&lt;/span&gt; | dc
dc &amp;lt;&amp;lt;&amp;lt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;2 3 + p&amp;#x27;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;TR&lt;/h3&gt;
&lt;p&gt;문자 변환, 삭제, 압축 등을 가능하게 하는 명령어. 보통 파이프라인을 통해 추가적인 공정과 함께 사용&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;tr [문자열1] [문자열2]&lt;/code&gt;: 길이가 같은 문자열을 2개 사용하며 보통 문자열1의 해당하는 문자를 문자열2의 동일 인덱스 문자로 바꿔준다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-c: 두 번째 세트의 마지막 문자가 세트에 없는 문자를 전부 대체함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-s: 반복 발생하는 시퀀스를 전부 제거하고 설정한 문자로 대체&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-d: 해당 문자 제거&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-t: 명령 수행 전 문자열 2개의 길이를 맞춰 자르도록 처리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;SED&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Steam Editor&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;다양한 편집 기능을 지원하는 명령어, 기본적으로 버퍼를 기반으로 작동하여, 원본 파일은 수정 전까지 영향이 없다.&lt;/p&gt;
&lt;h4&gt;명령어 옵션&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;/[패턴]/ 의 형태로 패턴을 표현한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;g 추가 시 일치하는 모든 패턴에 대해 진행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;콤마 (,) 를 통해 범위를 조절한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;p: 모든 줄을 출력하며 패턴 일치하는 경우 1회 추가 출력&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-n 옵션 추가: 기본 출력 배제, 패턴 일치하는 줄만 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;d: 패턴에 대한 삭제 진행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;s: 패턴에 대한 치환&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;e: 다중 편집&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;n;&lt;/code&gt;: 다음 줄&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;y: 변환&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;i: 삽입&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;c: 변경&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;a: 추가&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 약간의 응용&lt;/span&gt;

sed -n &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;n; p&amp;#x27;&lt;/span&gt;: 짝수 줄 출력
sed -n &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;p; n&amp;#x27;&lt;/span&gt;: 홀수 줄 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;WC&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Word Count&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;-l: 파일의 라인 갯수 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-c: 파일의 바이트수 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-m: 파일 내 문자의 갯수 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;-w: 파일 내 단어의 갯수 확인&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>잡다한 Shell 기록 (2)</title><link>https://www.traceoflight.dev/ko/blog/shell-2/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/shell-2/</guid><description>Shell을 학습하는 여정, 2번째 이야기</description><pubDate>Thu, 20 Jul 2023 16:49:40 GMT</pubDate><content:encoded>&lt;h3&gt;List&lt;/h3&gt;
&lt;p&gt;보통 &lt;code&gt;ls&lt;/code&gt; 로 사용하는 명령어. 해당 명령어를 사용하여 디렉토리의 내용물을 확인할 수 있다. 추가적인 커맨드를 활용하면 리스트를 적절한 용도로 꺼낼 수 있어 요긴하다.&lt;/p&gt;
&lt;p&gt;자주 쓰는 커맨드와 특정 용도로 쓰는 데에 필요한 커맨드를 남기며, 추가적으로 필요한 부분은 &lt;code&gt;man&lt;/code&gt; 을 통해 매뉴얼을 불러오던지 이하 링크로 남길 document를 참고하도록 하자.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-l&lt;/strong&gt;: Long Default Format으로 표현해준다.
&lt;code&gt;working john 2008-07-25 11:56 csrc 1 alias.c-4.5 27&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-al&lt;/strong&gt;: 전체 내용을 표시해준다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-t&lt;/strong&gt;: modified된 시점에 따라서 정렬해준다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-m&lt;/strong&gt;: 각 요소들을 콤마와 공백 (, ) 로 분리하여 출력
&lt;code&gt;this, is, example&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-r&lt;/strong&gt;: 현재 순서의 반대로 출력&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-R&lt;/strong&gt;: 하위 디렉토리 내용들까지 재귀적으로 출력&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-h&lt;/strong&gt;: 단위를 사람이 보기 좋게 출력 (m, k, g 등 단위 사용)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/ls.1.html&quot;&gt;List Manual&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Find&lt;/h3&gt;
&lt;p&gt;파일을 탐색하는 명령어. 어느 위치를 기준으로 하위 디렉토리까지 전부 탐색하여 결과를 출력한다. 출력 외에도 다양한 기능들을 제공하는데 정말 잘 활용하고 싶다면 정규표현식에 대해서 알아보도록 하자.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-name&lt;/strong&gt;: 찾는 이름에 대한 정보를 넣는 커맨드이며, 정규표현식을 통한 제약이 가능하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-o&lt;/strong&gt;: or 연산자와 같은 기능을 하는 커맨드, A라는 조건에 a라는 행동을, B라는 조건에 b라는 행동을 하게 하고 싶다면 해당 커맨드를 사용하자.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-exec&lt;/strong&gt;: 추가적인 명령어를 적용할 수 있는 커맨드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-delete&lt;/strong&gt;: 찾은 파일을 제거하는 커맨드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;-print&lt;/strong&gt;: 찾은 파일을 출력하는 커맨드&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;마찬가지로 그 외의 커맨드는 여기서 검색하면 된다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://man7.org/linux/man-pages/man1/find.1.html&quot;&gt;Find Manual&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Echo &amp;amp; Printf&lt;/h3&gt;
&lt;p&gt;shell에서 echo 많이 사용하는데 echo 말고 printf도 사용이 가능하다. 솔직히 개행문자의 디폴트값 유무 정도 빼고는 잘 모르겠어서 이 부분은 ChatGPT에게 도움을 요청했다!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-2f0cb8656eb567ac-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;의외로 자주 쓰는 echo보다 printf가 좀 더 정교한  기능을 지원한다고 한다. 가볍게 사용하는 선에서 차이점을 느끼진 못하겠어서 일단 요 정도의 정보만 알고 가야겠다..&lt;/p&gt;
</content:encoded></item><item><title>잡다한 Shell 기록 (1)</title><link>https://www.traceoflight.dev/ko/blog/shell-1/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/shell-1/</guid><description>Shell을 학습하는 여정</description><pubDate>Mon, 17 Jul 2023 17:25:08 GMT</pubDate><content:encoded>&lt;h3&gt;파일 생성 관련&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;touch&lt;/code&gt;: 파일 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt;: 폴더 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;chmod&lt;/code&gt;: 파일 권한 설정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;chown&lt;/code&gt;: 파일 소유자 설정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mv&lt;/code&gt;: 파일 이동 및 rename&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;파일 정보 확인&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-f343d0b04676158d-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-rwxr-xr-x&lt;/code&gt; 부분: 파일의 권한을 확인하는 부분&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;맨 앞 자리가 File Type을 의미 (-, d, l)&lt;/li&gt;
&lt;li&gt;read-write-execute 권한에 대하여 user, group, others에 대해 3자리의 형태로 표기,
2진수의 형태로 r이 4, w이 2, x가 1의 값을 가지고 있어 &lt;code&gt;rwx&lt;/code&gt;의 값은 7로 바꿀 수 있고 &lt;code&gt;-xr&lt;/code&gt;은 4로 바꿀 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; 744 Slack.lnk
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이러한 형태의 명령어로 권한 설정이 가능하다.
3. 링크 갯수 (1이 적힌 부분)
4. 소유자 (빈 부분)과 소유 그룹에 대한 정보 (197609)
5. 파일 크기
6. 마지막으로 수정된 시간에 대한 정보
7. 파일 이름&lt;/p&gt;
&lt;h3&gt;ssh-keygen&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Secure Shell 공개키를 통한 Git 인증에 사용하는 케이스 다수&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Window 및 Linux 패키지에 포함되어 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;key를 생성한 경우 key와 &lt;code&gt;.pub&lt;/code&gt; 파일이 생성되는데 .pub 파일의 내용을 서버에 제공하여 열쇠 - 자물쇠의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;shell에서 파일의 용량을 조정하는 법&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;mkfile -n 10k test.sh
fallocate -l 10k test.sh
&lt;span class=&quot;hljs-built_in&quot;&gt;truncate&lt;/span&gt; -s 10k test.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이미 있는 파일이나 파일을 새로 만들 때 해당 명령어를 통해 파일의 Size를 조절할 수 있다.&lt;/p&gt;
&lt;h3&gt;파일 수정 시점 기록 변경&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;touch&lt;/span&gt; -t 2301011234 timefile.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;touch의 응용으로 23년 1월 1일 12시 34분에 마지막 수정이 된 것으로 파일의 수정 시점을 바꿀 수 있는 명령어&lt;/p&gt;
&lt;h3&gt;Hard Link &amp;amp; Symbolic Link&lt;/h3&gt;
&lt;h4&gt;Symbolic Link (Soft Link)&lt;/h4&gt;
&lt;p&gt;윈도우의 바로 가기와 같이 특정 폴더에 존재하는 원본 파일을 사용할 수 있도록 하는 링크이며 원본이 삭제된 경우 동작하지 않음&lt;/p&gt;
&lt;h4&gt;Hard Link&lt;/h4&gt;
&lt;p&gt;심볼릭 링크와 달리 원본을 복사하고 사본을 생성한다는 차이점이 존재하며, 원본이 삭제될 때 심볼릭 링크는 사용이 불가능하지만, 하드 링크의 경우는 결국 동일한 파일이기 때문에 여전히 사용할 수 있음, 링크 수에 관여하는 링크.&lt;/p&gt;
&lt;h4&gt;Code&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;ln&lt;/span&gt; [대상 폴더] [만들 링크 파일명] &lt;span class=&quot;hljs-comment&quot;&gt;# Hard Link&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;ln&lt;/span&gt; -s [대상 폴더] [만들 링크 파일명] &lt;span class=&quot;hljs-comment&quot;&gt;# Symbolic Link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;지우는 명령어는 &lt;code&gt;rm&lt;/code&gt;으로 파일 지우듯이 해제할 수 있음&lt;/p&gt;
&lt;h3&gt;Diff &amp;amp; Patch&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;diff a b &amp;gt; difference.patch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;diff&lt;/code&gt; 는 두 개의 파일을 라인 단위로 비교하는 명령어이며 &lt;code&gt;patch&lt;/code&gt; 는 diff 등을 통해 확인한 비교 내용을 바탕으로 파일을 수정할 수 있는 명령어이다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;patch -p{패치 경로의 depth} [원본] [patch 파일] &lt;span class=&quot;hljs-comment&quot;&gt;# 패치 파일 적용&lt;/span&gt;
patch -p{패치 경로의 depth} -R [원본] [patch 파일] &lt;span class=&quot;hljs-comment&quot;&gt;# 적용된 패치 파일을 되돌림&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 형태로 기존 파일에서 diff를 통해 판단된 내용을 그대로 적용하고 해제할 수 있다.&lt;/p&gt;
</content:encoded></item><item><title>2023 아시아나IDT 하반기 채용 전형 후기</title><link>https://www.traceoflight.dev/ko/blog/2023-idt/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/2023-idt/</guid><description>아시아나IDT의 채용 프로세스에 참가한 이야기</description><pubDate>Sat, 15 Jul 2023 09:23:14 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;개발 직군도 경제의 영향을 받아서 그런지 채용 전형 수나 채용 인원이 작년보다 많이 줄어들었다. 결국은 타이밍이 왔을 때 잡을 수 있는 사람이 승리자가 되는데, 그렇기에 더더욱 꾸준하게 해야겠다고 생각하고 있다.&lt;/p&gt;
&lt;h3&gt;서류 전형 &amp;amp; 역량 검사&lt;/h3&gt;
&lt;p&gt;타 회사들과 마찬가지로 서류에서 특이한 부분은 없었고 금융권 채용과 유사하게 역량 검사를 시행해야 하는 부분이 특이했었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-de67b160b1aa0129-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;정상적으로 다 답변했다고 생각했는데 (주의) 가 떠 있어서 불안하긴 했지만 캠이나 마이크 등에 이상이 없었기 때문에 그대로 제출했고,&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-bfb139a0580b844d-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;문제 없이 서류 합격을 받을 수 있었다. 여유가 있었다면 역량 검사를 한 번 더 체크했을 거 같다.&lt;/p&gt;
&lt;h3&gt;코딩 테스트&lt;/h3&gt;
&lt;p&gt;난이도나 문제 유형이나 둘 다 금융권 코딩 테스트가 생각이 났다. 전반적으로 평이한 난이도, SQL까지 비슷한 형태였다고 본다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-04f741f5ffa434c7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;결과는 통과, 아시아나IDT의 면접장을 볼 수 있는 기회를 얻었다!&lt;/p&gt;
&lt;h3&gt;최종 면접&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-3d3262bf0a5592a0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;건물 입구에서 면접자 방문증을 받아들고 찾아갔다. 준비하면서 봤던 타 후기들과 비슷하게 토론 면접과 인성 면접이 진행이 되었다.&lt;/p&gt;
&lt;p&gt;토론 면접을 진행하면서 뭔가 엄청난 역할을 하는 걸 기대했다기보다는 의사소통에 문제가 있는 사람을 선별하는 과정이라고 생각했다.&lt;/p&gt;
&lt;p&gt;인성 면접에서는 서류, 코딩테스트 결과 등을 종합한 것을 기반으로 질문을 받았다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;입사 지원하면서 이런 사람은 거의 없겠지만, 회사에 대해서 충분히 알아보지 않고 온 사람들은 질문에서 어려움을 느낄 수 있겠다고 생각했다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;면접자들에게 의견을 구하는 모습에서 회사의 발전 방향에 대해 고심하고 있다는 점을 느꼈다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;최종 결과&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-1e2142ef3cf56fc9-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;면접에서 평소보다 대답을 잘 했다고 생각했는데 나름 높은 경쟁률에도 불구하고 합격을 할 수 있었다!&lt;/p&gt;
&lt;h3&gt;소회&lt;/h3&gt;
&lt;p&gt;IT 업계에 입문할 때 듣는 이야기가 워낙 많은지라 SI/SM에 대한 막연한 두려움을 가지게 되는 경우가 많이 있고 실제로 나도 그랬다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-94c515233c0d9259-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;
&lt;s&gt;하이퍼 리얼리즘&lt;/s&gt;&lt;/p&gt;
&lt;p&gt;그럼에도 국내 IT 업계의 비중 대부분은 IT 서비스가 아닌 SI/SM이 위주이며 이를 간과한다면 합리적이지 못한 선택을 하게 될 수도 있다고 생각한다.&lt;/p&gt;
&lt;p&gt;취업 시장이 예전 같지 않은만큼 너무 좁은 목표를 향해 가는 것보다 지금 할 수 있는 최선의 선택지가 뭔지 고려하는 감각이 필요한 시점이라고 보고, 이를 명심한다면 좋은 결과를 얻을 수 있을 것이라 생각한다!&lt;/p&gt;
</content:encoded></item><item><title>[면접 질문] 객체 지향 프로그래밍이란?</title><link>https://www.traceoflight.dev/ko/blog/object-oriented-programming/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/object-oriented-programming/</guid><description>객체 지향 프로그래밍에 대한 면접 질문 정리</description><pubDate>Wed, 12 Jul 2023 07:28:03 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;어제 모 기업의 면접을 진행하면서 객체 지향 프로그래밍에 대한 답변을 해야 하는 상황이 있었는데 분명히 알고 있다고 생각하고 정리했던 적이 있었음에도 막상 답변을 하려고 하니까 어설프게 이야기 했던 일이 있었다.&lt;/p&gt;
&lt;p&gt;덕분에 약한 부분을 짚어냈다고 생각하고 다시 정리하는 시간을 가져보기로 했다!&lt;/p&gt;
&lt;h3&gt;객체란?&lt;/h3&gt;
&lt;p&gt;일반적인 정의부터 살펴보면 아래와 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;일반론: 실제 존재하는 것
컴퓨터 과학: 클래스에 정의된 내용대로 메모리에 생성된 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;객체 지향 언어들에서 정의한 것들은 아래와 같다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Java: 클래스의 인스턴스 혹은 배열
Python: 속성값이나 행동을 가지고 있는 데이터&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;자바의 클래스는 인스턴스가 아니지만 파이썬의 클래스는 인스턴스이다.&lt;/p&gt;
&lt;h3&gt;객체 지향 프로그래밍&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;객체의 역할과 관계를 정의하여 상호작용을 통한 프로그램을 구축하는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이렇게 정의할 수 있겠다.&lt;/p&gt;
&lt;h3&gt;객체 지향 언어의 특징&lt;/h3&gt;
&lt;h4&gt;추상화&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;객체 간의 공통적인 특징을 도출할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클래스 정의하는 부분이 이에 해당&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;다형성&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;조금 다른 방식으로 작동하는 함수에 대해 동일하게 호출할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;동일 명령에 대해 연결된 객체에 해석을 전가하는 방식&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Override(내부소스 재정의), Overload(매개변수에 따라 같은 이름의 다른 함수를 호출)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;캡슐화&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;구현한 부분을 외부에 공개하지 않고 숨길 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;외부와의 소통이 필요한 경우 메소드를 통해 정보를 주고 받음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;상속&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;하나의 클래스가 가진 특징을 다른 클래스가 물려 받는 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이미 작성된 클래스에 더해 새로운 클래스를 생성할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 11689, Python] GCD(n, k) = 1</title><link>https://www.traceoflight.dev/ko/blog/boj11689/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj11689/</guid><description>BOJ 11689, &quot;GCD(n, k) = 1&quot; 문제의 Python 풀이</description><pubDate>Fri, 07 Jul 2023 06:49:25 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/11689&quot;&gt;BOJ 11689&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;수학, 정수론, 오일러 피 함수&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;최근 백준 문제를 풀이할 때 진짜 실력을 높이기 위해서는 문제 분류를 배제하고 풀이해야 한다고 생각하여 실천 중에 있다. 하지만 이번에 정리하는 이 문제와 같은 것들을 만나면 상당히 골치가 아파지게 된다.&lt;/p&gt;
&lt;p&gt;이 문제의 경우, 처음에 10&lt;sup&gt;12&lt;/sup&gt; 까지 숫자를 1초 안에 체크할 수 있어야 하기 때문에 최소한 O(N) 수준보다 아래로 끌어내려야 한다는 생각까진 했었다. 서로소 판정이라면 보통 소인수분해를 진행하고 겹치는 숫자가 없으면 될 것이라고 생각했기 때문에 이하의 코드를 활용했었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;factorize&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_number: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;:

    result = []
    prime_list = find_prime(target_number)

    now_number = target_number
    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; now_number &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_prime &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; prime_list:
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; each_prime &amp;gt; now_number:
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; now_number % each_prime:
                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; now_number % each_prime:
                    now_number //= each_prime
                result.append(each_prime)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;하지만 이러한 코드를 기반으로 한 경우 시간복잡도를 만족시킬 수 없었다. 결국 고민 끝에 태그를 확인하기로 결정했고, &lt;code&gt;오일러 피 함수&lt;/code&gt; 라는 새로운 친구를 만나게 되었다.&lt;/p&gt;
&lt;p&gt;확인해보니 이 문제 그 자체인 함수였는데&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;φ(n) = {n 이하의 자연수 중 n과 서로소인 자연수의 갯수}&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;요렇게 구현할 수 있었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;euler_phi&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;number: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    오일러 피 함수를 활용한 자연수 n과 서로소인 수의 갯수를 구하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    checker = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;
    result = number

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(checker, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) &amp;lt;= number:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; number % checker:
            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; number % checker:
                number //= checker

            result -= result // checker

        checker += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; number &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        result -= result // number

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;2부터 쭉 나아가면서 진행한다.&lt;/li&gt;
&lt;li&gt;나눠지는 수가 있다면 나눌 수 있을만큼 나눠준다. (소인수분해)&lt;/li&gt;
&lt;li&gt;해당 수의 배수는 서로소일 수 없으므로 결과 갯수에서 뺀다.&lt;/li&gt;
&lt;li&gt;마지막에 남은 수가 있다면 해당 수는 소수, 해당 소수의 배수도 서로소가 될 수 없으므로 결과 갯수에서 빼준다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;여기서 조금 어려운 부분이 이 부분이었다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;result -= result // checker&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;왜 &lt;code&gt;number // checker&lt;/code&gt; 를 제거하는 게 아니라 result에서 나눈 값을 제거하는지가 궁금했는데 사실 당연한 부분이었다. &lt;code&gt;n&lt;/code&gt; 의 배수를 없애주고 &lt;code&gt;m&lt;/code&gt; 의 배수도 그 갯수 그대로 없애준다면 결과적으로 &lt;code&gt;n * m&lt;/code&gt; 의 배수는 2번 빠지게 되는 것이다!&lt;/p&gt;
&lt;p&gt;이러한 중복 처리되는 숫자를 처리하기 위해 이미 한 번 빠진 갯수에서 해당 숫자의 배수만큼을 빼게 되는 것라고 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;어찌되었건 해당 풀이법을 이해하는 순간 아주 쉬운 문제가 된다. 정수론 문제들이 이런 경향이 있는 거 같은데 배울 때는 좋지만 막상 첫 접근이 항상 어려워서 좀 불편하다..&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# GCD(n, k) = 1&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;euler_phi&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_number: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;):
    result = target_number
    check_number = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(check_number, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) &amp;lt;= target_number:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; target_number % check_number:
            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; target_number % check_number:
                target_number //= check_number
            result -= result // check_number
        check_number += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; target_number &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        result -= result // target_number

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result

target = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(euler_phi(target))
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[면접 질문] Dependency Injection</title><link>https://www.traceoflight.dev/ko/blog/dependency-injection/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/dependency-injection/</guid><description>DI에 관한 면접 질문 정리</description><pubDate>Thu, 06 Jul 2023 11:46:58 GMT</pubDate><content:encoded>&lt;h3&gt;의존성 주입&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;의존성: 객체가 다른 객체를 사용하고 있는 관계
→ 의존성 주입: 관계를 설정해주는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;의존성 주입이 필요한 이유?&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Product&lt;/span&gt; {

	&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Apple apple;
    
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;()&lt;/span&gt; {
    	&lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.apple = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Apple&lt;/span&gt;();
	}

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 예시를 작성해놓고 볼 때 Product라는 클래스가 Apple 생성자를 사용하는 경우 따로 주입 받지 않고 그대로 사용하고 있다.
Product를 사용할 경우, Apple이 그대로 딸려나오는 종속적인 관계로 이해할 수 있다. 이렇게 되면 객체끼리의 연결이 아닌 클래스 간의 관계라고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;또한 내가 &lt;code&gt;Orange&lt;/code&gt; 라는 클래스를 추가적으로 사용하고 싶다면 Product 클래스 생성자에 변화를 직접 줘야 하는 상황이고 이는 유연성이 떨어진다고 볼 수 있다.&lt;/p&gt;
&lt;p&gt;결론적으로 의존성 주입이 필요한 이유를 짚어보자면&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;클래스 간의 강한 결합력 + 코드의 유연성이 떨어짐&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이런 문제를 의존성 주입으로 해결할 수 있기 때문에 필요하다고 할 수 있겠다!&lt;/p&gt;
&lt;h3&gt;해결책의 적용&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Fruit&lt;/span&gt; {

}

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Apple&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Fruit&lt;/span&gt; {

}

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Product&lt;/span&gt; {

	&lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; Fruit fruit;
    
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;Product&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Fruit fruit)&lt;/span&gt; {
    	&lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.fruit = fruit;
    }
    
}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;각각의 클래스가 독립성을 보장 받고 있는 것을 확인할 수 있겠다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;새로운 Fruit 추가해도 Product가 변하지 않음&lt;/li&gt;
&lt;li&gt;클래스 관계 대신 객체 간의 관계가 형성됨&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[면접 질문] Java Stack &amp; Heap의 구조</title><link>https://www.traceoflight.dev/ko/blog/java-stack-heap/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/java-stack-heap/</guid><description>Java의 Stack과 Heap에 대한 면접 질문 정리</description><pubDate>Sun, 02 Jul 2023 17:19:40 GMT</pubDate><content:encoded>&lt;h3&gt;Java 메모리 구조&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;/blog/jvm&quot;&gt;JVM 구조와 원리의 내용을 참고하면 좋다.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;애플리케이션 실행을 위해 구축한 Java Runtime Data Area가 메모리에 위치하게 됨&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;PC Register, Native Method Stack, Method 영역은 모든 스레드가 공유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stack과 Heap 영역만 스레드 고유의 영역으로 가지게 됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Heap의 구조&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Eden → Survivor → Old&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;위와 같은 형태로 객체가 이동하게 되는데 기본적으로는 생성순으로 이해하면 될 것이다.&lt;/p&gt;
&lt;h3&gt;Garbage Collector의 역할&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Eden: 자바 객체가 생성되자마자 저장되는 공간&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Survivor &amp;amp; Old: 참조 정도에 따라 객체가 이동된 공간&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mark and Sweep&lt;/strong&gt; 알고리즘을 사용한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Minor Garbage Collector&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Eden과 Survivor 영역 (Young Generation) 의 메모리가 허용치를 초과하는 경우 객체의 참조에 따라 영역을 이동시키는 역할&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Major Garbage Collector&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Old 영역 (Tenured Generation) 의 메모리가 허용치를 초과할 경우, 참조되지 않는 객체를 전부 제거하고 메모리를 회수하는 역할&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;삭제 과정에서 가비지 컬렉터를 실행하는 스레드를 제외한 나머지 스레드 전부 정지 (&apos;Stop-The-World&apos;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Stack의 구조&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;기본 자료형 + 지역 변수 + 매개 변수&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;여기서 매개 변수의 경우, 객체의 주소값을 가지고 Heap 영역의 객체를 참조하는 형태로 사용된다.&lt;/p&gt;
&lt;p&gt;→ 매개 변수가 다른 객체를 참조하게 되는 경우, 주소값이 달라지는 것뿐이며, Heap에 저장된 객체가 바로 사라지지 않는다! (Major GC가 실행 전까지 Hold)&lt;/p&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://coding-factory.tistory.com/828&quot;&gt;코딩 팩토리의 글&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 27231, Python] 2023년이 기대되는 이유</title><link>https://www.traceoflight.dev/ko/blog/boj27231/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj27231/</guid><description>BOJ 27231, &quot;2023년이 기대되는 이유&quot; 문제의 Python 풀이</description><pubDate>Fri, 30 Jun 2023 10:32:49 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/27231&quot;&gt;BOJ 27231&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;브루트포스 알고리즘, 백트래킹&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-11d42ef72dcdad8a-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;요즘 예전에 못 풀었던 문제가 그럭저럭 해결되는 모습을 보아하니 실력이 향상되었다는 느낌이 들어서 기분이 좋다.&lt;/p&gt;
&lt;p&gt;이 문제의 경우도 마지막 시도는 5달 전에 대회에 출제된 시점이지만, 중간중간에 해결 기미가 보이지 않는 풀이법도 여러 번 끄적여봤었다.&lt;/p&gt;
&lt;p&gt;마지막 시도가 여러 번 있는 이유는 딱 한 가지 조건이 부족했기 때문인데 이 조건이 빠진다고 왜 시간초과를 받아버리는지는 아직 이유를 잘 모르겠다. &lt;s&gt;나중에 보충할 수 있는 이유라면 좋겠다.&lt;/s&gt; → 밑 내용을 정리하다가 생각났다. 역시 블로그 정리가 최고다!&lt;/p&gt;
&lt;p&gt;문제의 풀이 접근을 소개해보자면&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;+ 기호를 넣는 좌표를 비트마스킹을 활용하여 전수 체크&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;집합 혹은 중복을 허용치 않는 리스트에 넣고 정렬&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;제곱 크기를 늘려주면서 최종적으로 처음에 입력된 수 (아무리 잘게 쪼개봐야 이 수보다 클 수 없기 때문) 까지 존재하는 숫자 카운팅&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;그리고 여기서 문제가 생겼다.&lt;/p&gt;
&lt;p&gt;0, 1로 구성된 수의 경우 단일 숫자로 쪼갠다면 아무리 제곱해도 계속 값이 변하지 않기 때문에 &lt;code&gt;Hello, BOJ 2023!&lt;/code&gt; 를 출력해줘야 하지만 난 단순하게 1인 경우만 배제하고 있었다.&lt;/p&gt;
&lt;p&gt;아무리 제곱해도 숫자가 증가하지 않았기 때문에 while문에 걸려서 시간 초과를 받았던 것이다! 해당 파츠를 확인하기 위해 단일 숫자들에 대해서 2가 넘는지 체크하고 2가 넘는 항이 없다면 무조건 &lt;code&gt;Hello, BOJ 2023!&lt;/code&gt; 를 출력하는 것으로 엣지 케이스를 처리하여 정답을 받을 수 있었다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 2023년이 기대되는 이유&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;pow_target&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_num: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, exponent: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:

    result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    now_number = target_num

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; now_number:
        result += &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;((now_number % &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;), exponent)
        now_number //= &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result

testcase = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
result_dict = &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt;()
output = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):

    target_number = &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().rstrip(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\n&amp;#x27;&lt;/span&gt;)

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; result_dict.get(target_number) &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
        output.append(result_dict[target_number])

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        is_under_limit = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_element &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(target_number):
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(each_element) &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
                is_under_limit = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_under_limit:
            result_dict[target_number] = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Hello, BOJ 2023!&amp;#x27;&lt;/span&gt;
            output.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Hello, BOJ 2023!&amp;#x27;&lt;/span&gt;)
            &lt;span class=&quot;hljs-keyword&quot;&gt;continue&lt;/span&gt;

        length = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(target_number)

        check_list = []
        check_list.append(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number))

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &amp;lt;&amp;lt; length):

            calc_result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            now_start = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
            now_end = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(length):

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; i &amp;amp; (&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &amp;lt;&amp;lt; j):
                    now_end = j
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_end:
                        calc_result += &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number[now_start : now_end])
                    now_start = now_end
                    
            calc_result += &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number[now_start : length + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; calc_result &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; check_list:
                check_list.append(calc_result)

        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            result = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            check_amount = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(check_list)
            check_list.sort()

            max_value = check_list[-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]
            pointer = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
            counter = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; pointer &amp;lt; check_amount:
                now_result = pow_target(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(target_number), counter)

                &lt;span class=&quot;hljs-comment&quot;&gt;# 종료 조건 1&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_result &amp;gt; max_value:
                    &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; pointer &amp;lt; check_amount &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; now_result &amp;gt; check_list[pointer]:
                    pointer += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

                &lt;span class=&quot;hljs-comment&quot;&gt;# 종료 조건 2&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer &amp;gt;= check_amount:
                    &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_result == check_list[pointer]:
                    result += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

                counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            result_dict[target_number] = result
            output.append(result)

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; output:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 13325, Python] 이진 트리</title><link>https://www.traceoflight.dev/ko/blog/boj13325/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj13325/</guid><description>BOJ 13325, &quot;이진 트리&quot; 문제의 Python 풀이</description><pubDate>Wed, 28 Jun 2023 12:58:52 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/13325&quot;&gt;BOJ 13325&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;다이나믹 프로그래밍, 트리, 트리에서의 다이나믹 프로그래밍&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;나 같은 경우에는 바로 안 풀리는 문제라고 할지라도 꽤나 오래 묵히면서 장고하는 스타일이다!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-4b0aee5765d752b7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;그렇다보니 이렇게 시도했지만 맞지 못한 문제에 대회 문항과 함께 거창한 시도를 했지만 풀지 못한 문제가 쌓이게 된다..&lt;/p&gt;
&lt;p&gt;이것들을 치우기 위해 가끔 문제를 읽어보면서 곰씹는 편인데 오늘 드디어 이 글의 문제 해결법을 알게 되어 너무 기쁘다!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-5ef200830a30afc7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;무려 첫 시도 이후 8개월이나 걸린 문제고 바로 직전 시도로부터 몇 번 건드려본 적은 있지만 마땅한 방안이 나지 않아서 해결하지 못했었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;pre_order_detail&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;graph_dict: &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt;, target_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;:

    result = [target_node]

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(graph_dict[target_node]) &amp;gt;= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_element &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; pre_order_detail(graph_dict, graph_dict[target_node][&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]):
            result.append(each_element)
        result.append(target_node)

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(graph_dict[target_node]) &amp;gt;= &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_element &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; pre_order_detail(graph_dict, graph_dict[target_node][&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]):
            result.append(each_element)
        result.append(target_node)

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;원래는 위와 같은 재귀 함수의 형태로 전위 순회를 변형한 형태로 방문하는 노드를 찍어낸 뒤에 스택과 같은 자료 구조에 넣고 각 간선을 여차저차하는 방식을 생각했었다.&lt;/p&gt;
&lt;p&gt;하지만 생각해보니 결과적으로 비교하는 대상을 같은 부모 노드로부터 나온 간선으로 한정 짓는다면 2개씩 비교한 값 중 큰 값을 꾸준히 상위 간선에 합산시키면서 처리할 경우 깔끔하게 계산이 가능하다는 것을 알 게 되었다!&lt;/p&gt;
&lt;p&gt;나중에 풀고 분류를 보니 이런 문제의 유형이 트리 DP라고 한다. 확실히 DP의 그것과 많이 유사하다고 생각했다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 이진 트리&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

tree_height = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
node_number = &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, tree_height + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

edges = [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))
edge_sum = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;(edges)

now_start = node_number // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
now_end = node_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; now_end:

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;((now_end - now_start) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;):

        child_edge = now_start + (&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * i)
        next_node = child_edge // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        edges[next_node] += &lt;span class=&quot;hljs-built_in&quot;&gt;max&lt;/span&gt;(edges[child_edge], edges[child_edge + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])
        edge_sum += &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(edges[child_edge] - edges[child_edge + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

    now_end = now_start
    now_start = now_start // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(edge_sum)

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;처음에 생각했던 방식보다 코드 길이도, 시간 복잡도도 깔끔해진 모습이다. 이렇게 놓고 보니 확실히 Bottom-Up 형태를 갖추고 있다.&lt;/p&gt;
</content:encoded></item><item><title>[자투리] IaaS, PaaS, SaaS란?</title><link>https://www.traceoflight.dev/ko/blog/iaas-paas-saas/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/iaas-paas-saas/</guid><description>자주 듣지만 깊게 알아보지 않았던 단어들</description><pubDate>Mon, 26 Jun 2023 05:21:36 GMT</pubDate><content:encoded>&lt;h3&gt;공통으로 적힌 &apos;aaS&apos; 의 뜻?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&apos;As a Service&apos; 의 약자&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;제 3사에서 클라우드 컴퓨팅 서비스를 제공한다는 뜻!&lt;/p&gt;
&lt;h3&gt;차이점은?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;서비스로 제공하는 것이 인프라, 플랫폼, 소프트웨어로 다름
→ 관리 수준의 차이가 발생&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-7a2b2e1c34c6a3d0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h4&gt;1. IaaS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;온프레미스 인프라에서 발전한 유형&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인프라 서비스 클라우드로 제공&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;제공 업체는 네트워크, 서버, 가상화, 스토리지의 관리와 엑세스를 담당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AWS, Azure, GCP와 같은 업체가 여기에 해당&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. PaaS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IaaS보다 담당하는 영역이 광범위해짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;사용자가 자체 애플리케이션을 개발, 실행, 관리할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;빌드 및 배포를 위한 환경까지 제공&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. SaaS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;모든 애플리케이션을 제공 업체가 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;제공 업체가 소프트웨어의 유지보수, 업그레이드, 보안 전체 관리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.redhat.com/ko/topics/cloud-computing/iaas-vs-paas-vs-saas&quot;&gt;IaaS vs. PaaS vs. SaaS&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[면접 질문] Connection Pool이란? (Feat. ChatGPT)</title><link>https://www.traceoflight.dev/ko/blog/connection-pool/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/connection-pool/</guid><description>DB Connection Pool에 대한 면접 질문 정리</description><pubDate>Sun, 25 Jun 2023 17:05:44 GMT</pubDate><content:encoded>&lt;h3&gt;DB Connection Pool이란?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;DB와 미리 Connect 해놓은 객체를 Pool에 저장
클라이언트 요청 시 Connection을 대여
처리가 끝나면 Connection을 반납하여 Pool에 다시 저장&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;미리 연결해뒀다가 필요할 때 꺼내쓰는 형태의 커넥션 객체와 같다고 이해할 수 있을 거 같다.&lt;/p&gt;
&lt;h3&gt;사용하는 이유?&lt;/h3&gt;
&lt;p&gt;Java Spring의 경우,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DB에 직접 연결해서 처리하는 방식을 사용하는 경우&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;매번 JDBC Driver를 로드하고 커넥션 객체를 받아와야 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;요청 때마다 드라이버 로드, 객체 생성, 연결이 반복적으로 이루어짐&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;→ 매우 비효율적이라 이러한 문제를 해결하기 위해 Connection Pool을 사용한다.&lt;/p&gt;
&lt;p&gt;+ 그 외의 프레임워크들도 사용한다고 한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-bec4f7ed8c564abe-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;특징&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;WAS 실행 시 Connection 객체 Pool에 미리 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HTTP 요청에 따라 객체를 가져다 쓰고 반환&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Connection 요청마다 연결, 생성 시간이 소비되지 않음
→ 연결 부하 감소 효과가 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;동시 접속자 수가 Pool의 객체 개수보다 많은 경우?
→ 미리 생성된 커넥션 객체가 모자르면 반환까지 순번대로 대기&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Pool이 클수록 메모리 소모↑ 대기시간↓&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[자투리] main 함수의 위치에 관하여</title><link>https://www.traceoflight.dev/ko/blog/main/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/main/</guid><description>main 함수는 맨 위로 올리도록 하자</description><pubDate>Sun, 18 Jun 2023 11:50:50 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;내용적으로 짧은 배운 점들에 대해 &lt;code&gt;자투리&lt;/code&gt; 카테고리를 사용해보기로 했다!&lt;/p&gt;
&lt;h3&gt;main 함수의 위치를 맨 위로&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/live/ywg7cW0Txs4?feature=share&quot;&gt;CS50&lt;/a&gt; 강의를 듣다가 생각난 부분인데 나 같은 경우에는 코드를 보통 이런 식으로 짜는 경향이 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;example&lt;/span&gt;():
	&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hello&amp;#x27;&lt;/span&gt;)
    
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;():
	example()
    
main()

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;예시를 들자면 필요한 함수의 세부 정의를 전부 앞에 쭉 나열하고 이후에 main 함수를 추가적으로 나열하는 방식이다.&lt;/p&gt;
&lt;p&gt;근데 확실히 맨 앞에 본 함수가 나와 있어야 코드를 알아볼 때 다른 사람들에게 명료함을 줄 수 있다는 생각이 들었다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;():
	example()
    this_function()

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;example&lt;/span&gt;():
	&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;hello&amp;#x27;&lt;/span&gt;)
    
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;this_function&lt;/span&gt;():
	&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;function&amp;#x27;&lt;/span&gt;)
    
main()

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;전체적인 코드의 구현 형태를 보여주는 main 함수를 위로 올리고 세부 정의들을 이후 표기하는 것을 통해 코드의 기능을 좀 더 확실하게 보여줄 수 있도록 해야겠다.&lt;/p&gt;
</content:encoded></item><item><title>비범하지 않은, SSAFY 8기 수료 후기</title><link>https://www.traceoflight.dev/ko/blog/ssafy-8/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/ssafy-8/</guid><description>삼성 청년 SW 아카데미를 마무리하며</description><pubDate>Fri, 16 Jun 2023 17:28:37 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;마침내 삼성 청년 SW 아카데미, SSAFY 8기의 1년 간의 여정이 끝나는 순간이 왔다. 많은 일들이 있었지만 숨 가쁘게 달려왔기에 지금에서야, 지금이나마 한 번 적어볼까 한다. SSAFY 후기를 보면 대다수의 후기는 우수 이상의 등급으로 수료하고 상장 한두 개씩은 취득한 것을 볼 수 있는데...&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-aee8ee7c7a4b8132-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 후기는 수상 다수! 우수한 SSAFY형 인재! 와 같은 엄청난 사람이 아니라 어딘가에 있음직한 그 외의 SSAFY 입과생의 이야기라고 생각해주면 될 것 같다. 또한, 추후 SSAFY 과정을 이수할 분들에게도 도움이 될 수 있는 경험담이 되길 바라면서 적어본다.&lt;/p&gt;
&lt;h3&gt;입과&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-442ceb7c6829c573-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-219d272c02689759-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;통상적으로 비전공자에게 높은 것으로 알려진 SSAFY의 벽을 어찌어찌 뚫어냈다. 자기소개서는 합격, 면접에서는 불합격을 통보 받았다...만 그 희귀하다는 비전공 추가 합격 통보를 받고 서울 캠퍼스에 입과하게 되었다. 입과 직후에 하는 스타트캠프는 겪은 사람들만 안다는 고충이 있다는데 정말정말 막바지 합격자였던지라 스타트캠프를 생략할 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-fa0b9011434db360-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;SSAFY에 입과하게 되면 본인 앞으로 이름표가 주어지는데 해당 이름표조차 다른 초기 합격자 이름 위에 내 이름이 풀로 붙여져 있었다... 나중에 자꾸 떨어지려고 해서 테이프로 고정한 게 위 사진이다.&lt;/p&gt;
&lt;p&gt;지금 생각해보면 오히려 이 이름표 덕분에 조금 더 열심히 하게 되었다고 생각한다. 얻게 된 기회가 정말 귀하다는 것을 지속적으로 실감하고 동기부여 받으면서 다닐 수 있었던 것 같다!&lt;/p&gt;
&lt;h3&gt;1학기, Python 트랙&lt;/h3&gt;
&lt;p&gt;1학기에는 Java 트랙과 Python 트랙이 존재하는데 Java를 배우는 게 좋다는 것을 알고는 있었지만 Python 트랙을 수강하게 되었다. 1학기에 배웠던 것들에는 여러 가지가 있는데...&lt;/p&gt;
&lt;p&gt;막상 2학기에 가면 실제로 잘 배워둬서 써먹은 것들은 Algorithm, Git, Python 요 정도 뿐이었던 것 같다. 이마저도 Python, Algorithm은 프로젝트에 써먹는 것보단 코딩테스트 활용이 압도적으로 빈번한 수준...&lt;/p&gt;
&lt;p&gt;(프론트는 배우긴 하지만 대부분 리액트를 다시 익히니 존재감도 없다)&lt;/p&gt;
&lt;p&gt;그래도 트랙에 입과하게 된다면 SSAFY답게 거의 모든 사람들이 열정적으로 배워나가는 것을 볼 수 있다. 반 내에서 으쌰으쌰하면서 스터디도 만들고 같이 카페에서 공부도 하면서 지냈던 것 같다.&lt;/p&gt;
&lt;p&gt;나 같은 경우, 프로그래밍이라곤 대학 교양으로 깔짝한 것이 전부인지라 거의 제로 베이스였고 모든 걸 잘할 수는 없다고 생각해 선택과 집중이 필요하다고 생각했다. 그래서 채용 프로세스를 먼저 살펴보고 차근차근 뚫을 수 있도록 노력하자고 생각했다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;서류 전형 → 코딩 테스트 → 인성 면접 → 기술 면접 → 채용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;대부분의 기업이 이 범위를 벗어나지 않는다는 걸 확인했다. 결과적으로 &lt;strong&gt;&apos;코딩 테스트 못 뚫으면 미래가 없다&apos;&lt;/strong&gt; 고 생각했고 이는 알고리즘 몰빵 테크 트리의 시작이 되는데..&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-cfc4f764b173e0d0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;알고리즘 능력의 향상을 위해 스터디도 만들 정도로 시간 투자를 많이 했었지만 결국 플래티넘 5 달성을 끝으로 사실상 방전하게 되었다. 저 시절부터 삼성 소프트웨어 역량 평가 B형을 뚫기 위해 Java 언어도 틈틈히 공부하면서 단련했지만 아쉽게도 미취득으로 끝내게 되었다. 후기는 &lt;a href=&quot;/blog/b&quot;&gt;여기&lt;/a&gt;에 있고 B형을 취득하게 된다면 SSAFY에서 제공하는 다양한 혜택, 체험, 연계 등에 있어 우선순위가 상승하기 때문에 딸 수 있다면 꼭 따주도록 하자!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-b2e44c75355b7edc-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;(하지만 감을 잃지 않기 위해 꾸준히 낮은 수준의 문제라도 풀어내는 것은 중요하다고 생각하여 꾸준히 풀었다)&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-8836547a6ac0689c-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이런저런 고초를 겪고 거의 매주 있는 이론 및 실기 시험을 통과하는 나날을 지나 관통 프로젝트에 도달했다. 여기서는 지금 생각해보면  2학기에 도전하는 7주 프로젝트를 &lt;strong&gt;압도적으로 더 적은 인원과 시간으로&lt;/strong&gt; 해치워야 하는 수준을 요구했다! 어디선가 멋진 코드를 이쁘게 가져와서 응용하는 수준을 봤을거라 생각하고 있지만 그럼에도 결국 남들이 하지 못한 것을 하는 팀이 상을 거머쥐었던 것 같다. (예를 들자면, 배포와 같은 것들)&lt;/p&gt;
&lt;h3&gt;2학기, 프로젝트의 연속인 나날들&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-00a981c35d4a739d-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;2학기 과정에서는 내내 프로젝트를 하게 되는데 이게 SSAFY에서 제일 중요한 부분이라고 생각한다.&lt;/p&gt;
&lt;p&gt;지금 생각해보면 1학기 때는 기업을 지원하고 싶어도 &amp;quot;뭐 해봤어요?&amp;quot; 라고 묻는다면 대답할 거리가 없어서 자기소개서나 면접이나 어필할 수 있는 부분이 한정적인데, 2학기를 점차 진행하면서 결과에 관계 없이 내가 프로젝트에 충실히 참여했다면 &amp;quot;이런이런 부분을 했고 이런이런 부분에서 어려움을 느꼈지만 이런이런 방식으로 개선했다&amp;quot; 와 같은 말을 내놓을 수 있게 된다!&lt;/p&gt;
&lt;p&gt;주제가 저렇게 정해져 있는 것처럼 보이지만 특화 프로젝트가 아니라면 주제에 매몰되지 않고 어지간하면 팀에서 원하는 프로젝트를 진행할 수 있었다. 나의 경우, 앱 개발 프로젝트를 2회 진행했고 모바일 사양의 웹 개발을 1회 진행했다. 포지션의 경우는 사람마다 2학기에 하고자 하는 바가 다를 수 있는데 모든 포지션을 경험해보고 싶어서 백엔드 1회, 프론트 1회, 앱 1회의 경험을 가지고 가게 되었다.&lt;/p&gt;
&lt;p&gt;Python 트랙에 입과한다면, 대부분 Java와 담을 쌓게 되는데, 2학기 프로젝트의 99%가 스프링 부트를 사용하므로 어쩔 수 없이 프론트엔드로 향하게 되고 이는 본인 포지션의 Fix를 가져오게 된다. 따라서 내가 백엔드를 지망하겠다는 확고한 의지가 있다면 Python 트랙 수강생의 경우 Java를 따로 병행하는 것이 좋다. 필자의 경우도 Java 강의를 따로 수강하여 백엔드 포지션에 대해 지속적으로 여지를 남겨두고자 했고 결과적으로 백엔드 포지션도 1회 경험할 수 있었다.&lt;/p&gt;
&lt;h3&gt;취업 시도와 다양한 면접&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-3bc909615076161a-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;내가 이렇게 1학기부터 2학기까지 뭔가 보여주는 환상의 시간을 가지는 동안, 소수의 준비된 사람들은 꾸준히 기업과의 컨택을 시도하고 그 결과 중간중간 일명 싸탈, SSAFY 탈출을 하는 영광을 누리게 되었다. 그런 사람들을 보면서 처음에 생각했던 것은 &apos;아직 준비가 부족하니까... 프로젝트 다 끝나고 해도 늦지 않을거야&apos; 였지만 결과적으로 2학기를 병행하다보면 자연스럽게 탈출하는 여러 선두주자들을 보면서 준비를 진행하게 된다.&lt;/p&gt;
&lt;p&gt;누군가 사원증을 받는 동안 2학기 수료증을 받아들고 수료하는 본인의 모습이 아쉬울 수 있기 때문에 꾸준히 도전해보도록 하자. 필자는 많은 곳을 지원했고 결과적으로 받아들게 된 건 2학기 수료증이지만 그래도 후회 없는 지원을 했다고 생각한다.&lt;/p&gt;
&lt;p&gt;SSAFY의 다양한 혜택들과 쌓아온 기술을 가지고 코딩 테스트, 서류 전형을 통과하게 되면 면접이 남아있다. 인성 면접과 기술 면접 둘 다 맞아보기 전까진 어디가 부족한지 모르는 경우가 많다보니 교육 기간 중에 경험할 수 있다면 정말정말 좋다고 생각한다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-09b59b4e7d50faf7-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;면접은 확실히 해보면 해볼 수록 실력이 늘어난다. 실제로 모자란 부분을 채워가는 능력적인 부분도 그렇지만 면접관에 대한 대처 자세 등은 그 상황과 긴장감이 없다면 경험해 볼 수 없다고 생각하기 때문에 본인 능력이 된다면 실제 원하는 수준보다 낮은 기업의 면접이라도 꾸준히 응시하여 실제 원하는 기업에서 더 좋은 결과를 얻을 수 있도록 하자!&lt;/p&gt;
&lt;h3&gt;수료 그 뒤에는..&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-0a384db17a2502a8-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;그래서 이제 SSAFY 끝나고 뭐 할건데?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 질문에 대해 많은 시간 고민을 했고 아직도 답을 찾는 중이다. 기본적으로는 진행했던 프로젝트에 대해서 차분히 되돌아보는 시간을 가지는 한편으로, 배워왔던 내용에 대한 정리도 하고 싶고, 여전히 취업은 빨리 하고 싶은 상황이니...&lt;/p&gt;
&lt;p&gt;결국 전부 꾸준히 진행할 거 같다는 생각이 든다. 지금까지 해왔던 공부가 없어지는 것은 아니기 때문에 위로 계속 쌓는 게 최선이라 믿고 있다. 나의 SSAFY 8기 여정은 여기서 마무리 짓지만 개발자 인생이 여기서 끝나는 건 아니니까! 더 좋은 날이 기다릴 거라 믿고 꾸준히 노력하려고 한다.&lt;/p&gt;
</content:encoded></item><item><title>2023 LG CNS 상반기 채용 전형 후기</title><link>https://www.traceoflight.dev/ko/blog/2023-lg-cns/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/2023-lg-cns/</guid><description>깡!</description><pubDate>Fri, 16 Jun 2023 08:27:19 GMT</pubDate><content:encoded>&lt;h3&gt;들어가며&lt;/h3&gt;
&lt;p&gt;이번 상반기에 LG CNS 신입사원 채용 전형에 지원했고 마지막 면접까지 종료되었다. 결론부터 말하자면 아쉽게도 좋은 결과를 얻지 못했다. 하지만 실패를 덮어만 두기보다는 내가 어떤 부분이 모자랐는지 기록하고 다음 번에 더욱 잘하면 된다는 생각이 있어 이렇게 남겨본다. 이후 채용에 참가하는 사람들에게도 도움이 되었으면 좋겠다.&lt;/p&gt;
&lt;h3&gt;서류 전형&lt;/h3&gt;
&lt;p&gt;서류 전형에서 특이한 부분은 별로 없었던 것 같다. 특이점이라면 타 기업들 대비 자기소개서의 분량이 적었다는 점 정도? 다만, 서류에서 불합격을 받은 케이스가 주변에 있어서 의외로 변별 요소가 있었던 것 같다. 합격을 했다면 이후 코딩테스트 절차를 진행할 수 있었다.&lt;/p&gt;
&lt;h3&gt;코딩 테스트&lt;/h3&gt;
&lt;p&gt;전반적으로 난이도가 엄청 어렵지는 않았던 것 같다. 실버 ~ 골드 5 수준의 문제를 랜덤으로 풀이할 수 있다면 충분히 올솔이 가능했다고 생각한다. 굳이 방향성을 잡자면 창의적인 알고리즘을 요구하기보단 현장에서 어떤 문제가 나오더라도 대응할 수 있는 연습이 도움이 되었을 거 같다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-0050c757a54e8dd4-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;일정 수준 이상 해결했다면 면접으로 넘어갈 수 있으며 무사히 통과할 수 있었다.&lt;/p&gt;
&lt;h3&gt;1차 면접&lt;/h3&gt;
&lt;p&gt;코딩 테스트를 통과하고 1차 면접에 대한 정보를 받을 수 있었다. 기본적으로 화상 면접으로 진행되었고, 자기소개서에 적혀있던 문항에 대한 내용이나 일반적인 면접 문항 위주로 물어봐주셨던 것 같다. 면접관님이 해주셨던 이야기가 흐릿하게 기억에 남는데, 신입에게 큰 기대를 가지고 역량에 대한 평가를 하진 않는다고 하셨다. 그 뒤에도 뭔가 말씀해주셨는데.. 긴장을 한지라 기억에서 삭제가 된 상태다. 아무래도 역량을 덜 본다면 인성이나 자기소개 내용 검증, 성실성, 컬쳐핏 같은 것을 위주로 보지 않을까 싶다!&lt;/p&gt;
&lt;p&gt;여담이지만 코딩 테스트에서 좋은 결과를 냈다면 면접관님께 테스트에 대한 소소한 칭찬을 들을 수도 있다. 혹시나 있을지 모를 반례나 엣지 케이스에 대해서 신경을 좀 썼는데 결과에 대해 확답을 받은 거 같아서 기분이 좋았다.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-95c1802564fc051e-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;면접이 낯설어서 엄청 뻣뻣하고 어설프게 봤고 나와서 떨어졌다...고 생각했는데 2차 면접까지 갈 기회를 얻을 수 있었다.. 역시 면까몰은 과학이다.&lt;/p&gt;
&lt;h3&gt;2차 면접&lt;/h3&gt;
&lt;p&gt;다른 기업 전형들과 유사하게 실제 입사하게 된다면 가게 될 부서의 결정권을 가지신 분들이 직접 면접을 보러 오시는 것 같다. 처음에 자기 소개까지 소개해주셨는데 너무 떨린 나머지 기억을 못해서 죄송스러울 따름이다. 그래도 편하게 진행해주시려고 했던 거 같은데.. 1차 면접이랑 비슷하다고 생각한 순간 간혹 기술적인 부분을 치고 들어오셔서 횡설수설했던 것만 기억한다. 마지막으로 포부 있게 입사하게 된다면 어떤 자세로 업무에 임하면 좋은 결과를 얻을 수 있을지 여쭤봤는데 웃으면서 이런저런 좋은 말씀을 해주셨던게 기억에 남는다. 그리고..&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-306ab2ca84c94e03-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;받아든 결과는 솔직히 마음이 아팠다. 하지만 면접을 보고 난 뒤 생각해보면 아쉬웠던 부분이 많았다보니 납득할 수 없는 결과는 아니었다. 받았던 기술 질문이나, 지원한 회사에 대한 인지 수준 등 너무 부실하게 대답했던 면모가 있어서 면접관님이 볼 때 인상적으로 뽑고 싶다고 생각할만한 강점이 없었다고 생각한다.&lt;/p&gt;
&lt;h3&gt;소회&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-ca72109624ea74bc-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;아무래도 상반기 채용 전형 중에서 가장 합격에 가까웠던 기업이다보니 아쉽지 않을 수는 없다. 하지만, 지금 받아든 성적표가 앞으로 나아갈 방향을 알려준다고 생각하고 있고 실제로 모자랐던 부분을 계속 보완하기 위해 노력하고 있다.&lt;/p&gt;
&lt;p&gt;이 경험을 발판 삼아서 더 나은 모습이 되길 바란다. 나중에 나를 뽑지 않은 것을 후회하도록 만들어 줄 수 있다면 그거야말로 좋은 결과가 아닐까? 다음 CNS 채용 때는 &lt;strong&gt;&apos;나를 고를 수 있는 기업&apos;&lt;/strong&gt; 의 입장보다 &lt;strong&gt;&apos;내가 기업을 고를 수 있는 사람&apos;&lt;/strong&gt; 이 될 수 있도록 더더욱 노력해야겠다.&lt;/p&gt;
</content:encoded></item><item><title>[면접 질문] JVM의 구조와 원리</title><link>https://www.traceoflight.dev/ko/blog/jvm/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/jvm/</guid><description>JVM에 대한 면접 질문 정리</description><pubDate>Thu, 15 Jun 2023 16:30:41 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;23-06-27 미작성 내용 보충
23-07-01 내용 보충 및 작성 완료&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Java 개요&lt;/h3&gt;
&lt;h4&gt;1. Java의 개발 철학&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Write Once, Run Anywhere&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;플랫폼과 독립적인 언어를 지향&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;같은 언어로 짜여진 코드를 어떤 운영 체제에서든 실행시킬 수 있는 것을 초점으로 두고 개발됨 (일종의 크로스 플랫폼)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. JDK&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java Development Kit
자바 개발 툴이며 JRE, JVM을 전부 포함한다. 기본적으로 자바로 만든 프로그램만 실행하면 되는 사용자와 달리 개발자는 JDK를 설치해야 한다. JDK는 Compiler를 포함하고 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java Runtime Environment
자바 실행 환경으로 Java Class Library, Java Class Loader, JVM을 포함하고 있다. 클래스 로더와 라이브러리를 통해 작성된 자바 코드를 라이브러리와 결합하여 JVM에서 구동할 수 있도록 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Java Virtual Machine&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JVM이란?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Java Virtual Machine, 자바 가상 머신.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;자바 프로그램 실행 환경을 조성해주는 소프트웨어&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Java Code → Compiler → 기계어&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;애플리케이션 실행을 위한 메모리를 할당 받아서 Java Runtime Data Area를 구축한다.&lt;/p&gt;
&lt;h3&gt;Runtime Data Area&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Heap 영역&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Method 영역&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위 2개의 영역은 모든 Thread가 공유&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;PC Register&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Native Method Stack&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stack 영역&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;위 3개의 영역은 Thread마다 시작 시에 생성, 종료 시 없어진다.&lt;/p&gt;
&lt;h3&gt;각 영역별 세부 사항&lt;/h3&gt;
&lt;h4&gt;1. Heap&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;클래스의 인스턴스, 배열이 저장되는 공간&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;동적 메모리 관리 시스템 &apos;Garbage Collection&apos;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. Method&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;클래스, 인터페이스의 구조를 저장하는 공간&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. Stack&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C의 스택 구조와 유사하며, 지역 변수 및 함수의 실행 결과를 저장&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;함수의 호출과 반환을 담당하며 Stack Frame을 가진다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stack Frame 이란?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;각 함수마다 함수의 호출 정보가 포함된 구분된 공간
Frame은 LIFO 방식으로 처리됨
여유 공간이 없을 때 프레임이 추가될 경우 → Stack Overflow 발생
프롤로그, 에필로그를 활용한 포인터 방식으로 스택 복귀 위치 확인&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;4. Native Method Stack&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;C, CPP로 작성된 메서드의 실행 스택&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;코드 실행 시 Native Method Stack이 할당됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;StackOverflowError나 OutOfMemoryError 발생할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;동적으로 스택의 크기를 조정할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;5. PC Register&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;각 스레드마다 PC Register를 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스레드가 현재 할당된 명령을 실행할 때 명령의 주소를 기록&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;명령마다 값을 꾸준히 변동시켜 가리키는 값을 실행하도록 함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.1&quot;&gt;JVM Document&lt;/a&gt;
&lt;a href=&quot;https://m.blog.naver.com/goreng2/221770110714&quot;&gt;고랭이님의 블로그&lt;/a&gt;
&lt;a href=&quot;https://velog.io/@sgwon1996/JAVA%EC%9D%98-%EB%8F%99%EC%9E%91-%EC%9B%90%EB%A6%AC%EC%99%80-JVM-%EA%B5%AC%EC%A1%B0&quot;&gt;sgwon1996님의 velog&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[면접 질문] DB Index란?</title><link>https://www.traceoflight.dev/ko/blog/db-index/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/db-index/</guid><description>데이터베이스 인덱스에 대한 면접 질문 정리</description><pubDate>Tue, 13 Jun 2023 15:20:25 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;인덱스 사용의 장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;테이블 조회 속도 상승으로 인한 성능의 향상&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;시스템 부하를 줄일 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;인덱스 사용의 단점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DB 인덱싱을 위한 추가적인 저장 공간이 필요함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DB 관리를 위한 추가적인 작업 및 오버헤드 발생&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;인덱스 관리&lt;/h3&gt;
&lt;p&gt;인덱스를 항상 최신 정렬된 상태를 유지해야 원하는 값을 빠르게 탐색할 수 있기 때문에 데이터가 빈번하게 수정되는 속성에 인덱스를 걸게 된다면 역으로 오버헤드로 인한 성능 저하가 발생할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;INSERT: 삽입 시 삽입된 데이터의 인덱스를 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DELETE: 삭제한 데이터의 인덱스를 사용안함 처리해야 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UPDATE: 기존 인덱스 사용안함 처리 + 갱신된 데이터 인덱스 추가&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;사용하는 자료 구조&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;B+ Tree&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;B Tree 개선 사양&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;리프 노드에만 데이터를 저장&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;리프 노드끼리는 연결 리스트의 형태를 가짐&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Hash Table&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Key - Value 한 쌍으로 데이터를 저장
매우 빠른 시간 안에 데이터를 탐색할 수 있음
부등호 연산에 부적합하여 자주 사용하진 않음 (정렬 X)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;인덱스의 분류&lt;/h3&gt;
&lt;h4&gt;1. Key에 따른 분류&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기본 인덱스: 기본키 포함 (Key의 순서 = 레코드의 순서)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;보조 인덱스: 기본키 미포함 (Key의 순서 != 레코드의 순서)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. 파일 조직에 따른 분류&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;집중 인덱스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비집중 인덱스&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. 데이터 범위에 따른 분류&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;밀집 인덱스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;희소 인덱스&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://brunch.co.kr/@skeks463/25&quot;&gt;brunchstory by Nathan&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[1Day-1CS] 각 계층을 처리하는 기기</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-e4320ddf/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-e4320ddf/</guid><description>1일 1CS, 각 계층을 처리하는 기기에 대한 간단 정리</description><pubDate>Mon, 05 Jun 2023 15:08:16 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;2023-06-18 내용적 통일성을 위한 이전 글 내용 병합&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;애플리케이션 계층을 처리하는 기기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;L7 스위치: 로드밸런서라고도 하며, 서버의 부하를 분산하는 기기&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;스위치: 여러 장비를 연결하고 데이터 통신을 중재, 연결된 포트로만 전기 신호를 보내어 데이터를 전송하는 통신 네트워크 장비&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;시스템 처리 가능 트래픽의 증가를 목표로 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;URL, 서버, 캐시, 쿠키 등을 기반으로 트래픽을 분산&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;불필요 외부 데이터를 걸러내는 필터링 기능도 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;트래픽 모니터링 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;= Health Check를 통해 장애가 발생한 서버를 트래픽 분산 대상에서 제외&lt;/p&gt;
&lt;h3&gt;L4 스위치와 L7 스위치의 차이&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;L4 스위치는 전송 계층을 처리하는 기기로 스트리밍 관련 서비스에서 사용 불가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메시지 기반 인식 불가능, IP &amp;amp; Port 기반의 트래픽 분산&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클라우드 서비스에서 L7 스위치 로드밸런싱은 ALB (Application Load Balancer) 컴포넌트로, L4 스위치를 이용한 로드밸런싱은 NLB (Network Load Balancer) 컴포넌트로 진행&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Health Check&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;전송 주기와 재전송 횟수 등을 설정하고 반복적으로 서버에 요청을 보내는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;서버에 부하가 가지 않을 수준으로 적절할것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다양한 방식으로 요청을 보내며 정상적으로 처리된 경우 정상 서버로 판별함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;로드밸런서를 활용한 서버 이중화&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;2대 이상의 서버를 기반으로 가상 IP를 제공하고 이를 기반으로 안정적인 서비스 제공&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;특정 서버에서 에러가 발생하더라도 서비스가 지속되어야 하기 때문에 서버 이중화가 필요하다.&lt;/p&gt;
&lt;h3&gt;인터넷 계층을 처리하는 기기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;라우터: 여러 개의 네트워크를 연결, 분할, 구분시켜주는 역할
L3 스위치: L2 스위치 + 라우터&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;데이터 링크 계층을 처리하는 기기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;L2 스위치: 장치들의 Mac 주소를 관리, 패킷 전송 담당
브리지: 두 근거리 접속망을 상호 접속할 수 있도록 하는 통신망 연결 장치&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;물리 계층을 처리하는 기기&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;NIC (Network Interface Card): LAN 카드, 고유 식별Mac 주소가 여기에 존재함
리피터: 들어온 신호를 증폭하여 다른 쪽으로 전달
AP: 패킷을 복사하는 기기, 유선 LAN을 연결하여 무선 네트워크 연결을 위한 장치&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[면접 질문] Framework와 Library (Feat. ChatGPT)</title><link>https://www.traceoflight.dev/ko/blog/framework-library/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/framework-library/</guid><description>Framework와 Library에 대한 면접 질문 정리</description><pubDate>Sat, 03 Jun 2023 13:45:20 GMT</pubDate><content:encoded>&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;이번에 이에 대한 질문을 면접에서 처음으로 마주하게 되었는데 솔직히 안다고 생각했던 내용이었지만 명확하게 대답하지 못하고 우물쭈물하다가 동문서답을 해버리고 말았다... 그래서 다음에 마주했을 땐 그러지 말아야지 하는 생각으로 조금 더 확실하게 알고자 내용을 적어본다!&lt;/p&gt;
&lt;h3&gt;Library&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;개발 시 공통으로 사용할 수 있는 기능들을 모듈화한 것으로 특정 기능을 수행하도록 제작된 프로그램&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Framework&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;여러 기능을 가진 클래스, 라이브러리가 특정한 결과물을 구현하기 위해 합쳐진 형태&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;ChatGPT의 대답&lt;/h3&gt;
&lt;p&gt;위 정의들은 여러 글들을 읽어보고 개인적으로 정답에 가깝다고 생각해본 결과들이다. 하지만 뭔가 부실한 느낌이 있고 자세하게 정의된 응답이 듣고 싶어져서 ChatGPT를 활용해보기로 했다!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Library의 정의
&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-63d37d80c7d7a66e-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Framework의 정의
&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-f8277c02067f5cf0-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;그래서 뭐가 다른데?&lt;/h3&gt;
&lt;p&gt;위 대답을 통해 다시 Framework와 Library를 파악해보면&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Library&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;재사용 가능한 코드와 리소스의 모음
함수, 클래스, 메서드, 데이터 유형 등으로 구성&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Framework&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;소프트웨어의 개발을 위한 구조적인 틀 혹은 플랫폼
미리 정의된 코드와 라이브러리로 구성&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이 내용을 보면서 궁금한 점이 안 생길 수 없다. 프레임워크는 라이브러리를 포함할 수 있는데 라이브러리는 프레임워크를 포함할 수 없는 것일까?&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-27fca29bce6050ea-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;예상대로 프레임워크가 라이브러리를 포함할 수 있지만 그 역은 불가능하다는 점을 확인할 수 있었다. 또한, 해당 내용을 통해서 프레임워크와 라이브러리의 중요한 차이점을 확인할 수 있는데..&lt;/p&gt;
&lt;p&gt;바로 &lt;strong&gt;코드 흐름의 제어권&lt;/strong&gt;이다. 라이브러리의 경우는 &lt;strong&gt;개발자가 라이브러리의 기능을 호출해서 사용하는 형태&lt;/strong&gt;이지만 프레임워크의 경우, &lt;strong&gt;프레임워크에 의해 개발자의 메서드가 호출되는 형태&lt;/strong&gt;라는 점이 큰 차이점이 있다고 할 수 있다.&lt;/p&gt;
&lt;p&gt;프레임워크에서 나타나는 형태를 IoC (Inversion of Control), 제어의 역전이라고 한다. Dependency Injection과 관련이 있는 내용이니 따로 적을 일이 있을 것이라고 생각해서 크게 내용을 담진 않을 것이다.&lt;/p&gt;
&lt;h3&gt;결론&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;라이브러리는 재사용 가능한 코드와 리소스의 모음, 프레임워크는 개발을 위한 구조적인 틀 혹은 플랫폼이다. 일반적으로 기능적인 측면에서 비슷하게 작동하므로 굳이 차이점을 찾자면 사용 방식에서 찾을 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프레임워크는 라이브러리를 포함할 수 있지만 라이브러리는 프레임워크를 포함할 수 없다. 코드 흐름의 제어권의 경우 프레임워크는 프레임워크가, 라이브러리의 경우는 개발자가 가진다. 따라서 프레임워크의 경우 개발자가 프레임워크를 수정하는 것이 일반적으로 불가능하며 라이브러리의 경우는 필요에 따라 개발자가 커스터마이징하는 것이 가능하다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://curryyou.tistory.com/363&quot;&gt;카레유님의 Blog&lt;/a&gt;
ChatGPT 3.5&lt;/p&gt;
</content:encoded></item><item><title>[면접 질문] Fork와 Exec의 차이</title><link>https://www.traceoflight.dev/ko/blog/fork-exec/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/fork-exec/</guid><description>Process의 fork와 exec에 대한 면접 질문 정리</description><pubDate>Wed, 31 May 2023 07:48:53 GMT</pubDate><content:encoded>&lt;h3&gt;fork()와 exec()의 공통점&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;한 프로세스가 다른 프로세스를 실행시키기 위해 사용함&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;fork()&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;새로운 프로세스를 위한 메모리를 할당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프로세스가 추가됨 (pid가 다른 프로세스가 하나 생김)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;exec()&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;새로운 프로세스를 위한 추가적인 메모리를 할당하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;기존 프로세스를 덮어서 새로운 프로세스를 로드 (pid 동일)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;→ 호출한 이후에는 새로운 프로세스가 작동하므로 기존 프로그램의 exec 시점 이후의 프로그램은 작동하지 않음&lt;/p&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://woochan-autobiography.tistory.com/207#2.%20fork(),%20exec()%EC%9D%98%20%EC%B0%A8%EC%9D%B4%EC%A0%90&quot;&gt;U-chan Seon&apos;s Blog&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 2887, Python] 행성 터널</title><link>https://www.traceoflight.dev/ko/blog/boj2887/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj2887/</guid><description>BOJ 2887, &quot;행성 터널&quot; 문제의 Python 풀이</description><pubDate>Tue, 30 May 2023 15:33:18 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2887&quot;&gt;BOJ 2887&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;그래프 이론, 정렬, 최소 스패닝 트리&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-edb2ff1f13cf5892-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이 문제를 처음 마주하고 난 뒤 벌써 반 년이 넘게 지났다는 것에 놀라움이.. 그래도 최근에 플래티넘 문제를 소홀히 한 것 치곤 그래도 납득할 수 있다는 풀이로 해결했다는 점에서 의의가 충분하지 않았나 싶어 기록해보기로 했다.&lt;/p&gt;
&lt;p&gt;이 문제를 정공법으로 해결하기 위해서는 최대 10만 개의 좌표 중 2개를 골라 그 값들을 최소값부터 나열한 뒤 최소 간선부터 포함시켜 나가는 유니온 파인드 + 크루스칼 알고리즘의 조합으로 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;하지만 그렇게 풀이할 경우 10&lt;sup&gt;5&lt;/sup&gt; * 10&lt;sup&gt;5&lt;/sup&gt; 라서 가볍게 100억 개의 경우의 수를 가지게 되고 이는 결과적으로 100초 가량의 풀이 시간을 요구하기 때문에 불가능한 풀이 방법이라고 할 수 있다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tip: 1억 연산 횟수 당 1초 가량으로 고려하면 연산이 용이하다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;따라서 이 문제에서의 핵심은 어떻게 O(N&lt;sup&gt;2&lt;/sup&gt;) 의 경우의 수를 O(N) 단위로 내리느냐라고 할 수 있겠다.&lt;/p&gt;
&lt;p&gt;결론부터 말하자면 현재 문제에서 임의의 점에 대해서 스패닝 트리를 작성할 때 인접한 점 이외의 점은 고려하지 않아도 된다.&lt;/p&gt;
&lt;p&gt;임의의 점 A, B가 존재하고 C라는 점에 연결해야 하는 상황을 보자.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;x값의 차이(|X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;B&lt;/sub&gt;|)가 y, z보다 작은 최소값인 경우
→ C라는 점의 x값이 A와 B의 x값 사이에 존재함을 가정&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;|X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| + |X&lt;sub&gt;B&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| 인 경우 차이가 존재하지 않음&lt;/li&gt;
&lt;li&gt;|X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;B&lt;/sub&gt;| 를 유지하고 C를 추가로 연결하는 임의의 |X&lt;sub&gt;A&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| 나 |X&lt;sub&gt;B&lt;/sub&gt; - X&lt;sub&gt;C&lt;/sub&gt;| 가 존재한다면 &lt;strong&gt;반드시 기존 스패닝 트리보다 값이 커짐&lt;/strong&gt; → &lt;strong&gt;반례 존재로 불가&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;따라서 임의의 두 점을 연결하는 간선이 현 문제에서 최소 스패닝 트리에 포함된다면 그 두 점은 반드시 인접하고 있어야 한다는 증명이 된다!&lt;/p&gt;
&lt;p&gt;이 증명을 해결하는 점이 관건이며 나머지는 일반적인 유니온 파인드 문제와 크게 다르지 않다고 생각한다.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;추가) heapq 대신 PriorityQueue를 사용했을 때 시간 초과가 발생했는데 해당 이슈에 대한 답변을 찾을 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/36991716/whats-the-difference-between-heapq-and-priorityqueue-in-python&quot;&gt;What&apos;s the difference between heapq and PriorityQueue in python?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;PriorityQueue의 경우 Thread Safety를 보장하기 때문에 더 느리다고 한다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 행성 터널&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; heapq &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; heappush, heappop

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;check_union&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;union_info: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, now_target: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
    해당 노드의 현재 유니온을 조회하는 함수
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; union_info[now_target] == -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        union_info[now_target] = now_target

    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; union_info[now_target] != now_target:
        union_info[now_target] = check_union(union_info, union_info[now_target])

    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; union_info[now_target]

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_union&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;union_info: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, target_1: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_2: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
    두 점이 같은 유니온인지 확인하고 아니라면 합쳐주는 함수
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    union_1 = check_union(union_info, target_1)
    union_2 = check_union(union_info, target_2)

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; union_1 == union_2:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; union_1 &amp;gt; union_2:
            union_info[union_1] = union_2
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            union_info[union_2] = union_1

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

planet_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
coord_list = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(planet_number):
    coord_list.append([i] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())))

cost_queue = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;):
    coord_list.sort(key=&lt;span class=&quot;hljs-keyword&quot;&gt;lambda&lt;/span&gt; x: x[i])
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; j &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(planet_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):
        heappush(
            cost_queue,
            (
                coord_list[j + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;][i] - coord_list[j][i],
                (coord_list[j][&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], coord_list[j + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]),
            ),
        )

union_info = [-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(planet_number)]

total_length = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
line_number = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; cost_queue:
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; line_number == planet_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    now_length, nodes = heappop(cost_queue)
    node_a, node_b = nodes

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; make_union(union_info, node_a, node_b):
        total_length += now_length
        line_number += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(total_length)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[면접 질문] Process와 Thread의 차이, Multi Thread</title><link>https://www.traceoflight.dev/ko/blog/process-thread/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/process-thread/</guid><description>Process와 Thread의 차이에 대한 면접 질문 정리</description><pubDate>Mon, 29 May 2023 17:44:03 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;&lt;s&gt;아직 작성 중인 글입니다!&lt;/s&gt;
&lt;s&gt;23. 05. 30. 작성 완료&lt;/s&gt; → 23. 06. 09. 내용 추가&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Program&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;컴퓨터가 특정 작업을 수행하기 위해 작성된 실행 가능한 일련의 명령어 모음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;다양한 방식으로 정의되어 있지만 전반적으로 읽어봤을 때 이렇게 이해하기로 했다! 프로그램에 대한 정의를 먼저 확인한 이유는 프로세스의 정의가 좀 더 좁은 범위의 프로그램이기 때문이다.&lt;/p&gt;
&lt;h3&gt;Process&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&apos;실행 중인&apos;&lt;/strong&gt; 프로그램의 &lt;strong&gt;&apos;인스턴스&apos;&lt;/strong&gt; (Task와 거의 비슷한 의미로 사용)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메모리 상에서 실행되는 운영체제 기준의 작업 단위&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;생성에 많은 시간과 자원을 소비함 (오버헤드가 크다)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;프로그램 자체가 아닌 프로그램의 인스턴스로 여러 개가 동시에 존재하는 것이 가능하다는 것이 특징적인 부분이라고 생각한다.&lt;/p&gt;
&lt;h3&gt;Thread&lt;/h3&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프로세스 내 작업을 수행하는 CPU 기준의 실행 단위&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 프로세서는 1개 이상의 스레드가 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스레드는 각각의 레지스터와 스택을 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;힙 메모리 공간은 공유&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;그래서 둘의 차이는?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;프로세스가 좀 더 큰 범주의 단위라고 볼 수 있음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;하지만 단순하게 여기까지만 말하는 거라면 굉장히 포괄적인 답변이라고 생각할 수 있을 거 같아서 잘 정리된 글들을 참고해서 추가적인 정리를 해보았다!&lt;/p&gt;
&lt;h3&gt;작동 방식&lt;/h3&gt;
&lt;h4&gt;1. Process의 경우&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프로세스가 실행 시 별도의 메모리 영역을 운영 체제로부터 할당&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메모리 영역은 Code/Data/Stack/Heap의 형식을 가짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다른 프로세스의 메모리 영역에 접근할 수 없음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. Thread의 경우&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Process의 Stack 영역은 분할하여 고유 영역을 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;나머지 Code, Data, Heap 영역은 공유&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프로세스의 오류가 다른 프로세스의 영역으로 번지지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;But 하나의 스레드가 오류 발생하는 경우 전체 스레드 종료&lt;/strong&gt;
→ 메모리 영역을 공유하는 부분이 존재하기 때문&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;정리&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Process와 Thread의 차이점이란?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프로세스는 동적으로 사용 중인 프로그램, 스레드는 일종의 작업 실행 단위로 개념 자체가 다름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프로세스는 최소 1개 이상의 스레드를 포함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프로세스끼리는 메모리 공간을 일반적으로 공유하지 않으나 스레드는 공유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;각각의 오류 발생 시 프로세스는 혼자만 다운, 스레드는 동일 프로세스 내 전체 다운&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3&gt;+ Multi-Thread에 대하여&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;하나의 프로세스 내에서 여러 개의 스레드가 동시에 작업을 수행하는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;문맥 교환 (Context Switching)&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;기본적으로 동시에 처리할 수 있는 최대 작업 수는 Core의 수만큼
Core의 수보다 많은 스레드가 실행되는 경우 각 코어가 여러 작업을 번갈아가면서 수행
스레드가 교체될 때 현재까지의 작업 상태나 다음 작업에 필요한 데이터를 저장하고 읽어오는 작업&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;멀티 스레드와 프로세스의 장단점&lt;/h4&gt;
&lt;h5&gt;1) 멀티 스레드의 장점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프로세스 생성 및 자원 할당을 위한 시스템 콜이 졸어 자원의 효율적 관리가 가능.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;한 프로세스 내의 Stack을 제외한 메모리 공간을 공유하므로 스레드 간 데이터 주고 받는 처리 비용이 적음.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스레드 간의 통신 방법이 복잡하지 않아 프로그램 응답 시간을 단축할 수 있음.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2) 멀티 스레드의 단점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;디버깅의 어려움 및 설계 난이도의 상승&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다른 프로세스에서 스레드 제어 불가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메모리 공유로 인한 동기화 문제 (동시에 같은 자원에 접근)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스레드의 문제 발생 시 전체 프로세스에 영향&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;3) 멀티 프로세스의 장점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;프로세스에 문제 발생 시 해당 프로세스 외부로 영향이 확산되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;4) 멀티 프로세스의 단점&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;문맥 교환에서의 오버헤드가 큼&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프로세스 간 통신은 스레드 간 통신보다 어렵고 복잡한 편&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://ko.wikipedia.org/wiki/&quot;&gt;위키백과의 프로세스와 스레드 항목&lt;/a&gt;
&lt;a href=&quot;https://velog.io/@raejoonee/%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4%EC%99%80-%EC%8A%A4%EB%A0%88%EB%93%9C%EC%9D%98-%EC%B0%A8%EC%9D%B4&quot;&gt;프로세스와 스레드의 차이 by raejoonee&lt;/a&gt;
&lt;a href=&quot;https://gmlwjd9405.github.io/2018/09/14/process-vs-thread.html&quot;&gt;프로세스와 스레드의 차이 by heejeong Kwon&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[CI/CD] 인스턴스부터 DooD 배포까지의 흐름 (Feat. Nginx, Jenkins)</title><link>https://www.traceoflight.dev/ko/blog/ci-cd-dood-feat-nginx-jenkins/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/ci-cd-dood-feat-nginx-jenkins/</guid><description>Docker와 Nginx를 활용한 배포 기반 다지기</description><pubDate>Sat, 27 May 2023 14:55:17 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;23-06-16 볼륨 마운팅 명료성을 위해 경로 수정
23-07-05 개발 편의를 위해 세팅 조정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;/blog/cicd-docker-jenkins-git-webhook&quot;&gt;[CI/CD] Docker + Jenkins + Git Webhook을 활용한 FastAPI 서버 자동 배포 정리&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;이번 글을 작성하게 된 이유는 위에 있는 지난 글에 1차적으로 공부하려고 했던 내용을 담았지만 수정할 부분을 수정하고, 가다듬을 부분은 가다듬어서 깔끔한 하나의 글로 완성하고자 했기 때문인다.&lt;/p&gt;
&lt;p&gt;지난 번 이후의 배포 관련 Task와 주변 사람들의 배포를 도와주는 과정에서 어느 정도의 노하우를 터득했고 정형화했기 때문에 해당 기록을 남겨 다음 번에도 배포하는 과정에서 하나의 일관된 프로세스로 사용할 수 있으면 좋겠다! 해당 글을 순서대로만 따라한다면 아마 배포하는 것이 어렵지 않을 것이라고 생각한다.&lt;/p&gt;
&lt;h3&gt;1편 이후로 공부한 추가적인 내용&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Docker in Docker로 구현하는 것보다 Docker out of Docker로 구현하는 이유?&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기본적으로 Docker는 Docker 컨테이너 위에서 명령을 수행할 수 있도록 하는 것을 권장하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Docker in Docker는 Docker가 설치된 컨테이너에 막강한 권한을 부여하는 것으로 보안 위험을 초래할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;그나마 Docker out of Docker는 컨테이너 외부 Docker와의 소켓 공유를 통해 도커 명령을 실행하는 방식&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Docker API를 사용하는 방식은 어때?&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;사실 1편에서 문제 해결을 위해 사용해봤던 방식이고 실제로 효과를 봤다.
하지만 Docker out of Docker가 성공적으로 빌드된 상황이라면 CI/CD 절차에서 크게 아직 필요성을 느끼진 못할 듯..&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;따로 글을 나누기에는 애매한 거 같아서 간단하게 기록한 API 관련 내용&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Docker는 REST API를 통해 엔진과 클라이언트가 통신을 하는데 대부분 사용할 일이 없지만 사용할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;  docker --tlsverify --tlscacert=/.docker/ca.pem \
  --tlscert=/.docker/cert.pem --tlskey=/.docker/key.pem \
  -H={server_ip}:{port_number} &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; nginx \
  sed -i &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;4s/.*$/ server {container}:8000;/&amp;#x27;&lt;/span&gt; /etc/nginx/sites-available/default.conf
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 코드는 TLS 인증서를 가진 Docker Client를 통해 임의의 서버에 위치한 Nginx 설정 파일의 내용을 수정하는 코드이다.
-H 명령어를 통해서 해당 서버의 포트를 통해 Daemon(Docker Engine) 과 통신하며 나머지 코드는 인증서를 통한 접속 보안 절차이다.&lt;/p&gt;
&lt;p&gt;만약 인증서를 사용하지 않은 채로 포트를 열어두거나 한다면 누군가 열어둔 포트를 통해 컨테이너 탁란을 당할 수 있다!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-fb3d711504538106-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;컨테이너 탁란 실제 경험담. Docker에서 사용하는 일반적인 포트를 인증 보안 없이 풀어둔 결과...&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;인증서를 통한 보안 처리는 반드시 진행해야 하며 피치 못한 이유로 그렇지 못한다면 해당 포트를 통해 행할 수 있는 명령을 제한하는 것이 필수불가결하다.&lt;/p&gt;
&lt;p&gt;[Docker API Documents] (&lt;a href=&quot;https://docs.docker.com/engine/api/v1.43/&quot;&gt;https://docs.docker.com/engine/api/v1.43/&lt;/a&gt;) 의 내용을 보면 더욱 자세하게 확인 가능!&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;All in One 배포 기반 구축의 절차&lt;/h3&gt;
&lt;h4&gt;1. 인스턴스 접속 및 인스턴스 업데이트&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;ssh -i {secure shell key 경로} {사용자 이름}@{IP 주소}

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get update
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get upgrade
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ubuntu 세팅을 진행하는 경우 사용자 이름이 ubuntu인 경우가 많다.&lt;/p&gt;
&lt;h4&gt;2. 방화벽 설정&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw allow ssh    &lt;span class=&quot;hljs-comment&quot;&gt;# ssh를 22로 대체할 수 있다.&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw allow http   &lt;span class=&quot;hljs-comment&quot;&gt;# http를 80으로 대체할 수 있다.&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw allow https  &lt;span class=&quot;hljs-comment&quot;&gt;# https를 443으로 대체할 수 있다.&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw &lt;span class=&quot;hljs-built_in&quot;&gt;enable&lt;/span&gt; 	  &lt;span class=&quot;hljs-comment&quot;&gt;# 방화벽 가동&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ufw status 	  &lt;span class=&quot;hljs-comment&quot;&gt;# 방화벽 상태 확인&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;아마 클라우드를 사용하는 경우 기본적으로 클라우드 자체적인 포트 보안 설정이 있기 때문에 해당 설정에서 개방을 따로 해줘야 한다.
ufw는 우분투의 방화벽인데 처음에 설정할 때 꺼져 있는 경우 포트 허가를 해준 후 켜주는 절차가 필요하다.
위 설정을 통해 기본적인 http(80), https(443), ssh(22) 포트를 개방한 상태로 방화벽을 켤 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;반드시 포트 allow 설정 먼저 해두고 켜는 것을 추천한다. 22번, ssh 포트를 닫아둔 채로 방화벽을 켜면 접속할 수 없다..&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;3. Docker 및 Docker Compose 설치&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Docker 설치&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get update
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get install ca-certificates curl gnupg

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | &lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; gpg --dearmor -o /etc/apt/keyrings/docker.gpg
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; a+r /etc/apt/keyrings/docker.gpg

&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;deb [arch=&lt;span class=&quot;hljs-subst&quot;&gt;$(dpkg --print-architecture)&lt;/span&gt; signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
&lt;span class=&quot;hljs-subst&quot;&gt;$(. /etc/os-release &amp;amp;&amp;amp; echo &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$VERSION_CODENAME&lt;/span&gt;&amp;quot;&lt;/span&gt;)&lt;/span&gt; stable&amp;quot;&lt;/span&gt; | \
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get update
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;span class=&quot;hljs-comment&quot;&gt;# Docker Compose 설치&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; apt install docker-compose
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/engine/install/ubuntu/&quot;&gt;우분투 Docker 설치 Documents&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;2023년 5월 기준 Documents에서 필요한 내용만 몰아서 기재했다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; usermod -aG docker &lt;span class=&quot;hljs-variable&quot;&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 명령어를 통해 sudo 없이 docker 명령어를 사용할 수 있다.
해당 명령어를 넣지 않는다면 &lt;code&gt;/var/run/docker.sock: connect: permission denied&lt;/code&gt; 가 발생할 것이다.&lt;/p&gt;
&lt;h4&gt;4. docker-compose.yml 작성&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3.8&amp;#x27;&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
  {&lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}&lt;span class=&quot;hljs-string&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;driver:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bridge&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;services:&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Jenkins Container 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;jenkins:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins/jenkins:lts&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{원하는 포트 번호}:8080&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/jenkins:/var/jenkins_home&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;배포 파이프라인 툴은 Jenkins를 활용한다고 생각하고 작성했다.&lt;/p&gt;
&lt;p&gt;추가할 네트워크가 없다면 네트워크 부분은 아예 배제할 수 있고 Docker out of Docker를 사용하기 위해 소켓에 대한 볼륨 바인딩을 진행한다. 필요에 따라서 Time Zone이나 추가 볼륨 바인딩을 설정할 수 있다.&lt;/p&gt;
&lt;h4&gt;5. 사용할 도메인을 DNS 설정&lt;/h4&gt;
&lt;p&gt;도메인 사업자마다 다른 방식을 사용한다. 해당 도메인 사업자의 등록 방법을 보고 내가 사용할 서버의 IP를 등록해서 도메인과 이어주는 과정을 처리해야 한다.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.whatsmydns.net/&quot;&gt;What&apos;s My DNS&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;등록하고 바로 사용할 수 있는 게 아니라 DNS 서버에 반영되는 시간이 존재한다. 간단하게 얼마나 퍼졌나 확인할 수 있는 사이트를 위에 첨부했다.&lt;/p&gt;
&lt;h4&gt;6. Let’s Encrypt를 활용한 인증서 발급&lt;/h4&gt;
&lt;h5&gt;1) docker-compose.yml&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;nginx:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt; 			&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정을 위한 바인딩&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/sites-available:/etc/nginx/sites-available&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;				&lt;span class=&quot;hljs-comment&quot;&gt;# 인증서 공유를 위한 바인딩&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:80&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:443&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}

  &lt;span class=&quot;hljs-comment&quot;&gt;# Certbot 컨테이너 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;certbot:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 내용을 docker-compose.yml에 추가하고 따로 처리하진 않는다.&lt;/p&gt;
&lt;h5&gt;2) mount/sites-available/default.conf&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;&lt;span class=&quot;hljs-section&quot;&gt;server&lt;/span&gt; {
     &lt;span class=&quot;hljs-attribute&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;;
     &lt;span class=&quot;hljs-attribute&quot;&gt;listen&lt;/span&gt; [::]:&lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;;

     &lt;span class=&quot;hljs-attribute&quot;&gt;server_name&lt;/span&gt; my_domain.org; 

     &lt;span class=&quot;hljs-section&quot;&gt;location&lt;/span&gt; /.well-known/acme-challenge/ {
             &lt;span class=&quot;hljs-attribute&quot;&gt;allow&lt;/span&gt; all;
             &lt;span class=&quot;hljs-attribute&quot;&gt;root&lt;/span&gt; /var/www/certbot;
     }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;파일을 생성하고 &lt;code&gt;server_name&lt;/code&gt; 뒤에 내 도메인을 기재한 내용을 담는다.&lt;/p&gt;
&lt;h5&gt;3) mount/nginx.conf&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-nginx&quot;&gt;&lt;span class=&quot;hljs-attribute&quot;&gt;user&lt;/span&gt; nginx;
&lt;span class=&quot;hljs-attribute&quot;&gt;worker_processes&lt;/span&gt; auto;
&lt;span class=&quot;hljs-attribute&quot;&gt;worker_priority&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

&lt;span class=&quot;hljs-attribute&quot;&gt;pid&lt;/span&gt; /run/nginx.pid;
&lt;span class=&quot;hljs-attribute&quot;&gt;include&lt;/span&gt; /etc/nginx/modules-enabled/&lt;span class=&quot;hljs-regexp&quot;&gt;*.conf&lt;/span&gt;;

&lt;span class=&quot;hljs-section&quot;&gt;events&lt;/span&gt; {
        &lt;span class=&quot;hljs-attribute&quot;&gt;worker_connections&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1024&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;multi_accept&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;off&lt;/span&gt;;
}

&lt;span class=&quot;hljs-section&quot;&gt;http&lt;/span&gt; {

        &lt;span class=&quot;hljs-attribute&quot;&gt;sendfile&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;tcp_nopush&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;tcp_nodelay&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;keepalive_timeout&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;65&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;types_hash_max_size&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;2048&lt;/span&gt;;
        &lt;span class=&quot;hljs-attribute&quot;&gt;server_tokens&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;off&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;include&lt;/span&gt; /etc/nginx/mime.types;
        &lt;span class=&quot;hljs-attribute&quot;&gt;default_type&lt;/span&gt; application/octet-stream;
        &lt;span class=&quot;hljs-attribute&quot;&gt;log_format&lt;/span&gt;  main  &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&lt;span class=&quot;hljs-variable&quot;&gt;$remote_addr&lt;/span&gt; - &lt;span class=&quot;hljs-variable&quot;&gt;$remote_user&lt;/span&gt; [&lt;span class=&quot;hljs-variable&quot;&gt;$time_local&lt;/span&gt;] &amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$request&lt;/span&gt;&amp;quot; &amp;#x27;&lt;/span&gt;
                          &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&lt;span class=&quot;hljs-variable&quot;&gt;$status&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;$body_bytes_sent&lt;/span&gt; &amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$http_referer&lt;/span&gt;&amp;quot; &amp;#x27;&lt;/span&gt;
                          &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$http_user_agent&lt;/span&gt;&amp;quot; &amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$http_x_forwarded_for&lt;/span&gt;&amp;quot;&amp;#x27;&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;ssl_protocols&lt;/span&gt; TLSv1 TLSv1.&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; TLSv1.&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; TLSv1.&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;; &lt;span class=&quot;hljs-comment&quot;&gt;# Dropping SSLv3, ref: POODLE&lt;/span&gt;
        &lt;span class=&quot;hljs-attribute&quot;&gt;ssl_prefer_server_ciphers&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;access_log&lt;/span&gt; /var/log/nginx/access.log main;
        &lt;span class=&quot;hljs-attribute&quot;&gt;error_log&lt;/span&gt; /var/log/nginx/&lt;span class=&quot;hljs-literal&quot;&gt;error&lt;/span&gt;.log &lt;span class=&quot;hljs-literal&quot;&gt;debug&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;gzip&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;on&lt;/span&gt;;

        &lt;span class=&quot;hljs-attribute&quot;&gt;include&lt;/span&gt; /etc/nginx/sites-available/*;

}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;nginx를 처음 설치할 때 내용을 기반으로 적당한 기초 설정을 담았다.&lt;/p&gt;
&lt;h5&gt;4) Let&apos;s Encrypt를 통해 절차를 거친 인증서 발급&lt;/h5&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;curl -L https://raw.githubusercontent.com/wmnnd/nginx-certbot/master/init-letsencrypt.sh -o init-letsencrypt.sh
&lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; +x init-letsencrypt.sh
vi init-letsencrypt.sh			&lt;span class=&quot;hljs-comment&quot;&gt;# 여기서 도메인과 메일 주소를 입력해야 함&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; ./init-letsencrypt.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;인증서 발급 절차를 도와줄 파일을 외부에서 받아오고 권한을 설정한다. 이후 내 도메인과 메일 주소를 파일에 입력하고 해당 파일을 실행하는 것으로 인증서 발급을 진행할 수 있다. 발급이 실패할 경우 로그를 보고 실패 원인을 찾아 고쳐서 재시도하면 될 것이다.&lt;/p&gt;
&lt;h4&gt;7. 인증서 갱신까지 고려한 Nginx 세팅&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;nginx:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/sites-available:/etc/nginx/sites-available&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:80&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:443&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;연결을&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;원하는&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}
    &lt;span class=&quot;hljs-attr&quot;&gt;command:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;while :; do sleep 6h &amp;amp; wait $${!}; nginx -s reload; done &amp;amp; nginx -g \&amp;quot;daemon off;\&amp;quot;&amp;#x27;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Certbot 컨테이너 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;certbot:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;entrypoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;trap exit TERM; while :; do certbot renew; sleep 12h &amp;amp; wait $${!}; done;&amp;#x27;&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&apos;s Encrypt를 통해 발급한 인증서는 사용 기한이 제한되어 있으며 대신 유효 기간이 얼마 남지 않았다면 재발급을 진행할 수 있다. certbot 컨테이너와 nginx 컨테이너에 재발급 관련 명령어를 추가하여 인증서 갱신이 자동으로 진행되도록 처리할 수 있다. 인증서 발급이 완료된 상황으로 nginx가 에러로 인한 컨테이너 빌드 실패가 뜨지 않을 것이다.&lt;/p&gt;
&lt;h4&gt;8. Jenkins 컨테이너 내부에 Docker 설치&lt;/h4&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;추가된 내용) 원래는 명령어를 직접 나열했는데 직관적이지 못하다는 생각이 들어서 수정!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# /jenkins-docker-install.sh&lt;/span&gt;

apt-get update
apt-get install ca-certificates curl gnupg

install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
&lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; a+r /etc/apt/keyrings/docker.gpg

&lt;span class=&quot;hljs-built_in&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;deb [arch=&lt;span class=&quot;hljs-subst&quot;&gt;$(dpkg --print-architecture)&lt;/span&gt; signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/debian \
&lt;span class=&quot;hljs-subst&quot;&gt;$(. /etc/os-release &amp;amp;&amp;amp; echo &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&lt;span class=&quot;hljs-variable&quot;&gt;$VERSION_CODENAME&lt;/span&gt;&amp;quot;&lt;/span&gt;)&lt;/span&gt; stable&amp;quot;&lt;/span&gt; | \
&lt;span class=&quot;hljs-built_in&quot;&gt;tee&lt;/span&gt; /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null

apt-get update
apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기존 docker 설치 방법에서 sudo 명령어를 배제한 코드를 sh 파일로 제작했다. 이 파일을 마운트를 통해 내부에 넣고 실행시키면 깔끔하게 한 방에 설치할 수 있다!&lt;/p&gt;
&lt;hr&gt;
&lt;h4&gt;9. Docker Compose 처리&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;3.8&amp;#x27;&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
  {&lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}&lt;span class=&quot;hljs-string&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;driver:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;bridge&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;services:&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Jenkins Container 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;jenkins:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins/jenkins:lts&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;{포트 번호}:8080&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/jenkins:/var/jenkins_home&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/jenkins-html:/var/lib/jenkins&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./jenkins-docker-install.sh:/jenkins-docker-install.sh&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}

&lt;span class=&quot;hljs-comment&quot;&gt;# Nginx 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;nginx:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;nginx:latest&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/nginx.conf:/etc/nginx/nginx.conf&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./mount/nginx/sites-available:/etc/nginx/sites-available&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:80&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;443&lt;/span&gt;&lt;span class=&quot;hljs-string&quot;&gt;:443&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;networks:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;네트워크&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;이름&lt;/span&gt;}
    &lt;span class=&quot;hljs-attr&quot;&gt;depends_on:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; {&lt;span class=&quot;hljs-string&quot;&gt;선행&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;컨테이너&lt;/span&gt;}
    &lt;span class=&quot;hljs-attr&quot;&gt;command:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;while :; do sleep 6h &amp;amp; wait $${!}; nginx -s reload; done &amp;amp; nginx -g \&amp;quot;daemon off;\&amp;quot;&amp;#x27;&amp;quot;&lt;/span&gt;

  &lt;span class=&quot;hljs-comment&quot;&gt;# Certbot 컨테이너 설정&lt;/span&gt;
  &lt;span class=&quot;hljs-attr&quot;&gt;certbot:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;certbot/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;unless-stopped&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/conf:/etc/letsencrypt&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;./data/certbot/www:/var/www/certbot&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;environment:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;TZ=Asia/Seoul&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;entrypoint:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;/bin/sh -c &amp;#x27;trap exit TERM; while :; do certbot renew; sleep 12h &amp;amp; wait $${!}; done;&amp;#x27;&amp;quot;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 Jenkins 설정까지 추가한 뒤&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;language-xml&quot;&gt;docker-compose -f &lt;/span&gt;&lt;span class=&quot;hljs-template-variable&quot;&gt;{yml 파일 위치 및 파일명}&lt;/span&gt;&lt;span class=&quot;language-xml&quot;&gt; up -d
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;명령어를 통해 컨테이너를 전부 띄울 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker &lt;span class=&quot;hljs-built_in&quot;&gt;exec&lt;/span&gt; -it jenkins bin/bash
sh /jenkins-docker-install.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이렇게 Jenkins 컨테이너 내부에 Docker를 설치하는 것으로 Jenkins 내부 Shell 명령어를 통해 Docker Engine을 제어할 수 있게 된다.
기존 Docker Documents를 참고했으나 차이점은 sudo를 사용하지 않는다는 점과 Debian용 Docker를 설치한다는 점이 있겠다.&lt;/p&gt;
&lt;h3&gt;선택 사항&lt;/h3&gt;
&lt;h4&gt;1. Swap Memory 설정&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# swap memory 설정&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; fallocate -l {설정 용량} /swapfile   &lt;span class=&quot;hljs-comment&quot;&gt;# 설정 용량은 대체로 G 단위로 설정한다.&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;chmod&lt;/span&gt; 600 /swapfile
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; mkswap /swapfile
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; swapon /swapfile

&lt;span class=&quot;hljs-comment&quot;&gt;# 재부팅 시에도 지속 사용을 원할 경우&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; vi /etc/fstab 			&lt;span class=&quot;hljs-comment&quot;&gt;# &amp;#x27;/swapfile swap swap defaults 0 0&amp;#x27; 내용을 해당 파일에 삽입&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# swap 비활성화&lt;/span&gt;

&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; vi /etc/fstab 			&lt;span class=&quot;hljs-comment&quot;&gt;# &amp;#x27;/swapfile swap swap defaults 0 0&amp;#x27; 내용을 제거&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; swapoff -v /swapfile
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; /swapfile
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;인스턴스 성능 및 필요에 따라 인스턴스가 터지는 것을 방지하기 위한 스왑 메모리 설정을 진행할 수 있다.&lt;/p&gt;
&lt;h4&gt;2. Jenkins 플러그인 설치 오류 시 시도 방법&lt;/h4&gt;
&lt;p&gt;&amp;lt;해결책 1&amp;gt;
Jenkins 관리 &amp;gt; Plugin Manager &amp;gt; Advanced settings &amp;gt; 업데이트 사이트 파트에 접속
&lt;code&gt;https://updates.jenkins.io/update-center.json&lt;/code&gt; 를 &lt;code&gt;http://updates.jenkins.io/update-center.json&lt;/code&gt; 로 변경&lt;/p&gt;
&lt;p&gt;&amp;lt;해결책 2&amp;gt;
&lt;code&gt;skip-certificate-check&lt;/code&gt; 라는 이름의 플러그인 설치&lt;/p&gt;
&lt;p&gt;완벽한 해결책은 아니지만 해당 해결책을 전부 적용하는 것으로 어느 정도의 효과를 봤다.&lt;/p&gt;
&lt;h3&gt;마치며&lt;/h3&gt;
&lt;p&gt;Docker와 관련된 내용은 이후 일부 프레임워크 배포에 대한 것을 제외하면 여기서 일단락하려고 한다. 그래도 내가 만든 결과물을 실제 네트워크 상에서 볼 수 있다는 성취감이 있어서 배포에 대한 내용은 이후에도 기회가 된다면 더 적어볼 생각이 있다.&lt;/p&gt;
</content:encoded></item><item><title>[면접 질문] RESTful API란?</title><link>https://www.traceoflight.dev/ko/blog/restful-api/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/restful-api/</guid><description>RESTful API에 대한 면접 질문 정리</description><pubDate>Sun, 21 May 2023 17:27:57 GMT</pubDate><content:encoded>&lt;h3&gt;RESTful API&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;RESTful한 API를 말한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-3a8f738579ac35de-image.jpg&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;굉장히 당연한 말이지만 말 그대로이다!
그렇다면 각 단어의 뜻을 살펴본다면 RESTful API가 뭐하는 친구인지 알 수 있을 것이다.&lt;/p&gt;
&lt;h3&gt;API&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Application Programming Interface의 약자.
정의 및 프로토콜 집합을 사용하여 두 소프트웨어 구성 요소가 서로 통신할 수 있게 하는 메커니즘.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;이렇게 정의하고 있다. 내 방식대로 이해해보자면 소프트웨어의 구성 요소들끼리도 오브젝트 따위를 다루는 방식이 다 다르기 때문에 이 괴리를 처리하기 위해 규약을 정하여 서로 통신, 상호작용할 수 있도록 한 것을 말한다고 보면 될 것이다.&lt;/p&gt;
&lt;h3&gt;REST&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Representational State Transfer의 약자.
World Wide Web 등의 분산 하이퍼미디어 시스템을 위한 소프트웨어 아키텍처 중 하나.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;REST는 처음에 인터넷과 같은 복잡한 네트워크에서 통신을 관리하기 위한 지침으로 만들어졌고 대규모 통신에서 안정적인 지원이 가능하다고 하며 구현 및 수정도 용이하다.&lt;/p&gt;
&lt;h4&gt;REST 아키텍처의 원칙&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;균일한 인터페이스 (Uniform Interface)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;서버가 표준 형식으로 정보를 전송함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;표준 형식이 서버 내 리소스의 내부 표현과 다를 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;동일한 리소스에 대한 모든 API 요청은 특정 언어, 플랫폼에 관계없이 동일&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;무상태 (Stateless)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;각 요청은 다른 모든 요청에 대해 독립적&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서버가 추가적인 정보 없이 요청을 완전히 이해하고 이행할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;계층화 시스템 (Layered System)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;클라이언트 요청을 이행하기 위해 함께 작동하는 다양한 애플리케이션이 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다중 계층으로 서버를 구성, 서버와 클라이언트 사이에도 다른 승인된 중개자가 존재할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프록시, 게이트웨이 등의 중간 매체, 암호화, 로드밸런싱 계층 등이 추가될 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클라이언트에 보이지 않는 상태로 유지됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;캐시 가능성 (Cacheable)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;서버 응답 시간을 개선하기 위해 일부 응답을 저장하는 캐싱을 지원&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클라이언트 혹은 서버 측에서 캐싱을 구현함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;온 디맨드 코드 (On Demand Code)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;일반적으로 정적인 리소스를 전송&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;필요에 따라 실행 코드를 응답에 포함, 클라이언트 기능을 일시적으로 확장하거나 사용자 지정할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;RESTful API의 사용 이점&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;확장성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;클라이언트 - 서버 간 상호 작용을 최적화하므로 크기를 조정할 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;유연성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;완전한 클라이언트 - 서버 분리를 지원&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;각 부분이 독립적으로 발전할 수 있도록 서버 구성 요소를 단순화 &amp;amp; 분리&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;독립성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;사용되는 기술과 독립적&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API 설계와 관계 없이 다양한 프로그래밍 언어를 사용하여 클라이언트 &amp;amp; 서버 애플리케이션을 작성 및 기술을 변경할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;정리&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;RESTful API란?
REST 아키텍처를 사용한 애플리케이션 프로그래밍 인터페이스를 말하는 것으로 REST 아키텍처의 원칙을 준수한 프로그램 간의 상호 작용을 정리한 규약이다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;그래서 어떤 이점이 있는데?
해당 API를 사용하게 될 경우 확장성, 유연성, 독립성에서 이득이 있다고 할 수 있다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;참고&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/ko/what-is/restful-api/&quot;&gt;[AWS] RESTful API란 무엇인가요?&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>[1Day-1CS] 네트워크 기기의 처리 범위</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-2e8effb4/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-2e8effb4/</guid><description>1일 1CS, 네트워크 기기의 처리 범위와 애플리케이션 계층을 처리하는 기기에 대한 간단 정리</description><pubDate>Fri, 19 May 2023 17:06:42 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;2023-06-18 내용 범위 편집&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;계층별 처리 범위&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;애플리케이션 계층: L7 스위치&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인터넷 계층: L3 스위치, 라우터&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;데이터 링크 계층: L2 스위치, 브리지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;물리 계층: NIC, 리피터, AP&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>면접 질문 정리 시작! (질문 내역)</title><link>https://www.traceoflight.dev/ko/blog/velog-bdb80888/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/velog-bdb80888/</guid><description>실전 면접 질문 정리 및 시작 이유</description><pubDate>Tue, 16 May 2023 22:32:46 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-2d4a54a2ae94fc97-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;계기&lt;/h3&gt;
&lt;p&gt;본격적으로 기업에 이력서를 넣기 시작한지 얼마나 지났을까... 그래도 한 3달은 된 거 같은데 코딩 테스트는 모두 통과하는 건 아니지만 그래도 꽤 많은 통과율을 보여주고 있어 근래에 면접을 몇 번 다녀오는 성과가 있었다!&lt;/p&gt;
&lt;p&gt;하지만 내가 면접을 가더라도, 나름 CS 공부를 했다고 하더라도 면접에서 나오는 질문과 내가 공부한 CS 지식에는 차이가 있더라.. 그래서 면접에서 나왔던 문제들에 대해 핀포인트로 공부한 내용을 블로그에 담아보고자 한다.&lt;/p&gt;
&lt;h3&gt;질문 리스트&lt;/h3&gt;
&lt;h4&gt;Overall&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/restful-api&quot;&gt;RESTful API란?&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/process-thread&quot;&gt;Process와 Thread의 차이&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/blog/fork-exec&quot;&gt;Fork와 Exec의 차이&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/framework-library&quot;&gt;Framework와 Library&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Transaction이란?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OSI 7계층에 대하여&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서브넷과 게이트웨이, 사설IP에 대하여&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Backend&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/db-index&quot;&gt;DB Index란?&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/connection-pool&quot;&gt;Connection Pool이란?&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/jvm&quot;&gt;JVM의 구조와 원리&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/java-stack-heap&quot;&gt;자바 Heap &amp;amp; Stack의 구조&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;/blog/dependency-injection&quot;&gt;Dependency Injection&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스프링 IoC컨테이너가 어떻게 Bean들을 관리하는지
+ 프록시 패턴, Spring Bean은 프록시인데 어떻게 멀티스레드 동작을 하는지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;싱글톤 패턴과 Spring Dependency Injection&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Frontend&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;주소창에 접속 url을 입력하면 벌어지는 일&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 계층 간 데이터 송수신 과정 &amp; PDU</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-pdu/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-pdu/</guid><description>1일 1CS, 계층 간 데이터 송수신 및 TDU에 대한 간단 정리</description><pubDate>Sun, 07 May 2023 17:02:23 GMT</pubDate><content:encoded>&lt;h3&gt;캡슐화 &amp;amp; 비캡슐화 과정&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;캡슐화: 상위 계층의 헤더와 데이터를 하위 계층의 데이터 부분에 포함시키고 해당 계층의 헤더를 삽입하는 과정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;애플리케이션 → 전송 → 인터넷 → 링크 계층으로 전달&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전송 계층으로 전달되면서 세그먼트 혹은 데이터그램화 + TCP (Layer 4) 헤더 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인터넷 계층으로 전달되면서 IP (Layer 3) 헤더 추가 = 패킷&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;링크 계층으로 전달되면서 프레임 헤더 + 프레임 트레일러 추가 = 프레임&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;비캡슐화: 하위 계층에서 상위 계층으로 가며 각 계층의 헤더 부분을 제거하는 과정&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;비캡슐화는 반대로 진행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프레임 → 패킷 → 세그먼트, 데이터그램 → 메시지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;최종적으로 애플리케이션의 TDU (Transmission Data Unit) 메시지로 전달&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Protocol Data Unit&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;계층에서 계층으로 데이터가 전달될 때 한 덩어리의 단위&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;메시지, 세그먼트, 데이터그램, 패킷, 프래임, 비트 등 계층마다 명칭이 상이&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비트로 송신하는 것이 가장 빠르고 효율성이 높음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;애플리케이션 계층에서는 문자열 기반 송수신 (확장이 쉽다는 이유에서 기인함)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 반이중화 통신 (2), 무선 통신과 이더넷 프레임</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-70a48fb3/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-70a48fb3/</guid><description>1일 1CS, 반이중화 통신, 무선 통신, 이더넷 프레임에 대한 간단 정리</description><pubDate>Thu, 04 May 2023 14:01:28 GMT</pubDate><content:encoded>&lt;h3&gt;반이중화 통신의 종류&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CSMA/CD: 데이터를 보낸 이후 충돌이 발생 시 일정 시간 이후 재전송하는 방식&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CSMA/CA: 데이터를 보내기 전 캐리어 감지 등의로 사전에 가능한 한 충돌을 방지하는 방식&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터 송신 전 무선 매체 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;회선이 비어있는지 판단 (캐리어 감지)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;사용 중일 경우 랜덤값을 기반으로 간격을 늘려가면서 사용 가능성 체크 (IFS)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;무선 통신&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Wifi: 전자기기들이 무선 LAN 신호에 연결 할 수 있게 하는 기술, 무선 접속 장치가 필요하다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BSS(Basic Service Set)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기본 서비스 집합을 의미&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;공유기를 통한 단순 접속 + 동일 BSS 내의 AP 및 장치 서로 통신이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ESS(Extended Service Set)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;하나 이상의 연결된 BSS 그룹&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;장거리 무선 통신을 제공&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BSS 대비 더 많은 가용성과 이동성 지원&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;한 장소에서 다른 장소로 이동하여 중단 없이 네트워크에 계속 연결할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;이더넷 프레임&lt;/h3&gt;
&lt;p&gt;데이터 링크 계층에서 사용되는 전송 메커니즘&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Preamble: 이더넷 프레임의 시작을 알림&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SFD (Start Frame Delimiter): 다음 바이트부터 MAC 주소 필드 시작임을 알림&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DMAC, SMAC: 송수신 MAC 주소&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;EtherType: IP 프로토콜을 정의&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Payload: 전달받은 데이터&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CRC: 에러 확인 비트&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 2473, Python] 세 용액</title><link>https://www.traceoflight.dev/ko/blog/boj2473/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj2473/</guid><description>BOJ 2473, &quot;세 용액&quot; 문제의 Python 풀이</description><pubDate>Thu, 04 May 2023 13:15:05 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/2473&quot;&gt;BOJ 2473&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;이분 탐색, 정렬, 두 포인터&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;전형적인 투 포인터 문제에서 살짝 더 나간 문제인 거 같다.&lt;/p&gt;
&lt;p&gt;처음에 이 문제를 풀 때 3개의 용액을 합쳐야 하는 것 때문에 뭔가 다른 풀이가 있을 것이라고 생각한 나머지 의외로 정공법을 사용하지 않았고 그러다보니 실제 풀이가 늦어지는 결과를 낳았다.&lt;/p&gt;
&lt;p&gt;해당 문제에서 주의해서 봐야 할 부분은 전체 용액의 수가 5000 이하라는 점이다. 해당 조건이 없다면 이 문제를 절대 시간 내에 풀 수 없다... 처음에 이 조건을 유심히 보지 않아 다른 풀이법을 계속 찾게 된 점은 지금 봐도 아쉬운 점이었다.&lt;/p&gt;
&lt;p&gt;따라서 이 문제의 해결 방법은 이렇게 제시해 볼 수 있겠다.&lt;/p&gt;
&lt;p&gt;순서 정렬 → 용액 1개 고정 → 나머지 용액에 대해 해당 용액과 합하여 가장 0에 가까워 질 수 있도록 투포인터 알고리즘 사용 → 전부 순회했거나 0에 도달했다면 종료&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 세 용액&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

solution_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
solution_list = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

solution_list.sort()
characteristic_value = &lt;span class=&quot;hljs-number&quot;&gt;3000000000&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(solution_number):

    pointer_1 = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;
    pointer_2 = solution_number - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; pointer_1 &amp;lt; pointer_2:

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer_1 == idx:
            pointer_1 += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer_2 == idx:
            pointer_2 -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; pointer_1 &amp;gt;= pointer_2:
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        now_value = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;([solution_list[idx], solution_list[pointer_1], solution_list[pointer_2]])

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(now_value) &amp;lt; characteristic_value:
            characteristic_value = &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(now_value)
            result = [solution_list[idx], solution_list[pointer_1], solution_list[pointer_2]]

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; characteristic_value:
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_value &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:
            pointer_1 += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; now_value &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:
            pointer_2 -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; characteristic_value:
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

result.sort()

&lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(*result)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[1Day-1CS] 전이중화 통신과 반이중화 통신 (1)</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-1/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-1/</guid><description>1일 1CS, 전이중화 통신과 반이중화 통신 도입부에 대한 간단 정리</description><pubDate>Mon, 01 May 2023 16:24:13 GMT</pubDate><content:encoded>&lt;h3&gt;전이중화 통신&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;양쪽 장치가 동시에 송수신할 수 있는 방식&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;송신로와 수신로를 구분하여 데이터를 주고 받음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;현대 고속 이더넷이 해당 방식을 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;반이중화 통신&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;양쪽 장치는 서로 통신할 수 있으나 동시에 통신할 수 없음
한 경로를 기반으로 한 번에 한 방향만 통신&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터를 보낸 이후 충돌이 발생했다면 일정 시간 이후 재전송을 진행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;유선 LAN&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;트위스트 페어 케이블: 잡음(CrossTalk)를 줄이기 위해 꼬아 묶은 케이블&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;광섬유 케이블: 코어와 케이블의 굴절률 차이를 활용한 빛의 전송 케이블&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;무선 LAN&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;송신과 수신에 같은 채널을 사용하므로 반이중화 통신을 사용합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 인터넷 계층과 링크 계층</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-e167b4e7/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-e167b4e7/</guid><description>1일 1CS, 인터넷 계층과 링크 계층에 대한 간단 정리</description><pubDate>Thu, 27 Apr 2023 03:32:49 GMT</pubDate><content:encoded>&lt;h3&gt;인터넷 계층&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;장치로부터 받은 네트워크 패킷을 IP 주소로 지정된 목적지로 전송하기 위해 사용되는 계층&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;링크 계층&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;실절적으로 데이터를 전달하고 장치 간에 신호를 주고받는 규칙을 정하는 계층, 네트워크 접근 계층이라고도 불림&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;물리 계층: LAN을 통해 0, 1로 이루어진 데이터를 보내는 계층&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;데이터 링크 계층: Ethernet Frame을 통해 에러 확인, 흐름 및 접근 제어를 담당하는 계층&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 전송 계층</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-f7e9e56d/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-f7e9e56d/</guid><description>1일 1CS, 전송 계층에 대한 간단 정리</description><pubDate>Tue, 25 Apr 2023 17:14:48 GMT</pubDate><content:encoded>&lt;h3&gt;전송 계층&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;송신자와 수신자를 연결하는 통신 서비스를 제공
연결 지향 데이터 스트림 지원, 신뢰성, 흐름 제어를 제공
애플리케이션과 인터넷 계층 사이의 데이터 전달 중계 역할&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;TCP: 순서 보장, 연결 지향 프로토콜 사용, 수신 여부 확인 (가상회선 패킷 교환 방식)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UDP: 순서 보장 X, 수신 여부 확인 X, 단순한 데이터 전달 (데이터그램 패킷 교환 방식)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;가상회선 패킷 교환 방식&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;각 패킷에 가상회선 식별자가 포함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 패킷을 전송했다면 가상회선 해제, 패킷은 전송 순서대로 도착&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;데이터그램 패킷 교환 방식&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;패킷이 독립적 이동, 최적 경로 선택&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서로 다른 경로로 전송될 수 있고 순서도 다를 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCP의 연결 성립과 해제 과정&lt;/h3&gt;
&lt;h4&gt;연결: 3-way handshake&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;클라이언트가 자신의 ISN을 담은 연결 요청 플래그를 발송&lt;/li&gt;
&lt;li&gt;서버가 승인 번호로 서버의 ISN과 클라이언트의 ISN + 1을 반송&lt;/li&gt;
&lt;li&gt;클라이언트가 서버의 ISN + 1을 승인번호와 함께 재응답&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;연결 해제: 4-way handshake&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;클라이언트가 FIN 설정된 세그먼트를 보내고 FIN_WAIT 돌입&lt;/li&gt;
&lt;li&gt;데이러를 받은 서버가 클라이언트로 ACK 승인 세그먼트를 보내고 CLOSE_WAIT 돌입&lt;/li&gt;
&lt;li&gt;ACK 보낸지 일정 시간이 지난 이후 FIN 세그먼트 발송&lt;/li&gt;
&lt;li&gt;ACK를 받은 클라이언트 TIME_WAIT 돌입, 서버로 다시 ACK 재발송&lt;/li&gt;
&lt;li&gt;받은 서버가 CLOSE&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;TIME_WAIT을 쓰는 이유: 지연 패킷의 가능성, 연결 해제 확실하게 확인&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[BOJ 7490, Python] 0 만들기</title><link>https://www.traceoflight.dev/ko/blog/boj7490/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj7490/</guid><description>BOJ 7490, &quot;0 만들기&quot; 문제의 Python 풀이</description><pubDate>Mon, 24 Apr 2023 16:15:36 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/7490&quot;&gt;BOJ 7490&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;백트래킹, 브루트포스 알고리즘, 구현, 문자열&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;전형적인 백트래킹 문제라고 생각한다. 하지만 처리 과정이 살짝 난해한 점이 있었고 정렬 방식이 ASCII 순이라는 것도 조금 특이했던 것 같다.&lt;/p&gt;
&lt;p&gt;Python의 Eval 함수를 사용하면 쉽게 해결할 수 있다고 봤는데 해당 방식을 사용하지 않고 정공법으로 해결하였다.&lt;/p&gt;
&lt;p&gt;기본적으로 숫자의 합과 기존에 미처리된 숫자 2개를 들고 백트래킹을 진행하면서 &apos;덧셈&apos;, &apos;뺄셈&apos;, &apos;연산하지 않음&apos; 이 3가지 케이스에 대해서 전부 확인해준다는 생각으로 시도했고 맞았습니다를 받을 수 있었다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 0 만들기&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_sum_zero&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;
    result_arr: &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;,
    target_arr: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;,
    last_index: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;,
    now_index: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
    sum_now: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
    now_calc: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
    log=[],
&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&amp;quot;
    백트래킹을 활용하여 숫자들의 합이 0이 되도록 만드는 함수
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; last_index == now_index:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; sum_now + now_calc:
            result_arr.add(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;.join(log))

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; now_index:
            make_sum_zero(
                result_arr,
                target_arr,
                last_index,
                now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;,
                target_arr[now_index],
                [&lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(target_arr[now_index])],
            )

        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            new_number = target_arr[now_index]

            make_sum_zero(
                result_arr,
                target_arr,
                last_index,
                now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                sum_now + now_calc,
                new_number,
                log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;+&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
            )
            make_sum_zero(
                result_arr,
                target_arr,
                last_index,
                now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                sum_now + now_calc,
                -new_number,
                log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;-&amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
            )

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_calc &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;:
                make_sum_zero(
                    result_arr,
                    target_arr,
                    last_index,
                    now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                    sum_now,
                    &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; * now_calc - new_number,
                    log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
                )
            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
                make_sum_zero(
                    result_arr,
                    target_arr,
                    last_index,
                    now_index + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;,
                    sum_now,
                    &lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt; * now_calc + new_number,
                    log + [&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;(new_number)],
                )

testcase = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
output = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):
    arr_length = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
    result = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;()

    &lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 통해 결과 확인&lt;/span&gt;
    target_arr = [i &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; i &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, arr_length + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]
    make_sum_zero(result, target_arr, arr_length)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 혹여라도 겹치는 결과가 있다면 Set을 통해 배제, ASCII 순으로 정렬&lt;/span&gt;
    sort_result = &lt;span class=&quot;hljs-built_in&quot;&gt;sorted&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(result), key=&lt;span class=&quot;hljs-keyword&quot;&gt;lambda&lt;/span&gt; x: &lt;span class=&quot;hljs-built_in&quot;&gt;ascii&lt;/span&gt;(x))
    output.append(sort_result)

&lt;span class=&quot;hljs-comment&quot;&gt;# 문제 조건에 맞춰 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; element_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(output[idx])):
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(output[idx][element_idx])

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; idx != testcase - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[1Day-1CS] TCP/IP 4계층 모델과 애플리케이션 계층</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-tcp-ip-4/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-tcp-ip-4/</guid><description>1일 1CS, TCP/IP 4계층 모델과 애플리케이션 계층에 대한 간단 정리</description><pubDate>Mon, 24 Apr 2023 15:18:37 GMT</pubDate><content:encoded>&lt;h3&gt;인터넷 프로토콜 스위트 (Internet Protocol Suite)&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;인터넷에서 컴퓨터들이 서로 정보를 주고받는 데에 쓰이는 프로토콜의 집합&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;TCP/IP 4계층 모델로 설명하거나 OSI 7계층 모델로 설명&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCP/IP 4계층&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;네트워킹의 범위에 따라 4개의 추상화 계층으로 구성&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;애플리케이션 계층&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전송 계층&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인터넷 계층&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;링크 계층&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OSI 계층은 애플리케이션 계층 및 링크 계층을 세분화한 것이 특징&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;애플리케이션 계층&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;FTP, HTTP, SSH, SMTP, DNS 등 응용 프로그램이 사용되는 프로토콜 계층&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;FTP: 장치 간의 파일 전송&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SSH: Secure Shell Protocol, 암호화 네트워크 프로토콜&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HTTP: World Wide Web을 통해 웹 사이트를 이용하는 데에 사용하는 프로토콜&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SMTP: 전자 메일 전송을 위한 인터넷 표준 통신 프로토콜&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DNS: 도메인 이름과 IP 주소를 매핑해주는 서버&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;실질적으로 서비스를 사람들에게 제공하는 층&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[BOJ 25542, Python] 약속 장소</title><link>https://www.traceoflight.dev/ko/blog/boj25542/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj25542/</guid><description>BOJ 25542, &quot;약속 장소&quot; 문제의 Python 풀이</description><pubDate>Sun, 23 Apr 2023 18:10:04 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/25542&quot;&gt;BOJ 25542&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;브루트포스 알고리즘, 구현, 문자열&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;처음 이 문제를 대회에서 마주했을 때 아이디어 자체는 어렵지 않다고 생각했었다. 하지만 생각보다 구현에 손이 많이 가는 문제였고 7달 전의 나는 파이썬 코드 짜는 것도 굉장히 버거워했기 때문에 이 문제를 풀지 못했다.&lt;/p&gt;
&lt;p&gt;3달 전의 나도 이 문제를 해결하려고 했었지만 구상한 아이디어에서 추가적인 프루닝이 필요하다는 결론으로 인해 다시 고배를 마시고 문제를 뒤로 할 수 밖에 없었다.&lt;/p&gt;
&lt;p&gt;최근 여유도 생기고 기존에 풀지 못했던 것들을 다시 재도전하고 싶다는 욕구가 있어 다시 시도해봤는데 드디어 풀 수 있었다! 하지만 여전히 이 문제가 실버 문제라는 것에는 의문이 있다...&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-90c53486a9b70423-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;최초에는 기존에 있는 문자열로만 결과를 내려는 시도를 했었고 이는 당연히 반례가 존재하기 때문에 실패로 끝났다.&lt;/p&gt;
&lt;p&gt;다은에 시도한 코드도 조금 더 구현을 가미했지만 역시 기존 문자열만 사용했기 때문에 그 외의 문자열을 사용한 반례를 해결하지 못했다. 아래 코드를 첨부한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; itertools &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; product

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;is_similar&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;checker: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;, target: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;:
	&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    두 문자열이 비슷한지 확인하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;
    
    length = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(checker)
    counter = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(length):

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; checker[idx] != target[idx]:
            counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; counter &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
    
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 입력&lt;/span&gt;
store_number, name_length = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 문자열의 동일 인덱스를 집합화&lt;/span&gt;
name_list = []
store_chr_arr = [&lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;() &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(name_length)]

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(store_number):
    each_name = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
    name_list.append(each_name)

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(name_length):
        store_chr_arr[idx].add(each_name[idx])

result = &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 겹치지 않는 문자열의 Product를 비교&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_name_combination &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; product(*store_chr_arr):
    target_name = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.join(each_name_combination)
    
    is_answer = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; check_name &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; name_list:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_similar(target_name, check_name):
            is_answer = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_answer:
        result = target_name
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;CALL FRIEND&amp;#x27;&lt;/span&gt;)

&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;처음에 미사용 문자를 사용하려고 시도한 적은 있었지만 구현력이 부족하지 못해서 실제 구현으로 옮기진 못했는데 해당 방법을 통해 맞았습니다를 받을 수 있었다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 약속 장소&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;is_similar&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;checker: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;, target: &lt;span class=&quot;hljs-built_in&quot;&gt;str&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;bool&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    두 문자열이 비슷한지 확인하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    length = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(checker)
    counter = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(length):

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; checker[idx] != target[idx]:
            counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; counter &amp;lt;= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 정보 입력&lt;/span&gt;
store_number, name_length = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

name_list = []
first_checker = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 첫 문자열만 따로 분류하고 나머지는 이름 리스트에 기록&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(store_number):
    each_name = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().rstrip(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;\n&amp;#x27;&lt;/span&gt;))

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; first_checker:
        target_name = each_name
        first_checker = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        name_list.append(each_name)

&lt;span class=&quot;hljs-comment&quot;&gt;# 첫 문자열을 통해 문자열 변형된 후보를 양산&lt;/span&gt;
result_set = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;()

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(name_length):
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; alpha &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;65&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;91&lt;/span&gt;):
        temp = target_name[:]
        temp[idx] = &lt;span class=&quot;hljs-built_in&quot;&gt;chr&lt;/span&gt;(alpha)
        result_set.add(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&lt;/span&gt;.join(temp))

&lt;span class=&quot;hljs-comment&quot;&gt;# 확인하면서 후보를 소거&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; result_set &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; name_list:

    now_check_name = name_list.pop()
    remove_target = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;()

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; result_set:
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_similar(now_check_name, each_result):
            remove_target.add(each_result)

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; each_target &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; remove_target:
        result_set.remove(each_target)

&lt;span class=&quot;hljs-comment&quot;&gt;# 후보가 안 남았다면 문구를 출력, 후보가 남았다면 후보 중 하나를 출력한다.&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; result_set:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;CALL FRIEND&amp;#x27;&lt;/span&gt;)

&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result_set.pop())
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[1Day-1CS] 병목 현상, 네트워크의 분류와 분석</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-26405cdf/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-26405cdf/</guid><description>1일 1CS, 병목 현상과 네트워크의 분류 및 분석에 대한 간단 정리</description><pubDate>Sun, 23 Apr 2023 13:06:14 GMT</pubDate><content:encoded>&lt;h3&gt;병목 현상&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;전체 시스템의 성능이나 용량이 하나의 구성 요소로 인해 제한을 받는 현상&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;서버에서 이벤트를 열었을 때 트래픽이 많이 생기고 잘 관리하지 않는다면 발생&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;네트워크 토폴로지에 대한 정보가 있어야 병목 현상을 올바르게 해결 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;병목 현상의 주된 원인&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;네트워크 대역폭&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;네트워크 토폴로지&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서버 CPU, 메모리 사용량&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비효율적인 네트워크 구성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;네트워크의 분류&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;네트워크는 규모를 기반으로 분류&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;LAN (Local Area Network)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;근거리 통신망&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전송 속도가 빠르며 혼잡하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MAN (Metropolitan Area Network)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;대도시 지역 네트워크&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전송 속도는 평균, LAN보다 혼잡&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;WAN (Wide Area Network)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;광역 네트워크&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전송 속도 느림, MAN보다 혼잡&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;네트워크 성능 분석 명령어&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;ping&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;상태를 확인하고 싶은 대상 노드에 일정 크기 패킷을 전송&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;패킷 수신 상태와 도달 시간 등의 정보를 확인할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;netstat&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;접속된 서비스들의 네트워크 상태를 표시&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;네트워크 접속, 라우팅 테이블, 네트워크 프로토콜 등의 리스트를 보여줌&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;nslookup&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DNS 관련 내용의 확인을 위해 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;특정 도메인에 매핑된 IP를 확인할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;tracert (traceroute)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;목적지 노드까지의 네트워크 경로를 확인할 때 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;어느 구간에서 응답 시간이 느려지는지 등을 확인할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;그 외 다양한 명령어가 존재하며 wireshark, netmon 등의 프로그램을 사용함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 네트워크 토폴로지</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-21436c11/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-21436c11/</guid><description>1일 1CS, 네트워크 토폴로지 패턴에 대한 간단 정리</description><pubDate>Thu, 20 Apr 2023 12:56:24 GMT</pubDate><content:encoded>&lt;h3&gt;네트워크 토폴로지&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;노드와 링크가 어떻게 배치되어 있는지에 대한 방식, 연결 형태&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;트리 토폴로지&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;계층형 토폴로지, 트리 형태로 배치된 네트워크 구성&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;노드의 추가, 삭제가 쉬움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;특정 노드에 트래픽이 집중되는 경우 하위 노드에 영향을 끼침&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;버스 토폴로지&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;중앙 통신 회선 하나에 여러 개의 노드를 연결&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;근거리 통신망에 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;설치 비용이 적고 신뢰성이 우수하며 중앙 통신 회선에 노드의 추가, 삭제가 쉬움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스푸핑 문제가 존재&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;스푸핑:
LAN상에서 &lt;strong&gt;송신과 관련 없는 다른 호스트&lt;/strong&gt;에
&lt;strong&gt;가지 않도록 하는 스위치 기능을 마비&lt;/strong&gt;시키거나 속여서
&lt;strong&gt;특정 노드에 해당 패킷이 오도록 처리&lt;/strong&gt;하는 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;스타 토폴로지&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;중앙에 있는 노드에 모두 연결된 네트워크 구성&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;노드를 추가하거나 에러를 탐지하기 쉬움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;패킷의 충돌 발생 가능성이 적음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;중앙 노드 장애 발생 시 전체 네트워크 사용 불가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;설치 비용이 큼&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;링형 토폴로지&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;노드에서 노드로 데이터 이동, 고리 모양의 길을 통해 패킷을 처리&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;노드 수가 증가되어도 네트워크상의 손실이 거의 없음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;충돌 발생 가능성이 적고 노드 고장 발견이 쉬움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;네트워크 구성 변경이 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;장애가 발생하면 전체 네트워크에 영향을 끼침&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;메시 토폴로지&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;망형 토폴로지, 그물망형 연결 구조&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;한 단말에 장애가 발생해도 여러 개의 경로가 존재하여 네트워크 계속 사용 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;트래픽 분산 처리의 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;노드의 추가가 어렵고 구축 및 운용 비용이 큼&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 네트워크 시작, 처리량과 지연 시간</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-4b2e3588/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-4b2e3588/</guid><description>1일 1CS, 처리량과 지연 시간에 대한 간단 정리</description><pubDate>Mon, 17 Apr 2023 14:32:41 GMT</pubDate><content:encoded>&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;바야흐로 자소서의 계절이 도래해서 요즘 너무 바쁜 거 같은데 그래도 꾸준히 공부하는 것이 도움이 된다고 생각하므로 열심히 해보겠다는 다짐을 한 번 더 해본다!&lt;/p&gt;
&lt;h3&gt;네트워크&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;노드와 링크가 서로 연결만 되어 있거나 연결 및 리소스를 공유하고 있는 집합을 의미&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Node: 서버, 라우터, 스위치 등의 장치
Link: 무선 or 유선&lt;/p&gt;
&lt;h3&gt;처리량과 지연 시간&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;많은 처리량을 처리할 수 있으며 지연시간이 짧고, 장애 빈도가 적으며 좋은 보안을 갖춘 네트워크를 의미함&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;처리량: 링크 내에서 성공적으로 전달된 데이터의 양&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;트래픽: 특정 시점에 링크 내에 흐르는 데이터의 양
→ 트래픽이 많아졌다 = 흐르는 데이터가 많아졌다.
→ 처리량이 많아졌다 = 처리되는 트래픽이 많아졌다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;처리량은 트래픽, 대역폭, 네트워크 발생 에러, 장치 스펙에 영향을 받음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;지연 시간: 요청이 처리되는 시간, 왕복으로 측정&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;지연 시간은 매체 타입, 패킷의 크기, 라우터의 패킷 처리 시간에 영향을 받음&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[1Day-1CS] 디자인 패턴 &amp; 패러다임 정리</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-5e78c961/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-5e78c961/</guid><description>1일 1CS, 디자인 패턴 및 프로그래밍 패러다임에 대한 내용 일괄 정리</description><pubDate>Mon, 10 Apr 2023 16:56:14 GMT</pubDate><content:encoded>&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;지금 정리하고 있는 내용은 전부 &amp;quot;면접을 위한 CS 전공 지식 노트&amp;quot; 를 기반으로 이루어지고 있다. 사실 1일 1CS 시작하면서 언급했어야 할 내용 같지만 ㅋㅋ 지금에라도 적어본다.&lt;/p&gt;
&lt;h3&gt;디자인 패턴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;프로그램을 설계할 때 발생했던 문제점들을 객체 상호 관계 등을 통해 해결할 수 있도록 만든 규약&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;싱글톤 패턴: 1클래스 1인스턴스 / 모듈 결합력 이슈를 해결하기 위한 의존성 주입자 활용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;팩토리 패턴: 상위 클래스에서 큰 틀을 잡고 하위 클래스가 상속을 통해 구체화&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;전략 패턴: 캡슐화된 알고리즘을 컨텍스트 내부에서 교체하며 활용&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;옵저버 패턴: 상태 변화를 관찰, 변화 시 메서드 등을 통해 변화한 정보 전달&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;프록시 패턴: 대상 객체에 접근하기 전 흐름을 가로채는 인터페이스의 역할&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;이터레이터 패턴: 이터레이터를 사용하여 컬렉션의 요소에 접근, 하나의 인터페이스로 순회가 가능하다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;노출모듈 패턴: 접근 제어자를 만드는 패턴&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;MVC 패턴: Model, View, Controller로 구성되어 애플리케이션의 구성 요소를 분할하여 개발할 수 있도록 함&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;MVP 패턴: Controller만 Presenter로 교체&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MVVM 패턴: Controller만 View Model로 교체&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3&gt;프로그래밍 패러다임&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;선언형과 명령형의 구분
→ 선언형은 무엇을? 명령형은 어떻게?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;선언형&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;함수형 프로그래밍: 순수 함수를 쌓아 로직을 구현&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;명령형&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;객체지향 프로그래밍: 객체의 상호작용을 표현, 객체 메서드를 활용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;절차지향 프로그래밍: 연속적 계산으로 구성, 코드를 그대로 구현하는 것으로 충족&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 절차형 프로그래밍 &amp; 패러다임의 혼합</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-fbf17eb9/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-fbf17eb9/</guid><description>1일 1CS, 절차형 프로그래밍, 패러다임의 선택에 대한 간단 정리</description><pubDate>Sat, 08 Apr 2023 15:32:23 GMT</pubDate><content:encoded>&lt;h3&gt;절차형 프로그래밍&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;로직이 수행되어야 할 연속적 계산 과정으로 구성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;코드가 진행 방식대로 구현하는 것으로 완성되므로 가독성이 좋고 실행 속도가 빠름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모듈화가 어렵고 유지 보수성이 떨어지는 단점이 존재&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;패러다임의 선택&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;패러다임에 절대적 우위 같은 것이 존재하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서비스의 특징이나 비즈니스 로직을 고려한 패러다임을 선택&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;로직에 따른 취사선택도 좋음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] OOP의 설계 원칙</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-oop/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-oop/</guid><description>1일 1CS, 객체 지향 프로그래밍의 설계 원칙에 대한 간단 정리</description><pubDate>Thu, 06 Apr 2023 12:27:00 GMT</pubDate><content:encoded>&lt;h3&gt;단일 책임 원칙&lt;/h3&gt;
&lt;p&gt;Single Responsibility Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;모든 클래스는 각각 하나의 책임만 가져야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;개방-폐쇄 원칙&lt;/h3&gt;
&lt;p&gt;Open Closed Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;유지 보수 시 기존 코드들은 변경 사항이 적도록 하며, 확장이 용이해야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;리스코프 치환 원칙&lt;/h3&gt;
&lt;p&gt;Liskov Substitution Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다. 상속이 문제 없도록 잘 작동해야 한다는 뜻.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;인터페이스 분리 원칙&lt;/h3&gt;
&lt;p&gt;Interface Segregation Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;하나의 일반적인 인터페이스 대신 구체적인 여러 개의 인터페이스를 제작할 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;의존 역전 원칙&lt;/h3&gt;
&lt;p&gt;Dependency Inversion Principle&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;상위 계층은 하위 계층의 변화로부터 독립할 것, 자신보다 변하기 쉬운 것에 영향을 받지 않도록 상위 클래스나 추상화 인터페이스를 두어야 한다.&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>삼성 소프트웨어 역량 평가 B형 후기</title><link>https://www.traceoflight.dev/ko/blog/samsung-software-competency-evaluation-type-b/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/samsung-software-competency-evaluation-type-b/</guid><description>삼성 소프트웨어 역량 평가를 3회 전부 치루고 실패한 경험을 적은 수기</description><pubDate>Thu, 06 Apr 2023 12:08:47 GMT</pubDate><content:encoded>&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;먼저 결론부터 이야기하자면 현재까지 주어진 기회 3회 중에서 2회를 놓치고 말았다. 그래서 앞으로 어떤 식으로 공부해야 성공할 수 있을지를 남겨두고자 글을 남긴다.&lt;/p&gt;
&lt;h3&gt;자격&lt;/h3&gt;
&lt;p&gt;삼성 청년 소프트웨어 아카데미에서의 모의 역량 평가 A형 자격을 가지고 응시하였다.&lt;/p&gt;
&lt;h3&gt;회고&lt;/h3&gt;
&lt;p&gt;기존에는 아무래도 구현하는 것에 시간을 너무 할애했을 뿐 아니라 최적화 부분에 있어서도 많이 미흡하다는 느낌을 받았다. 앞으로 쳐볼 수 있는 기회가 1회 정도 남아있는데 최적화에 대해 공부를 많이 하고 들어가야겠다는 생각을 많이 했다.&lt;/p&gt;
&lt;h4&gt;1. 객체 사용 미흡&lt;/h4&gt;
&lt;p&gt;아무래도 Python을 사용하고 와서 그런지 객체 위주로 코딩하는 것에 익숙하지 않은 면이 있었고 많이 숙달하려고 했다고 하지만 아직 실력에 부족함을 느끼고 있다. 특히 Comparator와 같이 override하여 사용하는 부분들이 어렵다고 느낀다...&lt;/p&gt;
&lt;h4&gt;2. 자료 구조 숙지 상태&lt;/h4&gt;
&lt;p&gt;B형 통과자들의 이야기를 들어보면 전반적으로 자료 구조에 대한 이야기를 많이 강조하는데 내가 그만큼 자료 구조를 충분히 숙달하고 있냐라고 물어본다면 아직 부족한 면이 있기 때문에 마지막 테스트 시점까지 복습할 시간을 충분히 가질 필요가 있다고 생각한다.&lt;/p&gt;
&lt;h3&gt;+ 추가&lt;/h3&gt;
&lt;p&gt;4월 마지막을 끝으로 3회의 B형 여정이 마무리되었다. 결과적으로 B형 자격을 취득하지 못했고 마지막 문제는 거의 다 왔는데 마지막 한 발을 내딛지 못한 수준이라 아쉽다.&lt;/p&gt;
&lt;p&gt;하지만 시도하려고 했기에 노력을 했고, 노력을 했기 때문에 어느 정도의 실력 향상을 이룰 수 있었다고 생각한다.&lt;/p&gt;
&lt;p&gt;덕분에 기업 입사 코딩 테스트를 치룰 때 상대적으로 문제가 혜자로워 보이는 부분은 분명한 장점.&lt;/p&gt;
&lt;p&gt;아마 현재 내가 가지고 있는 자격은 임시 A형이므로 SSAFY 수료 이후에 더 이상 B형을 볼 기회는 없겠지만 그래도 또 하나 끝났다는 점에서 후련하다!&lt;/p&gt;
</content:encoded></item><item><title>[1Day-1CS] 명령형 프로그래밍 &amp; 객체 지향 프로그래밍</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-cdddda5a/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-cdddda5a/</guid><description>1일 1CS, 명령형 프로그래밍 &amp; 객체지향 프로그래밍에 대한 간단 정리</description><pubDate>Fri, 31 Mar 2023 11:39:05 GMT</pubDate><content:encoded>&lt;h3&gt;명령형 프로그래밍의 종류&lt;/h3&gt;
&lt;h4&gt;객체지향 프로그래밍 (Object-Oriented Programming)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;객체들의 집합으로 프로그램의 상호작용을 표현하며 객체 내부에 선언된 메서드를 활용하는 방식&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;설계에 많은 시간이 소요, 속도가 다른 프로그래밍 패러다임 대비 느린 편&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;객체지향 프로그래밍의 특징&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;추상화: 복잡한 시스템으로부터 핵심적인 개념, 기능을 간추려내는 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;캡슐화: 객체의 속성과 메서드를 하나로 묶고 일부를 외부로부터 은닉&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;상속성: 상위 클래스의 특성을 하위 클래스가 이어받아서 재사용, 추가, 확장이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다형성: 하나의 메서드나 클래스가 다양한 방법으로 동작 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overloading: 같은 이름을 가진 메서드를 여러 개 두는 것, &apos;컴파일&apos; 중 발생하는 &apos;정적&apos; 다형성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overriding: 상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의, &apos;런타임&apos; 중 발생하는 &apos;동적&apos; 다형성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 선언형 프로그래밍</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-dbfa4ad8/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-dbfa4ad8/</guid><description>1일 1CS, 선언형 프로그래밍에 대한 간단 정리</description><pubDate>Fri, 31 Mar 2023 11:36:56 GMT</pubDate><content:encoded>&lt;h3&gt;프로그래밍 패러다임&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;선언형 vs 명령형&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;선언형: 무엇을 풀어내는가에 집중하는 패러다임 (What)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;명령형: 어떻게 풀어내는가에 집중하는 패러다임 (How)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;예시)
선언형: 집의 주소 (위치를 정확하게 지정)
명령형: 집에 오는 경로 (위치까지 오는 방법을 제시)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;선언형 프로그래밍의 종류&lt;/h3&gt;
&lt;h4&gt;함수형 프로그래밍&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;작은 순수 함수들을 블록처럼 쌓아 로직을 구현, 고차 함수를 구현하여 재사용성을 높이는 프로그래밍 패러다임&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;순수 함수: 출력이 입력에만 의존하는 함수&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;고차 함수: 함수를 값처럼 매개 변수로 받아 로직을 생성한 함수&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;언어가 1급 객체 (First Class Object) 라면 고차 함수의 사용이 가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;1급 객체의 특징&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;변수나 메서드에 함수를 할당 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;함수 안에 함수를 매개 변수로 담을 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;함수가 함수를 반환할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
</content:encoded></item><item><title>[1Day-1CS] MVC 패턴과 유사 패턴</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-mvc/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-mvc/</guid><description>1일 1CS, MVC 패턴에 대한 간단 정리</description><pubDate>Thu, 30 Mar 2023 16:36:43 GMT</pubDate><content:encoded>&lt;h3&gt;MVC 패턴&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Model, View, Controller로 이루어진 디자인 패턴&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;애플리케이션의 구성 요소를 3분할, 각 구성 요소에만 집중하여 개발할 수 있도록 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;재사용성과 확정성이 용이함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;애플리케이션의 복잡도가 커질수록 Model과 View의 관계가 복잡해지는 단점 존재&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Model&lt;/h4&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;애플리케이션의 데이터로 DB, 상수, 변수 등을 의미&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;View&lt;/h4&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;사용자 인터페이스 요소를 의미하며 Model을 기반으로 한 사용자가 볼 수 있는 화면을 말함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모델이 가진 정보를 따로 저장하지 않음, 화면 표시 정보만 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;변경점이 발생하면 Controller에 전달함&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Controller&lt;/h4&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Model과 View를 잇는 Bridge 역할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event 등의 메인 로직을 담당하며 Life Cycle도 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Model 혹은 View의 변경을 통지 받으면 대응하는 내용을 필요 구성 요소에 전달&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h4&gt;유사 패턴&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;MVP 패턴: Controller를 Presenter로 대체, View와 Presenter의 관계가 1:1 이므로 더 강한 결합력 보유&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MVVM 패턴: Controller를 View Model로 대체, Command 및 Data Binding을 보유, UI 재사용성 및 단위 테스팅 용이성을 확보&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 프록시 패턴 &amp; 이터레이터 패턴 &amp; 노출모듈 패턴</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-c6863ddc/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-c6863ddc/</guid><description>1일 1CS, 프록시 패턴, 이터레이터 패턴, 노출모듈 패턴에 대한 간단 정리</description><pubDate>Tue, 28 Mar 2023 23:30:10 GMT</pubDate><content:encoded>&lt;h3&gt;프록시 패턴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;대상 객체에 접근하기 전 그 접근에 대한 흐름을 가로채 대상 객체 앞단의 인터페이스 역할을 하는 디자인 패턴&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;보안, 데이터 검증, 캐싱, 로깅에 사용하며 객체가 아닌 서버로도 활용됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;프록시 서버&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;서버와 클라이언트 사이에서 작동&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클라이언트가 자신을 통해 다른 네트워크 서비스에 간접적으로 접속할 수 있게 해주는 시스템 혹은 프로그램&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;대표적인 예시로 Apache, Nginx, CloudFlare 등이 존재함&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;프록시 서버의 사용 예시&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프록시를 거치기 때문에 실제 사용하는 포트를 숨길 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Nginx를 통해 정적 자원을 gzip하거나, 메인 서버 앞단 로깅하는 것이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CloudFlare의 경우, HTTPS 구축에 용이함을 제공하며 DDOS 공격 방어가 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;프론트엔드 프록시 서버를 통해 Cross Origin Resource Sharing (CORS) 에러를 방지할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;이터레이터 패턴&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;이터레이터를 통해 컬렉션의 요소들에 접근하는 디자인 패턴&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;자료형들의 구조와 관계없이 이터레이터라는 하나의 인터페이스로 순회가 가능하다는 장점이 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;보통 이터러블한 객체를 이터레이터 프로토콜을 통해 순회할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;노출모듈 패턴&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;즉시 실행 함수를 통해 private, public과 같은 접근 제어자를 만드는 패턴&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;JS의 경우에는 따로 접근 제어자가 존재하지 않기 때문에 이를 구현하여 구축하기도 함&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 팩토리 패턴 &amp; 전략 패턴 &amp; 옵저버 패턴</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs-f886ff08/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs-f886ff08/</guid><description>1일 1CS, 팩토리 패턴, 전략 패턴, 옵저버 패턴에 대한 간단 정리</description><pubDate>Mon, 27 Mar 2023 22:36:03 GMT</pubDate><content:encoded>&lt;h3&gt;팩토리 패턴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;객체를 사용하는 코드에서 객체 생성 파트를 추상화한 패턴&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;상위 클래스가 중요한 뼈대를 결정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;하위 클래스가 객체 생성에 관한 구체적인 내용을 결정&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;팩토리 패턴의 특징 및 장점&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;클래스 분리로 인한 느슨한 결합을 가짐
상위 클래스의 유연성을 확보 및 유지 보수성이 증대&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;전략 패턴 (정책 패턴)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;객체의 행위를 바꾸고 싶지 않은 경우 직접 수정하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전략에 해당하는 &lt;strong&gt;캡슐화한 알고리즘&lt;/strong&gt;을 컨텍스트 안에서 바꿔주면서 교체 가능하도록 설계&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;컨텍스트&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;개발자가 어떤 작업을 완료하는 데에 필요한 관련 정보를 의미함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;어떤 행위가 일어나기 위해서 필수적인 필수 컨텍스트와 행위의 효과적인 실행을 위한 선택 컨텍스트가 존재한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;옵저버 패턴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;주체가 특정 객체의 상태 변화를 관찰&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;상태 변화 시 메서드 등을 통해 옵저버들에게 변화 사실을 제공&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;주체와 객체를 따로 두지 않고 가변적인 객체를 기반으로 구축하기도 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MVC 패턴에도 활용되고 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[1Day-1CS] 싱글톤 패턴</title><link>https://www.traceoflight.dev/ko/blog/1day-1cs/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/1day-1cs/</guid><description>1일 1CS, 싱글톤 패턴에 대한 간단 정리</description><pubDate>Mon, 27 Mar 2023 15:29:32 GMT</pubDate><content:encoded>&lt;h3&gt;디자인 패턴이란?&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;프로그램 설계 시 발생했던 문제점이 존재
→ 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 규약으로 만듦&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;싱글톤 패턴&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;하나의 클래스 = 하나의 인스턴스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클래스 당 여러 개의 개별 인스턴스를 만들 수 있지만 그렇게 하지 않고 하나만 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;보통 DB 모듈에 많이 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;생산성 ↑, 의존성 ↓&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;싱글톤 패턴의 단점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;TDD(Test Driven Development: 테스트 주도 개발) 시 단위 테스트를 진행 시 Issue 발생 가능성&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;의존성이 높은 싱글톤 패턴 특성상 각 테스트마다 독립적인 인스턴스를 만들기가 어려움&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;의존성 주입&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;싱글톤 패턴의 모듈간 결합을 강하게 만드는 단점을 해결하기 위한 방법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;메인 모듈이 직접 다른 하위 모듈에 의존성을 주는 것 대신 &lt;strong&gt;의존성 주입자&lt;/strong&gt;를 통해 간접적으로 의존성을 주입 (디커플링)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;장점&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;모듈을 쉽게 교체할 수 있는 구조, Testing &amp;amp; Migration이 수월함, 의존성 방향의 일관성, Application 추론이 쉬워짐, 관계의 명확성 등등&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;단점&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;모듈이 더욱 분리 → 클래스 수의 증가로 복잡성 증대, 런타임 페널티&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;의존성 주입의 원칙&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;상위 모듈은 하위 모듈에서 어떤 것도 가져오지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;둘 다 추상화에 의존해야 함 + 추상화가 세부 사항에 의존하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded></item><item><title>[CI/CD] Docker + Jenkins + Git Webhook을 활용한 FastAPI 서버 자동 배포 정리</title><link>https://www.traceoflight.dev/ko/blog/cicd-docker-jenkins-git-webhook/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/cicd-docker-jenkins-git-webhook/</guid><description>실전 압축 자동 배포 구현하기</description><pubDate>Fri, 24 Mar 2023 02:08:12 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;내용 정리 중 &amp;gt; 2023년 5월 기준 업데이트 1차 완료
&lt;a href=&quot;/blog/ci-cd-dood-feat-nginx-jenkins&quot;&gt;배포 관련 내용은 좀 더 갈무리한 2편을 참고하는 것이 더 좋습니다.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;현재 진행하고 있는 프로젝트에서 인공지능 모델을 활용한 Output을 제공하는 서비스를 구축하고 있었다.&lt;/p&gt;
&lt;p&gt;해당 기능을 Firebase Cloud Function을 통해서 구축하고 싶었지만 모델을 로드하는 과정 등에 있어서 nodeJS + tensorflow.js의 사용으로 인한 모델의 변형 불가피, 태생적인 무거움으로 인한 시간 초과 등 다양한 방식으로 억까를 당했고 이를 해결하기 위해 인공지능 모델을 통한 결과물을 반환하는 간단한 서버를 구축해보기로 했다.&lt;/p&gt;
&lt;p&gt;이에 따라 서버를 구축 및 배포하는 과정이 내 몫으로 남게 되었고 1차적인 목표로 자동 배포의 구현, 이후 추가적인 목표로 무중단 배포까지 내 손으로 진행하고자 했다.&lt;/p&gt;
&lt;p&gt;본 포스트에서는 AWS 등의 인스턴스를 기반으로 한 시스템의 구축 및 자동 배포까지만 다루게 된다.&lt;/p&gt;
&lt;h3&gt;사전 개념 학습&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;CI: Continuous Integration (지속적 통합)&lt;/p&gt;
&lt;p&gt;개발자를 위한 자동화 프로세스로 코드의 변경 사항이 빌드와 테스트를 거쳐서 정기적으로 공유 리포지토리에 병합되는 과정으로 이 과정의 자동화는 개발 과정에 있어서 위험성을 줄이는 방안으로 사용되고 있음&lt;/p&gt;
&lt;p&gt;CI Server, Source Control Management, Build Tool, Test Tool 등으로 구성&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;CD: Continuous Delivery / Deployment (지속적 배포)&lt;/p&gt;
&lt;p&gt;배포 자동화 프로세스를 의미하며 파이프라인의 추가 단계에 대한 자동화를 통해 수동적인 개입 없이 변경사항이 product까지 자동적으로 배포되는 것이 가능, 지속적 통합 과정이 뒷받침되어야 하며 신뢰할 수 있는 환경을 구축한다면 하루에도 여러 번의 릴리스가 이루어질 수 있음&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;결과적으로 이러한 CI/CD 과정을 통해 제품 출시까지 걸리는 시간을 단축시킬 수 있고 인력의 효율성을 증대시키며 점진적이고 지속적인 과정들의 연속이기 때문에 큰 문제가 발생할 확률을 줄여나갈 수 있다.&lt;/p&gt;
&lt;h3&gt;Docker 환경 세팅&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;인스턴스 정보&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;EC2 프리티어 대신 상대적으로 조건이 좋은 Oracle Cloud의 프리티어로 결정
arm64 기반의 Ampere A1 Compute 2Core 및 12GB RAM을 할당해서 사용&lt;/p&gt;
&lt;p&gt;이 외에도 백업 등의 옵션을 무료로 어느 정도 지원하니 참고!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;리눅스 세팅
&lt;a href=&quot;https://bgpark.tistory.com/85&quot;&gt;EC2 password로 접속하는 방법&lt;/a&gt; - 로그인 관련 편의사항으로 ssh 세팅에 대해 다루는 글
&lt;a href=&quot;https://docs.docker.com/engine/install/ubuntu/&quot;&gt;도커 설치&lt;/a&gt; - 우분투 기준 도커 설치 DOCS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;필자가 참고한 자료를 정리했으며 도커 설치하는 과정 및 인스턴스 세팅에 대한 글은 많이 존재하고 있으니 찾아보면서 Docker를 세팅해주면 된다.&lt;/p&gt;
&lt;h3&gt;Docker in Docker 세팅 (실패 &amp;gt; API를 활용한 Docker out of Docker로 진행)&lt;/h3&gt;
&lt;h4&gt;사용 이유&lt;/h4&gt;
&lt;p&gt;도커 위에서 추가적으로 도커를 다루는 이유는 컨테이너를 컨테이너를 통해 통제하기 위함이며 기본적으로 해당 컨테이너의 권한이 막강해지기 때문에 보안의 위험성을 제기하기도 하지만 그 자체만으로 매력적인 것은 분명하다.&lt;/p&gt;
&lt;h4&gt;세팅했던 방법&lt;/h4&gt;
&lt;h5&gt;1. Docker 위에 Jenkins 컨테이너 빌드&lt;/h5&gt;
&lt;p&gt;먼저 Jenkins 컨테이너를 도커에서 빌드한다.
Docker Compose를 사용하면 조금 더 쉽게 빌드할 수 있으니 참고하도록 하자.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker pull jenkins/jenkins:lts

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;먼저 젠킨스 LTS 버전의 컨테이너를 받아준다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;vim docker-compose.yml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;yml 파일을 해당 명령어를 통해 생성 혹은 열어준다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;hljs-attr&quot;&gt;version:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;2.5.0&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# compose 버전을 입력할 것&lt;/span&gt;

&lt;span class=&quot;hljs-attr&quot;&gt;services:&lt;/span&gt;

  &lt;span class=&quot;hljs-attr&quot;&gt;jenkins:&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;container_name:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;image:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;jenkins/jenkins:lts&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Jenkins LTS 버전을 사용&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;restart:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;always&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# 자동 재시작 옵션&lt;/span&gt;
    
    &lt;span class=&quot;hljs-attr&quot;&gt;ports:&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;8181:8080&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# host의 8181 포트를 Jenkins의 8080 포트로 연결&lt;/span&gt;
      
    &lt;span class=&quot;hljs-attr&quot;&gt;volumes:&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# host의 volume을 해당 옵션을 통해 공유할 수 있다.&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/home/opendocs/jenkins:/var/jenkins_home&lt;/span&gt;
      &lt;span class=&quot;hljs-bullet&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;/var/run/docker.sock:/var/run/docker.sock&lt;/span&gt;
      
    &lt;span class=&quot;hljs-attr&quot;&gt;user:&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;root&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;privileged:&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;# Docker In Docker 사용을 위한 핵심 옵션&lt;/span&gt;
    
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;yml 파일에 예시 코드와 같이 필요한 내용을 입력한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;docker-compose -f {파일명} up
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;해당 명령어를 통해 docker-compose.yml을 기반으로 한 세팅을 진행할 수 있으며 파일명의 변경이 없이 docker-compose.yml이라는 이름 그대로 사용한다면 -f 옵션을 사용하지 않아도 된다. 자세한 것은 Docker Compose Docs를 참고하도록 하자!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;Docker Compose Documents&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;+ sudo 없이 docker 사용하는 방법 → Docker 그룹에 현재 사용자를 추가하기&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 해당 명령어를 통해 현재 사용자를 Docker 그룹에 추가할 수 있음&lt;/span&gt;
&lt;span class=&quot;hljs-built_in&quot;&gt;sudo&lt;/span&gt; usermod -aG docker &lt;span class=&quot;hljs-variable&quot;&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;2. Jenkins Container 세팅&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;설정한 IP주소의 Docker를 통해 할당한 Port Number로 브라우저 접속&lt;/li&gt;
&lt;li&gt;Jenkins 설치 로그에 적힌 키를 화면에 입력하기&lt;/li&gt;
&lt;/ol&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 해당 명령어를 통해 컨테이너의 로그를 확인할 수 있음&lt;/span&gt;
docker logs jenkins
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;추천 플러그인 설치하기&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;문제가 발생할 수 있는데 일단 설치 마무리 짓고 이후에 해결하면 된다.
마무리 짓지 않으면 설치되지 않은 플러그인으로 인해 의존성 에러가 계속 발생한다...&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://wingsh.tistory.com/261&quot;&gt;플러그인 설치 Time Out 해결법&lt;/a&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GitHub API Plugin 설치하기&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Webhook 트리거로 작동시킬 수 있도록 도와주는 플러그인이다. 설치해주자. 설치 뒤 Secret으로 Git ID/PW 등록해둘 것.&lt;/p&gt;
&lt;h5&gt;3. Github 설정&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Settings의 Developer Settings 내의 Token을 생성하도록 한다. 현재 글 쓰는 시점 기준으로 Classic 토큰을 사용하며 repo, admin:repo_hook 정도만 권한 설정해주면 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;자동 배포할 Repo 설정에서 Webhooks에 Webhook을 추가한다. http://{jenkins_url}/github-webhook/ 정도로 설정하면 된다. 마지막 / 를 빼면 문제가 생길 수 있으니 얌전히 달아두자.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;4. Jenkins 프로젝트 세팅&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;프로젝트를 추가한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;빌드 구성 - 소스 코드 관리에서 Git을 선택하고 기존에 등록한 Secret을 골라주면 webhook 신호를 받을 수 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GitHub hook trigger for GITScm polling 옵션을 골라줘야 트리거 작동이 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;필요에 따라 branch 선정도 진행 후 세팅을 마무리 지어주고 테스트를 진행하도록 하자.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[BOJ 4803, Java] 트리</title><link>https://www.traceoflight.dev/ko/blog/boj4803/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj4803/</guid><description>BOJ 4803, &quot;트리&quot; 문제의 Java 풀이</description><pubDate>Tue, 28 Feb 2023 00:26:49 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/4803&quot;&gt;BOJ 4803&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;자료 구조(data_structures), 깊이 우선 탐색(dfs), 분리 집합(disjoint_set), 그래프 이론(graphs), 그래프 탐색(graph_traversal), 트리(trees)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;트리의 성질을 통해 트리의 갯수를 카운팅하는 문제였다. 이 문제에서는 연결 요소로 구성된 것들 중에 사이클을 배제하는 것으로 해결할 수 있다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;모든 노드에 대해 방문 확인&lt;/li&gt;
&lt;li&gt;방문하지 않은 점에 대해서 트리에 편입하면서 깊이 탐색&lt;/li&gt;
&lt;li&gt;사이클을 형성한 경우 구성하고 있는 모든 점을 방문 처리&lt;/li&gt;
&lt;li&gt;사이클을 형성하지 않았다면 해당 집합은 트리이므로 1 카운트&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;위와 같은 로직을 통해 구현하였고 깊이탐색을 하면서 카운팅 처리를 어떻게 할까 고심한 결과 아래와 같은 코드를 구성하였다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;dfs&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowNode, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; parent, &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt;[] visitLog, HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph)&lt;/span&gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nextNode : graph.get(nowNode)) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; !visitLog[nextNode]) {

                visitLog[nextNode] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; dfs(nextNode, nowNode, visitLog, graph);
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
                }

            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; visitLog[nextNode]) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
            }

        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

    }

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;최초 지점에서부터 재귀의 형태로 방문 처리하며 조사를 하다가 사이클이 나온 경우 기본적으로 모든 지점을 순회한 다음 0을 반환하는 구조로 작성했다.&lt;/p&gt;
&lt;p&gt;만약 사이클이 나타나지 않았다면 정상적으로 순회를 마무리하고 1을 반환하여 해당 함수의 반환값을 계속 카운팅하면 트리의 갯수를 확인할 수 있다!&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;dfs&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowNode, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; parent, &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt;[] visitLog, HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; graph)&lt;/span&gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nextNode : graph.get(nowNode)) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; !visitLog[nextNode]) {

                visitLog[nextNode] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; dfs(nextNode, nowNode, visitLog, graph);
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
                }

            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nextNode != parent &amp;amp;&amp;amp; visitLog[nextNode]) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
            }

        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;testCase&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        ArrayList&amp;lt;String&amp;gt; outputArr = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;) {

            &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;treeInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nodeNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(treeInfo.nextToken());
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;edgeNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(treeInfo.nextToken());

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nodeNumber == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; edgeNumber == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
            }

            testCase += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;treeCount&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
            &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt;[] isVisited = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;boolean&lt;/span&gt;[nodeNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;];

            &lt;span class=&quot;hljs-type&quot;&gt;StringBuilder&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;stringBuilder&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringBuilder&lt;/span&gt;();
            stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;Case &amp;quot;&lt;/span&gt;);
            stringBuilder.append(testCase);
            stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;: &amp;quot;&lt;/span&gt;);

            HashMap&amp;lt;Integer, ArrayList&amp;lt;Integer&amp;gt;&amp;gt; treeGraph = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; nodeNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {
                treeGraph.put(i, &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;());
            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; edgeNumber; i++) {

                &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;edgeInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;startNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(edgeInfo.nextToken());
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;endNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(edgeInfo.nextToken());

                treeGraph.get(startNode).add(endNode);
                treeGraph.get(endNode).add(startNode);

            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; nodeNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {

                isVisited[i] = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
                treeCount += dfs(i, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, isVisited, treeGraph);
            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (treeCount == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;No trees.&amp;quot;&lt;/span&gt;);
            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (treeCount == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;There is one tree.&amp;quot;&lt;/span&gt;);
            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (treeCount &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;A forest of &amp;quot;&lt;/span&gt;);
                stringBuilder.append(treeCount);
                stringBuilder.append(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot; trees.&amp;quot;&lt;/span&gt;);
            }

            outputArr.add(stringBuilder.toString());

        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; testCase; i++) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i != testCase - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                output.write(outputArr.get(i) + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;);
            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                output.write(outputArr.get(i));
            }

        }

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 1485, Python] 정사각형</title><link>https://www.traceoflight.dev/ko/blog/boj1485/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj1485/</guid><description>BOJ 1485, &quot;정사각형&quot; 문제의 Python 풀이</description><pubDate>Sat, 25 Feb 2023 03:05:13 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1485&quot;&gt;BOJ 1485&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;기하학(geometry), 정렬(sorting)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;정사각형 판별을 해당 절차를 통해서 진행하면 된다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;4개의 점을 잇는 6개의 변의 길이를 전부 확인&lt;/li&gt;
&lt;li&gt;정렬&lt;/li&gt;
&lt;li&gt;앞 4개의 길이가 같은지 확인&lt;/li&gt;
&lt;li&gt;뒷 2개가 정사각형의 대각선 길이로 적합한지 확인&lt;/li&gt;
&lt;li&gt;전부 만족한 경우만 정사각형을 그릴 수 있는 것으로 처리&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 정사각형&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; math &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sqrt, isclose
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; itertools &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; combinations

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;distance&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;coord_1: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, coord_2: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; sqrt(&lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(coord_1[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] - coord_2[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) + &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(coord_1[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] - coord_2[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;))

testcase = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())

output = []

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(testcase):

    is_square = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

    coord_info = []

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;):
        coord_info.append(&lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())))

    edge_info = []

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; edge_distance &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; combinations(coord_info, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;):
        edge_info.append(distance(edge_distance[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], edge_distance[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]))

    edge_info.sort()

    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;):
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; isclose(edge_info[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], edge_info[idx]):
            is_square = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_square:
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;):
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; isclose(&lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(edge_info[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;) * &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(edge_info[idx], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;)):
                is_square = &lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; is_square:
        output.append(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
        output.append(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)

&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; output:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 12850, Java] 본대 산책 2</title><link>https://www.traceoflight.dev/ko/blog/boj12850/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj12850/</guid><description>BOJ 12850, &quot;본대 산책 2&quot; 문제의 Java 풀이</description><pubDate>Wed, 22 Feb 2023 14:05:40 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/12850&quot;&gt;BOJ 12850&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;분할 정복을 이용한 거듭제곱(exponentiation_by_squaring), 그래프 이론(graphs), 수학(math)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;h4&gt;분할정복 (Devide and Conquer)&lt;/h4&gt;
&lt;p&gt;그대로 해결하기 어려운 문제를 작은 문제들로 분할하여 해결하는 알고리즘&lt;/p&gt;
&lt;p&gt;해당 문제의 경우 인접 행렬을 그리고 그 인접 행렬의 n 제곱연산을 진행한 값의 행렬값이 도착지에 도달하는 경우의 수라는 것을 안다면 어렵지 않게 해결할 수 있다.&lt;/p&gt;
&lt;p&gt;분할 정복과 행렬 연산에 대한 공부가 선행되긴 하지만 하위 난이도 문제 여러 개를 결합시킨 수준에서 납득이 가는 난이도였다고 생각한다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; HashMap&amp;lt;Integer, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][]&amp;gt; matrixRecord = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrixCalculation(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrix1, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrix2) {
        &lt;span class=&quot;hljs-comment&quot;&gt;/* 행렬 연산 함수 */&lt;/span&gt;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] resultArr = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;];

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;; i++) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;; j++) {

                &lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;sum&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;k&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; k &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;; k++) {
                    sum += ((&lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt;) matrix1[i][k] * (&lt;span class=&quot;hljs-type&quot;&gt;long&lt;/span&gt;) matrix2[k][j]) % &lt;span class=&quot;hljs-number&quot;&gt;1000000007&lt;/span&gt;;
                }

                resultArr[i][j] = (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;) (sum % &lt;span class=&quot;hljs-number&quot;&gt;1000000007&lt;/span&gt;);

            }
        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; resultArr;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] matrixDivision(HashMap&amp;lt;Integer, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][]&amp;gt; matrixInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; calculationCount) {
        &lt;span class=&quot;hljs-comment&quot;&gt;/* 분할 정복을 통한 행렬 연산 함수 */&lt;/span&gt;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;halfCount&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; calculationCount / &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] halfMatrix;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] otherHalfMatrix;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 기존 값이 존재할 경우 불러오기&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (matrixInfo.containsKey(halfCount)) {
            halfMatrix = matrixInfo.get(halfCount);
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            halfMatrix = matrixDivision(matrixInfo, halfCount);
        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (matrixInfo.containsKey(calculationCount - halfCount)) {
            otherHalfMatrix = matrixInfo.get(calculationCount - halfCount);
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            otherHalfMatrix = matrixDivision(matrixInfo, calculationCount - halfCount);
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 연산 후 행렬 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] calculationResult = matrixCalculation(halfMatrix, otherHalfMatrix);
        matrixInfo.putIfAbsent(calculationCount, calculationResult);

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; calculationResult;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;walkTime&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());

        &lt;span class=&quot;hljs-comment&quot;&gt;// 기본 행렬 및 본대 인접 행렬 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] baseMatrix = {
                {&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
        };

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] graph = {
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
                {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
        };

        &lt;span class=&quot;hljs-comment&quot;&gt;// 해시맵에 초기값들 등록&lt;/span&gt;
        matrixRecord.put(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, baseMatrix);
        matrixRecord.put(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, graph);

        &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 통해 분할정복 연산 실행&lt;/span&gt;
        matrixDivision(matrixRecord, walkTime);

        &lt;span class=&quot;hljs-comment&quot;&gt;// 결과 출력&lt;/span&gt;
        output.write(Integer.toString(matrixRecord.get(walkTime)[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;][&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]));

        output.flush();
        output.close();

    }

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Refactoring 1 - 1. Type &apos;...&apos; is not assignable to type &quot;...&quot;</title><link>https://www.traceoflight.dev/ko/blog/refactoring-1-1/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/refactoring-1-1/</guid><description>Type &apos;string&apos; is not assignable to type &apos;&quot;text&quot; | &quot;outlined&quot; | &quot;contained&quot; | undefined&apos;.&quot; 에러를 해결하는 과정</description><pubDate>Tue, 21 Feb 2023 16:40:07 GMT</pubDate><content:encoded>&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-title class_&quot;&gt;Button&lt;/span&gt;
onClick={handleLogin}
variant=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;contained&amp;quot;&lt;/span&gt;
  &amp;gt;
    &lt;span class=&quot;hljs-variable constant_&quot;&gt;LOGIN&lt;/span&gt;
&amp;lt;/&lt;span class=&quot;hljs-title class_&quot;&gt;Button&lt;/span&gt;&amp;gt;
&lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;Button&lt;/span&gt; &lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{handleGoogleLogin}&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;img&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;src&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{logoSrc}&lt;/span&gt;
&lt;span class=&quot;hljs-attr&quot;&gt;alt&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;alternative image&amp;quot;&lt;/span&gt;
/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;Social Login&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;p&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;Button&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;문제 발생&lt;/h3&gt;
&lt;p&gt;이런 코드를 TypeScript에서 map을 사용하여 재구축하는 과정에서 에러가 발생했다.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Type &apos;string&apos; is not assignable to type &apos;&amp;quot;text&amp;quot; | &amp;quot;outlined&amp;quot; | &amp;quot;contained&amp;quot; | undefined&apos;.&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;위와 같은 에러였는데 MUI를 사용했고 MUI Button의 variant 속성의 값에서 에러를 뱉고 있었다. 이를 해결하기 위해서 한참 고민했고 StackOverFlow나 ChatGPT를 통해 열심히 뒤져보다가 마침내 찾아낼 수 있었다.&lt;/p&gt;
&lt;h3&gt;해결 방법&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Variant&lt;/span&gt; = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;text&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;outlined&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;contained&amp;quot;&lt;/span&gt; | &lt;span class=&quot;hljs-literal&quot;&gt;undefined&lt;/span&gt;;

&lt;span class=&quot;hljs-keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;SubmitButtonProps&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ButtonProps&lt;/span&gt; {
  &lt;span class=&quot;hljs-attr&quot;&gt;variant&lt;/span&gt;?: &lt;span class=&quot;hljs-title class_&quot;&gt;Variant&lt;/span&gt;;
  &lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;?: &lt;span class=&quot;hljs-function&quot;&gt;() =&amp;gt;&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Promise&lt;/span&gt;&amp;lt;&lt;span class=&quot;hljs-built_in&quot;&gt;void&lt;/span&gt;&amp;gt;;
  &lt;span class=&quot;hljs-attr&quot;&gt;contains&lt;/span&gt;?: &lt;span class=&quot;hljs-title class_&quot;&gt;React&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;ReactNode&lt;/span&gt;;
}

{loginButtonSettings.&lt;span class=&quot;hljs-title function_&quot;&gt;map&lt;/span&gt;(
  &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;{ onClick, contains, variant }: &lt;span class=&quot;hljs-title class_&quot;&gt;SubmitButtonProps&lt;/span&gt;, &lt;span class=&quot;hljs-attr&quot;&gt;index&lt;/span&gt;: &lt;span class=&quot;hljs-built_in&quot;&gt;number&lt;/span&gt;&lt;/span&gt;) =&amp;gt;&lt;/span&gt; (
    &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;SubmitButton&lt;/span&gt;
    &lt;span class=&quot;hljs-attr&quot;&gt;key&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{index}&lt;/span&gt;
  	&lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{onClick}&lt;/span&gt;
	&lt;span class=&quot;hljs-attr&quot;&gt;contains&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{contains}&lt;/span&gt;
	&lt;span class=&quot;hljs-attr&quot;&gt;variant&lt;/span&gt;=&lt;span class=&quot;hljs-string&quot;&gt;{variant}&lt;/span&gt;
	/&amp;gt;&lt;/span&gt;&lt;/span&gt;
  )
)}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위와 같은 형태로 type이라는 값을 통해 variant에 들어갈 속성값들을 미리 정하면서 interface에도 잡아줘야 한다. 사실 이 부분보다는 아래 적을 내용이 중요하다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; loginButtonSettings = [
  {
    &lt;span class=&quot;hljs-attr&quot;&gt;onClick&lt;/span&gt;: loginHandler,
    &lt;span class=&quot;hljs-attr&quot;&gt;contains&lt;/span&gt;: &lt;span class=&quot;language-xml&quot;&gt;&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;Login&lt;span class=&quot;hljs-tag&quot;&gt;&amp;lt;/&lt;span class=&quot;hljs-name&quot;&gt;div&lt;/span&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;,
    &lt;span class=&quot;hljs-attr&quot;&gt;variant&lt;/span&gt;: &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;contained&amp;quot;&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Variant&lt;/span&gt;, &lt;span class=&quot;hljs-comment&quot;&gt;// 바로 여기!&lt;/span&gt;
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;여기에 적은 것처럼 &amp;quot;contained&amp;quot;는 일반적으로 string으로 인식하기 때문에 Variant라는 속성값에 포함되었던 바로 그 값이라는 것을 인지시켜주어야 한다!&lt;/p&gt;
</content:encoded></item><item><title>Refactoring에 들어가며</title><link>https://www.traceoflight.dev/ko/blog/refactoring/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/refactoring/</guid><description>Refactoring에 들어가기 전에 회고 및 Stack 사용 이유</description><pubDate>Tue, 21 Feb 2023 16:26:20 GMT</pubDate><content:encoded>&lt;h3&gt;기록 이유&lt;/h3&gt;
&lt;p&gt;약 7주 간의 짧다면 짧고 길다면 긴 프로젝트를 거치면서 React와 어느 정도 친해지는 시간은 가졌다고 생각한다. 근데 생각과는 달리 나는 이 친구를 멋지고 깔끔하게 키우고 싶은데 어느 새인가 지저분해지는 게 멋대로 자란 수염을 보는 것 같다...&lt;/p&gt;
&lt;p&gt;그래서 해당 코드를 고쳐보자! 라고 생각하게 되었고 간단하게 지나온 프로젝트의 기록을 남기면서 이번 기회에 TypeScript도 사용해 볼 기회를 가지고자 한다.&lt;/p&gt;
&lt;h3&gt;왜 React를 사용하는가?&lt;/h3&gt;
&lt;p&gt;기존에 참가했던 프로젝트에서는 VueJS도 사용해볼 수 있는 기회가 있어 Vue를 기반으로 코드를 작성한 경험이 있었는데 뭔가 장단점을 가지고 비교할 수 있는 숙련자가 아니었을 뿐더러 React를 사용해 본 적조차 없었기 때문에 일단 가장 지금 핫한 프레임워크니까 찍어먹어보자! 라는 생각을 가지고 사용하게 되었다. 아무래도 Vue와 비교했을 때 Vue의 단점을 체감하기보단 React의 장점을 체감하는 계기가 되었던 것 같다.&lt;/p&gt;
&lt;h4&gt;생태계가 넓다&lt;/h4&gt;
&lt;p&gt;이건 수치상으로도 그렇고 많이들 잘 알려진 장점이라고 생각하는데 Vue에서 사용했던 대부분의 라이브러리들은 React에서도 사용할 수 있을 뿐더러 이쪽이 메인이고 Vue가 사은품인 느낌으로 제공이 된다는 느낌을 받았다.&lt;/p&gt;
&lt;h4&gt;직관적이다&lt;/h4&gt;
&lt;p&gt;아직 다양한 Hook을 사용하지 못해서 그런건지는 몰라도 Props를 처리하는 방식이나 코드 작성 방식 등에서 훨씬 편하다고 느꼈다.&lt;/p&gt;
&lt;p&gt;ue의 경우는 마치 머리, 가슴, 배처럼 template, script, style을 작성하는 형태를 통해 코드 간의 구분감을 살린 느낌이었다면 React는 기본적으로 Fuction Component를 JavaScript 코드와 구분감을 주지 않는 형태로 작성하는 편이라서 변수 접근 등에 있어서 훨씬 편리함을 느꼈다.&lt;/p&gt;
&lt;p&gt;물론 Vue처럼 분리하게 되면 코드를 읽는 것이 좀 더 편할지는 모르겠지만 작성하는 기준으로는 분명한 차이가 존재했고 지금에 와서도 둘 중에 뭘 쓸래? 라고 묻는다면 React를 사용할 것이다.&lt;/p&gt;
&lt;h4&gt;Event 처리가 편리했다&lt;/h4&gt;
&lt;p&gt;윗 내용과 어느 정도 공유되는 부분이 있는 내용인데 EventHandler를 작성할 때 Vue를 사용하던 시절에 비해 훨씬 직관적으로 적을 수 있었다고 기억한다. Vue의 경우는 Function과 Variable을 따로 구분해서 적는 파트가 많았던 것 같은데 React는 일반적인 프로그래밍 언어 사용하듯 그 자리에서 변수 선언하고 처리하는 형태가 가능하다보니 매일 먹던 백반과 같은 푸근하고 든든한 느낌을 받았다.&lt;/p&gt;
&lt;h3&gt;TypeScript를 사용하려는 이유&lt;/h3&gt;
&lt;p&gt;실제 업계에서 뽑는 장단점과는 다를 수 있겠지만 React의 위와 같은 장점을 개인적으로는 꼽을 수 있었고 여전히 Refactoring 과정에서도 React를 선택한 이유가 되었다.&lt;/p&gt;
&lt;p&gt;마찬가지로 Refactoring을 할 때 왜 굳이 JS 대신 TS를 쓰려고 하는지에 대한 이유도 적어두는 편이 좋을 것 같아 여기에 남긴다.&lt;/p&gt;
&lt;h4&gt;오류잡이&lt;/h4&gt;
&lt;p&gt;TS의 장점으로 JS의 단점을 해결하는 부분이 굉장히 크다고 생각한다. 기본적으로 JS는 굉장히 느슨한 언어라고 생각하고 실제로도 그렇다. 그렇다보니 오류가 이상한 곳에서 발생하고 해결도 난해할 때가 가끔 존재하는데 이런 부분을 TS가 잘 잡아줄 것이라고 기대하고 있다.&lt;/p&gt;
&lt;h4&gt;익숙함&lt;/h4&gt;
&lt;p&gt;JS는 어쩔 수 없는 개발 역사에 의해 개인적으로 프로그래밍 언어스럽지 못한 부분들이 굉장히 많다고 생각한다. 하지만 TS는 분명히 JS 기반임에도 불구하고 굉장히 착착 들어맞는 구조를 제공하는 것으로 JS에서 아쉬웠던 부분을 해결해주고 있었다! 물론 손이야 더 많이 갈 수 있지만 오히려 안정된 구조의 익숙함에서 오는 편안함이 TS를 사용하도록 유도하고 있다..&lt;/p&gt;
&lt;h3&gt;맺음말&lt;/h3&gt;
&lt;p&gt;앞으로 꾸준히 기존에 사용했던 코드와 비교하면서 혹은 배운 내용을 해당 포스팅 아래로 꾸준히 남겨볼 예정이다. 얼마나 시간이 걸릴지는 모르겠으나 굉장히 보람찬 작업이 될 것이라 기대하고 있다!&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 1922, Java] 네트워크 연결</title><link>https://www.traceoflight.dev/ko/blog/boj1922/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj1922/</guid><description>BOJ 1922, &quot;네트워크 연결&quot; 문제의 Java 풀이</description><pubDate>Mon, 20 Feb 2023 07:55:51 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/1922&quot;&gt;BOJ 1922&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;그래프 이론, 최소 스패닝 트리&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;h4&gt;서론&lt;/h4&gt;
&lt;p&gt;요즘 문제만 풀다보니 이론에 소홀해지는 감이 있어 이론을 간단하게라도 짚으면서 문제 풀이를 기록하고자 한다.&lt;/p&gt;
&lt;h4&gt;MST(minimum spanning tree, 최소 신장 트리)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;스패닝 트리란?&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;그래프 내의 모든 정점을 포함하는 트리를 의미한다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;최소 스패닝 트리&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;스패닝 트리 중 가장 총 간선 길이가 짧은 것&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;주요 특징&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;n 개의 정점을 지나는 (n - 1) 개의 간선을 가짐
길이를 최소한으로 사용하기 때문에 사내 네트워크 구축 등에 활용 가능&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;프림 알고리즘&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;초기 정점 1개 선택&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MST에 포함된 정점에 연결된 간선들 중 가장 짧은 것을 순차 선택&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 정점이 연결된 경우 종료&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;크루스칼 알고리즘&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;모든 간선을 가중치순 정리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;사이클을 만들지 않는 선에서 간선을 순차적으로 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 정점이 연결된 경우 종료&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-comment&quot;&gt;// 간선 정보 클래스 선언&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Comparable&lt;/span&gt;&amp;lt;Connection&amp;gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; cost;
        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; start;
        &lt;span class=&quot;hljs-keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; end;

        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; cost, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; start, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; end)&lt;/span&gt; {
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.cost = cost;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.start = start;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.end = end;
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 가중치를 통한 비교&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;compareTo&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(Connection other)&lt;/span&gt; {
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.cost - other.cost;
        }

    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 정점의 집합을 확인하는 함수&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;checkUnion&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] unionInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; targetVertex)&lt;/span&gt; {

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (unionInfo[targetVertex] != targetVertex) {
            unionInfo[targetVertex] = checkUnion(unionInfo, unionInfo[targetVertex]);
        }

        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; unionInfo[targetVertex];
    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 정점 2개가 집합을 이루는지 확인하는 함수&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;isUnion&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] unionInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex1, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex2)&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; checkUnion(unionInfo, vertex1) == checkUnion(unionInfo, vertex2);
    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 집합을 합쳐주는 함수&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;makeUnion&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] unionInfo, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex1, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; vertex2)&lt;/span&gt; {

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;group1&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; checkUnion(unionInfo, vertex1);
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;group2&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; checkUnion(unionInfo, vertex2);

        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (group2 &amp;gt; group1) {
            unionInfo[group2] = group1;
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            unionInfo[group1] = group2;
        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-comment&quot;&gt;// 정점 및 간선의 갯수 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;vertexNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;edgeNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());

        &lt;span class=&quot;hljs-comment&quot;&gt;// 간선 정보를 담을 우선순위 큐 선언&lt;/span&gt;
        PriorityQueue&amp;lt;Connection&amp;gt; costPriorityQueue = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;PriorityQueue&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-comment&quot;&gt;// 간선 정보 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; edgeNumber; i++) {
            &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;connectionInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;startNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(connectionInfo.nextToken());
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;endNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(connectionInfo.nextToken());
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cost&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(connectionInfo.nextToken());

            &lt;span class=&quot;hljs-type&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;connection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Connection&lt;/span&gt;(cost, startNode, endNode);
            costPriorityQueue.add(connection);

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 집합에 포함된 정점의 갯수와 최소 가중치 정보를 담을 변수 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;totalCost&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;totalEdge&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 집합 정보를 담을 배열 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] groupInfo = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[vertexNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;];
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; vertexNumber + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {
            groupInfo[i] = i;
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// Kruskal&amp;#x27;s Algorithm&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (totalEdge &amp;lt; vertexNumber - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt; &amp;amp;&amp;amp; !costPriorityQueue.isEmpty()) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 가중치 순으로 확인&lt;/span&gt;
            &lt;span class=&quot;hljs-type&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowConnection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; costPriorityQueue.poll();

            &lt;span class=&quot;hljs-comment&quot;&gt;// 집합 관계를 확인하여 아직 집합이 아닌 경우 집합에 추가하고 가중치 가산&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!isUnion(groupInfo, nowConnection.start, nowConnection.end)) {
                makeUnion(groupInfo, nowConnection.start, nowConnection.end);
                totalEdge += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
                totalCost += nowConnection.cost;
            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 최종 최소 가중치값 출력&lt;/span&gt;
        output.write(Integer.toString(totalCost));

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 14503, Java] 로봇 청소기</title><link>https://www.traceoflight.dev/ko/blog/boj14503/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj14503/</guid><description>BOJ 14503, &quot;로봇 청소기&quot; 문제의 Java 풀이</description><pubDate>Sat, 18 Feb 2023 12:31:09 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14503&quot;&gt;BOJ 14503&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;구현(implementation), 시뮬레이션(simulation)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;전형적인 구현 문제인데 문제 설명을 이해하는 것부터 좀 난해한 부분이 있다. 해당 부분에 대해서만 간단하게 첨언을 해볼까 한다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;현재 칸을 청소&lt;/li&gt;
&lt;li&gt;현재 칸을 기준으로 &lt;strong&gt;반시계로 90도 회전한 방향부터 체크&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;한 바퀴 다 돌아서 처음에 보고 있던 위치까지 확인한 후 청소할 곳이 없다면 후진&lt;/li&gt;
&lt;li&gt;후진할 곳도 없다면 청소 종료&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;해당 문제에서 정면 기준 왼쪽 먼저 체크한다는 부분을 간과하고 풀게 된다면 구현이고 뭐고 계속 헤맬 수 밖에 없는 구조를 가지고 있다. 그 점을 반드시 주의해서 풀도록 하자!&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; height;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; width;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;isNeedClean&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] table, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowYIndex, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; nowXIndex)&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; table[nowYIndex][nowXIndex] == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;mapSize&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

        &lt;span class=&quot;hljs-comment&quot;&gt;// 뒷 방향 등록 해시맵 선언&lt;/span&gt;
        HashMap&amp;lt;Integer, Integer&amp;gt; backward = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;);
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;);
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;);
        backward.put(&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;);

        height = Integer.parseInt(mapSize.nextToken());
        width = Integer.parseInt(mapSize.nextToken());

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] mapInfo = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[height][width];

        &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;startingPoint&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowY&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(startingPoint.nextToken());
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowX&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(startingPoint.nextToken());
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowDirection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(startingPoint.nextToken());

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; height; i++) {
            &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;mapLine&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; j &amp;lt; width; j++) {
                mapInfo[i][j] = Integer.parseInt(mapLine.nextToken());
            }

        }

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cleanCounter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] directionY = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;};
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] directionX = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;};

        Loop:
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (&lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 현재 칸이 청소가 필요하다면 청소 실시&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (isNeedClean(mapInfo, nowY, nowX)) {
                mapInfo[nowY][nowX] = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;;
                cleanCounter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
            }

            &lt;span class=&quot;hljs-comment&quot;&gt;// 주변 칸에 대해서 확인&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;; i++) {

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetDirection&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; (nowDirection + &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; - i) % &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;;
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetY&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowY + directionY[targetDirection];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetX&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowX + directionX[targetDirection];

                &lt;span class=&quot;hljs-comment&quot;&gt;// 청소할 칸이 있는 경우 이동 및 방향 전환&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (isNeedClean(mapInfo, targetY, targetX)) {
                    nowY = targetY;
                    nowX = targetX;
                    nowDirection = targetDirection;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 청소할 칸이 없는 경우 뒷칸 확인&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;) {
                    targetY = nowY + directionY[backward.get(nowDirection)];
                    targetX = nowX + directionX[backward.get(nowDirection)];

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 뒤로 이동할 수 없는 경우 청소 종료&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (mapInfo[targetY][targetX] == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt; Loop;

                        &lt;span class=&quot;hljs-comment&quot;&gt;// 이동할 수 있다면 뒤로 1칸 후진&lt;/span&gt;
                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                        nowY = targetY;
                        nowX = targetX;
                    }
                }

            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 이동 결과 출력&lt;/span&gt;
        output.write(Integer.toString(cleanCounter));

        output.flush();
        output.close();

    }

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>첫 면접 후기</title><link>https://www.traceoflight.dev/ko/blog/first-interview/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/first-interview/</guid><description>간단한 첫 면접의 후기</description><pubDate>Tue, 07 Feb 2023 11:30:12 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;2023-07-06 썸네일 편집 (&lt;a href=&quot;https://kr.freepik.com/free-vector/interview-concept-illustration_7446777.htm#from_view=detail_alsolike&quot;&gt;작가 storyset&lt;/a&gt; 출처 Freepik)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;서론&lt;/h3&gt;
&lt;p&gt;꽤 오랜만에 쓰는 글인 것 같다.&lt;/p&gt;
&lt;p&gt;현재 SSAFY 8기 과정을 이수하고 있다보니 생각보다 마음 잡고 작성할 시간이 나지 않았다.&lt;/p&gt;
&lt;p&gt;그런데 막상 면접 같은 중요한 과정을 겪고 나서도 이런 것들을 정리해놓지 않는다면 발전에 도움이 될 거 같지 않아 꾸역꾸역 글을 작성해본다.&lt;/p&gt;
&lt;h3&gt;면접 과정&lt;/h3&gt;
&lt;p&gt;화상 면접으로 진행되었고 면접 예상 시간이 길지 않아서 기술 면접보단 인성 면접에 가까울 것으로 예측했었는데 예상대로 기술 면접이 아니었다.&lt;/p&gt;
&lt;p&gt;이를 미리 예상하고 준비한 것을 다행으로 생각해야 할지, 아니면 경험을 얻을 기회를 날려서 아쉬워 해야할지 고민해야 할 정도...&lt;/p&gt;
&lt;p&gt;면접 질문의 경우는 생각 나는 것만 나열해보면&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;매번 나오는 자기소개 1분&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전공이 아닌 현재 분야를 선택한 이유? (필자는 비전공자)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;공백기에 대하여&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;근무 환경이 이러이러한데 생각한 것과 다를 수도 있다 괜찮은지?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;조금 추상적으로 적었는데 생각보다는 준비한 내용으로 대응할 수 있는 수준이어서 다행이었다. 특히 비전공자의 경우는 항상 전공자에 비해 CS 지식의 부족을 염두한 채 관련 질문을 노리고 던지는 경우가 많아서 어느 정도 준비할 필요가 있다!&lt;/p&gt;
&lt;h3&gt;개인적인 소회&lt;/h3&gt;
&lt;p&gt;그러나 기술 면접이 아니어서 그에 대한 질문이 크게 오고 가지 않았던 점은 다음 코딩테스트 통과가 언제일지 모르는만큼 더욱 아쉬웠던 것 같다.&lt;/p&gt;
&lt;p&gt;그리고 항상 염두해야 하는 점이지만 회사가 면접자를 판단하는만큼 면접자도 회사를 견적을 재볼 수 있는 시간이라고 들었던 적이 있는데 이번 면접에서 그 점을 뼈저리게 느낀 것 같다.&lt;/p&gt;
&lt;p&gt;이번에 면접을 치룬 회사의 경우는 내가 생각하던 직무와 너무 다른 일을 하게 될 것 같아서 합격을 하게 되어도 많은 고민을 하게 되지 않을까 싶다...!&lt;/p&gt;
</content:encoded></item><item><title>[BOJ 16934, Java] 게임 닉네임</title><link>https://www.traceoflight.dev/ko/blog/boj16934/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj16934/</guid><description>BOJ 16934, &quot;게임 닉네임&quot; 문제의 Java 풀이</description><pubDate>Wed, 28 Dec 2022 00:35:18 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/16934&quot;&gt;BOJ 16934&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;자료 구조(data_structures), 해시를 사용한 집합과 맵(hash_set), 문자열(string), 트리(trees), 트라이(trie)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;개인적으로 문자열 문제에 많이 약하다고 생각하고, 조금 더 열심히 공부해야 한다고 생각하는 편인데 이번 문제는 트라이 알고리즘을 사용하여 해결할 수 있는 문제였다.&lt;/p&gt;
&lt;p&gt;예제가 많아서 반례 체크는 어렵지 않았는데 이런 문제가 예제까지 깔끔하지 않았다면 더 골치 아파졌을 것 같다...&lt;/p&gt;
&lt;p&gt;자바에서 트리형 구조를 구현해보지 못했던 터라 시간을 조금 소모하긴 했지만 따로 도움을 받지 않고 구현했다는 것에 의의를 두자!&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Node&lt;/span&gt; {

        &lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt; nowChar;
        String value;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;count&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
        &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;isUnique&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
        HashSet&amp;lt;Node&amp;gt; childSet;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 헤드에 사용하기 위한 정의 방식&lt;/span&gt;
        Node() {

            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.childSet = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashSet&lt;/span&gt;&amp;lt;&amp;gt;();
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.value = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.isUnique = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 일반적인 서브노드들을 위한 정의 방식&lt;/span&gt;
        Node(&lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt; target) {

            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.nowChar = target;
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.childSet = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashSet&lt;/span&gt;&amp;lt;&amp;gt;();
            &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.value = &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;;

        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Trie&lt;/span&gt; {

        &lt;span class=&quot;hljs-comment&quot;&gt;// 헤드 노드 1개를 보유하고 시작&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;head&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Node&lt;/span&gt;();

        &lt;span class=&quot;hljs-comment&quot;&gt;/**
         * 문자열 1개를 트라이 클래스에 추가하는 메서드
         */&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;addString&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String target)&lt;/span&gt; {

            &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.head;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetLength&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; target.length();

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt;= targetLength; i++) {

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == targetLength) {

                    nowNode.count += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
                    nowNode.value = target;

                } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                    &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;hasChild&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;

                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (Node subNode : nowNode.childSet) {

                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (subNode.nowChar == target.charAt(i)) {

                            nowNode = subNode;
                            hasChild = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

                        }

                    }

                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!hasChild) {

                        &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;madeNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Node&lt;/span&gt;(target.charAt(i));
                        nowNode.childSet.add(madeNode);
                        nowNode = madeNode;

                    }

                }

            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;/**
         * 문자열의 고유 별칭을 찾아내는 메서드
         */&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; String &lt;span class=&quot;hljs-title function_&quot;&gt;findUnique&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String target)&lt;/span&gt; {

            &lt;span class=&quot;hljs-type&quot;&gt;Node&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowNode&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;this&lt;/span&gt;.head;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;targetLength&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; target.length();
            &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;isFirstTime&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;resultCount&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; targetLength + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;; i++) {

                &lt;span class=&quot;hljs-comment&quot;&gt;// 첫 번째로 만나는 고유값이 해당 문자열의 별칭&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowNode.isUnique &amp;amp;&amp;amp; isFirstTime) {

                    nowNode.isUnique = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                    isFirstTime = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                    result = i;
                    resultCount = nowNode.count;

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 이후로도 만나는 고유값은 고유값이 아니도록 처리&lt;/span&gt;
                } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowNode.isUnique) {
                        nowNode.isUnique = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                    }

                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 마지막 문자까지 확인&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == targetLength) {

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 마지막 문자까지 고유값을 체크하지 못한 경우&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (result == -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                        result = targetLength;
                        resultCount = nowNode.count;
                    }

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 카운팅 갯수에 따른 값을 반환&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowNode.count == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target.substring(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, result);

                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target + resultCount;
                    }

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 마지막 문자 이전까지는 트라이 내 탐색 방식으로 진행&lt;/span&gt;
                } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (Node subNode : nowNode.childSet) {

                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (subNode.nowChar == target.charAt(i)) {
                            nowNode = subNode;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;

                        }

                    }

                }

            }

            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;ERROR!&amp;quot;&lt;/span&gt;;

        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-comment&quot;&gt;// Trie Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 트라이 인스턴스 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;Trie&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nickNameTrie&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Trie&lt;/span&gt;();

        &lt;span class=&quot;hljs-comment&quot;&gt;// 유저 수 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;userNumber&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(input.readLine());

        &lt;span class=&quot;hljs-comment&quot;&gt;// 모든 유저에 대해 진행&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; userNumber; i++) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 닉네임 입력 및 트라이에 추가&lt;/span&gt;
            &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nickName&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; input.readLine();
            nickNameTrie.addString(nickName);

            &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 호출하여 해당 닉네임에 대한 별칭 출력&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == userNumber - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {
                output.write(nickNameTrie.findUnique(nickName));

            } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
                output.write(nickNameTrie.findUnique(nickName) + &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;);
            }

        }

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 17114, Java] 하이퍼 토마토</title><link>https://www.traceoflight.dev/ko/blog/boj17114/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj17114/</guid><description>BOJ 17114, &quot;하이퍼 토마토&quot; 문제의 Java 풀이</description><pubDate>Thu, 22 Dec 2022 04:36:35 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;[BOJ 17114] (&lt;a href=&quot;https://www.acmicpc.net/problem/17114&quot;&gt;https://www.acmicpc.net/problem/17114&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;구현(implementation), 그래프 이론(graphs), 그래프 탐색(graph_traversal), 너비 우선 탐색(bfs)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;개인적으로 BFS가 어디까지 더러워질 수 있는지를 잘 보여주는 문제라고 생각한다.&lt;/p&gt;
&lt;p&gt;문제의 존재는 진즉에 알고 있었고, 해결법 자체도 이미 유명한만큼 잘 알려져 있어도 내가 해결하는 방식을 구현하는 것이랑은 다른 문제라는 것을 새삼 배워가게 된다.&lt;/p&gt;
&lt;p&gt;빠른 입출력은 기본이고, 너비 탐색을 하는 것에 있어서 군더더기를 날려주지 않는다면 시간 초과를 받을 수 있는 문제.&lt;/p&gt;
&lt;p&gt;파이썬에서 sys.stdin.readline으로 해결을 볼 수 있을지는 모르겠지만 java에서는 다행히 BufferedReader 선에서 처리가 가능했다.&lt;/p&gt;
&lt;p&gt;이 문제를 풀고 나서 찾아보니 스마트하게 푸는 방식이 따로 있는 것으로 보이지만 여기서는 고전적인 BFS를 무식하게 확장하는 것으로 해결했다.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;11차원 배열에 좌표 정보 입력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;안 익은 토마토는 카운팅, 익은 토마토는 좌표 기록&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;익은 토마토를 순회하면서 인접한 안 익은 토마토를 익은 토마토 리스트에 집어넣으면서 카운팅한 값을 감소, 해당 과정을 조건에 따라서 반복한다&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;카운팅이 0이 된다면 다 익었기 때문에 걸린 날짜를 출력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;카운팅이 0이 되지 않았지만 기존 안 익은 토마토에서 (3)번 항목을 반복했을 때 갯수가 변화하지 않았다면 더 이상 익히는 게 불가능하다는 이야기이므로 -1을 출력한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;이 문제를 해결할 때 2번과 3번 항목을 처리하는 데에 있어서 다른 방식, &lt;strong&gt;그러니까 카운팅을 매번 반복하는 방식이나 한 번 사용한 익은 토마토의 좌표를 제거해주지 않는다면 시간 초과를 받을 수 있는데...&lt;/strong&gt; 여기서 한참 해메면서 해결했다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;p&gt;코드가 상당히 긴데... 11중 for문을 사용하고 인접 좌표를 표현하는 점에서 어쩔 수 없는 부분이라고 생각한다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; tomatoLeft;

    &lt;span class=&quot;hljs-comment&quot;&gt;/**
     * 토마토가 익는 메커니즘을 반영하여 1일 뒤의 배열로 변경하는 함수
     */&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;ripeTomato&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][][][][][][][][][][] target, Queue&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[]&amp;gt; tomatoQueue, &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] sizeInfo)&lt;/span&gt; {

        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][] movements = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[][]{
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;},
        };

        ArrayList&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[]&amp;gt; ripeList = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] nowIdx : tomatoQueue) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] movement : movements) {

                &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;isNotOverIndex&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;

                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;; i++) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;gt; nowIdx[i] + movement[i] || nowIdx[i] + movement[i] &amp;gt;= sizeInfo[i]) {
                        isNotOverIndex = &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;
                        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
                    }
                }

                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx00&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx01&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx02&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx03&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx04&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx05&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx06&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx07&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx08&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx09&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;];
                &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nextIdx10&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; nowIdx[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;] + movement[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;];

                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (

                        isNotOverIndex

                                &amp;amp;&amp;amp; target[nextIdx00][nextIdx01][nextIdx02]
                                [nextIdx03][nextIdx04][nextIdx05][nextIdx06]
                                [nextIdx07][nextIdx08][nextIdx09][nextIdx10]
                                == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

                ) {

                    ripeList.add(

                            &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{
                                    nextIdx00, nextIdx01, nextIdx02,
                                    nextIdx03, nextIdx04, nextIdx05, nextIdx06,
                                    nextIdx07, nextIdx08, nextIdx09, nextIdx10
                            }

                    );

                }

            }

        }

        tomatoQueue.clear();

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] ripeCoord : ripeList) {

            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (

                    target[ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]]
                            [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]]
                            [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]] == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

            ) {

                target[ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]]
                        [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]]
                        [ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]][ripeCoord[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]] = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                tomatoLeft -= &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                tomatoQueue.add(ripeCoord);

            }

        }

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));
        &lt;span class=&quot;hljs-type&quot;&gt;BufferedWriter&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;output&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedWriter&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;OutputStreamWriter&lt;/span&gt;(System.out));

        &lt;span class=&quot;hljs-comment&quot;&gt;// 배열 사이즈 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[] storageSize = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[&lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;];
        &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;sizeInput&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;11&lt;/span&gt;; i++) {
            storageSize[i] = Integer.parseInt(sizeInput.nextToken());
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 창고 정보 입력&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[][][][][][][][][][][] tomatoStorage = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[storageSize[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]]
                [storageSize[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]]
                [storageSize[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]][storageSize[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]];

        Queue&amp;lt;&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt;[]&amp;gt; ripeTomatoQueue = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;LinkedList&lt;/span&gt;&amp;lt;&amp;gt;();

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx10&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx10 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;10&lt;/span&gt;]; idx10++) {
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx09&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx09 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;9&lt;/span&gt;]; idx09++) {
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx08&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx08 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;8&lt;/span&gt;]; idx08++) {
                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx07&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx07 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;7&lt;/span&gt;]; idx07++) {
                        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx06&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx06 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;]; idx06++) {
                            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx05&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx05 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;]; idx05++) {
                                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx04&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx04 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;]; idx04++) {
                                    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx03&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx03 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;]; idx03++) {
                                        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx02&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx02 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;]; idx02++) {
                                            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx01&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx01 &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]; idx01++) {

                                                &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;storageInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(), &lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[ ]&amp;quot;&lt;/span&gt;);

                                                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;idx00Counter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; idx00Counter &amp;lt; storageSize[&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;]; idx00Counter++) {

                                                    &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;nowInput&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; Integer.parseInt(storageInfo.nextToken());

                                                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowInput == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;) {

                                                        ripeTomatoQueue.add(
                                                                &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;int&lt;/span&gt;[]{
                                                                        idx00Counter, idx01, idx02,
                                                                        idx03, idx04, idx05, idx06,
                                                                        idx07, idx08, idx09, idx10
                                                                }
                                                        );

                                                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (nowInput == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {

                                                        tomatoLeft += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                                                    }

                                                    tomatoStorage[idx00Counter][idx01][idx02]
                                                            [idx03][idx04][idx05][idx06]
                                                            [idx07][idx08][idx09][idx10]
                                                            = nowInput;

                                                }

                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 지난 날짜 카운팅 변수 및 모두 익지 못하는 상황을 체크하기 위한 Flag 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;dayCounter&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;
        &lt;span class=&quot;hljs-type&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;cantComplete&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;false&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 모두 익지 않았다면 반복&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (tomatoLeft &amp;gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 호출하여 기존 배열 깊은 복사 후 1일 뒤의 배열 확인&lt;/span&gt;
            &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;lastTomato&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; tomatoLeft;
            ripeTomato(tomatoStorage, ripeTomatoQueue, storageSize);

            &lt;span class=&quot;hljs-comment&quot;&gt;// 날짜 1 카운트&lt;/span&gt;
            dayCounter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

            &lt;span class=&quot;hljs-comment&quot;&gt;// 아직 다 익지 않았지만 기존이랑 차이가 없다면 전부 익을 수 없는 상황이므로 Flag 변경 후 break&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (tomatoLeft != &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;amp;&amp;amp; tomatoLeft == lastTomato) {
                cantComplete = &lt;span class=&quot;hljs-literal&quot;&gt;true&lt;/span&gt;;
                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;;
            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 문제 조건에 따라서 출력&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (cantComplete) {
            output.write(&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;-1&amp;quot;&lt;/span&gt;);
        } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {
            output.write(Integer.toString(dayCounter));
        }

        output.flush();
        output.close();

    }

}

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 3865, Java] 학회원</title><link>https://www.traceoflight.dev/ko/blog/boj3865/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj3865/</guid><description>BOJ 3865, &quot;학회원&quot; 문제의 Java 풀이</description><pubDate>Mon, 12 Dec 2022 13:50:33 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/3865&quot;&gt;BOJ 3865&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;너비 우선 탐색(bfs), 자료 구조(data_structures), 깊이 우선 탐색(dfs), 그래프 이론(graphs), 그래프 탐색(graph_traversal), 해시를 사용한 집합과 맵(hash_set), 파싱(parsing), 문자열(string)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;최근에 마주한 코딩 테스트들에서 문자열에 관한 문제들이 자주 출제되는 경향을 보이는 거 같아 아무래도 문자열에 연관된 문제를 찾던 중 발견한 문제.&lt;/p&gt;
&lt;p&gt;깊이 탐색을 사용하는 문제여서 아무래도 익숙했고 아직 자바 언어에 대한 숙지가 부족하다보니 풀이에 시간은 조금 걸렸지만 큰 틀은 깊이 탐색에서 벗어나지 않았다.&lt;/p&gt;
&lt;p&gt;문자열 데이터를 잘 가공해주고 학회와 학생 이름에 대해 방문 기록 집합을 계속 체크하면서 아직 방문하지 않은 경우 각 케이스에 대해 재귀 + 카운팅 처리로 마무리할 수 있는 문제였다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.io.*;
&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; java.util.*;

&lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Main&lt;/span&gt; {

    &lt;span class=&quot;hljs-comment&quot;&gt;/**
     * 해당 학회의 총 인원수를 반환하는 함수
     */&lt;/span&gt;

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;getTotalPerson&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String target)&lt;/span&gt; {

        &lt;span class=&quot;hljs-comment&quot;&gt;// 결과값 변수 선언&lt;/span&gt;
        &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;;

        &lt;span class=&quot;hljs-comment&quot;&gt;// 아직 방문하지 않은 경우에 대해서만 처리&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!visitLog.contains(target)) {

            &lt;span class=&quot;hljs-comment&quot;&gt;// 방문 기록&lt;/span&gt;
            visitLog.add(target);

            &lt;span class=&quot;hljs-comment&quot;&gt;// 사람이 아닌 학회일 경우&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (clubGraph.containsKey(target)) {

                &lt;span class=&quot;hljs-comment&quot;&gt;// 해당 학회의 방문하지 않은 구성원에 대해 재귀함수를 호출, 결과값에 합산&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (String eachPerson : clubGraph.get(target)) {

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 구성원이 학회라면 재귀함수 호출&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (clubGraph.containsKey(eachPerson)) {
                        result += getTotalPerson(eachPerson);

                    &lt;span class=&quot;hljs-comment&quot;&gt;// 학생이라면 아직 방문하지 않았을 경우 결과값 1 추가&lt;/span&gt;
                    } &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt; {

                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!visitLog.contains(eachPerson)) {

                            visitLog.add(eachPerson);
                            result += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;;

                        }

                    }

                }

            }

        }

        &lt;span class=&quot;hljs-comment&quot;&gt;// 결과값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result;

    }

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;strToInt&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String inputString)&lt;/span&gt; {
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; Integer.parseInt(inputString);
    }

    &lt;span class=&quot;hljs-comment&quot;&gt;// 학회 수, 첫 학회, 학회 관계 그래프, 학생 기록 집합 정적 변수 선언&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; clubNumber;
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; String firstClub;
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; HashMap&amp;lt;String, ArrayList&amp;lt;String&amp;gt;&amp;gt; clubGraph = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashMap&lt;/span&gt;&amp;lt;&amp;gt;();
    &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; Set&amp;lt;String&amp;gt; visitLog = &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;HashSet&lt;/span&gt;&amp;lt;&amp;gt;();

    &lt;span class=&quot;hljs-keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;hljs-params&quot;&gt;(String[] args)&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;throws&lt;/span&gt; IOException {

        &lt;span class=&quot;hljs-type&quot;&gt;BufferedReader&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;BufferedReader&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;InputStreamReader&lt;/span&gt;(System.in));

        &lt;span class=&quot;hljs-comment&quot;&gt;// 학회의 수 입력, 입력값이 0이라면 반복 종료&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; ((clubNumber = strToInt(input.readLine())) != &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {

            clubGraph.clear();
            visitLog.clear();

            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;hljs-type&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;; i &amp;lt; clubNumber; i++) {

                &lt;span class=&quot;hljs-comment&quot;&gt;// 줄 단위 입력&lt;/span&gt;
                &lt;span class=&quot;hljs-type&quot;&gt;StringTokenizer&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;clubInfo&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;StringTokenizer&lt;/span&gt;(input.readLine(),&lt;span class=&quot;hljs-string&quot;&gt;&amp;quot;[:,.]&amp;quot;&lt;/span&gt;);

                &lt;span class=&quot;hljs-comment&quot;&gt;// 학회 이름 변수 선언&lt;/span&gt;
                &lt;span class=&quot;hljs-type&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;clubName&lt;/span&gt; &lt;span class=&quot;hljs-operator&quot;&gt;=&lt;/span&gt; clubInfo.nextToken();

                &lt;span class=&quot;hljs-comment&quot;&gt;// 첫 학회라면 따로 변수에 기록&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (i == &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) {
                    firstClub = clubName;
                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 기존에 없던 학회라면 추가&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!clubGraph.containsKey(clubName)) {
                    clubGraph.put(clubName, &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;ArrayList&lt;/span&gt;&amp;lt;&amp;gt;());
                }

                &lt;span class=&quot;hljs-comment&quot;&gt;// 나머지를 전부 학회의 원소로 추가&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; (clubInfo.hasMoreTokens()) {
                    clubGraph.get(clubName).add(clubInfo.nextToken());
                }

            }

            &lt;span class=&quot;hljs-comment&quot;&gt;// 함수를 호출하여 결과값을 출력 스택에 추가&lt;/span&gt;
            System.out.println(getTotalPerson(firstClub));

        }

    }

}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>SQLD 합격 후기 및 자료</title><link>https://www.traceoflight.dev/ko/blog/sqld/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/sqld/</guid><description>SQLD 합격 후기</description><pubDate>Tue, 29 Nov 2022 15:32:31 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;md-media-frame media-load-frame&quot; data-media-shell&gt;&lt;img src=&quot;/media/image/imported-0d43c36638e8bf56-image.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; data-md-fallback data-media-load&gt;&lt;span class=&quot;md-media-fallback md-image-fallback&quot; hidden&gt;이미지를 불러올 수 없습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;47회 SQL 개발자 자격 시험에 합격했다. 진로를 확실히 비틀어버린 뒤에 처음으로 취득하는 자격증이라 굉장히 뿌듯한 감이 있다.&lt;/p&gt;
&lt;p&gt;처음에는 1달 정도를 투자하고 싶었는데 다른 할 일들에 치이거나 너무 이론적으로 접근하는 등.. 시간 낭비를 꽤 많이 한 것 같아서 아쉬운 부분이 있다. 공부하면서 확인했던 점들을 여기에 남긴다.&lt;/p&gt;
&lt;p&gt;마지막 파트에 개인적으로 정리한 개념들이 기재되어 있는데 이후에 실전적인 부분이나, 내가 암기하기 편하도록 편집된 점들이 이곳저곳에 남아서 맞지 않는 부분 등이 존재할 수 있다! 그래도 혹시 누군가가 공부할 때에 도움이 될 수 있으니 전체 내용을 남겨두고 나중에 생각나면 편집할 예정이다.&lt;/p&gt;
&lt;h1&gt;소요 시간 및 공부 방법&lt;/h1&gt;
&lt;p&gt;실질적으로 소모한 시간은 2주 가량, 문제 풀이에는 1주 가량을 소비했다.&lt;/p&gt;
&lt;p&gt;처음에는 &lt;a href=&quot;https://dataonair.or.kr/&quot;&gt;Data on Air&lt;/a&gt;에서 제공하는 개념 설명을 통해 왕도에 가까운 방향으로 공부를 진행하고 싶었지만 SQLD 자체가 개념적인 부분보다는 실전적인 SQL 구문의 형태로 제공되는 문제 수가 훨씬 많은 것을 보고 초반부에 하차하게 되었다. 하지만 여전히 내용 자체는 좋다고 생각하기 때문에 시간이 많다면 한 번 확인하는 것을 추천한다!&lt;/p&gt;
&lt;p&gt;그 다음으로는 유튜브에 존재하는 다양한 형태의 강의를 통해 대략적인 개요를 잡았다. SQLD에 한해서는 꽤 많은 양의 정리된 강의가 존재하고 있기 때문에 좋아보이는 것을 골라잡는 것으로 충분할 것이다.&lt;/p&gt;
&lt;p&gt;마지막으로 문제풀이인데 문제의 경우는 관련 카페 혹은 블로그에 기출 문제를 복원해놓은 자료들이 존재한다. 일명 &amp;quot;노랭이&amp;quot; 라고 불리는 책도 좋지만 기출문항에 대한 풀이도 소홀히 하지 않는 것이 중요하다! 노랭이의 경우는 2단원까지 1회독 및 오답 노트 정리만 진행하였고 나머지 시간 동안 전부 기출 문제 풀이에 시간을 사용했다.&lt;/p&gt;
&lt;p&gt;개인적으로 추천하는 복원 문제 모음 사이트는 &lt;a href=&quot;https://yunamom.tistory.com/category/%EC%9E%90%EA%B2%A9%EC%A6%9D/SQLD%20%EA%B8%B0%EC%B6%9C%EB%AC%B8%EC%A0%9C&quot;&gt;이 블로그&lt;/a&gt;를 추천하고 싶다. 답을 입력하는 것으로 즉시 해당 문제의 정오를 확인할 수 있기 때문.&lt;/p&gt;
&lt;h1&gt;개념 정리&lt;/h1&gt;
&lt;p&gt;참고사항: 1단원 쪽이 2단원보다 문제 비중이 적어 후순위로 밀렸고 그에 따라 필요한 내용만 기재하여 내용이 충분치 않을 수 있음&lt;/p&gt;
&lt;h2&gt;1단원&lt;/h2&gt;
&lt;h2&gt;엔터티의 분류&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기본 / 키 엔터티&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;중심 엔터티&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;행위 엔터티&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;데이터 모델링&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;정보 시스템 구축을 위한 데이터 관점의 업무 분석 기법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;현실 세계의 데이터를 약속된 표기법에 의해 표현&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;데이터 베이스를 구축하기 위한 분석 / 설계의 과정&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;데이터 모델링을 진행할 때의 유의점&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;중복&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비유연성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비일관성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;데이터 모델링의 종류&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;개념적: 추상화 수준이 높고, 업무 중심으로 포괄적 진행&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;논리적: Key, 속성, 관계 등을 정확하게 표현, 재사용성이 높도록 설계&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;물리적: 실제 데이터 베이스에 이식할 수 있도록 하며 물리적 성격을 고려합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;데이터 베이스 스키마의 구조&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;외부&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;개념&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;내부&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;ERD 작성 순서&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;엔터티를 그린다.&lt;/li&gt;
&lt;li&gt;엔터티를 적절하게 배치한다.&lt;/li&gt;
&lt;li&gt;엔터티 간의 관계를 설정한다.&lt;/li&gt;
&lt;li&gt;관계명을 기술한다.&lt;/li&gt;
&lt;li&gt;관계 참여도를 기술한다.&lt;/li&gt;
&lt;li&gt;관계 필수 여부를 기술한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;엔터티의 특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;해당 업무에서 필요하고 관리해야 할 정보&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;유일한 식별자여야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2개 이상의 인스턴스를 보유한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;실제로 사용되어야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;속성을 보유해야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;최소 1개 이상의 관계를 형성해야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;1개 엔터티: 2개 이상의 인스턴스 집합 + 2개 이상의 속성
1개 속성: 1개 이상의 속성값
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;속성의 특성에 따른 분류&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기본 속성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;설계 속성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;파생 속성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;도메인&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;각 속성이 가질 수 있는 값의 범위&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;엔터티 내 속성에 대한 데이터 타입, 크기, 제약사항 지정&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;속성 명칭 부여&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;해당 업무에서 사용하는 명칭이어야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서술식 속성명은 사용하지 않는다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;약어의 사용을 자제한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;전체 데이터 모델에서 유일성을 확보해야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;ERD에서는 존재적 관계와 행위적 관계를 구분하지 않는다.
하지만 Class 다이어 그램에서는 구분하며 연관 관계, 의존 관계를 서술해야 한다.&lt;/p&gt;
&lt;h2&gt;관계의 표기법&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;관계명: 관계의 이름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;관계차수: 1 : 1, 1 : M, M : N&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;관계선택사양: 필수, 선택&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;관계 읽기&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기준 엔터티를 1개 One 또는 각 Each로 읽는다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;대상 엔터티의 관계 참여도를 읽는다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;관계 선택 사양과 관계명을 읽는다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;식별자 종류&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;대표성: 주 식별자 vs 보조 식별자&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;스스로 생성 여부: 내부 vs 외부&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;단일 속성 식별: 단일 vs 복합&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;의미 여부: 본질 vs 인조&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;주 식별자의 특징&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;유일성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;희소성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;불변성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;존재성&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;성능 데이터 모델링&lt;/h2&gt;
&lt;p&gt;데이터 베이스 성능 향상을 목적으로 성능 관련 사항을 데이터 모델링에 반영&lt;/p&gt;
&lt;h2&gt;1차 정규화 대상&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;중복 속성에 대한 분리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;로우 단위의 중복&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;칼럼 단위의 중복&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;반정규화&lt;/h2&gt;
&lt;p&gt;정규화된 엔터티, 속성, 관계의 중복, 통합, 분리를 통해
시스템의 성능을 향상, 개발 및 운영의 단순화
무결성이 깨질 수 있음에도 성능 저하가 예상될 때 수행한다.&lt;/p&gt;
&lt;h3&gt;절차&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;반정규화의 대상 조사&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;범위 처리 빈도&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;대량의 범위 처리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;통계성 프로세스&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;테이블 JOIN 갯수&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다른 방법으로 진행할 수 있을 경우 해당 방법으로 유도 검토&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;JOIN이 많은 경우 view table 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;대량의 데이터 처리 시 clustering&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;대량의 데이터를 보유한 경우 파티셔닝을 통해 데이터 분할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;index maintenance&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;응용 application 의 logic 변경&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;슈퍼 / 서브 타입 데이터 모델 변환 기술&lt;/h2&gt;
&lt;p&gt;개별적으로 발생하는 Transaction -&amp;gt; 개별 테이블
슈퍼 + 서브 타입 -&amp;gt; 슈퍼 + 서브 테이블
전체 -&amp;gt; 하나의 테이블&lt;/p&gt;
&lt;h2&gt;PK 순서를 결정하는 기준&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;인덱스를 효율적으로 이용할 수 있도록 지정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;앞쪽에 위치한 속성의 값이 비교자일 것&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;가급적 &apos;=&apos;, BETWEEN, &apos;&amp;lt;&amp;gt;&apos;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;분산 데이터 베이스 장점 및 단점&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;장점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;지역 자치성, 점진적으로 시스템의 용량 확장이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;신뢰성과 가용성 / 효용성과 융통성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;빠른 응답 속도, 통신 비용의 절감, 지역 사용자의 요구 수용 증대&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;데이터의 가용성과 신뢰성 증가, 시스템 규모 조절&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;단점&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;개발 비용 및 오류 잠재성 증가, 처리 비용 증가, 데이터의 무결성을 위협&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;설계 과정의 어려움, 관리의 복잡성과 비용, 불규칙한 응답속도, 통제의 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;2단원&lt;/h2&gt;
&lt;h2&gt;SQL문의 종류&lt;/h2&gt;
&lt;h3&gt;DCL&lt;/h3&gt;
&lt;p&gt;Data Control Language, 권한을 관리하는 명령어&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;GRANT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;권한을 부여하는 역할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GRANT {permission} ON {table} TO {user};&lt;/code&gt;의 형태로 사용&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;WITH GRANT, WITH ADMIN의 비교

GRANT: 특정 사용자에게 권한 부여가 가능한 권한을 부여, 부여한 부모의 권한이 회수될 때 자식의 권한도 회수
ADMIN: 테이블에 대한 모든 권한을 부여, 부여한 부모의 권한 회수와 관계 없는 권한
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;REVOKE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;권한을 회수하는 역할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;REVOKE {permission} ON {table} FROM {user};&lt;/code&gt;의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;권한의 종류&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;ALL&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;-- 모든 권한 부여&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;SELECT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;INSERT&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;UPDATE&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;DELETE&lt;/span&gt; &lt;span class=&quot;hljs-comment&quot;&gt;/*  */&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;REFERENCES&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;ALTER&lt;/span&gt; INDEX &lt;span class=&quot;hljs-comment&quot;&gt;/*  */&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;/* ROLE: 다양한 권한을 하나의 그룹으로 묶어서 관리 */&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE&lt;/span&gt; ROLE {role_name}; &lt;span class=&quot;hljs-comment&quot;&gt;-- 권한 그룹 생성&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;GRANT&lt;/span&gt; {permission_type} &lt;span class=&quot;hljs-keyword&quot;&gt;TO&lt;/span&gt; {role_name}; &lt;span class=&quot;hljs-comment&quot;&gt;-- 해당 그룹에 권한 등록&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;GRANT&lt;/span&gt; {role_name} &lt;span class=&quot;hljs-keyword&quot;&gt;TO&lt;/span&gt; {user_1}, {user_2}...; &lt;span class=&quot;hljs-comment&quot;&gt;-- 다른 유저들에게 권한 그룹 부여&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DDL&lt;/h3&gt;
&lt;p&gt;Data Definition Language, 데이터를 정의하는 명령어&lt;/p&gt;
&lt;p&gt;SQL Server 기준으로 Auto Commit을 지원&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CREATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;테이블 구조 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;CREATE TABLE {table_name} {table_elements};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sql&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;CREATE TABLE&lt;/span&gt; EXAMPLE (
&lt;span class=&quot;hljs-comment&quot;&gt;/* 
  컬럼명은 영어, 한글, 숫자 전부 가능 
  첫 글자를 문자로 지정해야 하며, 컬럼의 데이터 타입은 반드시 설정해야 한다.
*/&lt;/span&gt;
		NAME  varchar2(max_length)  &lt;span class=&quot;hljs-comment&quot;&gt;-- 최대 길이를 가진 가변길이 문자열&lt;/span&gt;
  	ID번호 &lt;span class=&quot;hljs-type&quot;&gt;char&lt;/span&gt;(length)          &lt;span class=&quot;hljs-comment&quot;&gt;-- 고정된 길이 문자열&lt;/span&gt;
		나이_2 number(max_length)    &lt;span class=&quot;hljs-comment&quot;&gt;-- 숫자형 데이터 타입&lt;/span&gt;
  	생일   &lt;span class=&quot;hljs-type&quot;&gt;date&lt;/span&gt;                  &lt;span class=&quot;hljs-comment&quot;&gt;-- 날짜형 데이터 타입&lt;/span&gt;
);
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;CONSTRAINT (조건)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;default: 기본값 지정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;not null: null 입력 불가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;primary key: 기본키 지정 (not null, unique, 다수 가능)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;foreign key: 외래키 지정 (다수 가능)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ALTER&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;테이블 및 컬럼에 대해 이름과 속성의 변경, 추가, 삭제 등의 구조 수정 역할&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ALTER TABLE {table_name} {detail_order} {detail_property(if need)} TO {change_target};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;세부 명령어&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;RENAME: 테이블, 컬럼의 이름을 변경&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;MODIFY: 컬럼의 속성을 변경&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ADD: 컬럼을 추가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DROP: 컬럼을 제거&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ADD CONSTRAINT / DROP CONSTRAINT: 제약조건을 추가, 제거&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;RENAME&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;테이블, 컬럼의 이름을 ALTER를 거치지 않고 변경할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;다수의 테이블명을 동시에 변경 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;DROP&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;테이블, 컬럼을 ALTER를 거치지 않고 제거할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TABLE {table_name} CASCADE CONSTRAINT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Oracle에만 존재하는 옵션으로, SQL Server에는 존재하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FK 제약조건, 참조 테이블을 먼저 제거하고, 해당 테이블을 삭제한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;해당 테이블의 데이터를 외래키 참조 제약사항도 모두 제거&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TRUNCATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;테이블 초기화 (삭제가 아님!)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;내부 데이터만 제거되고 테이블의 존재 및 컬럼은 남는다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;DROP vs TRUNCATE vs DELETE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DROP: 테이블을 통째로 제거 후 메모리 release&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;TRUNCATE: 테이블, 컬럼의 존재가 남고 나머지 데이터에 대한 메모리 release&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DELETE: 레코드를 제거, 데이터에 대한 로그가 남아 반영 전까지 롤백이 가능하고 메모리 release 없음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;DML&lt;/h3&gt;
&lt;p&gt;Data Manipulation Language, 레코드를 조작하는 명령어&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;INSERT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터를 레코드에 입력&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;INSERT INTO {table_name} {column_name} VALUES {change_column_name};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;칼럼명 지정을 안하고도 입력이 가능하지만 지정하지 않은 경우 모든 값이 입력되어야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;UPDATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기존 데이터를 수정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;UPDATE {table_name} SET {column_name} = {column_value} WHERE {condition};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;DELETE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;기존 데이터를 제거&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;DELETE FROM {table_name} WHERE {condition};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FROM 생략 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SELECT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;특정 데이터를 조회&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SELECT {select_target} FROM {select_origin} WHERE {condition};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;GROUP BY {calc_type} HAVING {condition} / ORDER BY {sort_condition}&lt;/code&gt; 의 형태로 조건을 넣기도 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;DISTINCT&lt;/h4&gt;
&lt;p&gt;중복값 없이 조회하는 조건 (a, b, NULL, a, b, NULL) =&amp;gt; (a, b, NULL)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;COUNT&lt;/h4&gt;
&lt;p&gt;(*): 전체 행의 수를 NULL 값을 포함하여 카운팅&lt;/p&gt;
&lt;p&gt;({column_name}): 특정 컬럼의 행값을 NULL을 제외하고 카운팅&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;TCL&lt;/h3&gt;
&lt;p&gt;Transaction Control Language, Transaction 제어 명령어&lt;/p&gt;
&lt;p&gt;Transaction: DB의 상태를 변화시키는 작업&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;* transaction의 특징
고립성: 실행되는 동안 다른 transaction에 영향을 받아 잘못된 결과를 만들면 안됨
일관성: 실행 전 데이터베이스에 잘못된 점이 없다면 transaction 수행 후에도 내용에 오류가 있으면 안됨
지속성: transaction이 갱신한 데이터베이스 내용은 영구적으로 저장
원자성: transaction에서 정의한 연산은 모두 성공적으로 실행되거나 전혀 실행되지 않음 (All or Nothing)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;COMMIT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;데이터에 대한 변화를 DB에 반영&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SAVEPOINT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;코드 분할의 분기점이 될 수 있도록 savepoint를 지정&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SAVEPOINT {savepoint_name};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ROLLBACK&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;이전의 상태로 되돌리는 명령어&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SAVEPOINT 혹은 직전 COMMIT으로 되돌리기가 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ROLLBACK TO {rollback_point};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SAVEPOINT가 없다면 가장 최신의 COMMIT으로 복원&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TCL의 효과&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;데이터 무결성의 보장&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;영구적 데이터 변경 전 데이터의 변경사항을 확인&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;논리적 연관성이 있는 작업들을 그룹화 처리 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;함수&lt;/h2&gt;
&lt;h3&gt;문자형 함수&lt;/h3&gt;
&lt;p&gt;SELECT, WHERE 등의 조건을 지정할 때 많이 사용&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;LOWER&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;영어 문자열을 소문자로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;UPPER&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;영어 문자열을 대문자로 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CONCAT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;문자열 2개를 결합&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Oracle &apos;||&apos;, SQL Server &apos;+&apos; 동일한 역할&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SUBSTR&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;문자열 M번째에서부터 N개의 문자를 남기고 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;LENGTH, LEN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;공백을 포함한 문자열의 길이&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TRIM, LTRIM, RTRIM&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;양 끝단의 지정된 문자를 모두 제거, 지정된 문자가 없다면 공백을 제거&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;숫자형 함수&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ROUND&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;반올림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TRUNC&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;버림&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CEIL&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;크거나 같은 최소 정수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;FLOOR&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;작거나 같은 최대 정수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;MOD&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;모듈로 연산&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SIGN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;양수는 1, 0은 0, 음수는 -1을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ABS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;절댓값&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;날짜형 함수&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SYSDATE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;쿼리를 실행 중인 현재의 날짜 및 시간을 출력&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;EXTRACT&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;EXTRACT ({information} FROM {data})&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;날짜형 데이터에서 원하는 값을 추출하는 법&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;형 변환&lt;/h3&gt;
&lt;p&gt;해당 함수들을 통해 데이터 타입을 변경할 수 있다&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TO_NUMBER&lt;/h4&gt;
&lt;p&gt;문자열 &amp;gt; 숫자&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TO_CHAR&lt;/h4&gt;
&lt;p&gt;숫자, 날짜 &amp;gt; 문자 (포맷에 따라서 다르게 생성)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;TO_DATE&lt;/h4&gt;
&lt;p&gt;문자열 &amp;gt; 날짜 (포맷에 따라서 다르게 생성)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;기본 구조&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;DECODE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IF문&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;조건이 심플하게 정리될 때&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CASE WHEN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;길어진 IF문&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;조건의 정리가 길게 필요할 때&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ORDER BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;조회된 테이블의 정렬&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;기준을 여러 개 사용할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;WHERE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;IN, NOT IN: 목록 내의 값들 중 어느 하나만 일치, 불일치한다면 조건을 만족&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;IS NULL, IS NOT NULL: NULL인지 아닌지 판단해서 T / F&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;BETWEEN a AND b: a와 b 사이에 값이 존재하는지 확인해서 T / F 반환 (a와 b를 포함)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;비교 연산자: =, &amp;gt;, &amp;lt;, &amp;gt;=, &amp;lt;= 등&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A LIKE B: a에 대하여 b와 유사한 문자열을 찾아줌&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;%: 문자 1개 이상이 존재한다는 의미&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;_: 문자 1개&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;명시적 형변환 vs 암시적 형변환

명시적 형변환: 함수를 활용하여 데이터 타입을 변경
암시적 형변환: 데이터베이스가 알아서 바꿔주는 것
&amp;gt;&amp;gt; 숫자 타입의 PK는 암묵적으로 인덱스가 되는데 데이터의 조회 등으로 암시적 형변환이 발생한 경우, 인덱스로 사용이 불가능
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;WITH&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;서브 쿼리를 사용해서 임시테이블, view처럼 사용 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;별칭 지정 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인라인 뷰 혹은 임시테이블로 판단&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;WITH {table_name} AS {table_condition}&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;GROUP BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;조건에 따라서 grouping 진행하는 명령어&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;값의 조합이 다르다면 다른 그룹&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;HAVING&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;grouping 이후 상태 기반의 조건문&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;COUNT(카운팅), SUM(합), AVG(평균), MAX(최대), MIN(최소), STDDEV(표준편차), VARIAN(분산) 등&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DISTINCT(중복 제거), ALL(전체) 등의 조건을 사용할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;NULL 함수&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;NVL, ISNULL&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;NULL이면 다른 값으로 변경하는 함수&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;데이터 타입이 다르면 사용할 수 없음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;NVL2&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;NULL인지 아닌지에 따라서 다른 결과를 반환하는 함수&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;NULL이 아닐 경우 1번 파라미터, NULL인 경우 2번 파라미터를 반환&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;NULLIF&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;파라미터 2개가 같을 경우 NULL을 반환, 다를 경우 1번 파라미터를 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;COALESCE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;NULL이 아닌 최초의 값을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;GROUP 함수&lt;/h3&gt;
&lt;p&gt;그룹 대상 컬럼값, 집계 대상 컬럼값은 NULL로 출력&lt;/p&gt;
&lt;p&gt;일반 그룹함수로 동일한 결과를 추출할 수 있음&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ROLLUP&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;부분합과 전체합을 보여준다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;함수의 인자가 주어진 순서에 따라 결과값이 달라지며 계층 구조로 집계값을 반환한다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CUBE&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;그룹화할 수 있는 모든 경우에 대해서 인자합을 생성&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;GROUPING SETS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;괄호로 묶은 집합별 집계가 가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;GROUPING&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;소계, 합계 등이 계산되면 1을 반환, 아니라면 0을 반환하는 함수&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;JOIN&lt;/h3&gt;
&lt;p&gt;일반적으로 테이블 간의 결합, 집합과 유사&lt;/p&gt;
&lt;p&gt;테이블과 테이블, 조인 결과와 테이블, 조인 결과끼리의 JOIN이 가능&lt;/p&gt;
&lt;p&gt;관련된 두 테이블에 적어도 하나의 공통 속성이 존재할 때 적용 가능&lt;/p&gt;
&lt;p&gt;JOIN을 명시하는 ANSI 표준형 쿼리가 있고 그렇지 않는 비표준형 쿼리가 존재한다.&lt;/p&gt;
&lt;p&gt;JOIN이 나열된 경우 한 번에 2개씩 작업, 모두 동시에 작업 불가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;교집합&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;INNER JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;비표준형 표기 , 로 축약&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;양쪽 테이블의 교집합을 JOIN&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;LEFT JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;비표준형 사용 시 왼쪽에 (+) 표기&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;왼쪽 테이블에서 전부, 오른쪽 테이블에서 교집합만 JOIN&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;RIGHT JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;비표준형 사용 시 오른쪽에 (+) 표기&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;오른쪽 테이블에서 전부, 왼쪽 테이블에서 교집합만 JOIN&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;OUTER JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;양쪽에 (+) 사용 불가로 OUTER JOIN을 사용할 수 없으므로 ANSI 표준형 쿼리를 사용해야 한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UNION과 다르게 공통 속성이 1개만 존재해도 적용이 가능하다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;합집합&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;UNION (ALL)&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;조회대상 컬럼의 수가 같고 각 컬럼의 속성이 동일할 때 적용할 수 있는 결합 방식&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;데이터의 양이 Data1 + Data2가 된다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;UNION ALL은 중복 데이터를 제거하지 않고 합치게 됨&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;차집합&lt;/p&gt;
&lt;p&gt;교집합을 배제하는 하나의 집합만 확인하려고 할 때 적용 가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;MINUS(Oracle)&lt;/h4&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;EXCEPT(SQL Server)&lt;/h4&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;결합되는 대상 간의 일치 정도&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;EQUI JOIN: 동일한 컬럼을 사용하여 두 Relations을 결합&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;non-EQUI JOIN: 정확하게 일치하지 않는 컬럼들을 사용하여 두 Relations을 결합&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;ex) A.key &amp;lt;, &amp;gt;, &amp;lt;=, &amp;gt;= B.key
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CROSS JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Key 없이 JOIN하면 두 테이블에 대해 Cartesian Product 발생&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;5개의 행 * 3개의 행 = 15개의 행으로 조회
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SELF JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;한 테이블 내에서 연관관계를 가진 두 컬럼 간의 JOIN&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;테이블명 및 컬럼명이 모두 일치하기 때문에 ALIAS 사용 필수&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;Optimizer Join&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JOIN을 수행하는 과정에서 성능 최적화를 위한 방식 선택, Hint로 기입&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;계층형 조회&lt;/h3&gt;
&lt;p&gt;트리 형태의 데이터에 대해 조회를 수행하는 것&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;계층 구조의 시작점은 START WITH로 설정(ROOT NODE)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;자식 노드가 없는 노드 = LEAF NODE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;계층을 LEVEL로 표기&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;CONNECT BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;계층 구조가 연결된 방향성을 확인&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;자식 &amp;gt; 부모&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;부모 &amp;gt; 자식&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;CONNECT BY PRIOR a = b&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;a 컬럼과 b 컬럼이 동일한 레코드 간 계층화 발생&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;b -&amp;gt; a 순으로 재배치&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SIBLINGS BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;자매 노드들 간의 배치 순서를 결정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;WINDOW 함수&lt;/h3&gt;
&lt;p&gt;레코드 사이의 관계를 쉽게 정의하기 위한 함수&lt;/p&gt;
&lt;p&gt;&lt;code&gt;SELECT WINDOW_FUNCTION {arguments} OVER {partition by column} {order_style} FROM {table};&lt;/code&gt; 의 형태로 사용&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;WINDOW_FUNCTION&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;윈도우 함수&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;그룹 내 집계함수: COUNT, SUM, MIN, MAX, AVG 등&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;그룹 내 순위함수&lt;/p&gt;
&lt;p&gt;순위함수를 만들더라도 자동으로 sorting 하지 않기 때문에 ORDER BY 절을 활용해야 한다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;RANK&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;동일한 순위에 대해 동일한 순위 부여&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;동일한 순위를 하나의 건수로 계산하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;DENSE_RANK&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;동일한 순위에 대해 동일한 순위 부여&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;동일한 순위를 하나의 건수로 계산&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;ROW_NUMBER&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;동일한 순위에 대해 고유 순위 부여&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;그룹 내 비율 관련 함수&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;PERCENT_RANK&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;값이 아닌, &amp;quot;순서&amp;quot;를 대상으로, 파티션 내에서의 순서별 백분율을 조회함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;NTILE(n)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;파티션 별로 전체 건수를 n등분한 값을 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;CUME_DIST&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;파티션 내 전체에서 현재 행의 값 이하인 레코드 건수에 대한 누적 백분율을 조회&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;누적 분포 상에서 0 ~ 1 값을 가짐&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;그룹 내 행 순서 함수&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;FIRST_VALUE&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;파티션 내에서 가장 처음 나오는 값 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;LAST_VALUE&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;파티션 내에서 가장 마지막에 나오는 값 반환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;LAG(column_name, record_difference)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;이전 행을 가져온다&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;LEAD(column_name, record_difference, value_if_null)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;다음 행을 가져온다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DEFAULT = 1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ARGUMENTS&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;인수(컬럼명 등 함수의 작업이 이뤄지는 대상)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;PARTITIAN BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;테이블의 레코드를 쪼개는 기준&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;ORDER BY&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;쪼개진 레코드들 내에서 혹은 전체 테이블에서 레코드들을 어떤 기준으로 정렬할지 지정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;WINDOWING&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;함수의 연산 대상이 되는 레코드의 범위를 정함&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;RANGE&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;범위 지정 시 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;BETWEEN a AND b&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;a부터 b까지 적용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;UNBOUNDED PRECEDING&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;시작 위치 = 첫 번째 행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;UNBOUNDED FOLLOWING&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;시작 위치 = 마지막 행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;CURRENT ROW&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;시작 위치 = 현재 행&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;테이블 파티션&lt;/h3&gt;
&lt;p&gt;대용량의 테이블을 여러 개의 데이터 파일에 분리하여 저장하는 것&lt;/p&gt;
&lt;p&gt;물리적으로 분리된 데이터 파일에 저장 =&amp;gt; 성능 향상 및 독립적 관리 가능&lt;/p&gt;
&lt;p&gt;조회의 범위를 줄이는 효과 =&amp;gt; 성능 향상&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;RANGE PARTITION&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;값의 범위를 기준으로 파티션을 나눠 저장하는 방법&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;LIST PARTITION&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;특정 값을 기준으로 분할&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;HASH PARTITION&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;데이터베이스 관리 시스템이 자체적으로 해시함수를 사용해 분할하고 관리하는 방식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Optimizer&lt;/h2&gt;
&lt;p&gt;같은 SQL문이더라도 어떻게 실행하느냐에 따라서 성능이 달라짐 (성능의 지표: 소요시간, 자원사용량 등)&lt;/p&gt;
&lt;p&gt;따라서, SQL문을 분석하여 일정 기준에 따라서 실행 계획을 세울 필요가 있으며 이 때 옵티마이저를 사용한다.&lt;/p&gt;
&lt;p&gt;옵티마이저는 실행 성능에 영향을 줄 수 있지만 결과값은 달라지지 않는다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-test&quot;&gt;SQL문 작성 =&amp;gt; 파싱 (문법 검사, 구문 분석) =&amp;gt; 옵티마이저 (비용 기반 / 규칙 기반) =&amp;gt; 실행 계획 (PLAN_TABLE 저장) =&amp;gt; SQL 실행
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;비용 기반&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;최신 Oracle 기준 비용 기반 Optimizer를 기본값으로 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;시스템 통계와 오브젝트 통계를 통해 해당 SQL문 실행에 대한 총 비용을 계산 후 최소 비용 실행 계획을 수립&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;규칙 기반&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;15가지 우선순위를 기준으로 실행 계획을 수립&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;일반적으로 ROWID를 기반으로 스캔하는 것이 가장 우선순위가 높음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;INDEX&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;인덱스 키를 기준으로 정렬 =&amp;gt; 탐색이 빨라짐&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PK는 자동적으로 INDEX가 됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;하나의 테이블에 여러 개의 인덱스를 생성할 수 있으며, 하나의 인덱스가 여러 컬럼으로 구성될 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;내림차순으로 생성 및 정렬됨&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;자주 변화하는 속성을 인덱스로 설정하는 것은 좋지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;보조 인덱스에는 UNIQUE 속성의 인덱스가 아니라면 중복 데이터의 입력이 가능하다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인덱스 스캔보다 전체 스캔이 더 효율적이고 비용 기반으로 유리할 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;파티션 테이블은 파티션에 대해 파티션 키 인덱스를 생성 가능, Global 인덱스라고 부름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인덱스가 늘어나면 당연히 데이터의 증가이므로 입력, 삭제, 수정 속도의 하락을 불러올 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모든 데이터 타입으로 인덱스 형성이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;인덱스의 종류로 순차 인덱스, 비트맵, 결합 인덱스, 클러스터, 해시 인덱스가 존재한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;SCAN 방식&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;Index Unique SCAN&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;인덱스 키 값이 중복되지 않을 때 해당 키를 통해 탐색&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;Index Unique SCAN&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;특정 범위를 조회하는 WHERE 문을 사용하여 해당 영역을 스캔&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;범위에 따라서 단수 혹은 0개의 결과 출력도 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h5&gt;Index Full SCAN&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;인덱스의 처음부터 끝까지 모두 스캔&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h3&gt;Optimizer Join의 종류&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;Nested Loop JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;외부(선행, Driving) 테이블을 먼저 조회하여 연결 대상 데이터를 찾고, 내부(후행) 테이블을 연결&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;선행 테이블의 처리 범위에 따라 처리량이 결정, 따라서 선행 테이블의 크기가 작은 것을 찾을 필요 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Row 간 처리, Table 간 처리 모두 순차적으로 발생&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;최적의 순서를 찾아주는 것이 중요&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Random Access가 발생하기 때문에 (선행 테이블에서 두 번째 테이블을 참조할 때 발생) 성능 지연을 감소시키기 위해 Random Access 발생이 적도록 해야 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;선행 테이블 처리 범위가 넓거나, Random Access 범위가 넓은 경우 SORT MERGE JOIN보다 불리해지는 케이스 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;quot;INDEX 필수&amp;quot;, Unique INDEX 시 유리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;OnLine Transaction Processing(OLTP)에 유용함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;중첩된 반복문과 동일한 형식, 선행 테이블의 조건을 만족하는 경우의 수만큼 반복적 수행&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;Sort Merge JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;두 테이블을 각각 정렬하고, 완료되면 병합&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;정렬이 발생하기 때문에 데이터 양이 많을 경우 느려진다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;정렬 대상 데이터 양이 많을 경우 임시 디스크를 사용하기 때문에 성능 저하가 발생한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;EQIU JOIN, non-EQIU JOIN 모두 가능&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;br /&gt;
&lt;h4&gt;HASH JOIN&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;두 테이블 중 작은 테이블을 HASH 메모리에 로딩, 두 테이블의 JOIN 키를 사용하여 해시 테이블 생성&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;두 테이블을 동시에 스캔&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;선행 테이블에는 &amp;quot;작은 데이터&amp;quot;가 먼저 와야 함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;시스템 자원을 최대한 활용 가능, 자원을 너무 많이 사용할 수 있으며 부하 등의 우려 존재&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;대용량 처리에 빠른 처리 속도를 보임&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;EQUI JOIN에서만 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;INDEX를 사용하지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;JOIN 방식&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;먼저 선행 테이블을 결정, 선행 테이블에서 주어진 조건에 해당하는 레코드를 선택
해당 행이 선택되면 JOIN Key를 기준으로 해시 함수를 사용
해시 테이블을 메인 메모리에 생성, 후행 테이블에서 주어진 조건을 만족하는 행을 찾음
후행 테이블의 JOIN Key를 사용해서 해시함수를 적용, 해당 버킷을 검색
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;PL/SQL&lt;/h2&gt;
&lt;p&gt;SQL을 확장시켜 다양한 절차적 프로그래밍을 가능하게 한 언어&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Block 구조로 되어있어서 기능별로 모듈화가 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Declare 문으로 시작하며, 변수 및 상수를 선언하여 사용 가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DECLARE, BEGIN ~ END는 필수, EXCEPTION은 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DML, IF, LOOP 등 다양한 절차적 언어를 사용&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Oracle에 내장되어 있으며 동일한 언어를 사용하는 프로그램과 호환이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;응용 프로그램의 성능을 향상시킴&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Procedure, User Defined Function, Trigger 객체를 작성할 수 있다.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Procedure 내부에 작성된 절차적 코드는 PL/SQL 엔진이 처리하고 일반적인 SQL 문장은 SQL 실행기가 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;분산 데이터베이스&lt;/h2&gt;
&lt;p&gt;하나의 데이터베이스 시스템(DBMS)이 네트워크를 통해 물리적으로 분리된 데이터베이스들을 제어하는 형태의 DB&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;성능 향상: 분산 데이터베이스가 병렬 작업을 하기 때문에 속도가 빠름&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;모듈화가 되어 있어 다른 모듈에 영향을 주지 않고 시스템의 갱신이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;분산 데이터베이스 추가를 통한 용량의 확장이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;중요 데이터를 보호하기 용이&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;신뢰성이 높음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;관리 및 통제의 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;보안관리, 무결성 통제의 어려움&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;복잡한 구조&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-text&quot;&gt;메모

count(*): 전체 행의 수를 카운팅, null 포함
count({column_name}) null 을 제외한 행의 수를 카운팅
null: 모르는 값을 상징, 값의 부재를 말함
(null is null) = TRUE
null과의 모든 비교는 null 반환
0 혹은 &amp;#x27; &amp;#x27;과 동일한 값이 아님 

서브쿼리: SELECT문 내의 SELECT문이 반복 사용된 쿼리, 단일행 및 다중행으로 구분
- 정렬을 수행하는 ORDER BY를 사용할 수 없다.
- 여러 행을 반환하는 서브 쿼리는 다중 행 연산자를, 단일 행을 반환하는 서브쿼리는 단일 행 연산자를 사용
- 메인 쿼리에서 서브 쿼리의 컬럼을 자유롭게 사용할 수 없음
- EXIST는 True 혹은 False를 반환한다

스칼라 서브쿼리: 한 행과 한 컬럼만 반환하는 서브쿼리
인라인뷰: 서브쿼리가 FROM 절 내에 쓰여진 것

view 테이블
- 사용상의 편의를 위해 사용
- 수행속도의 향상을 위해 사용
- SQL의 성능을 향상시키기 위해 사용
- 임시적인 작업을 위해 사용
- 보안관리를 위해 사용

실행 순서
SELECT ALIAS =&amp;gt; FROM =&amp;gt; WHERE =&amp;gt; GROUP BY =&amp;gt; HAVING =&amp;gt; SELECT =&amp;gt; ORDER BY

조회 행수 제한
몇 번째 행을 조회하는지 부여하는 조건문
ROWNUM {row_number}: Oracle
TOP {row_number}: SQL Server
LIMIT {row_number}: MySQL

ROWID
해당 데이터가 어떤 데이터 파일 상에서 어느 블록에 저장되었는지 알려준다.
데이터베이스에 저장되어 있는 데이터를 구분할 수 있는 유일한 값이다.
ROWID의 번호는 데이터 블록에 데이터가 저장된 순서이다.
테이블에 데이터를 입력하면 자동으로 생성된다.
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 17471, Python] 게리맨더링</title><link>https://www.traceoflight.dev/ko/blog/boj17471/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj17471/</guid><description>BOJ 17471, &quot;게리맨더링&quot; 문제의 Python 풀이</description><pubDate>Mon, 07 Nov 2022 11:14:53 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/17471&quot;&gt;BOJ 17471&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;너비 우선 탐색(bfs), 브루트포스 알고리즘(bruteforcing), 조합론(combinatorics), 깊이 우선 탐색(dfs), 그래프 이론(graphs), 그래프 탐색(graph_traversal), 수학(math)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;처음에는 해당 문제를 유니온 파인드 문제라고 생각하고 접근해서 간선을 지워보기도 하고, 다른 제약 조건을 설정해보기도 했는데 오히려 정직하게 접근해서 풀어야 하는 문제였다..&lt;/p&gt;
&lt;p&gt;0.5초라는 제약 조건을 걷어내고 보면 모든 조합에 대해서 깊이 탐색을 통해 체크하겠다는 생각을 해볼 수 있는데 파이썬을 사용하다보니 시간을 짧게 제공하면 정직한 풀이를 배제하게 되는 것이 패착 요인이었다.&lt;/p&gt;
&lt;p&gt;구역의 갯수가 최대 10개로 한정적이라는 것을 고려한다면 충분히 브루트포스를 통해 해결할 수 있으며 오히려 다른 방향으로 힘을 쏟게 된다면 피를 볼 수 있는 문제다.&lt;/p&gt;
&lt;p&gt;따라서 이 문제는 모든 구역을 두 개로 분할하여 선거구가 성립하는지를 확인하고, 선거구가 성립한다면 두 선거구의 인구 차이를 확인하여 기존 인구 차이값보다 작은 값이 나오면 갱신하는 방향으로 해결할 수 있다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 게리맨더링&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; itertools &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; combinations

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-comment&quot;&gt;# 상한값 선언&lt;/span&gt;
INF = &lt;span class=&quot;hljs-number&quot;&gt;2000000000&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 구역 갯수 입력&lt;/span&gt;
area_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())

&lt;span class=&quot;hljs-comment&quot;&gt;# 구역별 인구 정보 입력&lt;/span&gt;
people_number = [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

&lt;span class=&quot;hljs-comment&quot;&gt;# 인접 구역 관계 그래프 입력&lt;/span&gt;
graph = [[] &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; area_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):
    near_area, *graph[area_idx] = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# 총 인구수 확인&lt;/span&gt;
max_people = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;(people_number)

&lt;span class=&quot;hljs-comment&quot;&gt;# 최소 차이값 변수 선언&lt;/span&gt;
min_difference = INF

&lt;span class=&quot;hljs-comment&quot;&gt;# 한 선거구의 포함될 모든 구역 수에 대해 체크 &lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; areas &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):

    &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 구역 중에서 한 선거구에 포함될 구역 확정&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; target_areas &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; combinations(&lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), areas):

        &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 선거구에 포함되는 구역 집합 선언 및 해당 선거구 인원수 변수 선언&lt;/span&gt;
        target_set = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(target_areas)
        sum_areas = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# Depth First Search&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 집합에 포함된 한 구역에서 시작하는 깊이 탐색&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; first_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; target_set:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 선거구 내 구역 수 체크 카운터 선언&lt;/span&gt;
            counter = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 방문 리스트 선언&lt;/span&gt;
            is_visited = [&lt;span class=&quot;hljs-literal&quot;&gt;False&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]

            &lt;span class=&quot;hljs-comment&quot;&gt;# 깊이 탐색을 진행할 스택 선언 및 초기 조건 입력&lt;/span&gt;
            progress_stack = [first_area]
            sum_areas += people_number[first_area]
            is_visited[first_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 탐색 진행&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; progress_stack:

                &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 구역 확인&lt;/span&gt;
                now_area = progress_stack.pop()

                &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 인접 구역에 대해 확인&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; graph[now_area]:

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 같은 선거구에 속해있고 방문하지 않았을 경우만 조사&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; target_set:
                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_visited[next_area]:

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 방문 처리, 인구수 합산, 선거구 카운팅&lt;/span&gt;
                            is_visited[next_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
                            sum_areas += people_number[next_area]
                            counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 다음 구역 스택에 추가&lt;/span&gt;
                            progress_stack.append(next_area)

            &lt;span class=&quot;hljs-comment&quot;&gt;# 1회의 조사로 선거구의 모든 정보를 획득하므로 반복하지 않음&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 남은 구역들에 대해서 다른 하나의 선거구라 가정하고 깊이 탐색 진행&lt;/span&gt;

        other_set = &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, area_number + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)) - &lt;span class=&quot;hljs-built_in&quot;&gt;set&lt;/span&gt;(target_set)
        sum_other_areas = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; first_other_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; other_set:

            other_counter = &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;
            sum_other_areas += people_number[first_other_area]

            progress_stack = [first_other_area]
            is_visited[first_other_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; progress_stack:
                
                now_area = progress_stack.pop()

                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; graph[now_area]:
                    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; next_area &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; other_set:
                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; is_visited[next_area]:
                            is_visited[next_area] = &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;
                            sum_other_areas += people_number[next_area]
                            progress_stack.append(next_area)
                            other_counter += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 양쪽 선거구를 조사했을 때 남는 구역이 없을 경우만 성립&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; counter + other_counter == area_number:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 두 선거구의 인구 차이를 확인하여 기존값보다 작다면 갱신&lt;/span&gt;
            now_min = &lt;span class=&quot;hljs-built_in&quot;&gt;abs&lt;/span&gt;(sum_areas - sum_other_areas)
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; min_difference &amp;gt; now_min:
                min_difference = now_min

&lt;span class=&quot;hljs-comment&quot;&gt;# 한 번도 갱신하지 못했다면 선거구 분할 실패이므로 -1 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; min_difference == INF:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hljs-comment&quot;&gt;# 갱신한 경우 결과를 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(min_difference)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 14438, Python] 수열과 쿼리 17</title><link>https://www.traceoflight.dev/ko/blog/boj14438/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj14438/</guid><description>BOJ 14438, &quot;수열과 쿼리 17&quot; 문제의 Python 풀이</description><pubDate>Tue, 01 Nov 2022 13:52:01 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/14438&quot;&gt;BOJ 14438&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;세그먼트 트리(segtree), 자료 구조(data_structures)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;세그먼트 트리에 처음 입문하는 사람들이 가장 많이 접하는 세그먼트 트리 유형의 문제라고 생각한다.&lt;/p&gt;
&lt;p&gt;구간합, 구간곱, 구간 내 최대값 등 다양한 값들에 대해 선형 리스트를 기준으로 O(NlogN)이라는 시간에 구축하여 각 구간에 대한 정보를 O(logN)이라는 빠른 속도로 접근할 수 있다는 장점이 존재한다.&lt;/p&gt;
&lt;p&gt;이 문제는 크게 세그먼트 트리를 구축하는 함수, 구간 정보를 찾는 함수, 변경된 값을 반영하는 함수로 나눌 수 있다.&lt;/p&gt;
&lt;h4&gt;생성 함수&lt;/h4&gt;
&lt;p&gt;세그먼트 트리를 생성하는 함수를 먼저 보면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, result_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end:&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    최소 숫자 정보를 담는 세그먼트 트리를 생성하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 노드는 포인터가 가리키는 인덱스의 값과 동일&lt;/span&gt;
        result_list[now_node] = target_list[start]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위를 나타내는 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 최소값으로 갱신&lt;/span&gt;
        val_1 = make_segtree(target_list, result_list, start, mid, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = make_segtree(target_list, result_list, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값을 비교하여 둘 중 최소값을 현재 노드에 기록&lt;/span&gt;
        result_list[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드의 값을 반환&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result_list[now_node]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기본적으로 전체 리스트를 구간별로 쪼개면서 각 구간에 대한 정보를 세그먼트 트리의 각 노드에 담는 과정을 보여주고 있다.&lt;/p&gt;
&lt;p&gt;재귀 방식을 사용했기 때문에 구간 길이가 1이 될 때까지 재귀가 진행될 때까지 재귀 스택을 쌓게 되며, 도달한다면 해당 주소에 리스트 1개 값에 대한 정보를 입력한다.&lt;/p&gt;
&lt;p&gt;이후 반환된 값들을 통해 리프 노드가 아닌 노드들은 조건에 맞는 값을 취사선택하면서 루트에 마지막으로 도달하게 된다.&lt;/p&gt;
&lt;p&gt;따라서 루트 노드에 들어 있는 값은 전 구간에서 문제에서 요구한 조건에 가장 걸맞는 값이 되는 것이다.&lt;/p&gt;
&lt;h4&gt;탐색 함수&lt;/h4&gt;
&lt;p&gt;다음으로 구간 내 최소값을 찾는 함수에 대해 확인하면&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;find_min_number&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, left: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, right: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    해당 구간의 최소값을 찾는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위 내로 포인터가 좁혀진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; left &amp;lt;= start &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; right &amp;gt;= end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target_tree[now_node]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위를 아예 벗어난 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; left &amp;gt; end &lt;span class=&quot;hljs-keyword&quot;&gt;or&lt;/span&gt; right &amp;lt; start:

        &lt;span class=&quot;hljs-comment&quot;&gt;# None 값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위가 걸친 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 값을 확인&lt;/span&gt;
        val_1 = find_min_number(target_tree, start, mid, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = find_min_number(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 반환된 값들 중 None이 존재하는 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_2

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_1

        &lt;span class=&quot;hljs-comment&quot;&gt;# None이 없다면&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값 중에서 더 작은 값을 반환&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기본적으로 내가 찾는 구간이 포함된 곳이라면 세부적으로 진행해서 완벽하게 내가 찾는 구간만 포함할 때까지 진행하고 해당 값을 반환하여 상위 함수에서 확인할 수 있도록 코드를 구성했다.&lt;/p&gt;
&lt;p&gt;만약 범위를 벗어난 경우는 None을 반환하도록 하여 조건을 통해 Pruning만 해주면 완벽하게 범위에 있는 구간만 선택하여 비교할 수 있다.&lt;/p&gt;
&lt;h4&gt;수정 함수&lt;/h4&gt;
&lt;p&gt;마지막으로 값의 수정이 이루어진 경우 반영하는 함수를 보자&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;change_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_idx: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_val: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    리스트에 생긴 변경점을 트리에 반영하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;
    
    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표로 하는 인덱스랑 동일하다면 변경값을 반영&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == target_idx:
            target_tree[now_node] = target_val

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위로 주어진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표 인덱스가 범위 내에 존재할 경우에만 갱신 가능성 존재&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start &amp;lt;= target_idx &amp;lt;= end:

            &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
            mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 변경될 수 있는 인덱스를 재조사&lt;/span&gt;
            change_segtree(target_tree, start, mid, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
            change_segtree(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 하위 노드들의 갱신이 진행된 이후 현재 노드의 갱신 진행&lt;/span&gt;
        target_tree[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node], target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;현재 변경된 값의 인덱스가 포함된 구간이라면 전부 바꿔줘야 하기 때문에 해당 인덱스를 포함한 구간이냐 아니냐를 기준으로 변별을 진행한다.&lt;/p&gt;
&lt;p&gt;생성 함수와 마찬가지로 한 개의 인덱스로 조여질 때까지 재귀 스택을 쌓게 되며 해당 인덱스 1개만을 포함하는 노드값의 변경을 시작으로 반환을 진행하면서 수정된 값을 반영하고 최종적으로 루트 노드까지 체크하여 마무리하게 될 것이다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;p&gt;위 과정을 통해 문제에서 요구한 동작을 전부 모듈화 할 수 있으며 이하 전체 코드를 확인할 수 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 수열과 쿼리 17&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys
&lt;span class=&quot;hljs-keyword&quot;&gt;from&lt;/span&gt; math &lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; ceil, log2

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;make_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, result_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end:&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    최소 숫자 정보를 담는 세그먼트 트리를 생성하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 노드는 포인터가 가리키는 인덱스의 값과 동일&lt;/span&gt;
        result_list[now_node] = target_list[start]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위를 나타내는 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 최소값으로 갱신&lt;/span&gt;
        val_1 = make_segtree(target_list, result_list, start, mid, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = make_segtree(target_list, result_list, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값을 비교하여 둘 중 최소값을 현재 노드에 기록&lt;/span&gt;
        result_list[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드의 값을 반환&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; result_list[now_node]

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;find_min_number&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, left: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, right: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    해당 구간의 최소값을 찾는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위 내로 포인터가 좁혀진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; left &amp;lt;= start &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; right &amp;gt;= end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 노드값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; target_tree[now_node]

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위를 아예 벗어난 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; left &amp;gt; end &lt;span class=&quot;hljs-keyword&quot;&gt;or&lt;/span&gt; right &amp;lt; start:

        &lt;span class=&quot;hljs-comment&quot;&gt;# None 값을 반환&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 범위가 걸친 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
        mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 구간을 분할하여 값을 확인&lt;/span&gt;
        val_1 = find_min_number(target_tree, start, mid, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
        val_2 = find_min_number(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, left, right, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 반환된 값들 중 None이 존재하는 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_1 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_2

        &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; val_2 &lt;span class=&quot;hljs-keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; val_1

        &lt;span class=&quot;hljs-comment&quot;&gt;# None이 없다면&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 두 구간의 최소값 중에서 더 작은 값을 반환&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(val_1, val_2)

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;change_segtree&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;target_tree: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, start: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, end: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_idx: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, target_val: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, now_node: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    리스트에 생긴 변경점을 트리에 반영하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;
    
    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 한 곳으로 모인 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == end:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표로 하는 인덱스랑 동일하다면 변경값을 반영&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start == target_idx:
            target_tree[now_node] = target_val

    &lt;span class=&quot;hljs-comment&quot;&gt;# 포인터가 범위로 주어진 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 목표 인덱스가 범위 내에 존재할 경우에만 갱신 가능성 존재&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; start &amp;lt;= target_idx &amp;lt;= end:

            &lt;span class=&quot;hljs-comment&quot;&gt;# Devide and Conquer Algorithm&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점 선언&lt;/span&gt;
            mid = (start + end) // &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;

            &lt;span class=&quot;hljs-comment&quot;&gt;# 중간 지점을 기준으로 변경될 수 있는 인덱스를 재조사&lt;/span&gt;
            change_segtree(target_tree, start, mid, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node)
            change_segtree(target_tree, mid + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, end, target_idx, target_val, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

        &lt;span class=&quot;hljs-comment&quot;&gt;# 하위 노드들의 갱신이 진행된 이후 현재 노드의 갱신 진행&lt;/span&gt;
        target_tree[now_node] = &lt;span class=&quot;hljs-built_in&quot;&gt;min&lt;/span&gt;(target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node], target_tree[&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * now_node + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;])

&lt;span class=&quot;hljs-comment&quot;&gt;# 수열의 크기 및 수열 정보 입력&lt;/span&gt;
target_length = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
target_arr = [&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;*&amp;#x27;&lt;/span&gt;] + &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

&lt;span class=&quot;hljs-comment&quot;&gt;# 수열의 구간 최소 숫자를 담을 세그먼트 트리 리스트 선언&lt;/span&gt;
segtree_arr = [&lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;pow&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, ceil(log2(target_length) + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)))]

&lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 호출하여 트리 생성&lt;/span&gt;
make_segtree(target_arr, segtree_arr, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, target_length, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

&lt;span class=&quot;hljs-comment&quot;&gt;# 퀴리 갯수 입력 및 출력 리스트 선언&lt;/span&gt;
query_number = &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;())
output = []

&lt;span class=&quot;hljs-comment&quot;&gt;# 쿼리 실행&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(query_number):

    &lt;span class=&quot;hljs-comment&quot;&gt;# 각 쿼리의 정보&lt;/span&gt;
    order_type, num_1, num_2 = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

    &lt;span class=&quot;hljs-comment&quot;&gt;# 타입 1의 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; order_type == &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 리스트 값을 변경 및 함수를 호출하여 트리에 반영&lt;/span&gt;
        target_arr[num_1] = num_2
        change_segtree(segtree_arr, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, target_length, num_1, num_2, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 타입 2의 경우&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;elif&lt;/span&gt; order_type == &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;:

        &lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 호출하여 해당 구간의 최소 숫자를 출력 리스트에 추가&lt;/span&gt;
        output.append(find_min_number(segtree_arr, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, target_length, num_1, num_2, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;))

&lt;span class=&quot;hljs-comment&quot;&gt;# 결과 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; result &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; output:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Git Intro</title><link>https://www.traceoflight.dev/ko/blog/git-intro/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/git-intro/</guid><description>git 이전의 저장 시스템과 git의 작동 및 명령어에 대한 정리글</description><pubDate>Fri, 28 Oct 2022 13:19:01 GMT</pubDate><content:encoded>&lt;h1&gt;Intro&lt;/h1&gt;
&lt;p&gt;git에 대해서 공부하면서 필요한 내용에 대해 정리해 둔 포스트이며 아마 큰 변화가 없다면 혹은 추가적인 공부가 필요하지 않다면 인트로이자 마지막 글이 될 것으로 생각한다.&lt;/p&gt;
&lt;h2&gt;Git이란?&lt;/h2&gt;
&lt;p&gt;버전 관리 도구의 일종으로 버전 관리를 통해 파일의 변화를 기록했다가 특정 시점의 기록을 다시 사용할 수 있도록 하는 시스템&lt;/p&gt;
&lt;h3&gt;로컬 버전 관리&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;디렉토리의 복사&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;가장 Naive 한 방법&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;실수로 파일을 잘못 고칠 수도 있고, 잘못 복사할 수도 있다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;VCS (Version Control System)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;DB를 활용하여 파일의 변경 정보를 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Revision Control System이 대표적&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Patch Set(파일에서 변경되는 부분)을 관리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;일련의 Patch Set을 활용하여 모든 파일을 특정 시점으로 되돌릴 수 있음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;중앙집중식 버전 관리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;프로젝트를 진행할 경우 다른 개발자와의 협업이 잦음&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;이럴 경우 파일을 관리하는 서버가 별도로 존재하고 클라이언트가 중앙 서버에서 파일을 받아서 사용하는 방식이 유리&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;중앙 서버에 문제가 발생할 경우 시스템의 백업이 존재하지 않는다면 모든 히스토리를 잃을 수 있고 이는 로컬에서도 존재하고 있었던 문제&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;분산 버전 관리 시스템&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;단순하게 스냅샷만 보관하는 것이 아닌 저장소와 히스토리를 동시에 복제한다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;서버에 문제가 발생했을 경우, 해당 복제물을 통해 작업의 재개가 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;클라이언트 중에서 아무거나 골라 서버를 복원하는 것도 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;리모트 저장소의 존재로 다양한 방식의 협업이 가능&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GitHub도 이 원격 저장소의 일종&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;General Usage&lt;/h2&gt;
&lt;h3&gt;설정 및 파일 접근 명령어&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 전역 사용자 설정&lt;/span&gt;
git config --global user.name {name} &lt;span class=&quot;hljs-comment&quot;&gt;# 이름&lt;/span&gt;
git config --global user.email {email_address} &lt;span class=&quot;hljs-comment&quot;&gt;# 이메일&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 로컬 사용자 설정 (해당 디렉토리에서 실행)&lt;/span&gt;
git config user.name {name} &lt;span class=&quot;hljs-comment&quot;&gt;# 이름&lt;/span&gt;
git config user.email {email_address} &lt;span class=&quot;hljs-comment&quot;&gt;# 이메일&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 설정 조회&lt;/span&gt;
git config --list

&lt;span class=&quot;hljs-comment&quot;&gt;# 생성&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;mkdir&lt;/span&gt; {path}/{folder_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 폴더&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;touch&lt;/span&gt; {file_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 파일&lt;/span&gt;
git init &lt;span class=&quot;hljs-comment&quot;&gt;# 파일 관리 시스템&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 저장소 및 히스토리 복제&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;clone&lt;/span&gt; {repository_url}

&lt;span class=&quot;hljs-comment&quot;&gt;# 원격 저장소&lt;/span&gt;
git remote add {remote_repo_name} {remote_repo_url} &lt;span class=&quot;hljs-comment&quot;&gt;# 추가&lt;/span&gt;
git remote -v &lt;span class=&quot;hljs-comment&quot;&gt;# 정보 확인&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# commit history&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt; --oneline &lt;span class=&quot;hljs-comment&quot;&gt;# 정보 표시 간략화&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt; --all &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 head 이후의 최신 기록들을 포함한 전체 정보를 표시&lt;/span&gt;
git &lt;span class=&quot;hljs-built_in&quot;&gt;log&lt;/span&gt; --graph &lt;span class=&quot;hljs-comment&quot;&gt;# 브랜치를 시각화하여 분기를 표현한 그래프 형태로 정보를 표시&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;저장소 관리에 사용하는 명령어&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git status &lt;span class=&quot;hljs-comment&quot;&gt;# 변경사항을 확인하는 명령어&lt;/span&gt;
git commit -m {message} &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 스테이지에 존재하는 변경 사항을 커밋&lt;/span&gt;

git add {file_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 특정한 파일을 스테이지에 추가하는 경우&lt;/span&gt;
git add . &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 레포지토리의 변경사항을 전부 스테이지에 추가하는 경우&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Undoing&lt;/h2&gt;
&lt;h3&gt;스테이지 비우기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git &lt;span class=&quot;hljs-built_in&quot;&gt;rm&lt;/span&gt; --cached &lt;span class=&quot;hljs-comment&quot;&gt;# root commit이 존재하지 않을 때&lt;/span&gt;
git restore --staged &lt;span class=&quot;hljs-comment&quot;&gt;# root commit이 존재할 때&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;commit의 수정&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git commit --amend 
&lt;span class=&quot;hljs-comment&quot;&gt;# 스테이지에 파일이 없는 경우: 직전 커밋의 메시지를 수정&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# 스테이지에 파일이 있는 경우: 기존 커밋에 현재 스테이지를 더하여 덮어쓰기 진행&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;commit 특정 시점까지 전부 되돌리기&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git reset --soft {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 미래 파일들 전부 stage에 돌려놓음&lt;/span&gt;
git reset --mixed {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# default, 미래 파일들을 전부 working directory에 유지 (add 필요)&lt;/span&gt;
git reset --hard {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 미래 파일 전부 제거&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;과거 commit을 제거&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;git revert {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 과거 commit을 제거 후, 제거했음을 commit으로 추가&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;reset은 commit 갯수가 줄어들기 때문에 협업에 부적합, 따라서 협업 시 reset 대신 revert 사용을 권장&lt;/p&gt;
&lt;h2&gt;Git Branch&lt;/h2&gt;
&lt;p&gt;Branch: 작업 공간을 분할, 독립적으로 작업할 수 있도록 돕는 장치&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;원본 상태를 계속 유지할 수 있어 안전함&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;하나의 브랜치에서 하나의 작업을 진행하여 협업의 효율이 증가&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Git의 경우 Branch의 생성 속도도 빠르고 파일 용량도 크지 않음&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;관련 명령어&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 조회&lt;/span&gt;
git branch &lt;span class=&quot;hljs-comment&quot;&gt;# 로컬 저장소의 브랜치 대상&lt;/span&gt;
git branch -r &lt;span class=&quot;hljs-comment&quot;&gt;# 원격 저장소의 브랜치 대상&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 생성&lt;/span&gt;
git branch {branch_name}
git branch {branch_name} {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 특정 커밋 지점을 기준점으로 생성&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 제거&lt;/span&gt;
git branch -d {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 병합 완료된 경우&lt;/span&gt;
git branch -D {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 병합하지 못한 브랜치 강제 삭제&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 브랜치 이동&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;# 이동 전 반드시 현재 브랜치의 변경사항을 기록할 것&lt;/span&gt;
git switch {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 이미 있는 브랜치로 이동&lt;/span&gt;
git switch -c {branch_name} &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 이름의 브랜치를 생성 후 이동&lt;/span&gt;
git switch -c {branch_name} {commit_id} &lt;span class=&quot;hljs-comment&quot;&gt;# 특정 커밋 지점을 기준점으로 하는 해당 이름의 브랜치를 생성 후 이동&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Merge&lt;/h2&gt;
&lt;p&gt;분기된 브랜치를 병합하는 과정&lt;/p&gt;
&lt;h3&gt;병합의 종류&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Fast - Forward: 브랜치가 가리키는 커밋을 맨 앞으로 이동&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;3 - Way Merge: 각 브랜치의 제일 최신 커밋 2개 + 두 브랜치의 공통 조상을 사용한 병합&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Merge Confilict: 같은 파일을 수정했을 경우 충돌 발생 =&amp;gt; 충돌을 해결한 뒤 3 - Way Merge를 진행&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 해당 브랜치를 현재 위치한 브랜치에 병합&lt;/span&gt;
git merge {merged_branch}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Git Fork&lt;/h2&gt;
&lt;p&gt;소유권이 없는 원격 저장소를 복제하는 것, 주로 오픈 소스와 같은 협업 대상이 다수일 때 사용&lt;/p&gt;
&lt;h3&gt;Fork 된 소스에 내 커밋이 반영되는 과정&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#    원본 원격 저장소 (upstream) &amp;lt;----------- 복제본 원격 저장소 (origin)&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                \           merge request      /|&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                 \                              |&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                  \                 push branch | pull master&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                   \                            |&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                    \     ( pull upstream )     |/&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#                     ------------------&amp;gt; 로컬 저장소 (user)&lt;/span&gt;
&lt;span class=&quot;hljs-comment&quot;&gt;#&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;원본 저장소를 내 원격 저장소에 복제&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;해당 원격 저장소에서 로컬로 저장&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;로컬에서 브랜치를 생성해서 작업 후 해당 작업들을 커밋&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;원본 원격 저장소에 변경 사항에 대한 merge 요청을 push&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;원본 원격 저장소에서 해당 변경 사항을 merge&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;해당 원본 저장소에서 변경된 내용을 pull&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;pull upstream&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;sync origin &amp;amp; pull origin&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;로컬에서 merge된 내 브랜치를 제거&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</content:encoded></item><item><title>[BOJ 7579, Python] 앱</title><link>https://www.traceoflight.dev/ko/blog/boj7579/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj7579/</guid><description>BOJ 7579, &quot;앱&quot; 문제의 Python 풀이</description><pubDate>Fri, 28 Oct 2022 10:13:23 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/7579&quot;&gt;BOJ 7579&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;다이나믹 프로그래밍(dp), 배낭 문제(knapsack)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;해당 문제를 풀이할 때 중요하게 봐야 했던 부분을 개인적으로 꼽자면 문제 조건이었다고 생각한다.&lt;/p&gt;
&lt;p&gt;사용 중인 메모리 바이트 조건은 10^7 이었고 활성화 어플의 수는 최대 100개, 비용의 경우도 100 이하의 조건을 만족해햐 했다.&lt;/p&gt;
&lt;p&gt;가짓수를 확인할 용도로 메모리 바이트 조건을 활용하기엔 범위가 매우 넓었고 그에 따라 적절한 변수로 비용을 설정, 모든 비용마다 주소를 할당하여 최대한 줄일 수 있는 메모리를 기록하는 방식을 사용하겠다는 생각을 하게 되었다.&lt;/p&gt;
&lt;p&gt;여기서 DP를 사용해야 한다는 것을 추측했고 더 나아가서 cost, value값이 각각 존재할 때 가치에 따라서 기존값을 갱신하는 방식을 사용했던 knapsack 알고리즘을 이용하여 해결하겠다는 설계를 해볼 수 있었다.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 앱&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-comment&quot;&gt;# 앱 갯수, 필요 메모리 입력&lt;/span&gt;
app_number, need_memory = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 앱의 메모리와 비활성화 시의 비용 입력&lt;/span&gt;
app_memories = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))
disable_costs = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split()))

&lt;span class=&quot;hljs-comment&quot;&gt;# 앱의 메모리와 비용 합쳐서 짝을 지어줌&lt;/span&gt;
memories_and_costs = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;zip&lt;/span&gt;(app_memories, disable_costs))

&lt;span class=&quot;hljs-comment&quot;&gt;# 최대 필요 비용 연산&lt;/span&gt;
sum_cost = &lt;span class=&quot;hljs-built_in&quot;&gt;sum&lt;/span&gt;(disable_costs)

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 비용별 최대 절약 가능한 메모리 리스트 선언&lt;/span&gt;
cost_list = [&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; _ &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(sum_cost + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]

&lt;span class=&quot;hljs-comment&quot;&gt;# Knapsack Algorithm&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 모든 앱에 대해 확인&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; now_memory, now_cost &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; memories_and_costs:

    &lt;span class=&quot;hljs-comment&quot;&gt;# 최대 필요 비용까지 조사&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; last_cost &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(sum_cost, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):

        &lt;span class=&quot;hljs-comment&quot;&gt;# 최대 비용을 넘지 않는 선에서 확인&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; last_cost + now_cost &amp;lt;= sum_cost:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 기존 최대값보다 컸다면 갱신&lt;/span&gt;
            cost_list[last_cost + now_cost] = &lt;span class=&quot;hljs-built_in&quot;&gt;max&lt;/span&gt;(
                cost_list[last_cost + now_cost], cost_list[last_cost] + now_memory
            )

&lt;span class=&quot;hljs-comment&quot;&gt;# 비용을 0에서부터 조사해서 기준 메모리 이상을 절약한 경우의 비용을 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(sum_cost + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;):
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; cost_list[idx] &amp;gt;= need_memory:
        &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(idx)
        &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>[BOJ 15683, Python] 감시</title><link>https://www.traceoflight.dev/ko/blog/boj15683/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/boj15683/</guid><description>BOJ 15683, &quot;감시&quot; 문제의 Python 풀이</description><pubDate>Sun, 23 Oct 2022 10:46:34 GMT</pubDate><content:encoded>&lt;h3&gt;문제 링크&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15683&quot;&gt;BOJ 15683&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;분류&lt;/h3&gt;
&lt;p&gt;브루트포스 알고리즘(bruteforcing), 구현(implementation), 시뮬레이션(simulation)&lt;/p&gt;
&lt;h3&gt;설명&lt;/h3&gt;
&lt;p&gt;분류가 브루트포스 알고리즘인 문제이지만 이 문제를 구현할 때 백트래킹 알고리즘을 사용했다.&lt;/p&gt;
&lt;p&gt;기본적으로 모든 감시 카메라가 볼 수 있는 방향에 대해 전부 조사를 진행하며 모든 감시 카메라가 방향 세팅이 완료된 경우 함수를 호출하여 감시 사각지대의 갯수를 확인하고 기존 최소값보다 작다면 해당 값을 갱신해주는 방법을 활용했다.&lt;/p&gt;
&lt;p&gt;풀이를 진행한 후 주석 처리를 바로 진행하는 편이라 앞으로의 포스팅에도 세부적인 풀이법은 코드 주석에 담겨 있을 예정.&lt;/p&gt;
&lt;h3&gt;풀이 코드&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;hljs-comment&quot;&gt;# 감시&lt;/span&gt;

&lt;span class=&quot;hljs-keyword&quot;&gt;import&lt;/span&gt; sys

&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt; = sys.stdin.readline

&lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;check_blind_spot&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;matrix: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, y_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, x_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;:
    &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
    현재 사무실 내 사각지대 갯수를 반환하는 함수
    &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 사각지대 변수 선언&lt;/span&gt;
    blind_here = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 좌표에 대해서 조사&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(y_range):
        &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(x_range):

            &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 좌표값이 0일 경우만 카운팅&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; matrix[y_idx][x_idx]:
                blind_here += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 결과 반환&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; blind_here

&lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 가로 및 세로 크기 입력&lt;/span&gt;
height, width = &lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV 정보 및 사무실 정보를 담을 리스트 선언&lt;/span&gt;
cctvs = []
work_space = []

&lt;span class=&quot;hljs-comment&quot;&gt;# 초기 사각지대 갯수 확인&lt;/span&gt;
blind_spot = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 정보 입력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(height):

    &lt;span class=&quot;hljs-comment&quot;&gt;# 행 정보 확인&lt;/span&gt;
    temp = &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;input&lt;/span&gt;().split())

    &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 요소들에 대해 조사&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; x_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(width):

        &lt;span class=&quot;hljs-comment&quot;&gt;# 만약 CCTV가 있다면 리스트에 추가&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; temp[x_idx] &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;12345&amp;#x27;&lt;/span&gt;:
            cctvs.append(((y_idx, x_idx), &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(temp[x_idx])))

        &lt;span class=&quot;hljs-comment&quot;&gt;# CCTV도 아니고 벽도 아니라면 초기 사각지대&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; temp[x_idx] == &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;0&amp;#x27;&lt;/span&gt;:
                blind_spot += &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 행 정보를 리스트에 추가&lt;/span&gt;
    work_space.append(&lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;(&lt;span class=&quot;hljs-built_in&quot;&gt;map&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;lambda&lt;/span&gt; x: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt;(x), temp)))

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV 갯수 변수 선언&lt;/span&gt;
cctv_amount = &lt;span class=&quot;hljs-built_in&quot;&gt;len&lt;/span&gt;(cctvs)

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV 방향 정보 딕셔너리 선언&lt;/span&gt;
cctv_directions = {
    &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)], &lt;span class=&quot;hljs-number&quot;&gt;3&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
    &lt;span class=&quot;hljs-number&quot;&gt;5&lt;/span&gt;: {&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;: [(&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (-&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;), (&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, -&lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)]},
}

&lt;span class=&quot;hljs-comment&quot;&gt;# 각 CCTV의 방향 정보를 담은 리스트 선언&lt;/span&gt;
max_direction = [&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;dummy&amp;#x27;&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;]

&lt;span class=&quot;hljs-comment&quot;&gt;# CCTV가 존재하지 않는 경우 기존 사각지대의 갯수를 출력&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; cctv_amount:
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(blind_spot)

&lt;span class=&quot;hljs-comment&quot;&gt;# 만약 존재한다면 CCTV 방향에 따른 사각지대의 갯수를 조사&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

    &lt;span class=&quot;hljs-comment&quot;&gt;# 최종 사각지대 갯수 변수 선언&lt;/span&gt;
    result = blind_spot

    &lt;span class=&quot;hljs-keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;min_blind_spot&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;field: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, cctv_list: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;, sight: &lt;span class=&quot;hljs-built_in&quot;&gt;dict&lt;/span&gt;, max_direction: &lt;span class=&quot;hljs-built_in&quot;&gt;list&lt;/span&gt;,
                       now_cctv: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, y_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = height, x_range: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = width,
                       limit_cctv: &lt;span class=&quot;hljs-built_in&quot;&gt;int&lt;/span&gt; = cctv_amount&lt;/span&gt;) -&amp;gt; &lt;span class=&quot;hljs-literal&quot;&gt;None&lt;/span&gt;:
        &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;&amp;#x27;&amp;#x27;
        CCTV를 모두 최적의 상태로 설치할 때 최소 사각지대 갯수를 확인하는 함수
        &amp;#x27;&amp;#x27;&amp;#x27;&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 결과값 전역 변수 등록&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;global&lt;/span&gt; result

        &lt;span class=&quot;hljs-comment&quot;&gt;# Back Tracking&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 모든 CCTV를 전부 확인한 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; now_cctv == limit_cctv:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 사각지대 갯수 확인&lt;/span&gt;
            now_result = check_blind_spot(field, y_range, x_range)

            &lt;span class=&quot;hljs-comment&quot;&gt;# 기존 최소값보다 작은 경우 갱신&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; result &amp;gt; now_result:
                result = now_result

            &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt;

        &lt;span class=&quot;hljs-comment&quot;&gt;# 아직 확인하지 않은 CCTV가 존재하는 경우&lt;/span&gt;
        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

            &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 확인할 CCTV 정보 확인&lt;/span&gt;
            cctv_idx, cctv_type = cctv_list[now_cctv]

            &lt;span class=&quot;hljs-comment&quot;&gt;# 좌표 분리&lt;/span&gt;
            y_cctv, x_cctv = cctv_idx

            &lt;span class=&quot;hljs-comment&quot;&gt;# CCTV에 종류에 따라 감시 방향의 경우의 수만큼 조사&lt;/span&gt;
            &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; direction_code &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-built_in&quot;&gt;range&lt;/span&gt;(max_direction[cctv_type]):

                &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 주시 방향 확인&lt;/span&gt;
                cctv_directions_now = sight[cctv_type][direction_code]

                &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 주시 방향에서 볼 수 있는 좌표를 담을 리스트 선언&lt;/span&gt;
                now_view = []

                &lt;span class=&quot;hljs-comment&quot;&gt;# 깊이 탐색을 진행할 방향 설정&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; direction &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; cctv_directions_now:

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 이동 방향 좌표 분리&lt;/span&gt;
                    move_y, move_x = direction

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 초기 좌표 설정&lt;/span&gt;
                    now_y, now_x = y_cctv, x_cctv

                    &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 방향에 대해서 반복 조사&lt;/span&gt;
                    &lt;span class=&quot;hljs-keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;hljs-literal&quot;&gt;True&lt;/span&gt;:

                        next_y, next_x = now_y + move_y, now_x + move_x

                        &lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 범위를 벗어나지 않은 경우&lt;/span&gt;
                        &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;lt;= next_y &amp;lt; y_range &lt;span class=&quot;hljs-keyword&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt; &amp;lt;= next_x &amp;lt; x_range:

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 벽을 만났다면 반복 종료&lt;/span&gt;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; field[next_y][next_x] == &lt;span class=&quot;hljs-number&quot;&gt;6&lt;/span&gt;:
                                &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                            &lt;span class=&quot;hljs-comment&quot;&gt;# 벽을 만난 것이 아닐 경우&lt;/span&gt;
                            &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:

                                &lt;span class=&quot;hljs-comment&quot;&gt;# 해당 좌표가 사각지대일 경우&lt;/span&gt;
                                &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;not&lt;/span&gt; field[next_y][next_x]:

                                    &lt;span class=&quot;hljs-comment&quot;&gt;# 리스트에 기록 후 비사각지대 처리&lt;/span&gt;
                                    now_view.append((next_y, next_x))
                                    field[next_y][next_x] = &lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;#&amp;#x27;&lt;/span&gt;

                                &lt;span class=&quot;hljs-comment&quot;&gt;# 현재 좌표 갱신&lt;/span&gt;
                                now_y, now_x = next_y, next_x

                        &lt;span class=&quot;hljs-comment&quot;&gt;# 사무실 범위를 벗어났다면 반복 종료&lt;/span&gt;
                        &lt;span class=&quot;hljs-keyword&quot;&gt;else&lt;/span&gt;:
                            &lt;span class=&quot;hljs-keyword&quot;&gt;break&lt;/span&gt;

                &lt;span class=&quot;hljs-comment&quot;&gt;# 수집한 좌표들을 다음 CCTV에 조사&lt;/span&gt;
                min_blind_spot(field, cctvs, cctv_directions, max_direction, now_cctv + &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;)

                &lt;span class=&quot;hljs-comment&quot;&gt;# 초기화&lt;/span&gt;
                &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; y_idx, x_idx &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; now_view:
                    field[y_idx][x_idx] = &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;# 함수를 호출하여 결과 도출&lt;/span&gt;
    min_blind_spot(work_space, cctvs, cctv_directions, max_direction)

    &lt;span class=&quot;hljs-comment&quot;&gt;# 결과값 출력&lt;/span&gt;
    &lt;span class=&quot;hljs-built_in&quot;&gt;print&lt;/span&gt;(result)

&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>첫 글</title><link>https://www.traceoflight.dev/ko/blog/intro/</link><guid isPermaLink="true">https://www.traceoflight.dev/ko/blog/intro/</guid><description>이 블로그를 시작하게 된 이유</description><pubDate>Sat, 22 Oct 2022 18:26:40 GMT</pubDate><content:encoded>&lt;p&gt;기존에는 기록을 개인적으로, 나만 볼 수 있도록 정리했었다.&lt;/p&gt;
&lt;p&gt;하지만 그렇다면 굳이 이쁘게 정리할 필요도 없는 것이 아닐까 싶어 고민에 들어갔고, 이쁘게 정리해서 잘 볼 수 있는 곳에 올리기 vs 대충 적기 중에 잘 볼 수 있는 곳에 올리기를 선택했다.&lt;/p&gt;
&lt;p&gt;공부하고 정리한 내용이 나에게도, 혹시라도 글을 읽게 될 다른 누군가에게도 도움이 되길 바랍니다.&lt;/p&gt;
</content:encoded></item></channel></rss>