<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>낙타선생 놀이터</title>
    <link>https://camel-it.tistory.com/</link>
    <description> IT기술 지식의 기록 및 나눔을 위한 블로그 입니다.

GitHub: https://github.com/camel-master
Email: rlaalfks@gmail.com</description>
    <language>ko</language>
    <pubDate>Wed, 8 Apr 2026 17:30:06 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>낙타선생</managingEditor>
    <image>
      <title>낙타선생 놀이터</title>
      <url>https://tistory1.daumcdn.net/tistory/2882493/attach/3d4830972b0b417e9edd60dabefe740f</url>
      <link>https://camel-it.tistory.com</link>
    </image>
    <item>
      <title>[독서] 그들의 생각을 바꾸는 방법</title>
      <link>https://camel-it.tistory.com/151</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이 책은 어떻게 상대를 설득하여 마음을 바꿀 수 있는지에 대한 내용을 담고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 대상의 마음을 변화시키기에 앞서 &quot;나는 왜 다른 사람의 마음을 바꾸고 싶은가?&quot;라는 이유를 확실하게 정립해야 한다. 설득에 앞서 설득 대상에게 왜 당신의 마음을 바꾸고 싶어 하는지 진솔하게 이야기 하는 것을 통해 상대와 논쟁이 아닌 대화를 할 수 있게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;객관적 사실보다 개인의 감정과 신념이 여론형성에 더 큰 영향력을 미치는 탈진실의 시대에서는 객관적 사실만으로는 상대방의 마음을 바꿀 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;5장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소속공동체는 세계관 형성에 지속적인 영향을 미치며, 해당 공동체를 떠나야 변화를 맞이할 가능성이 높아진다. 또한 기존 공동체 탈출을 위해 주변 인물들의 인간적인 대우와 호의가 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소속공동체에 대한 소속감은 안정감으로 이어지고 이는 공동체에서 제시하는 가치관을 버리기 어렵게 한다. 공동체에 반한는 행동을 할 경우 사회적 사망 등의 페널티에 이를 수 있기 때문이다. 기존 공동체 탈출을 위해서는 자신을 받아줄 또다른 공동체의 따뜻한 배려와 기다림이 필요하다. 이때 공통된 목표를 제시하는 것도 도움이 된다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;또다른 중요한 공동체 찾기 + 다정하고 인간적인 대우&lt;/li&gt;
&lt;li&gt;기존공동체에 대한 의문 발생&lt;/li&gt;
&lt;li&gt;기존공동체로 부터 탈출&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7장&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리의 뇌는 확실하다고 판단되는 내용에 대해서는 더이상 해당 사항에 대한 사고를 하지 않으려고 하는 확증편향을 가지고 있다. 확증편향으로 인해 항상 진실에 가까운 방향으로 추론하지는 못한다.(자신이 원하는 방향으로만 결론을 내린다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한 우리 뇌는&amp;nbsp; 잘못된 정보에 대한 경계심 역시 가지고 있어 유용한 아이디어나 혁신에 대해 거짓부정을 만들어 쉽게 믿지 못한다. 확증편향과 거짓 부정으로 인해 정보의 흐림이 정체되어 버린다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;확증편향 + 거짓부정 &amp;rarr; 정보 흐름의 정체 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;편향되고 게으른 뇌로 인해 발생한 정보 흐름의 정체는 역설적으로 그러한 뇌를 사용해 논증하고,&amp;nbsp; 논증을 이용하여 집단의 토론과 숙고를 거쳐 개인의 주장을 조정함으로 해소할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;논증을 통해 어느정도 정보 흐름의 정체를 해소할 수 있다고는 하지만, 동일 의견을 가진 개인들로 구성된 집단 내부에서 논증을 하게 되면 동일한 의견의 논증만 제공되어 결과적으로 편향될 수 밖에 없다. 이러한 공동체에 소속되어 있는 개인은 공동체에 반하는 의견을 제시하기 어려워진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인이 중요한 도덕적, 정치적&amp;nbsp; 이슈들에 대해 정보를 수집하고 판단하는 것에는 한계가 있어 이슈들에 대해 무지한 상태로 있을 수 있다. 따라서 이러한&amp;nbsp; &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;이슈에 대해 전문가의 의견을 따르는 것은 합리적인 선택이다. 그러나 전문가의 의견을 따르기 시작하면 제3자의 반박논증을 크게 신경쓰지 않게된다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;편향된 공동체와 전문가 의견을 따름으로 발생하는 편향성은 설득을 통해 해결할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;설득을 통해 현재 속한 공동체의 판단이 잘못되었다고 느끼는 경우 마음을 바꿀 가능성이 높아진다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;8장&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;믿음은 사실이라 간주하는 정보들이다. 태도는 특정 대상에 대한 감정 기반의 평가다. 믿음과 태도가 합쳐져 가치관이 된다. 사람들은 특정 사안이 자신에게 얼마나 밀접하게 관련 되어 있는지에 따라 사안을 다르게 대한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;설득대상과 관련도가 떨어지는 경우 즉, 인지적 능력을 비교적 덜 사용해도 되는 경우의 효과적 설득 방법은 다음과 같다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반대로 사실정보를 통해 복잡한 판단이 필요한 사안은 인지적 능력을 적극적으로 사용하도록 유도한다. 설득대상이 사안에 대한 지식과 마음을 바꿀 동기가 있다면 설득할 준비가 된 것이다. 준비가 덜된경우 새로운 정보를 받아들이기 쉬운 환경에서 신뢰할 수 있는 정보원을 통해 사실을 전달한다. 설득에 앞서 개인의 가치관과 동기를 파악하는 것이 무엇보다 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설득 프로세스는 누가, 무엇을, 누구에게, 어떤 채널을 통해 전달하고 어떤 효과가 있을지 고려해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;딥캔버싱 단계&lt;/b&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;라포르를 형성한다. 상대방의 수치심을 유발하거나 비난할 의도가 전혀 없음을 알리고 대화에 대한 동의를 구한다.&lt;/li&gt;
&lt;li&gt;대화 주제인 이슈에 대한 지지도를 0~10으로 표현해달라고 한다.&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;/li&gt;
&lt;li&gt;질문자는 왜 현재와 같은 견해를 갖게 됐는지 개인적인 이야기를 잠시 들려준다. 단, 대화가 논쟁이 되지 않도록 주의 한다.&lt;/li&gt;
&lt;li&gt;지지도를 다시 묻는다. 대화를 마무리하고 인사를 나눈다.&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>ETC</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/151</guid>
      <comments>https://camel-it.tistory.com/151#entry151comment</comments>
      <pubDate>Wed, 10 Apr 2024 19:40:26 +0900</pubDate>
    </item>
    <item>
      <title>Windows 11 우클릭 컨텍스트 창 스타일 변경</title>
      <link>https://camel-it.tistory.com/150</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;WIndows11 &lt;/span&gt;&lt;span&gt;탐색기에서&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;우클릭&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;시&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이전&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;버전의&lt;/span&gt;&lt;span&gt; windows&lt;/span&gt;&lt;span&gt;에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;비해&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;간소화&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;된&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;컨텍스트&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;창이&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;뜨도록&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;변경되었으나&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;자주&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용하는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;기능들을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용하기&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;위해&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;한&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;번&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;더&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;클릭해야&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;하는&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;불편함이&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;있어&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;레지스트리를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;수정하여&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이전&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;버전과&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;같이&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;사용하고자 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;437&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjavX2/btsB7bKHa0P/brMlm3xHgXTtKXQhXMVO7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjavX2/btsB7bKHa0P/brMlm3xHgXTtKXQhXMVO7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjavX2/btsB7bKHa0P/brMlm3xHgXTtKXQhXMVO7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjavX2%2FbtsB7bKHa0P%2FbrMlm3xHgXTtKXQhXMVO7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;603&quot; height=&quot;437&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;437&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1. Windows key + R &lt;/span&gt;&lt;span&gt;로&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;실행창&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;열어&lt;/span&gt;&lt;span&gt; regedit &lt;/span&gt;&lt;span&gt;입력&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;259&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uPUBM/btsB2QOAcEe/5wJ2PQtKEkqt83mPLid4FK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uPUBM/btsB2QOAcEe/5wJ2PQtKEkqt83mPLid4FK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uPUBM/btsB2QOAcEe/5wJ2PQtKEkqt83mPLid4FK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuPUBM%2FbtsB2QOAcEe%2F5wJ2PQtKEkqt83mPLid4FK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;400&quot; height=&quot;259&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;259&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span&gt;레지스트리에서&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;HKEY_CURRENT_USER\Software\Classes\CLSID&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;키&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;값을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;추가&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;255&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5xKNp/btsB3cYsPY8/KC5Lh5KcBSmA3LOshU2xok/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5xKNp/btsB3cYsPY8/KC5Lh5KcBSmA3LOshU2xok/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5xKNp/btsB3cYsPY8/KC5Lh5KcBSmA3LOshU2xok/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5xKNp%2FbtsB3cYsPY8%2FKC5Lh5KcBSmA3LOshU2xok%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;255&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;255&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;추가할&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;키&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이름은&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;b&gt;&lt;span&gt;{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}&lt;/span&gt;&lt;/b&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;358&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dXGIG2/btsB6trfD5R/sphklJ4smF3YziZFNgxTmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dXGIG2/btsB6trfD5R/sphklJ4smF3YziZFNgxTmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dXGIG2/btsB6trfD5R/sphklJ4smF3YziZFNgxTmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdXGIG2%2FbtsB6trfD5R%2FsphklJ4smF3YziZFNgxTmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;372&quot; height=&quot;358&quot; data-origin-width=&quot;372&quot; data-origin-height=&quot;358&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. &lt;/span&gt;&lt;span&gt;위에서&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;생성한&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;키에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;하위에&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;새로운&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;키&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;값을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;추가한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX1Kb8/btsB6K7Hta9/e0jSoL7k7bJG6SwXjRXNL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX1Kb8/btsB6K7Hta9/e0jSoL7k7bJG6SwXjRXNL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX1Kb8/btsB6K7Hta9/e0jSoL7k7bJG6SwXjRXNL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX1Kb8%2FbtsB6K7Hta9%2Fe0jSoL7k7bJG6SwXjRXNL0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;671&quot; height=&quot;267&quot; data-origin-width=&quot;671&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;추가할 &lt;span&gt;키&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이름은&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;b&gt;&lt;span&gt;InprocServer32&lt;/span&gt;&lt;/b&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;이다&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;43&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mjuZI/btsB3cxpWBY/txHKk20vrSqfNjlwzAbSk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mjuZI/btsB3cxpWBY/txHKk20vrSqfNjlwzAbSk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mjuZI/btsB3cxpWBY/txHKk20vrSqfNjlwzAbSk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmjuZI%2FbtsB3cxpWBY%2FtxHKk20vrSqfNjlwzAbSk1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;286&quot; height=&quot;43&quot; data-origin-width=&quot;286&quot; data-origin-height=&quot;43&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. &lt;span&gt;추가한&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;InprocServer32 &lt;/span&gt;&lt;span&gt;키를&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;선택하고&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;오른쪽&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;분할창의&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;기본값을&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;더블클릭 한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;646&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CzIOf/btsB4UXAmSX/xuW22o8KZ8IpwpWqZ2WffK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CzIOf/btsB4UXAmSX/xuW22o8KZ8IpwpWqZ2WffK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CzIOf/btsB4UXAmSX/xuW22o8KZ8IpwpWqZ2WffK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCzIOf%2FbtsB4UXAmSX%2FxuW22o8KZ8IpwpWqZ2WffK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;598&quot; height=&quot;646&quot; data-origin-width=&quot;598&quot; data-origin-height=&quot;646&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;문자열 편집창에서 값 데이터 입력 없이 확인 클릭한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/D0wS9/btsB3cqB3IB/DqKh6tHeQ5ImMYNbD6Q8X0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/D0wS9/btsB3cqB3IB/DqKh6tHeQ5ImMYNbD6Q8X0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/D0wS9/btsB3cqB3IB/DqKh6tHeQ5ImMYNbD6Q8X0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FD0wS9%2FbtsB3cqB3IB%2FDqKh6tHeQ5ImMYNbD6Q8X0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;570&quot; height=&quot;222&quot; data-origin-width=&quot;570&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 레지스트리 편집기를 닫고 컴퓨터를 재시작 한다.&lt;/p&gt;</description>
      <category>ETC</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/150</guid>
      <comments>https://camel-it.tistory.com/150#entry150comment</comments>
      <pubDate>Sun, 17 Dec 2023 13:22:53 +0900</pubDate>
    </item>
    <item>
      <title>순열과 조합</title>
      <link>https://camel-it.tistory.com/148</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[순열 - Permutation]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순열은 뽑는 순서를 고려하여 n개의 원소 중에 r개를 뽑아 나열할 수 있는 경우의 수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 '뽑은 순서를 고려'한다는 말은 만약 a, b, c 3개의 원소를 뽑는다고 했을 때 a를 뽑고 b를 뽑고 c를 뽑는 경우와 b를 뽑고 a를 뽑고 c를 뽑는 경우를 각각 다른 경우로 인정한다는 말이다. 즉, {a, b, c} &amp;ne; {b, c, a}이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순열 공식은 다음과 같이 간단하게 생각해볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;₅P₃ 을 구해보도록 하자. 5개의 원소를 가진 집합 S = {1, 2, 3, 4, 5}가 존재할 때, 집합 S에서 순서를 고려하여 원소를 3개씩 뽑아보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫 번째 수를 뽑을 때는 {1, 2, 3, 4, 5} 중에 하나를 뽑을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두 번째 뽑을 수는 첫 번째 뽑은 수를 제외한 나머지 4개의 수 중 하나를 뽑을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 번째 뽑을 수는 지금까지 뽑은 두 수를 제외한 나머지 3개의 수 중 하나를 뽑을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 모든 경우의 수는 5 x 4 x 3 = 60이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 식을 좀 더 자세히 풀어보면 고를 수 있는 원소의 수를 하나씩 줄여가면서&amp;nbsp; r번 곱하는 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVL5kj/btrRa2663CH/nYCuOagGxjaDcWnB4KZ6d1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVL5kj/btrRa2663CH/nYCuOagGxjaDcWnB4KZ6d1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVL5kj/btrRa2663CH/nYCuOagGxjaDcWnB4KZ6d1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVL5kj%2FbtrRa2663CH%2FnYCuOagGxjaDcWnB4KZ6d1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;417&quot; height=&quot;49&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;150&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팩토리얼을 사용하여 위의 수식을 표현하면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;equation.png&quot; data-origin-width=&quot;121&quot; data-origin-height=&quot;41&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cup8iI/btsED5ACOJl/IX4mPc06PM2St020gKC410/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cup8iI/btsED5ACOJl/IX4mPc06PM2St020gKC410/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cup8iI/btsED5ACOJl/IX4mPc06PM2St020gKC410/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcup8iI%2FbtsED5ACOJl%2FIX4mPc06PM2St020gKC410%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;144&quot; height=&quot;49&quot; data-filename=&quot;equation.png&quot; data-origin-width=&quot;121&quot; data-origin-height=&quot;41&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 순열을 구하는 공식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/n3lBF/btrQ0wAZrOb/R61M9d3X1rRXzuSMFXQVl1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n3lBF/btrQ0wAZrOb/R61M9d3X1rRXzuSMFXQVl1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n3lBF/btrQ0wAZrOb/R61M9d3X1rRXzuSMFXQVl1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn3lBF%2FbtrQ0wAZrOb%2FR61M9d3X1rRXzuSMFXQVl1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;228&quot; height=&quot;83&quot; data-origin-width=&quot;533&quot; data-origin-height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[조합 - Combination]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조합은 뽑은 순서와 상관없이 n개의 원소 중에 r개를 뽑을 수 있는 경우의 수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조합은 뽑는 순서를 고려하지 않기 때문에&amp;nbsp; a, b, c 3개의 원소를 뽑는다고 했을 때 {a, b, c} = {a, c, b} = {b, a, c} = {b, c, a} = {c, a, b} = {c, b, a}와 같이 동일한 원소로 구성된 경우에는 뽑은 순서에 상관없이 같은 경우라고 본다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 조합은 뽑는 순서를 고려하지 않기 때문에 조합 원소를 구하기 위해 모든 순열 가운데 중복되는 조합원소들 중 하나만 남기고 제거하는 과정이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;S = {1, 2, 3, 4, 5}에서 순서를 고려하지 않고 3개를 뽑는 경우의 수 ₅C₃을 구하기 위해 우선 ₅P₃의 모든 경우를 나열하면 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;₅P₃ = {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 3}, {1, 3, 2}, {2, 1, 3}, {2, 3, 1}, {3, 1, 2}, {3, 2, 1},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 4}, {1, 4, 2}, {2, 1, 4}, {2, 4, 1}, {4, 1, 2}, {4, 2, 1},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 5}, {1, 5, 2}, {2, 1, 5}, {2, 5, 1}, {5, 1, 2}, {5, 2, 1},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 3, 4}, {1, 4, 3}, {3, 1, 4}, {3, 4, 1}, {4, 1, 3}, {4, 3, 1},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 3, 5}, {1, 5, 3}, {3, 1, 5}, {3, 5, 1}, {5, 1, 3}, {5, 3, 1},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 4, 5}, {1, 5, 4}, {4, 1, 5}, {4, 5, 1}, {5, 1, 4}, {5, 4, 1},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 3, 4}, {2, 4, 3}, {3, 2, 4}, {3, 4, 2}, {4, 2, 3}, {4, 3, 2},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 3, 5}, {2, 5, 3}, {3, 2, 5}, {3, 5, 2}, {5, 2, 3}, {5, 3, 2},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 4, 5}, {2, 5, 4}, {4, 2, 5}, {4, 5, 2}, {5, 2, 4}, {5, 4, 2},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {3, 4, 5}, {3, 5, 4}, {4, 3, 5}, {4, 5, 3}, {5, 3, 4}, {5, 4, 3}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;} = 60개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 순서만 다르고 구성원소는 같은 경우를 모두 제거해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;₅P₃ = {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 3}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{1, 3, 2}, {2, 1, 3}, {2, 3, 1}, {3, 1, 2}, {3, 2, 1},&lt;/s&gt;&amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {1, 2, 3}과 동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 4}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{1, 4, 2}, {2, 1, 4}, {2, 4, 1}, {4, 1, 2}, {4, 2, 1}&amp;nbsp;&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {1, 2, 4}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 5}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{1, 5, 2}, {2, 1, 5}, {2, 5, 1}, {5, 1, 2}, {5, 2, 1},&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {1, 2, 5}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 3, 4}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{1, 4, 3}, {3, 1, 4}, {3, 4, 1}, {4, 1, 3}, {4, 3, 1},&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {1, 3, 4}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 3, 5}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{1, 5, 3}, {3, 1, 5}, {3, 5, 1}, {5, 1, 3}, {5, 3, 1},&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {1, 3, 5}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 4, 5}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{1, 5, 4}, {4, 1, 5}, {4, 5, 1}, {5, 1, 4}, {5, 4, 1},&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {1, 4, 5}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 3, 4}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{2, 4, 3}, {3, 2, 4}, {3, 4, 2}, {4, 2, 3}, {4, 3, 2},&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {2, 3, 4}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 3, 5}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{2, 5, 3}, {3, 2, 5}, {3, 5, 2}, {5, 2, 3}, {5, 3, 2},&lt;/s&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {2, 3, 5}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 4, 5}, &lt;s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;{2, 5, 4}, {4, 2, 5}, {4, 5, 2}, {5, 2, 4}, {5, 4, 2},&lt;/span&gt;&lt;/s&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt; &lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {2, 4, 5}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {3, 4, 5}, &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;s&gt;{3, 5, 4}, {4, 3, 5}, {4, 5, 3}, {5, 3, 4}, {5, 4, 3}&lt;/s&gt; &amp;nbsp;&lt;span style=&quot;color: #000000;&quot;&gt;=&amp;gt; {3, 4, 5}와 &lt;span style=&quot;color: #000000;&quot;&gt;동일한 6개의 원소 중 5개를 제거&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 과정을 거친 후 남은 것들이 조합의 원소가 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;₅C₃ = {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 3},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 4},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 2, 5},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 3, 4},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 3, 5},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {1, 4, 5},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 3, 4},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 3, 5},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {2, 4, 5},&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; {3, 4, 5}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;} = 10개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 순열 원소를 구하기 위해 모든 조합 원소 가운데 중복된 원소를 제거하는 과정을 다시 살펴보면, ₅C₃ 을 구성하는 하나의 조합 원소와 동일한 순열 원소는 ₅P₃에서&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 6개씩 존재하는 것을 확인할 수 있다. 그렇다면 &lt;span style=&quot;color: #ee2323;&quot;&gt;₅P₃을 6으로 나누면&lt;/span&gt; &lt;span style=&quot;color: #ee2323;&quot;&gt;₅C₃의 원소 갯수를 알 수 있다&lt;/span&gt;는 말이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 나누는 수 6은 어떻게 구할 수 있을까? 이는 3개의 원소 가운데 3개를 뽑는 순열 원소의 갯수( ₃P₃ )라고 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 ₅C₃ 을 도출하는 과정을 식으로 옮기면 다음과 같이 된다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;175&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1mzoD/btrR83YFRft/dBudQvW5YAlKnZhcbnMlR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1mzoD/btrR83YFRft/dBudQvW5YAlKnZhcbnMlR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1mzoD/btrR83YFRft/dBudQvW5YAlKnZhcbnMlR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1mzoD%2FbtrR83YFRft%2FdBudQvW5YAlKnZhcbnMlR0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;316&quot; height=&quot;47&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 일반화 시켜키면 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ztRWE/btrSa7eucOq/GVdgjt2DOMa2NUWIF82kyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ztRWE/btrSa7eucOq/GVdgjt2DOMa2NUWIF82kyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ztRWE/btrSa7eucOq/GVdgjt2DOMa2NUWIF82kyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FztRWE%2FbtrSa7eucOq%2FGVdgjt2DOMa2NUWIF82kyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;648&quot; height=&quot;96&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;96&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 n개의 원소 중에 r개를 고르는 조합 nCr의 공식은 다음과 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxD3U1/btrQ3ThsKB7/QBfgfDjCcyOZKJ99hKhb4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxD3U1/btrQ3ThsKB7/QBfgfDjCcyOZKJ99hKhb4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxD3U1/btrQ3ThsKB7/QBfgfDjCcyOZKJ99hKhb4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxD3U1%2FbtrQ3ThsKB7%2FQBfgfDjCcyOZKJ99hKhb4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;82&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 조합을 통해 알 수 있는 것이 로또 1등 당첨 확률이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로또는 1 ~ 45 숫자들 가운데 순서와 상관 없이 6개를 뽑는 게임이므로 다음과 같이 ₄₅C₆ 을 구하면 모든 조합 경우의 수를 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;45! &amp;divide; {(45 - 6)! &amp;times; 6!} = (45 &amp;times; 44 &amp;times; 43 &amp;times; 42&amp;nbsp; &amp;times; 41 &amp;times; 40) &amp;divide; (6 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;times;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 5 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;times;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 4 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;times;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 3 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;times;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 2 &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&amp;times;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt; 1) = &lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;8,145,060&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그중 하나만 1등 당첨번호이므로 로또 1등 당첨확률은 1/8,145,060 이다.&lt;/p&gt;</description>
      <category>ETC</category>
      <category>경우의수</category>
      <category>순열</category>
      <category>조합</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/148</guid>
      <comments>https://camel-it.tistory.com/148#entry148comment</comments>
      <pubDate>Sat, 12 Nov 2022 17:16:26 +0900</pubDate>
    </item>
    <item>
      <title>로지텍 MX KEYS MINI 사용기</title>
      <link>https://camel-it.tistory.com/146</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;키보드 자체는 그럭저럭. 그런데 비싸다.&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;&quot;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;K380을 대신해 사용할 키보드가 필요하던 중 MX KEYS MINI의 발매 소식을 듣게 되었다. 와이프의 업무환경을 개선해주기 위해 MX KEYS를 구매한 적이 있는데 당시 깔끔한 디자인과 마감, 넓은 키캡, 적당한 키감 등 좋은 인상이 남아 있었기에 구매를 결정하게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로 영문 각인 키보드를 선호하는데, 로지텍은 국내 정발 제품은 따로 영문 각인을 제공하지 않는다. 로지텍은 로컬 워런티 정책이기 때문에 국내 정발 제품이 아니라면 정식 A/S를 받을 수 없다는 문제가 있었으나, 난 영문 각인이 좋기에 A/S를 포기하고 해외 직구로 구매했다. 만약 직구를 통해 구매한 경우 부품의 수급은 &lt;a href=&quot;https://www.replacementlaptopkeys.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.replacementlaptopkeys.com/&lt;/a&gt; 를 이용하면 되겠다. 단, 배송비가 좀 걱정이 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MX KEYS MINI를 실사용 후 K380과 비교해본 특징은 다음과 같다. 장점이 될 수도 있고 단점이 될 수도 있는 것은 녹색, 장점은 파랑, 단점은 빨강으로 표기했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #409d00;&quot;&gt;키가 더 깊이 눌린다&lt;/span&gt;.&lt;/b&gt; K380에 비해 조금 더 구분감이 있다고 볼 수 있겠다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;백라이트 기능&lt;/b&gt;&lt;/span&gt;이 있어서 어두운 환경에서도 사용할 수 있다. 필자의 경우 가끔 아이들 재워놓고 코딩할 때 사용하기 좋았다. 공홈에는 백라이트 활성화 시 약 10일간 동안 사용할 수 있다고 하는데, 현재 백라이트를 켜고 하루 2~3시간 사용 기준으로 만충 시 15일 이상 사용 가능했다.&lt;/li&gt;
&lt;li&gt;키보드 구조상 하단부가 비어 있는 형태이기 때문에 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;통울림이 발생&lt;/b&gt;&lt;/span&gt;한다. 밑에 수건을 깔아 흡음을 시도해볼 수 있지만, 키보드의 정숙성 최우선 선택 조건이라면 저렴한 K380을 고르는 것이 좋다.&lt;/li&gt;
&lt;li&gt;K380과 동일한 사양으로 총 &lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;3대의 기기와 페어링&lt;/b&gt;&lt;/span&gt; 할 수 있다. (keys to go와는 다르다 keys to go와는)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;&lt;b&gt;K380보다 넓은 사각형 키캡&lt;/b&gt;&lt;/span&gt;이 적용되어 있다. 키캡의 중앙부가 인체공학적으로 살짝 곡면처리 되어 있어 오타를 줄여준다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;무겁고 크다.&lt;/b&gt;&lt;/span&gt; 무게는 506.5g으로 423g인 K380에 비해무겁다. 크기도 K380보다 좀더 크다.&amp;nbsp;휴대성은 K380쪽 승리다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;비싸다.&lt;/span&gt;&lt;/b&gt; 가장 큰 단점은 비싼 가격 휴대용 미니 키보드에 투자하기는 망설여지는 가격임에 틀림없다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;(MX Keys Mini VS K380)&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 83.0203%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7907%; text-align: center;&quot;&gt;&lt;b&gt;항목&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 95.7899%; text-align: center;&quot;&gt;&lt;b&gt;내용&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;휴대성&lt;/td&gt;
&lt;td style=&quot;width: 95.7899%;&quot;&gt;가볍고 작은 K380 승&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;소음&lt;/td&gt;
&lt;td style=&quot;width: 95.7899%;&quot;&gt;통울림 없이 조용한 K380 승&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;편의성&lt;/td&gt;
&lt;td style=&quot;width: 95.7899%;&quot;&gt;백라이트 및 일반 키보드 사이즈 키캡으로 편한 타이핑이 가능한 MX KEYS MINI 승&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;가격&lt;/td&gt;
&lt;td style=&quot;width: 95.7899%;&quot;&gt;K380 압승&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 17.7907%;&quot;&gt;키감&lt;/td&gt;
&lt;td style=&quot;width: 95.7899%;&quot;&gt;개인 취향에 따름.&amp;nbsp;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가성비를 따지면 여전히 K380이 압도적이라고 생각한다. 타이핑량이 많은 작업을 한다거나 저조도 작업환경에서의 사용을 고려한다면&amp;nbsp; MX KEYS MINI를 선택하는 것도 나쁘지는 않다고 생각한다. (가격만 문제가 안된다면)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사진 하나 없는 짧은 리뷰이지만 아무쪼록 구매하시는 분들에게 도움이 되었으면 한다.&lt;/p&gt;</description>
      <category>ETC</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/146</guid>
      <comments>https://camel-it.tistory.com/146#entry146comment</comments>
      <pubDate>Sat, 19 Mar 2022 17:07:20 +0900</pubDate>
    </item>
    <item>
      <title>초성 낱말 찾기</title>
      <link>https://camel-it.tistory.com/144</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;초등학교 1학년생 딸아이의 국어 과제로 초성 낱말 찾기가 주어지는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매번 초성에 맞춰 눈빠지게 글자 찾기가 귀찮아서 초성 문자열이 주어지면 거기에 맞는 글자 조합을 출력하는 프로그램을 작성해 봤다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;주어지는 글자들을 초성별로 모은다.&lt;/li&gt;
&lt;li&gt;초성으로만 구성된 문자열을 받아서 초성에 해당하는 문자들에 대해 production으로 초성 순서에 맞는 글자 조합들을 만들어 출력한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre id=&quot;code_1638526207762&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from itertools import product

def get_char_set(ch_list):
    views = list()
    for cl in ch_list:
        for c in ch_list[cl]:
            views.append(c)
    views.sort()
    print('입력된 글자: ' + ', '.join(views))
initial_consonants = [
    'ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ', 'ㅂ', 'ㅃ',
    'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'
]

f_c_num = 44032 # '가'에 해당하는 code

code_n_ic = dict()
for i in range(len(initial_consonants)):
    for code in range(f_c_num, f_c_num + 588):
        code_n_ic[code] = initial_consonants[i]
    f_c_num += 588


# {'ㄱ': ['가', '길', '긴'], ...} 형태로 저장.
ch_list = dict()
for i in range(len(initial_consonants)):
    ch_list[initial_consonants[i]] = list()
print('초성 낱말 찾기에 사용될 글자들을 한 글자 씩 입력 후 엔터')
print('입력 완료 시 0 입력 후 엔터')
while True:
    print('&amp;gt;&amp;gt;', end='')
    ch = input()
    if len(ch) &amp;gt; 1:
        print('한 글자씩만 입력')
        continue
    if ch == '0':
        break
    try:
        ch_list[code_n_ic[ord(ch)]].append(ch)
        get_char_set(ch_list)
    except KeyError:
        pass

# 초성 string을 입력 받는다.
print('ㅅㄹㅎ 와 같은 형태의 자음으로만 이뤄진 문자열을 입력하고 엔터')
print('종료 하려면 0입력 후 엔터')
while True:
    ic_str = input()
    if ic_str == '0':
        break
    is_no_res = False
    word_list = list()
    for ch in ic_str:
        try:
            if len(ch_list[ch]) == 0:
                is_no_res = True
            word_list.append(ch_list[ch])
        except KeyError:
            print('&amp;gt;&amp;gt; 결과 없음 &amp;lt;&amp;lt;')

    if is_no_res:
        print('&amp;gt;&amp;gt; 결과 없음 &amp;lt;&amp;lt;')
    else:
        for word in product(*word_list):
            print(''.join(word))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;국어사전 DB가 있으면 사전에 등록된 단어인지 아닌지를 구분하여 알려주도록 개선해볼 수도 있겠다. ^^&lt;/p&gt;</description>
      <category>ETC</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/144</guid>
      <comments>https://camel-it.tistory.com/144#entry144comment</comments>
      <pubDate>Fri, 3 Dec 2021 19:11:11 +0900</pubDate>
    </item>
    <item>
      <title>빠른 리스트 객체 복사</title>
      <link>https://camel-it.tistory.com/143</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;한 줄 요약: 내부 데이터가 imutable 객체로 구성된 list type 객체의 깊은 복사가 필요할 때는 slicing을 사용하자.&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[mutable type과 깊은 복사의 필요성]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list는 mutable type이다. 따라서 list 변수는 데이터가 존재하는 메모리 주소를 가지고 있는 셈이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 코드를 보자.&lt;/p&gt;
&lt;pre id=&quot;code_1637369202211&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;L1 = [1, 2, 3]
L2 = l1
print(L1)
print(L2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L1 = [1, 2, 3]이고 L2에 L1을 넣었으니 L1과 L2을 각각 출력하면 동일하게 [1, 2, 3]이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 L2 [1]의 값을 10으로 변경 후 다시 L1과 L2를 출력해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1637369347745&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;L2[1] = 10

print(L1)
print(L2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;L1과 L2가 모두 [1, 10, 3]으로 변경되는 것을 볼 수 있다. 이 것이 바로 동일한 메모리 참조하는 mutable type의 특징인데, L1과 L2가 동일한 메모리 주소를 가르키기 때문에 어떤 변수를 사용해서 접근하더라도 같은 데이터를 만지게 된다. 따라서 L1과 L2가 완전히 별개의 객체로 다뤄지게 하려면 깊은 복사(deep copy)를 해줄 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[깊은 복사를 하는 방법]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python은 mutable type 객체의 deep copy를 지원하는 copy 라이브러리를 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서 copy 라이브러리를 사용하여 L1과 L2과 별개의 객체가 되도록 변경해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1637369773421&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from copy import deepcopy


L1 = [1, 2, 3]
L2 = deepcopy(L1)
print(L1)
print(L2)
print('----------')

L2[1] = 10

print(L1)
print(L2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 위의 코드를 실행한 결과다. L1과 L2과 별개의 객체로 인식되고 있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;81&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W8UJH/btrlEJ4Vwi0/Oo00nC4Hg2CguSNzuGVIj1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W8UJH/btrlEJ4Vwi0/Oo00nC4Hg2CguSNzuGVIj1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W8UJH/btrlEJ4Vwi0/Oo00nC4Hg2CguSNzuGVIj1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW8UJH%2FbtrlEJ4Vwi0%2FOo00nC4Hg2CguSNzuGVIj1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;81&quot; height=&quot;107&quot; data-origin-width=&quot;81&quot; data-origin-height=&quot;107&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python에서 제공하는 slicing 기능을 사용하면 list type의 객체에 대해 보다 간편하고 빠르게 깊은 복사할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1637370150109&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;L1 = [1, 2, 3]
L2 = L1[:]
print(L1)
print(L2)
print('----------')

L2[1] = 10

print(L1)
print(L2)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행하면 copy 라이브러리를 사용한 것과 동일한 결과를 보여준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;주의!&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;리스트를 구성하는 데이터들이 mutable 객체인 경우는 슬라이싱을 통한 복사를 사용할 수 없다. &lt;/b&gt;&lt;/span&gt;엄밀히 말하면 슬라이싱을 통한 리스트 복사는 얕은복사이다. 다음을 예를 살펴보자.&lt;/p&gt;
&lt;pre id=&quot;code_1643853616659&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 2차원 리스트
test1 = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# 슬라이싱으로 복사
test2 = test1[:]

# 데이터를 변경하기전 test1, test2를 출력
print(test1)
print(test2)

# test1[0][0]의 데이터를 변경
test1[0][0] = -1

# test1[0][0]과 test2[0][0]이 모두 변경 되어버림.
print(test1)
print(test2)

# test1[0]과 test2[0]의 객체 id를 확인해보면
# 동일한 객체임을 알 수 있다.
print(id(test1[0]), id(test2[0]))
print(test1[0] is test2[0])

# 다차원 리스트의 깊은 복사는 copy 라이브러리를 사용하자.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;mutable한 데이터를 포함한 리스트의 복사는 copy 라이브러리를 사용한다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;[두 가지 imutable 객체로 구성된 리스트 객체에 대한 두 가지 복사 방법에 대한 속도 비교]&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;slicing을 사용한 복사는 라이브러리를 사용한 것보다 빠르게 동작한다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3,000 * 3,000 크기의 2차원 리스트에 대해 깊은 복사를 수행할 때 라이브러리를 사용한 것과 slicing을 사용한 것에 어느 정도 속도 차이가 있는지 확인해보자.&lt;/p&gt;
&lt;pre id=&quot;code_1637370503543&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import time
from copy import deepcopy

N = 3000
M = 3000

test = [[0] * M for _ in range(N)]
val = 1
for i in range(N):
    for j in range(M):
        test[i][j] = val
        val += 1


s_time = time.process_time()
# deepcopy with library
temp1 = deepcopy(test)
e_time = time.process_time()
print(f&quot;time elapsed : {int(round((e_time - s_time) * 1000))}ms&quot;)

s_time = time.process_time()
# deepcopy with slicing
temp2 = [t[:] for t in test]
e_time = time.process_time()
print(f&quot;time elapsed : {int(round((e_time - s_time) * 1000))}ms&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 system에 따라 전반적인 실행 속도의 차이가 있을 수는 있겠으나. 라이브러리와 slicing을 사용한 깊은 복사 속도는 엄청나게 큰 차이가 있음을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;41&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqD6n8/btrlEma3HTi/D3zMxV0k9goRDrvc6KL1zK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqD6n8/btrlEma3HTi/D3zMxV0k9goRDrvc6KL1zK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqD6n8/btrlEma3HTi/D3zMxV0k9goRDrvc6KL1zK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqD6n8%2FbtrlEma3HTi%2FD3zMxV0k9goRDrvc6KL1zK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;176&quot; height=&quot;41&quot; data-origin-width=&quot;176&quot; data-origin-height=&quot;41&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Python</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/143</guid>
      <comments>https://camel-it.tistory.com/143#entry143comment</comments>
      <pubDate>Sat, 20 Nov 2021 10:12:20 +0900</pubDate>
    </item>
    <item>
      <title>[BOJ] 치킨배달 (15686)</title>
      <link>https://camel-it.tistory.com/141</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15686&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://www.acmicpc.net/problem/15686&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1633564160305&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;15686번: 치킨 배달&quot; data-og-description=&quot;크기가 N&amp;times;N인 도시가 있다. 도시는 1&amp;times;1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸&quot; data-og-host=&quot;www.acmicpc.net&quot; data-og-source-url=&quot;https://www.acmicpc.net/problem/15686&quot; data-og-url=&quot;https://www.acmicpc.net/problem/15686&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/u1zLh/hyLSt1Tlrd/hT4JVgKg7KEJmFZ6AQSTnK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630&quot;&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15686&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://www.acmicpc.net/problem/15686&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/u1zLh/hyLSt1Tlrd/hT4JVgKg7KEJmFZ6AQSTnK/img.png?width=1200&amp;amp;height=630&amp;amp;face=0_0_1200_630');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;15686번: 치킨 배달&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;크기가 N&amp;times;N인 도시가 있다. 도시는 1&amp;times;1크기의 칸으로 나누어져 있다. 도시의 각 칸은 빈 칸, 치킨집, 집 중 하나이다. 도시의 칸은 (r, c)와 같은 형태로 나타내고, r행 c열 또는 위에서부터 r번째 칸&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;www.acmicpc.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[풀이]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 처음 읽었을 때 BFS를 통해 풀어야겠다고 생각했는데 그이유는 다음 두 가지다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;집과 치킨집 사이의 최단거리라는 워딩이 주어짐&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;주어지는 지도 정보가 2차원 배열 형태&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS로 풀기로 정하고 세운 계획은 다음과 같다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;지도 정보를 2차원 리스트에 저장한다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;모든 치킨집 좌표 중 M개만 선택하는 조합을 생성한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;지도 정보를 복사한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;조합을 사용하여 복사한 지도 정보에서 M개의 치킨집만 남기고 모두 제거한다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;복사한 지도를 선형으로 탐색하다가 집을 만나면 해당 집에서 부터 BFS를 수행하여 가장 가까운 치킨집을 찾고 그 거리가 치킨 거리가 된다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;모든 집들에 대해 치킨거리를 계산하여 그 합을 구하면 치킨집 중 M개를 선택한 조합 요소에 대한 치킨거리의 합이 된다.&lt;/li&gt;
&lt;li&gt;치킨집을 M개씩 선택한 모든 조합요소별로 치킨거리 합을 구하고 그 가운데 가장 작은 값을 구하면 우리가 얻고자 하는 답이 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세운 계획을 바탕으로 작성한 코드는 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1633565005100&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
from collections import deque
from itertools import combinations
from copy import deepcopy


def bfs(new_map_info, s_pos):
    # direction vectors: 상, 우, 하, 좌
    dy = [-1, 0, 1, 0]
    dx = [0, 1, 0, -1]
    max_idx = len(new_map_info) - 1

    # 새로운 집을 발견 할 때마다 큐와 방문내역을 초기화 한다.
    queue = deque(list())
    visited = [[0] * (N + 1) for _ in range(N + 1)]

    # 탐색 진입 점을 큐에 넣어준다.
    queue.append(s_pos)
    # 진입 지점 방문 처리
    visited[s_pos[0]][s_pos[1]] = 1

    # 큐가 비워질 때까지 혹은 치킨 집을 찾을 때까지 반복
    while queue:
        c_pos = queue.popleft()

        for i in range(4):
            n_pos = (c_pos[0] + dy[i], c_pos[1] + dx[i])
            if 0 &amp;lt; n_pos[0] &amp;lt;= max_idx and 0 &amp;lt; n_pos[1] &amp;lt;= max_idx:
                # 치킨 집이면 탐색 종료하고 마지막 방문 지점을 리턴
                if new_map_info[n_pos[0]][n_pos[1]] == 2:
                    return n_pos
                # 치킨집 못찾으면 계속 BFS 진행. 집이든 빈칸이든 가리지 않고 방문 처리
                visited[n_pos[0]][n_pos[1]] = 1
                queue.append(n_pos)


N, M = map(int, sys.stdin.readline().rstrip().split())
map_info = [[0] * (N + 1) for _ in range(N + 1)]
for i in range(1, N + 1):
    for j, m in enumerate(map(int, sys.stdin.readline().rstrip().split()), 1):
        map_info[i][j] = m

all_c_pos = set()  # All of chicken positions
for r in range(1, N + 1):
    for c in range(1, N + 1):
        if map_info[r][c] == 2:
            all_c_pos.add((r, c))

c_p_comb = combinations(all_c_pos, M)   # chicken position set by M

a_c_dists = []  # 치킨가게 조합 별로 각 집으로 부터의 치킨거리를 누적한 값들을 저장해 놓을 리스트
for el in c_p_comb:
    closed_c_pos = all_c_pos.difference(set(el))    # 폐점한 치킨 집
    new_map_info = deepcopy(map_info)

    for ccp in closed_c_pos:
        new_map_info[ccp[0]][ccp[1]] = 0    # 폐점한 치킨 집을 맵에서 제거

    acc_c_dist = 0    # 누적 치킨거리
    for r in range(1, N + 1):
        for c in range(1, N + 1):
            # 집을 찾아서 BFS로 최단거리의 치킨집을 탐색
            if new_map_info[r][c] == 1:
                chk_pos = bfs(new_map_info, (r, c))   # 치킨집 위치를 찾았다.
                # 현재위치를 고려하여 치킨거리를 구해서 누적 치킨거리에 더해준다.
                acc_c_dist += abs(r - chk_pos[0]) + abs(c - chk_pos[1])
    a_c_dists.append(acc_c_dist)

print(min(a_c_dists))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행결과 예시의 테스트 케이스는 잘 통과 했지만 제출 시 시간초과 판정을 받았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 위의 코드를 작성하면서 의아했던 것은 BFS를 돌면서 첫번 째 치킨집을 만날 때까지 카운트를 증가시키면 치킨거리를 구할 수 있는데 왜 집과 치킨집 사이의 거리를 구하는 공식을 명시적으로 알려줬을까 였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그에 대한 답은 문제에 있었는데 치킨 집은 13개 까지만 남길 수 있으므로 &amp;nbsp;13개의 치킨집과 모든 집의 좌표 간에 치킨거리를 완전탐색으로 계산해도 큰 무리가 없을 것으로 판단되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[개선]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BFS를 사용하지 않고 집과 치킨집 사이의 치킨거리를 완전탐색으로 구하여 문제를 해결하도록 해보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;주어진 맵정보에서 치킨집의 좌표들과 집의 좌표들을 각각 추출하도록 한다.&lt;/li&gt;
&lt;li&gt;치킨집 좌표에서 M개를 선택하는 조합을 만든다.&lt;/li&gt;
&lt;li&gt;각 조합 요소는 M개의 치킨집 좌표이다. 모든 조합요소들에 대해 다음의 로직을 실행한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 집에서 부터의 치킨거리를 확인한다.&lt;/li&gt;
&lt;li&gt;모든 집의 치킨거리를 합한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;3을 통해 구해진 조합 요소별 치킨거리 합 가운데 가장 작은 값이 구하고자 하는 답이 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 코드로 옮겨보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1633568056697&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys
from itertools import combinations as comb
f_input = sys.stdin.readline
# N: map size
# M: number of chicken joints
N, M = map(int, f_input().split())
cj_pos = set()
h_pos = set()
for r in range(1, N + 1):
    for c, map_info in enumerate(map(int, f_input().split()), 1):
        if map_info == 2:
            cj_pos.add((r, c))
        elif map_info == 1:
            h_pos.add((r, c))

ans = int(1e9)
for cj_comb in comb(cj_pos, M):
    c_dist = 0
    for h in h_pos:
        shortest_dist = int(1e9)
        for cj in cj_comb:
            if shortest_dist &amp;gt; abs(h[0] - cj[0]) + abs(h[1] - cj[1]):
                shortest_dist = abs(h[0] - cj[0]) + abs(h[1] - cj[1])
        c_dist += shortest_dist
    if ans &amp;gt; c_dist:
        ans = c_dist

print(ans)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항상 느끼는 것인데, 문제를 풀 때는 절대 기계적으로 접근하면 안된다. 입력과 실행되는 로직을 통해 대략적인 시간복잡도를 생각하면서 풀어야 효율적으로 풀 수 있다.&lt;/p&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/141</guid>
      <comments>https://camel-it.tistory.com/141#entry141comment</comments>
      <pubDate>Thu, 7 Oct 2021 09:56:14 +0900</pubDate>
    </item>
    <item>
      <title>Python 실행속도 개선 방법</title>
      <link>https://camel-it.tistory.com/140</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;python 코드 최적화와 관련한 좋은 포스팅을 발견하여 참고를 위해 번역하여 정리해 놓는다. (&lt;a href=&quot;https://towardsdatascience.com/10-techniques-to-speed-up-python-runtime-95e213e925dc&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://towardsdatascience.com/10-techniques-to-speed-up-python-runtime-95e213e925dc&lt;/a&gt;)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;[최적화에 앞서 고려할 부분]&lt;/b&gt;&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;정상적으로 작동하는 명확하고 가독성 좋은 코드를 작성하는 것이 최적화의 전제조건이다. 명확하고 가독성 좋은 코드의 속도를 개선하는 것이 이해하기 어렵고 가독성 좋지 않은 코드를 개선하는 것보다 훨씬 쉽기 때문이다.&lt;/li&gt;
&lt;li&gt;최적화는 비용을 수반한다. 대체로 시간복잡도와 공간복잡도는 반비례 관계가 된다. 실행시간을 줄이기 위해서는 메모리를 더 사용하게 되고 메모리 사용을 줄이고자 하면 실행시간이 늘어날 수밖에 없다.&lt;/li&gt;
&lt;li&gt;코드 작성의 우선순위는 최적화 보다 가독성을 확보하는데 둔다. 최적화를 위해 코드의 가독성을 떨어트려서는 안 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 적절한 자료구조의 사용&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.1&lt;/b&gt; in 연산을 사용하여 특정 데이터가 자료구조 안에 있는지 찾고자 할 때 적합한 자료구조는 set이다. list에서 자료를 찾는데 필요한 시간 복잡도는 O(n)이지만 set에서 자료를 찾는 데는 O(1) 밖에 소요되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1.2&lt;/b&gt;&amp;nbsp;딕셔너리를 사용할 때는 데이터 초기화 작업이 dict 보다 빠른 defaultdict를 사용하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2. 리스트컴프리핸션을 제네레이터 표현으로 대체한다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제너레이터 표현식은 이터레이터를 메모리에 저장하지 않고 결과를 얻을 수 있어 공간 복잡도를 줄이는 효과도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633335541985&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import sys

# 리스트 컴프리핸션 (bad)
nums_sum_list_comprehension = sum([num ** 2 for num in range(1000000)])

# 제네레이터 표현식 (good)
nums_sum_generator_expression = sum((num ** 2 for num in range(10000000)))

# Bad
nums_squared_list = [num ** 2 for num in range(1000000)]
print(sys.getsizeof(nums_squared_list))  # 87632

# Good
nums_squared_generator = (num ** 2 for num in range(1000000))
print(sys.getsizeof(nums_squared_generator))  # 128&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;3. 글로벌 변수는 로컬 변수로 대체한다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;글로벌 변수의 사용은 시스템의 심각한 오류를 야기할 수 있으며, 실행 속도 또한 로컬 변수에 비해 느리므로 불가피한 경우가 아니라면 로컬변수로 사용하도록 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4. dot 연산을 피한다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.1&lt;/b&gt; import한 라이브러리 가운데 코드에서 자주 쓰이는 function의 경우는 from {라이브러리명} import {함수명}과 같이 직접적으로 함수까지 지정하여 dot 연산을 피할 수 있다. 이렇게 하면 매번 dot 연산 시에 호출되는 __getattribute__()나 __getattr__() 호출을 막아 실행 시간을 줄일 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633336635242&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import math
from sys import stdin as ss
r_line = ss.readline
s = r_line()
print(s)

sqrt = math.sqrt
print(sqrt(4))&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;4.2&lt;/b&gt; 클래스 프로퍼티를 위해 사용하는 dot 연산 역시 위와 같은 맥락이다. 사용을 최소화할수록 속도가 올라간다.&lt;/p&gt;
&lt;pre id=&quot;code_1633337122969&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 개선 전
class Car:
    def __init__(self, seq, run_dist):
        self.seq = seq
        self.run_dist = run_dist
     
    def add_run_dist():
        for _ in range(100000):
            self.run_dist += 1	# 매번 dot 연산을 통해 클래스 속성에 접근&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1633337286325&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 개선 후
class Car:
    def __init__(self, seq, run_dist):
        self.seq = seq
        self.run_dist = run_dist
     
    def add_run_dist():
        r_dist = self.run_dist
        for _ in range(100000):
            r_dist += 1	# 매번 dot 연산을 통해 클래스 속성에 접근
        self.run_dist = r_dist&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;5. 불필요한 추상화를 피한다.&amp;nbsp;&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 코드들을 하나로 묶기 위해 사용되는 데코레이터, 클래스 속성 접근, 디스크립터 등도 코드의 실행속도를 저하시킬 수 있다. 대부분의 경우에서 추상화가 필요한지 다시 한번 생각해볼 필요가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬은 C/C++ 프로그래머들이 클래스 속성에 접근하기 위해 사용하는 getter/setter 스타일보다 더 간단한 문법을 제공한다.&lt;/p&gt;
&lt;pre id=&quot;code_1633337679034&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Bad: 559ms
class DemoClass:
    def __init__(self, value: int):
        self.value = value

    @property
    def value(self) -&amp;gt; int:
        return self._value

    @value.setter
    def value(self, x: int):
        self._value = x

def main():
    size = 1000000
    for i in range(size):
        demo_instance = DemoClass(size)
        value = demo_instance.value
        demo_instance.value = i

main()&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1633337701291&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 318ms
class DemoClass:
    def __init__(self, value: int):
        self.value = value  ###

def main():
    size = 1000000
    for i in range(size):
        demo_instance = DemoClass(size)
        value = demo_instance.value
        demo_instance.value = i

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;6. 데이터 중복을 피한다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.1&lt;/b&gt; 의미 없는 데이터 복사를 피한다.&lt;/p&gt;
&lt;pre id=&quot;code_1633337808824&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Bad: 8.27s
def main():
    size = 10000
    for _ in range(size):
        value = range(size)
        value_list = [x for x in value]  ###
        square_list = [x * x for x in value_list]  ###

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드에서 value_list는 의미가 없다. 따라서 다음과 같이 코드를 수정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633337848482&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 6.01s
def main():
    size = 10000
    for _ in range(size):
        value = range(size)
        square_list = [x * x for x in value]  ###

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.2&lt;/b&gt; 두 변수 값 swap 시 temp 변수는 필요하지 않다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대부분의 다른 언어들과 다르게 파이썬에서는 두 변수 간 데이터 swap은 다음과 같이 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1633338054399&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;a = 10
b = 15
a, b = b, a
print(f'a={a}, b={b}')&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;6.3&lt;/b&gt; 문자열을 붙일 때는 + 연산 대신 join()을 사용한다.&lt;/p&gt;
&lt;pre id=&quot;code_1633338133228&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Bad: 4.29s
import string
from typing import List

def concatString(string_list: List[str]) -&amp;gt; str:
    result = ''
    for str_i in string_list:
        result += str_i  ###
    return result

def main():
    string_list = list(string.ascii_letters * 100)
    for _ in range(10000):
        result = concatString(string_list)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이썬의 str 타입 객체는 그 내용을 변경할 수 없는 객체이기 때문에 두 str 타입의 객체를 + 연산하는 경우 각각의 문자열을 새로운 메모리 공간에 복사하여 작업을 수행하게 된다. join()을 사용하게 되면 문자열 병합에 필요한 총 메모리 공간을 미리 계산한 뒤 필요한 메모리를 확보 후 해당 공간에 각각의 문자열을 복사하여 실행시간을 줄일 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633338524036&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 326ms
import string
from typing import List

def concatString(string_list: List[str]) -&amp;gt; str:
    return ''.join(string_list)  ###

def main():
    string_list = list(string.ascii_letters * 100)
    for _ in range(10000):
        result = concatString(string_list)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;7. if문에 두 개 이상의 조건이 주어질 때 각 조건들 사이에 &amp;nbsp;논리연산자에 따라 조건의 순서를 변경해준다.&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;if condition1 and condition2: condition 간에 논리 연산이 and 인 경우 condition 중에 False 값을 많이 가진 condition을 condition1에 오도록 하면 뒤 따라오는 condition2에 대한 확인 작업을 피할 수 있다.&lt;/li&gt;
&lt;li&gt;if condition1 or condition2: condition 간에 or 연산이 적용된 경우 condition 중에 True 값을 많이 가진 condition을 condition1에 오도록 하면 뒤따라오는 condition2에 대한 확인 작업을 피할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;8. 반복문 최적화&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.1&lt;/b&gt; while 문은 for 문으로 대체한다.&lt;/p&gt;
&lt;pre id=&quot;code_1653347639729&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Bad: 8.70s
def computeSum(size: int) -&amp;gt; int:
    sum_ = 0
    i = 0
    while i &amp;lt; size:
        sum_ += i
        i += 1
    return sum_

def main():
    size = 10000
    for _ in range(size):
        sum_ = computeSum(size)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;for문이 while문 보다 빠르게 실행된다. 반복문의 실행 도중에 반복문의 종료 조건을 계산하는 경우가 아니라면 for 문을 사용하도록 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1653347661900&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 4.91s
def computeSum(size: int) -&amp;gt; int:
    sum_ = 0
    for i in range(size):  ### explicit for loop
        sum_ += i
    return sum_

def main():
    size = 10000
    for _ in range(size):
        sum_ = computeSum(size)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.2&lt;/b&gt; 명시적 for문은 암시적 for문으로 변경한다. 즉, 직접 인덱싱 하지 않고 이터레이션을 사용하여 반복문에서 사용할 요소에 접근한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 explicit for loop 코드를 implict for loop로 변경하여 성능을 개선한다.&lt;/p&gt;
&lt;pre id=&quot;code_1633339475566&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 1.60s
def computeSum(size: int) -&amp;gt; int:
    return sum(range(size))  ### implicit for loop

def main():
    size = 10000
    for _ in range(size):
        sum = computeSum(size)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8.3&lt;/b&gt; 반복문 내부의 연산을 줄인다.&lt;/p&gt;
&lt;pre id=&quot;code_1633339654152&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Bad: 13.2s
import math

def main():
    size = 10000
    sqrt = math.sqrt
    for x in range(size):
        for y in range(size):
            z = sqrt(x) + sqrt(y)  ###

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예를 보면 이중 반복문 안에서 가장 안쪽에 sqrt()를 두 번 사용하고 있다. sqrt() 호출 중 x에 해당하는 것을 첫 번째 for문의 scope로 옮겨주는 것으로 실행 속도를 개선할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633339670002&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 4.91s
import math

def main():
    size = 10000
    sqrt = math.sqrt
    for x in range(size):
        sqrt_x = sqrt(x)  ### 
        for y in range(size):
            z = sqrt_x + sqrt(y)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;9. numba.jit를 사용한다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;numba는 파이썬 코드를 실행할 수 있는 기계어 코드로 실시간 변환해준다. 이를 통해 코드의 실행 속도를 크게 개선할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1633340035426&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Bad: 5.95s
def computeSum(size: float) -&amp;gt; int:
    sum = 0
    for i in range(size):
        sum += i
    return sum

def main():
    size = 10000
    for _ in range(size):
        sum = computeSum(size)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드 실행하기 전에 numba를 import 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1633340061302&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Good: 2.27s
import numba

@numba.jit
def computeSum(size: float) -&amp;gt; int:
    sum = 0
    for i in range(size):
        sum += i
    return sum

def main():
    size = 10000
    for _ in range(size):
        sum = computeSum(size)

main()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;10. cProfile 모듈을 사용하여 함수의 실행 시간을 확인할 수 있다.&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cProfile.run()은 지정된 함수의 실행 시간을 출력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1653348981246&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import cProfile

def computeSum(size: int) -&amp;gt; int:
    return sum(range(size)) 

def main():
    size = 10000
    for _ in range(size):
        sum = computeSum(size)

if __name__ == &quot;__main__&quot;:
    cProfile.run(&quot;main()&quot;)
    
# Output
&quot;&quot;&quot;
         20004 function calls in 1.467 seconds
   Ordered by: standard name
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
    10000    0.005    0.000    1.464    0.000 &amp;lt;stdin&amp;gt;:1(computeSum)
        1    0.002    0.002    1.467    1.467 &amp;lt;stdin&amp;gt;:1(main)
        1    0.000    0.000    1.467    1.467 &amp;lt;string&amp;gt;:1(&amp;lt;module&amp;gt;)
        1    0.000    0.000    1.467    1.467 {built-in method builtins.exec}
    10000    1.459    0.000    1.459    0.000 {built-in method builtins.sum}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
&quot;&quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 코드 구간에 대한 실행시간을 확인할 경우는 &lt;a href=&quot;https://camel-it.tistory.com/97&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://camel-it.tistory.com/97&lt;/a&gt;&amp;nbsp;를 참고&lt;/p&gt;</description>
      <category>Python</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/140</guid>
      <comments>https://camel-it.tistory.com/140#entry140comment</comments>
      <pubDate>Mon, 4 Oct 2021 18:38:20 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 디스크 컨트롤러</title>
      <link>https://camel-it.tistory.com/139</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1632785485412&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 디스크 컨트롤러&quot; data-og-description=&quot;하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다. 예를&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42627#&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42627&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bYjrFT/hyLKiVgq0h/uVfrChjIK8RuSvVp20R9KK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/bu58pB/hyLKjmj7hV/QLpDJZ2LLYLCYGHHHERlNK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/42627#&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42627#&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bYjrFT/hyLKiVgq0h/uVfrChjIK8RuSvVp20R9KK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/bu58pB/hyLKjmj7hV/QLpDJZ2LLYLCYGHHHERlNK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 디스크 컨트롤러&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;하드디스크는 한 번에 하나의 작업만 수행할 수 있습니다. 디스크 컨트롤러를 구현하는 방법은 여러 가지가 있습니다. 가장 일반적인 방법은 요청이 들어온 순서대로 처리하는 것입니다. 예를&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[풀이]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 해결을 위해 가장 짧은 실행 시간을 얻어내도록 job 실행 순서를 스케쥴링 해야한다. 스케쥴링에는 다음 두 가지를 고려한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;요구사항 가운데 먼저 요청된 job이 먼저 실행된다가 있으므로 job 수행 순서를 결정하는 첫 번째 &amp;nbsp;기준은 &quot;요청시각&quot;이다.&lt;/li&gt;
&lt;li&gt;두 번째 기준은 실행시간인데, 이 &quot;실행시간&quot;이 heap을 통해 스케쥴링할 대상이다. 실행시간을 기준으로 스케쥴링을 하는 이유는 하나의 job도 실행되고 있지 않는 상태에서는 가장 빨리 도래하는 요청 건을 처리하면 되지만 어떤 job이 실행되고 있는 상태에서 여러 건의 요청이 들어온다고 한다면 그중 가장 짧은 실행 시간의 job부터 실행해야 나머지 요청 job들의 대기 시간이 줄어들어 결과적으로 총 실행 시간을 줄일 수 있기 때문이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 간단히 말하면 &lt;b&gt;요청 순서대로 정렬하여 처리하되 pendding 된 job들이 있는 경우 heap을 사용하여 그 job들을 수행시간을 오름차순으로 정렬하여 가장 수행시간이 짧은 job부터 연속적으로 수행되도록 하는 것이 이 문제의 골자이다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제를 해결하기 위해서 각 job의 수행 시간을 구해서 누적해야 하는데, 다음 두 가지 경우를 고려하여 job의 실행 시간을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 처리 중인 job이 있는 상태에서 요청이 들어오면 요청된 job은 현재 처리 중인 job이 완료된 직후에 실행된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 경우 요청된 job의 실행 시간은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요청 job의 실행 시간 = 현재 job의 완료 시각 + 요청 job의 수행 시간 - 요청 job의 요청 시각&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수행되는 job이 하나도 없는 상태에서 새로운 요청이 있다면 요청된 job의 실행 시간은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;요청 job의 실행 시간 = 요청 job의 요청 시각 + 요청 job의 수행시간&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 바탕으로 본 문제를 해결하기 위한 의사 코드를 작성하면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1632787650266&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# 첫번 째 정렬 기준 요청시각, 두번 째 정렬 기준 수행시간 으로 정렬
# 데이터를 수행시간, 요청시각으로 변경한 이유는 heap에서 수행시간을 기준으로 정렬해야 하기 때문임.
queue = sort([(수행시간, 요청시각), ...])

# 가장 먼저 시작되는 가장 짧은 수행시간의 job을 heap에 넣는다.
heap.push(queue.pop())

현재_job_종료시각 = 0
총_실행_시간 = 0

# heap에 내용이 있다는 것은 처리할 job이 있다는 뜻이므로
while heap is not empty:
    job_info = heap.pop()	# 실행 시간을 확인해야 할 job
    job_수행시간 = job_info[0]
    job_요청시각 = job_info[1]
    현재_job_종료시각 = max(현재_job_종료시각 + job_수행시간, job_요청시각 + job_수행시간)
    총 실행 시간 = 총 실행 시간 + 현재_job_종료시각 - job_요청시각

    # 실행 중인 job이 있어 pendding된 job들이 있는 경우
    while queue가 비어있지 않고 다음 요청 job의 요청 시각이 현재_job_종료 시각보다 앞에 오는 모든 경우:
    	heap.push(다음 요청 job 들)
    # 실행 중인 job이 하나도 없는 경우
    if queue가 비어있지 않고 heap에 내용이 없는 경우:
        heap.push(다음 요청 job)

answer = 총_실행_시간을 jobs의 길이로 나눈 몫&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;의사 코드를 바탕으로 python으로 구현해보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1632788940195&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import heapq
from collections import deque

def solution(jobs):
    jobs_q = deque(sorted([(job[1], job[0]) for job in jobs], key=lambda x:(x[1], x[0])))
    
    heap = list()
    heapq.heappush(heap, jobs_q.popleft())
    e_time = 0
    t_time = 0
    
    while heap:
        job_inf = heapq.heappop(heap)
        p_time = job_inf[0]
        r_time = job_inf[1]
		
        e_time = max(e_time + p_time, r_time + p_time)
        t_time += e_time - r_time
        
        while jobs_q and jobs_q[0][1] &amp;lt; e_time:
            heapq.heappush(heap, jobs_q.popleft())
        
        if jobs_q and not heap:
            heapq.heappush(heap, jobs_q.popleft())
            
    return t_time // len(jobs)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/139</guid>
      <comments>https://camel-it.tistory.com/139#entry139comment</comments>
      <pubDate>Tue, 28 Sep 2021 09:30:20 +0900</pubDate>
    </item>
    <item>
      <title>[프로그래머스] 위장</title>
      <link>https://camel-it.tistory.com/137</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[문제]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;figure id=&quot;og_1631261282517&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 위장&quot; data-og-description=&quot;&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42578&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42578&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iFcbm/hyLySOvi0E/73iolc1PF0bnXtNzsRzqDK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/czeRvg/hyLyTzSY5O/WrKY4Xk2zOlSzq0Lktz4D0/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/42578&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/42578&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iFcbm/hyLySOvi0E/73iolc1PF0bnXtNzsRzqDK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/czeRvg/hyLyTzSY5O/WrKY4Xk2zOlSzq0Lktz4D0/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 위장&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[풀이]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-시행착오-&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코테 때와는 다르게 어떤 타입의 문제인지 미리 알 수 있는 상태였고 hash 유형이니까 별생각 없이 주어진 clothes 리스트를 가공하여 {의상 종류: 의상 이름} 형태로 딕셔너리를 만들어 놓고 풀어가려고 시도했던 것이 화근이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 생각없이 딕셔너리부터 만들어 놓은 뒤에 진행된 사고의 흐름은 다음과 같았다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;적어도 하나의 의상은 입어야 한다는 제한사항이 있네!&lt;/li&gt;
&lt;li&gt;특정 의상 타입 가운데 하나의 의상을 선택해 시작 의상으로 설정하고 나머지 타입들에 해당하는 의상을 넣거나 넣지 않거나 해서 의상 요소들을 저장하면서 중복된 의상들의 경우는 제거하면 ([파랑 안경, 검정 티, 빨강바지]와 [검정 티, 빨강바지, 파랑 안경]은 순서는 바뀌었지만 동일한 요소로 간주하여 하나만 남기도록 처리)&lt;/li&gt;
&lt;li&gt;마지막에 남은 요소들의 갯수가 정답이 되겠다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 로직에서 2번 과정을 수행하기 위해 딕셔너리의 모든 요소들 간에 product 연산을 했는데 이는 시간복잡도를 많이 높이는 원인이 되었으며 중복 원소를 제거하는 로직 수행 과정 중에 데이터를 tuple -&amp;gt; list -&amp;gt; tuple 형태로 변환한다거나 하는 비효율 적인 알고리즘이 되고 말았다. 통상 해시 알고리즘을 사용하는 경우는 효율성을 테스트하기 위해 시간복잡도 제한이 엄격하게 걸리는 경우가 많은걸 생각해볼 때 상당히 좋지 않은 알고리즘이 작성된 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부끄럽지만 다시는 같은 실수를 반복하지 않기위해 위의 로직을 박제해 놓는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 것은 큰 낭패를 볼 수 있으므로 절대 &lt;span style=&quot;color: #ef5369;&quot;&gt;짐작하여 데이터를 미리 가공해 놓으면 안된다&lt;/span&gt;는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반드시 차분히 요구사항과 입출력을 분석하여 알고리즘의 뼈대가 잡혔을 때 구현을 시작해야한다.&lt;/p&gt;
&lt;pre id=&quot;code_1631269559708&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from itertools import product


def solution_fail(clothes):
    answer = 0
    clothes_dict = dict()
    for c in clothes:
        try:
            temp_cloths = clothes_dict[c[1]]
            clothes_dict.setdefault(c[1], temp_cloths.append(c[0]))
        except KeyError:
            clothes_dict.setdefault(c[1], [c[0]])
    # print(clothes_dict)
    all_clothes = []
    clothes_set = set()
    for key in clothes_dict.keys():
        all_clothes.clear()
        another_keys = []
        for k in clothes_dict.keys():
            another_keys.append(k)
        another_keys.remove(key)

        # 현재 key에 해당하는 복장의 리스트를 생성한다.
        all_clothes.append(clothes_dict[key])

        # 다른 key들에 해당하는 복장의 리스트 들을 생성하되 공백 요소를 포함하여 생성한다.
        for another_key in another_keys:
            another_clothes = clothes_dict[another_key]
            another_clothes.append('')
            all_clothes.append(another_clothes)

        try:
            all_clothes[0].remove('')
        except:
            pass

        for elem in product(*all_clothes):
            elem = list(elem)
            elem.sort()
            elem = tuple(elem)
            clothes_set.add(elem)
    try:
        clothes_set.remove(('', '', ''))
    except KeyError:
        pass
    return len(clothes_set)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-재도전-&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 의상이 주어진다고 해보자.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;의상 종류&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;의상 이름&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;모자&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;야구모자, 중절모&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;안경&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;뿔테안경, 금테안경&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;신발&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;운동화, 구두&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 의상 종류별 의상 수를 CC라 하자&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;먼저 생각해야 할 중요한 점은 의상을 선택하지 않을 수도 있다는 점이다. 즉, 야구모자를 선택했지만 안경과 신발은 착용하지 않을 수도 있다. 따라서 각 의상 종류별로 CC에 해당 의상 종류가 선택되지 않을 수 있는 경우의 수를 고려해 1을 더해준다.&lt;/li&gt;
&lt;li&gt;의상 종류별로 착용하는 것은 동시에 일어나는 사건이므로 각 종류의 CC를 모두 곱 연산해준다.&lt;/li&gt;
&lt;li&gt;마지막으로 주의할 점은 의상 종류 가운데 반드시 한 종류 이상은 착용해야 한다. 모두 착용하지 않는 경우의 수는 1가지뿐이다. 따라서 전체 경우의 수에서 모두 착용하지 않는 경우의 수 1을 빼준다.&amp;nbsp;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 로직을 코드로 옮기면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1631269333124&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def solution(clothes):
    cloths_type = dict()

    # 각 의상 종류 별로 의상 수의 초기값을 1로 설정해 딕셔너리를 생성한다..
    # 초기값이 1인 이유는 각 의상 종류 별로 착용하지 않는 경우의 수가 있기 때문이다.
    for cloths in clothes:
        cloths_type.setdefault(cloths[1], 1)

    # 각 의상 종류 별로 의상 수를 더해준다.
    for cloths in clothes:
        temp_val = cloths_type[cloths[1]] + 1
        cloths_type[cloths[1]] = temp_val

    # 모든 의상 종류별로 동시에 착용 수있는 경우의 수를 구하는 것이므로 곱연산을 진행한다.
    result = 1
    for val in cloths_type.values():
        result *= val

    # 모든 경우에서 의상을 하나도 착용하지 않은 경우를 빼고 리턴한다.
    return result - 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;color: #953b34;&quot;&gt;&lt;b&gt;[개선]&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;python에서 hash가 필요할 때 강력하게 사용할 수 있는 것이 collections 패키지의 Counter 함수이다. Counter 함수는 ierable 객체를 인수로 받아 각 원소별로 갯수를 카운팅하여 Counter&amp;nbsp;객체로 반환해준다. Counter 객체는 dict의 서브타입으로 딕셔너리와 동일하게 key로 value(갯수)를 접근할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1631446897608&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import Counter


def solution(clothes):
    # Counter를 사용해서 의상 종류별 의상 수를 파악한다.
    cnt_by_cloths = Counter((cloths[1] for cloths in clothes))

    # 모든 의상 종류별로 동시에 착용 수 있는 경우의 수를 구하는 것이므로 곱연산을 진행한다.
    # 이 때 의상을 입지 않는 경우도 있으므로 각 의상 타입별로 (의상 수 + 1) 하여 곱연산 한다.
    ans = 1
    for key in cnt_by_cloths:
        ans *= cnt_by_cloths[key] + 1

    # 모든 경우에서 의상을 하나도 착용하지 않은 경우를 빼고 리턴한다.
    return ans - 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이와 같이 hash가 필요할 때 Counter를 사용하면 가독성 좋은 코드를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음과 같이 collections.defaultdict()를 사용하여 &amp;nbsp;풀 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1631575845887&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;from collections import defaultdict


def solution(clothes):
    clothes_dict = defaultdict(lambda: 1)
    for c in clothes:
        clothes_dict[c[1]] += 1
    
    # 동시 사건에 대한 경우의 수 = 곱연산.
    ans = 1
    for key in clothes_dict:
        ans *= clothes_dict[key]
    
    return ans - 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;defaultdict는 존재하지 않는 키에 접근할 경우 &lt;b&gt;키: 미리 설정된 초기값&lt;/b&gt; 으로 딕셔너리 요소를 추가해주므로 일반 딕셔너리에 비해 편리하게 사용할 수 있다.&lt;/p&gt;</description>
      <category>Data Structure &amp;amp; Algorithm</category>
      <author>낙타선생</author>
      <guid isPermaLink="true">https://camel-it.tistory.com/137</guid>
      <comments>https://camel-it.tistory.com/137#entry137comment</comments>
      <pubDate>Fri, 10 Sep 2021 17:22:18 +0900</pubDate>
    </item>
  </channel>
</rss>