<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>바위타는 두루미</title>
    <link>https://doromi.tistory.com/</link>
    <description>바위타는 개발자 두루미의 일상입니다.</description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 20:13:30 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>DoRoMii</managingEditor>
    <image>
      <title>바위타는 두루미</title>
      <url>https://tistory1.daumcdn.net/tistory/2833543/attach/d2c0b33a02824c7183db92ab100531df</url>
      <link>https://doromi.tistory.com</link>
    </image>
    <item>
      <title>[CleanCode]10.클래스</title>
      <link>https://doromi.tistory.com/123</link>
      <description>&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;&amp;nbsp; - 자바의 경우 정적공개상수 -&amp;gt; 정적 비공개상수 -&amp;gt;비공개 인스턴스변수 ( 공개 변수가 필요한 경우는 거의 없음 ) 순으로 나오고&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 변수 다음에는 공개함수, 비공개함수는 자신을 호출하는 공개 함수 직후에 넣는다.&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; &amp;nbsp;- 변수와 유틸함수는 공개하지 않는 편이 낫지만, protected로 선언해 테스트 코드에 접근을 허용하기도함.&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; - 얼마나 작아야하는가 ? -&amp;gt; 클래스가 맡은 책임을 센다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 클래스 이름은 그 클래스의 책임을 기술해야하고 간결해야한다 ( 책임의 크기가 작도록 )&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;nbsp; SRP (단일 책임 원칙)은 클래스나 모듈을 변경할 이유가 하나뿐이어야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;nbsp; 큰 클래스 몇개가 아니라 작은 클래스 여럿으로 이루어진 시스템이 바람직하다.&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; - 일반적으로 메서드가 변수를 더 많이 사용할 수록 메서드와 클래스의 응집도가 높다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;nbsp; 때떄로 몇몇 메서드만이 사용하는 인스턴스 변수가 많아지면 -&amp;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; - SRP 뿐만아니라 OCP(Open-closed&amp;nbsp; Principle )도 지원해야한다. : 확장에 개방적이고 수정에 폐쇄적&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 새 기능을 수정하거나 변경할때 건드릴 코드가 최소인 시스템이 바람직하다.&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; - 상세한 구현에 의존하는 코드는 테스트가 어렵다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 시스템의 결합도를 낮추면 유연성과 재사용성도 높아진다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 결합도가 낮다는 것은 각 시스템 요소가 다른 요소로부터 그리고 변경으로부터 잘 격리되어있다는 의미다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 결합도를 낮추면 DIP(Dependency Inversion Principle)을 따르는 클래스가 나온다. : 상세 구현 보다추상화에 의존하자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;</description>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/123</guid>
      <comments>https://doromi.tistory.com/123#entry123comment</comments>
      <pubDate>Thu, 10 Mar 2022 01:38:39 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode]9.단위테스트</title>
      <link>https://doromi.tistory.com/122</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;TDD 법칙 세가지&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;1. 실패하는 단위 테스트를 작성할 때까지 실제 코드를 작성하지 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 컴파일은 실패하지 않으면서 실행이 실패하는 정도로만 단위테스트를 작성한다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 현재 실패하는 테스트를 통과할 정도만 실제 코드를 작성한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=&amp;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;&amp;nbsp; - 지저분한 테스트 코드일수록 실제 코드가 변경할때 함께 변화하기 어렵다.&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; - 이를위해서는 단위테스트가 필요하다. 단위테스트가 없다면 수정이 두렵다.&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; - &quot;가독성&quot;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 테스트는 명확히 세부분으로 나뉨 : 테스트자료를 만들기 -&amp;gt; 테스트자료 조작하기 -&amp;gt; 결과가 올바른지 확인하기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 테스트에 적용하는 표준은 실제코드에 적용하는 표준과 달라도된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 실제코드만큼 효율적일 필요는 없다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트당 assert 하나!&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 가혹하다 느낄 수 있지만, 결론이 하나이기 때문에 코드를 이해하기 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 즉, 테스트 함수마다 한 개념만 테스트하라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;F.I.R.S.T&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - Fast : 테스트는 빨라야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - Independent : 각 테스트는 의존성이 없어야한다. 어떤 순서로 실행해도 괜찮아야 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - Repeatable : 어떤 환경에서도 반복 가능하도록! 네트워크 없는 환경에서도 !&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - Self-Validating :&amp;nbsp; 테스트는 bool로 결과를 내서 스스로 성공과 실패를 가늠하도록 해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - Timely :&amp;nbsp; 적시에, 즉 테스트하려는 실제 코드를 구현하기 직전에 구현한다.&amp;nbsp;&lt;/p&gt;</description>
      <category>book</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/122</guid>
      <comments>https://doromi.tistory.com/122#entry122comment</comments>
      <pubDate>Sun, 6 Mar 2022 00:00:27 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode]7.오류처리</title>
      <link>https://doromi.tistory.com/121</link>
      <description>&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;- Try-Catch-Finally 문부터 작성하라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 강제로 예외를 일으키는 테스트 케이스를 작성한 후 테스트를 통과하게 코드를 작성하는 방법을 권장한다.&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; 확인된 예외는 OCP를 위반한다. 하위단계에서 코드를 변경하면 상위단계 메서드 선언부를 전부 고쳐야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 아주 중요한 라이브러리를 작성한다면 확인된 예외를 이용해 모든 예외를 잡아야하지만, 일반적인 어플리케이션은 의존성이라는 비용이&amp;nbsp; &amp;nbsp; &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; -예외를 던질때에는 정보를 담아 예외와 함께 던지자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 실패한 연산 이름과 실패 유형도 언급한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - logging을 사용한다면 catch블록에서 오류를 기록하도록 정보를 넘겨준다.&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; &amp;nbsp;- 오류를 분류할때 가장 중요한 관심사는 오류를 잡아내는 방법&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 외부라이브러리의 예외를 설정할때&amp;nbsp; 감싸는 class는 매우 유용하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - 외부 라이브러리에 대한 의존성이 줄어든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; - 예외 클레스가 한개만 있어도 충분한 코드가 많다.&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;- null을 반환하지 마라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - null을 반환하면 null체크 누락시 큰 문제가 발생한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - null을 반환하고 싶다면 예외를 던지거나 특수사례 객체를 반환하도록 하자.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- null을 전달하지 마라.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- null을 전달할 가능성이 있으면 애초에 넘기지 못하도록 정책을 만드는게 나을 수 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- exception class를 만든다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- assert를 이용한다.&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;</description>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/121</guid>
      <comments>https://doromi.tistory.com/121#entry121comment</comments>
      <pubDate>Thu, 3 Mar 2022 23:06:13 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode]6.객체와 자료구조</title>
      <link>https://doromi.tistory.com/120</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 get, set함수를 만들어 변수를 다룬다고 class가 아니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그보다는 추상 인터페이스를 이용해 사용자가 구현을 모른 채 자료의 핵심을 조작할 수 있어야 진정한 의미의 class이다.&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;객체 vs 자료구조&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 자료구조를 사용코드 : 자료구조 변경없이 새 함수를 추가하기 쉽다. | 함수 변경없이 새로운 자료구조 추가하기 어렵다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 객체지향 코드 : 함수 변경없이 class 추가하기 쉽다. | class변경없이 새로운 함수 추가하기 어렵다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 분별있는 프로그래머는 모든 것이 객체라는 생각이 미신임을 잘 안다. 때로는 단순한 자료구조와 절차적인 코드가 적합한 상황이 있다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;디미터 법칙&lt;/b&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;gt; 모듈은 자신이 조작하는 객체의 속사정을 몰라야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 클레스 C의 메서드 f는 다음과 같은 객체의 메서드만 호출해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;( Class C, f가 생성한 객체,&amp;nbsp; f인수로 들어온 객체, C인스턴스 변수에 저장된 객체 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; ex) final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath() =&amp;gt; (X)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;=&amp;gt; 위와 같은 코드를 기차충돌이라고 부른다. 피하는편이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;Option opts = ctxt.getOptions();&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;File scratchDir = opts.getScratchDir();&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;final String outputDir = scratchDir.getAbsolutePath();&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;=&amp;gt;&amp;nbsp; 이렇게 나누는 편이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 하지만 ctxt, Options, ScratchDir이 객체라면 내부구조를 숨겨야 하므로 디미터 규칙을 위반한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;자료구조라면 디미터 법칙이 적용되지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 조회함수를 사용하는 바람에 혼란을 일으킨다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; fianl String outputDir = ctxt.options.scratchDir.absolutePath;&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; 반은 객체, 반은 자료구조인 잡종 구조가 나온다. 이러한 잡종구조는 함수는 물론 새로운 자료구조도 추가하기 어렵다. 따라서 피해야한다. - 구조체 감추기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;만약 ctxt, options, scratchDir이 모두 객체라면 outputDir 경로는 어떻게 얻어야 할까&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;ctxt가 객체라면 뭔가를 하라고 말해야지, 속을 드러내면 안된다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;ctxt에게 임시 파일을 생성하라고 말하자 ctxt.crateScratchFileStream(classFileName)이런식으로&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;&amp;nbsp;- 자료구조체 : 공개 변수만 있고 함수가 없는 클레스 =&amp;gt; Data Transfer Object (DTO) 라고 하기도 함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- Bean 구조 : 비공개 변수를 조회/설정 함수로 조작한다. =&amp;gt; 특별한 이익을 제공하진 않는다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 활성 레코드 : 공개 변수가 있거나 비공개 변수에 조회/설정 함수가 있지만, save나 find같은 탐색함수도 제공한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 활성 레코드에 비즈니스 코드를 추가하는 경우가 있지만, 이는 바람직하지 않음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>book</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/120</guid>
      <comments>https://doromi.tistory.com/120#entry120comment</comments>
      <pubDate>Wed, 2 Mar 2022 01:19:08 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode] 5. 형식맞추기</title>
      <link>https://doromi.tistory.com/119</link>
      <description>&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;좋은 형식은 무엇일까?&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;&amp;nbsp; - 큰 파일보다 작은 파일이 이해하기 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 신문기사처럼 작성하라 : 상단은 고차원 , 하단으로 갈수록 저차원 (세부구현)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 개념은 빈 행으로 분리하라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 수직거리 : 밀접한개념은 세로로 가까이 두어야한다.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 변수는 사용하는 위치에 최대한 가까이 선언한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 인스턴스 변수는 모아라 : 자바는 상단에, c++는 하단에 선언하는 편&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 종속함수 : 함수가 다른함수를 호출한다면 두 함수는 세로로 가까이, 가능하다면 호출하는 함수가 먼저!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 개념적 유사성이 높으면 가까이&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 가로형식 맞추기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 짧은 행이 선호되지만, 저자는 개인적으로 120자 정도의 행길이를 제한한다.&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; - 들여쓰기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 들여쓰기를 무시하고 싶은 상황(짧은 조건문, 짧은 함수) 에서도 들여쓰기!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 빈 while이나 for문의 경우 세미콜론은 새 행에 제대로 들여써주기&amp;nbsp;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>book</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/119</guid>
      <comments>https://doromi.tistory.com/119#entry119comment</comments>
      <pubDate>Tue, 1 Mar 2022 03:08:02 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode]4.주석</title>
      <link>https://doromi.tistory.com/118</link>
      <description>&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;진실은 오직 code!&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;1. 법적인 주석 : file 첫머리에 저작권정보와 소유권정보&amp;nbsp; -&amp;gt;Good&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 의미를 명로하게 밝히는 주석 : 인수나 반환값이 표준 라이브러리나 변경하지 못하는 코드에 속한다면 의미를 명료하게 밝히는 주석이 유용하다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 경고하는 주석&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. todo주석&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 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;</description>
      <category>book</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/118</guid>
      <comments>https://doromi.tistory.com/118#entry118comment</comments>
      <pubDate>Thu, 24 Feb 2022 16:22:44 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode]3.함수</title>
      <link>https://doromi.tistory.com/117</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 함수를 만드는 법&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;&amp;nbsp; - if/else문 , while문 등에 들어가는 블록은 한줄이여야한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 장점 : 바깥을 감싸는 함수가 작아지고, 함수명이 적절하다면 코드 이해도 쉽다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 한가지만 하기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 함수가 한가지만 하는지 확인하는 방법&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 추상화 수준이 1개인지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 의미있는 이름으로 다른함수를 추출할 수 있다면 그것은 여러작업을 하고있다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 섹션으로 나뉘어지는지 확인&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 함수의 추상화 수준은 하나로!&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;nbsp; 이유 : 근본개념인지 세부사항인지 알기 어렵고, 사람들이 세부사항을 점점 더 추가한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; -&amp;nbsp; 코드는 위에서 아래로 읽히도록, 아래로 갈수록 추상화 수준을 낮추기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. Switch문&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - switch문은 길고, 본질적으로 여러작업을함&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 꼭 써야한다면 추상 factory에 꽁꽁숨겨서 단 한번만 사용하도록&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 서술적인 이름을 사용하라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 길어도 겁먹지 말고, 서술적으로 작성&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 일관성있는 서술어를 사용하기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;6. 함수 인수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 이상적인 인수는 0&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 단항형식&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 인수로 질문을 던지는 경우 bool fileExists(&quot;MyFile&quot;) = &amp;gt; O&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 인수로 인해 상태를 바꾸는 이벤트 =&amp;gt; O&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 그외는 가급적 피하기, 특히 void transform(Stringbuffer out) 금지 ! (출력인자를 넘기는것)&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 플레그 인수 -&amp;gt; 끔찍 : 이미 여러가지를 한다는 의미! ( true면 A , False면 B를 한다는 것 )&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 이항 함수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 자연적인 순서가 있는 경우엔 인정&amp;nbsp; ex)&amp;nbsp; Point(0,0)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 그 외에는 혼란을 줄 수 있음&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 삼항 함수&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; - 마찬가지로, 그만한 가치가 있는 경우엔 인정 ex ) assertEquals (1.0, amount, .001)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 인수 객체&amp;nbsp; : 차라리 여러개의 인수가 필요하다면 객체로 넘기는것이 개념을 표현하기 때문에 더 낫다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 같은 함수명의 다양한 인수를 갖는 여러개의 함수 -&amp;gt; 필요한 경우도 있음 But 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;7.부수 효과를 일으키지 마라&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;8.명령과 조회를 분리하라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;9.오류코드보다 예외를 사용하라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 예외를 사용할때 try/catch는 본래 추하기 때문에, 별도의 함수로 뽑아내는 것이 좋다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 오류처리할때도 한가지만 작업해야한다. 오류만! 처리하기&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - enum으로 error코드를 지정하고 사용하면, 의존성도 높고 새 enum추가시 재컴파일 해야하지만, 예외를 사용하면 새로운 예외는 Exception클레스에서 파생되어서 더 낫다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;10. 반복하지 마라&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11. 구조적 프로그래밍&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 구조적 프로그래밍 : 함수내 모든 입구와 출구가 하나여야한다 , loop에서 break, continue사용 X, goto 금지&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 하지만 함수가 작다면 별 이익을 제공하지 못함&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;&amp;nbsp; - 처음에는 길고 복잡하게 짜고, testcase를 만든 후 점차 다듬기 (testcase는 통과해야함)&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;</description>
      <category>book</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/117</guid>
      <comments>https://doromi.tistory.com/117#entry117comment</comments>
      <pubDate>Tue, 22 Feb 2022 02:15:59 +0900</pubDate>
    </item>
    <item>
      <title>[CleanCode 정리] 2.의미있는 이름</title>
      <link>https://doromi.tistory.com/116</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기억하고 싶은 내용&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Naming 이름지을때 생각해보아야 할 규칙&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 의도를 분명히 하기. thelist ( X) , gameBoard (O)&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; - 개발시 이용하는 용어 주의하기 List가 아닌데 List사용 X&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp;- 흡사한 이름 사용하지 않기 - 한눈에 보기 어려운 이름&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 의미있게 구분하기 : 컴파일러만 통과하는 코드는 x&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; - 두 변수가 구분이 안되는 경우 ~Data, ~Info =&amp;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;&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;&amp;nbsp; - 접두어 붙일 필요없다. -&amp;gt; 클래스, 함수는 작아져야하고, 멤버변수를 다른 색상으로 표시하는 IDE를 사용해야 마땅함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; - 인터페이스클레스의 경우에는 구체클레스에 접두어 또는 접미어를 붙이는 것이 낫다 ~Imp, C~&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; but Manager, Processor, Data, Info 단어 피하고 , 동사는 사용하지 않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ex ) Customer, AddressParser&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 메서드 이름 : 동사나 동사구 | 접근자, 변경자, 조건자는 get, set, is를 붙인다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ex) postPayment, deletePage, save&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; * 생성자를 중복 정의할때는 정적 펙토리 메서드를 이용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; ex) Complex fulcrumPoint&amp;nbsp; = Complex.FromRealNumber(23.0) (O)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Complex fulcrumPoint = new Complex(23.0) (X)&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;ex ) 똑같은 메서드를 class에 따라 fetch, retrieve, get 으로 사용 X&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 비슷한 코드 기반에 controller, manager, driver을 섞어쓰면 혼란&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; ex ) 두개를 더해서 새로운 값을 만드는 것 : add , 다른 숫자 한개를 더하는것 : add =&amp;gt;X&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;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;b&gt;오늘 읽은 소감&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;- 멤버변수에 접두어를 붙일 필요없다. 대신 멤버변수를 다른 색상으로 표시하는 IDE를 사용해야 마땅하다는 사실&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- Data, Info 를 주의하자&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 이름 길이는 범위에 비례하도록 하자.&lt;/p&gt;</description>
      <category>book</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/116</guid>
      <comments>https://doromi.tistory.com/116#entry116comment</comments>
      <pubDate>Sun, 20 Feb 2022 21:31:58 +0900</pubDate>
    </item>
    <item>
      <title>[ 2012,Alexnet] ImageNet Classification with Deep ConvolutionalNeural Networks 논문 리뷰</title>
      <link>https://doromi.tistory.com/115</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘 리뷰해볼 논문은 2012년에 Alex Krizhevsky 님께서 작성한 &quot;&lt;b&gt;ImageNet Classification with Deep ConvolutionalNeural Networks&lt;/b&gt; &quot; 입니다. 저자의 이름을 따서 AlexNet으로 더 유명한 CNN 네트워크 구조를 소개하고 있습니다.&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;[Abstract]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- ILSVRC 대회는 약 1.2million 고해상도 이미지를 1000개의 class로 분류해 내는 대회인데, 2010년 대회기준 test set에서 top-1, top-5 error rate이 각각 37.5%, 17.0%로 앞선 SOTA보다 확실히 더 나은 성적을 갖는 neural network를 구성함.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 그 neural network는 60 milion 파라미터랑 650,000 뉴런을 으로 구성되어있는데, 네트워크 구성은 5개의 CNN 레이어(일부 레이어는 max pooling 적용)와 3개의 Fully connected 레이어(마지막은 1000class에 대한 softmax 연산 적용)로 되어 있음.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 학습을 빠르게 하기 위해 non-saturating neuron ( non-saturationg 되는 activation function (ReLU) ) 를 적용하고, GPU로 연산할 수 있도록 구현함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- overfitting을 방지하기 위해서 FC(fully connected)레이어에 dropout 기법을 적용함.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 결국 ILSVRC 2012대회에서 top-5 error를 15.3%로 달성하며 2위인 26.2%와 상당한 격차로 1등을 차지함.&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. Introduction ]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Machine learning method 에서 성능을 높이기 위해서는 1. 많은 dataset이 필요하고 , 2. 강력한 모델로 학습시키고 , 3. overfitting을 방지하기 위한 기술을 적용해야한다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;- 큰 dataset의 등장&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; 이전에는 공개된 데이터셋의 양도 많지 않은 편이였고, 인식 task도 간단한 편이였으나 실제 물체를 인식하려고 했을때에는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;variability가 크기( 형체나 모습이 다양함 )때문에 더 큰 데이터셋이 필요했는데 최근 LabelMe 나 ImageNet 과 같은 방대한 데이터셋이 등장하고 사용할 수 있게 되었다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;- CNN&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; 큰 데이터셋을 학습시켜도 그 많은 지식을 가지고 있을만한 모델이 필요하다. CNN은 넓이나 깊이를 통해 모델의 크기를 조절할 수 있고,&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;stationarity of statistics and locality of pixel dependencies (&lt;/span&gt;이미지의 한 부분에 대한 통계가 어떤 다른 부분들과 동일하다는 특징 and &lt;span style=&quot;color: #343a40;&quot;&gt;이미지를 구성하는 특징들은 이미지 전체가 아닌 일부 지역에 근접한 픽셀들로만 구성되고, 근접한 픽셀들끼리만 종속성을 가지는 특징&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;) 이라는 이미지의 특성을 잘 살려서 연산할 수 있다. 또한 일반적인 feed-forword (모든 픽셀이 각 node와 연결되어있는 형태)에 비해 연결이 적기 때문에 학습이 쉽다는 특징이 있다.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;ref : https://seongkyun.github.io/study/2019/10/27/cnn_stationarity/&lt;/i&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- GPU&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; gpu가 2d conv net 을 연산하기에 최적화되어 있고, 큰 CNN architecture를 학습시키기에 충분히 좋다.&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;따라서 이 논문의 주요 contribution은 다음과 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 가장 큰 CNN architecture 구성했고 그 모델로 ILSVRC 2010, 2012 대회 기준 최고의 성적을 얻었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. &lt;span&gt;2D convolution에 최적화한 GPU 연산을 구현했다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3. 성능을 향상시키기 위한 기법과 학습 시간을 줄이기 위한 기법을 적용했다. -&amp;gt; section 3&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;4. overfitting을 방지하기 위한 기법을 적용했다. -&amp;gt; section 4&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;span&gt;[ 2. The Dataset ]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;ImageNet은 &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;15 million장의 label된 고해상도 이미지와 약 22,000 categorie로 구성된 거대한 데이터 셋입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, AppleSDGothicNeo-Regular, 'Malgun Gothic', '맑은 고딕', dotum, 돋움, sans-serif; letter-spacing: 0px;&quot;&gt;ILSVRC 대회는 ImageNet데이터에서 각 카테고리당 약 1000장의 이미지를 갖는 1000개의 label에 대해서 classificaton을 하는 task에 대해 경쟁을 하는 대회입니다.&amp;nbsp;&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;span&gt;ImageNet 에서는 2개의 error rate을 이용해 구분을 합니다 : top-1 , top-5.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;각 class 에 대한 confidence score을 sort했을때 가장 높은 score을 가진 1개의 class가 정답이 아닌경우의 비율 : top-1&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;상위 score에 대해서 5개의 class들 중 정답이 아닌 경우의 비율 : top-5&amp;nbsp; 입니다. &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;ImageNet은 다양한 resolution을 갖는 이미지들이 있지만, 여기서는 256x256으로 down sampling을 진행해서 이미지를 사용했고.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직사각형 형태의 이미지는 짧은 쪽에 대해 256으로 맞추고 중앙을 기준으로 crop 하여 256x256으로 변환하여 사용했다고 한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;픽셀 값에 대해서 평균값을 각 픽셀에 대해 빼주는 연산을 제외하고는 따로&amp;nbsp; preprocessing하지는 않았다고 한다.&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. The Architecture &lt;/span&gt;]&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 네트워크의 구조는 5개의 conv레이어와 3개의 fc레이어로 구성되어 있고, 이 구조를 이용해서 더 나은 성능과 빠른 학습 속도를 위해 적용한 기술들을 알아보자.&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;3.1 ReLU &lt;span&gt;Nonlinearity&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;기존의 네트워크들은 전통적으로 sigmoid 나 tanh 함수를 이용하여 각 레이어의 Nonlinearity 를 부여했지만, 이 네트워크에서는 Relu라는 연산을 이용했다. Relu 는 &lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;) = max(0&lt;/span&gt;&lt;span&gt;,x&lt;/span&gt;&lt;span&gt;) 형태를 띄며 기존에 &lt;/span&gt;&lt;span&gt;saturating &lt;/span&gt;&lt;span&gt;nonlinearity 방식이 아닌 양수에 대해서는 saturating하지 않는 특징을 갖으며, 학습속도가 매우 빠르다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 그래프는 &lt;/span&gt;&lt;span&gt;CIFAR-10 데이터 셋을 4개의 conv 레이어로 구성된 네트워크로 실험한 것을 보여주는데, 이경우&amp;nbsp; error-rate 가 0.25에 도달하는데 Relu가 tanh에 비해 6배정도 빠름을 알 수 있습니다.&amp;nbsp;&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;span&gt;사실 여기서 처음으로 전통적인 activation fucntion이 아닌 새로운 방식을 도입한 것은 아니다. contrast nomalization과&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;local average pooling 과 함께&amp;nbsp;&lt;/span&gt;&lt;span&gt;f(x) = | tanh(x) |를 적용해서 &lt;/span&gt;&lt;span&gt;Caltech-101에 대해 잘 작동하도록 시도한 적이 있지만 이경우에는 overfitting을 막고자 하는게 주 목적이였고, 빠른 학습속도를 만들고자 하는 우리의 목적과는 다름을 알 수 있다. 빠른 학습속도는 큰 데이터셋을 큰 규모의 모델에서 학습시킬때 좋은 효과를 주기 때문입니다.&amp;nbsp;&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 data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;3.2 Training on Multiple GPUs &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1개의 GTX 580 GPU 는 3GB of memory 뿐이기 때문에 모델의 최대 크기는 거기에 맞춰서 제한적일 수 밖에 없습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;1.2 milion 개의 뉴런들을 1개의 GPU에 맞추기에는 너무 많았고, 그래서 2개의 GPU로 나눠서 학습시키기로 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;또한 다른 GPU의 memory에 직접 읽고 쓸 수 있기때문에 GPU병렬화에 잘 맞았습니다.&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;span&gt;그래서 전체 커널의 반씩 각 GPU 에서 연산할 수 있도록 나누었고, layer 3의 커널만 layer2의 모든(다른 GPU에 있는 것까지 포함한) output을 가지고 연산할 수 있도록 추가적인 기술을 첨가했습니다. 나머지는 같은 GPU에 있는 커널의 output만 가지고 연산합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이 방식은 GPU 한개만 사용한 것에 비해 top-1 and top-5 error rated을 각각 1.7% 과 1.2% 감소시켰습니다.&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;span&gt;[ &lt;/span&gt;&lt;span&gt;4.Reducing Overfitting &lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;이어서,,,,&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Vision</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/115</guid>
      <comments>https://doromi.tistory.com/115#entry115comment</comments>
      <pubDate>Sat, 15 May 2021 18:07:22 +0900</pubDate>
    </item>
    <item>
      <title>CS231n 한글 정리 | Lecture 3  | Loss Fuctions and Optimization ( Optimization , gradient )</title>
      <link>https://doromi.tistory.com/112</link>
      <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;자, 그럼 이제는 어떻게 실제 Loss를 줄이는 W를 찾을 수 있는걸까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 질문을 우리는 &quot;&lt;b&gt;최적화 (Optimization)&lt;/b&gt; &quot; 라고 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;최적화를 한다는 것은 우리가 다양한 산과 계곡이 있는 엄청 큰 골짜기를 걷고 있는 것입니다.&lt;/p&gt;&lt;p&gt;내가 위치하고 있는 곳의 높이가 Loss가 되는것이고 우리의 임무는 이 골짜기의 밑바닥을 찾는 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;하지만 이문제는 매우 어렵습니다. 그래서 우리는 다양한 iterative한 방법을 사용합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;가장 먼저 생각할 수 있는것은 &quot;&lt;b&gt;Random search(임의 탐색)&lt;/b&gt;&quot; 입니다.&lt;/p&gt;
&lt;p&gt;*매우 구린방법입니다.&lt;/p&gt;
&lt;p&gt;CIFAR-10에서는 클래스가 10개니까 임의확률은 10%가 되고, 무작위 시행을 거치게 되면 약 15%의 정확도를 보이는군요.&lt;/p&gt;&lt;p&gt;최신 알고리즘의 성능 SOTA가 95%인것을 생각하면 매우 좋지 않죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;두번째 방법은 &quot;&lt;b&gt;local geometry(기하학적 특성 이용하기)&lt;/b&gt;&quot; 입니다.&lt;/p&gt;
&lt;p&gt;우리는 발로 경사를 느끼고 어느 방향으로 가야 내려갈 수 있을지를 알 수 있을 것입니다. &amp;nbsp;&lt;/p&gt;&lt;p&gt;경사를 느끼고 방향을 정하는 것을 계속 반복하다보면 골짜기를 다 내려갈 수 있을 것입니다.&lt;/p&gt;&lt;p&gt;이 방법은 우리가 NN이나 Linear Classifer같은 것은 훈련시킬때 일반적으로 사용합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 경사(slope)는 무엇일까요? 미분 수업이 기억나나요?&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 504px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E89C3D5E60C2C206&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E89C3D5E60C2C206&quot; width=&quot;504&quot; height=&quot;269&quot; filename=&quot;3-17.png&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;어떤 점 (x)에서 도함수(derivative)를 계산해보면 작은 스텝(h)가 있고 그 스탭간의 함수 차이를 비교하기 위해 뺄셈을 하고, 그 스텝사이즈를 0에 가깝게 만들면 이것이 바로 그 점(x)에서의 경사가 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이 개념은 다변수함수(multi-variable function)로도 확장시킬 수 있습니다.&lt;/p&gt;
&lt;p&gt;실제로 x는 스칼라가 아니라 벡터입니다. x가 벡터이기 때문에 이 개념을 다변수로 확장시켜야 합니다.&lt;/p&gt;
&lt;p&gt;다변수인 상황에서 미분으로 일반화 시키면 gradient이고&lt;b&gt; gradient는 벡터 x의 각 요소를 편도함수들의 집합&lt;/b&gt;입니다.&lt;/p&gt;&lt;p&gt;입력이 3개면 gradient도 3개가 되겠죠.&lt;/p&gt;&lt;p&gt;그리고 이 gradient의 각 요소가 알려주는 것은 바로 &quot;&lt;b&gt;우리가 그쪽으로 갈때&amp;nbsp;함수 f의 경사가 어떤지&quot;&lt;/b&gt; 일것입니다.&lt;/p&gt;
&lt;p&gt;즉 gradient는 편도함수들의 벡터가 되고, 방향은 함수에서 &lt;b&gt;&quot;가장 많이 올라가는 방향&quot;&lt;/b&gt;이 됩니다.&lt;/p&gt;&lt;p&gt;gradient의 방향이 반대가 되면 가장 많이 내려가는 방향이 되겠죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 특정방향에서 얼마나 가파른지 알고싶으면 어떻게 해야할까요?&lt;/p&gt;&lt;p&gt;그것은 그 방향의 유닛벡터와 gradient벡터를 내적한 것과 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;gradient는 매우 중요합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;왜냐하면 gradient가 함수의 어떤 점에서의 선형 1차 근사 함수를 알려주기 때문입니다.&lt;/p&gt;&lt;p&gt;그래서 실제로 많은 딥러닝 알고리즘들이 &lt;b&gt;gradient를 계산하고 파라미터 벡터를 반복적으로 업데이트 &lt;/b&gt;하는데에 사용합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;컴퓨터로 gradient를 유용하게 사용할 수 있는 방법은 유한 차분법(finite difference method)를 이용하는 것입니다.&lt;/p&gt;&lt;p&gt;다시 gradient의 극한식으로 돌아가봅시다.&lt;br /&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9992AF3D5E60C2C031&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9992AF3D5E60C2C031&quot; width=&quot;820&quot; height=&quot;412&quot; filename=&quot;3-12.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;왼쪽에 W가 있습니다 .이 W의 loss는 1.25정도 되는군요.&lt;/p&gt;&lt;p&gt;우리가 첫번째 요소에 아주작은값 h (0.0001)을 더해보고 loss를 구해봅시다. 그러면 1.24342에서 1.24322로 감소하는 군요.&lt;/p&gt;
&lt;p&gt;이제 극한식을 이용하여 gradient를 구합니다.&lt;/p&gt;&lt;p&gt;이것을 각 요소마다 반복합니다&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;실제로는 시간이 매우 많이 걸리므로 매우 끔찍합니다.&lt;/p&gt;&lt;p&gt;하지만 우리는 미적수업을 들었으므로 미분이라는 마법을 이용하여 바로 gradient를 구할 수 있습니다.&lt;/p&gt;&lt;p&gt;아래와 같은 식으로 간단히 구할 수 있죠.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 472px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C0773D5E60C2C135&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C0773D5E60C2C135&quot; width=&quot;472&quot; height=&quot;237&quot; filename=&quot;3-13.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;해석적으로 푸는 것이 수치적으로 푸는 것보다 더 효율적입니다. (물론 디버깅을위해 수치적으로 계산하는 방식이 쓰일 수는 있습니다.)&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그럼 우리가 구한 gradient를 이용하여 gradient의 반대방향으로 업데이트를 하고 아주 조금씩 이동하여 결국 수렴할 것입니다!&lt;/p&gt;&lt;p&gt;하지만 &lt;b&gt;스텝사이즈&lt;/b&gt;(이동하는 정도, learning rate)는 하이퍼파라미터입니다.&lt;/p&gt;&lt;p&gt;스텝사이즈를 올바르게 결정하는 것도 매우 중요한 문제입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;근데 앞으로 더 쩌는 스탭들을 볼 수 있을 것입니다.&lt;/p&gt;&lt;p&gt;기본은 gradient를 이용하는 것이지만 다음 스텝을 결정하기 위해서 이전의 모든 스탭의 gradient의 정보를 이용하는 방법들도 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;우리가 배워야할 한가지가 더 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;손실함수를 정의한 것을 다시 상기해보면, Loss를 구할때 전체 트레이닝셋 loss의 평균으로 사용했습니다.&lt;/p&gt;&lt;p&gt;하지만 실제로는 N이 매우 커질 수 있습니다. ImageNet 데이터 셋의 경우 N은 130만개입니다.&lt;/p&gt;
&lt;p&gt;그러면 &lt;b&gt;시간이 매우 걸리게 되겠죠.&lt;/b&gt;&lt;/p&gt;&lt;p&gt;gradient 계산하는 과정을 살펴보면 Loss는 그저 각 데이터 Loss의 Gradient의 합이라는 것을 알 수 있고, 그러니 N개의 전체 트레이닝셋을 한번 더 돌면서 계산해야하는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그래서 실제로는 &lt;b&gt;stochastic gradient descent&lt;/b&gt;라는 방식을 사용합니다.&lt;/p&gt;&lt;p&gt;전체 데이터 셋의 gradient와 loss를 계산하기 보다는 &lt;b&gt;Minibatch&lt;/b&gt;라는 작은 트레이닝 샘플로 나누어서 학습하는 방식입니다.&lt;/p&gt;
&lt;p&gt;보통 2의 승수로 정하며 32,64,128로 쓰는편입니다.&lt;/p&gt;&lt;p&gt;그래서 이 작은  minibatch를 이용하여 Loss의 전체합의 추정치와 실제 gradient의 추정치를 계산하는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;앞으로 이 더 간지나는 update rules들이 정확히 어떻게 여러 gradient들을 통합시키는지 알아보겠습니다.&lt;/p&gt;&lt;p&gt;또한 방금 설명한 &lt;b&gt;SGD&lt;/b&gt;는 거의 모든 DNN알고리즘에 사용되는 기본적인 학습 알고리즘입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;사실 Linear Classifier는 이미지에서는 그리 좋은 방법은 아닙니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;그래서 DNN이 유행하기 전에 Linear Classifier를 이용하기 위해서는 두가지 스테이지를 거쳐서 사용했습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;첫번째는, 이미지의 여러가지 &lt;b&gt;특징표현&lt;/b&gt;을 계산하는 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;이미지나 모양새와 같은 특징표현을 연결하여 특징 벡터로 만들고&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;두번째는, 이 특징벡터를 Linear Classifier에 입력값으로 주는 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;특징변환의 한 예로는 &lt;b&gt;컬러 히스토그램&lt;/b&gt;이 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 809px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9926AD3D5E60C2C12D&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9926AD3D5E60C2C12D&quot; width=&quot;809&quot; height=&quot;396&quot; filename=&quot;3-14.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;이미지에서 Hue값만 뽑아서 모든 픽셀을 양동이에 넣고 각 양동이에 담긴 픽셀의 갯수를 세는것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;이 개구리의 경우에는 초록색이 많은 것을 알 수 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;또다른 예로는 &lt;b&gt;HoG&lt;/b&gt;가 있습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 796px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A18D3D5E60C2C125&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A18D3D5E60C2C125&quot; width=&quot;796&quot; height=&quot;417&quot; filename=&quot;3-15.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;이번에는 이미지를 8*8 픽셀로 나누어서 각 픽셀의 지배적인 edge방향을 계산하고 각 edge들에 대해서 양동이에 넣는것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;그럼 edge에 대한 히스토그램이 되는것이죠&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이러한 방법도 있습니다. 바로 &lt;b&gt;Bag of words&lt;/b&gt; 입니다.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E8ED3D5E60C2C234&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E8ED3D5E60C2C234&quot; width=&quot;820&quot; height=&quot;421&quot; filename=&quot;3-16.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;NLP에서 영감을 받은 방식으로, 어떤 문장에서 여러 단어들의 발생빈도를 세서 특징벡터로 사용하는 방식을 이미지에 적용한것입니다.&lt;/p&gt;&lt;p&gt;우리는 이미지에 적용하기 위해 이미지들을 임의대로 조각내고, 각 조각을 K-means와 같은 알고리즘으로 군집화 합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;다양하게 구성된 각 군집들은 다양한 색과 다양한 방향에 대한 edge도 포착할 수 있습니다.&lt;/p&gt;&lt;p&gt;(이러한 것들을 시각 단어 (visual words) 라고 부릅니다. )&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 5-10년전에는 대부분 이런식으로 특징벡터를 뽑아서 Linear Classifier의 input으로 사용했습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;사실 이 개념들은 CNN과 DNN으로 넘어간다고 크게 달라지는 개념은 아닙니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;유일하게 다른 점이 있다면 &lt;b&gt;이미 만들어 놓은 특징을 쓰기 보다는 데이터로부터 특징을 직접 학습&lt;/b&gt;하려 한다는 점입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다음시간에는 CNN에 대해 심도있게 살펴볼 것이고 역전파(Backpropagation)에 대해 알아보겠습니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</description>
      <category>Study/Vision</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/112</guid>
      <comments>https://doromi.tistory.com/112#entry112comment</comments>
      <pubDate>Thu, 5 Mar 2020 18:18:49 +0900</pubDate>
    </item>
    <item>
      <title>CS231n 한글 정리 | Lecture 3 | Loss Fuctions and Optimization ( SVM Loss &amp;amp; Softmax )</title>
      <link>https://doromi.tistory.com/111</link>
      <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;Stanford University에서 2017년에 강의한 영상을 보며 정리한 자료입니다.&lt;/p&gt;&lt;p&gt;Link : https://www.youtube.com/playlist?list=PL3FW7Lu3i5JvHM8ljYj-zLfQRF3EO8sYv&lt;/p&gt;&lt;p&gt;자료출처 : http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture3.pdf&lt;/p&gt;&lt;p&gt;참조 :&amp;nbsp;https://github.com/insurgent92/CS231N_17_KOR_SUB/blob/master/kor/Lecture%203%20%20%20Loss%20Functions%20and%20Optimization.ko.srt&lt;/p&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;지난시간에는 임의의 W 행렬을 가지고 Linear Classification을 진행했는데요&lt;/p&gt;
&lt;p&gt;임의로 정한 것이기 때문에 스코어는 좋을 수도, 나쁠 수도 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99A4C3345E60BCC52A&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99A4C3345E60BCC52A&quot; width=&quot;500&quot; height=&quot;317&quot; filename=&quot;3-1.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;위의 사진에서는 고양이 이미지의 경우에는 car의 스코어가 가장 높습니다. 잘못된 분류죠&lt;/p&gt;&lt;p&gt;하지만, 자동차 이미지의 경우에는 자동차의 스코어가 가장 높습니다. 좋은 분류입니다.&lt;/p&gt;&lt;p&gt;이렇게 스코어를 눈으로 훑으면서 어느게 좋고 어느게 나쁜지를 살펴보기만 하는것은 좋지 않습니다.&lt;/p&gt;&lt;p&gt;이런 알고리즘을 만들고, 어떤 W가 가장 좋은지를 결정하기위해 좋다,나쁘다를 정량화 할 방법이 필요합니다. W가 얼마나 거지같은지 정량적으로 알려주는 함수를 손실함수(Loss Fuction)이라고 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이번강의에서는 몇가지 손실함수에 대해 알아보겠습니다.&lt;/p&gt;&lt;p&gt;우선 Linear Classification에서 W와 X로 구성된 함수f 기억나시나요?&lt;/p&gt;&lt;p&gt;X는 입력데이터고, W는 가중치입니다. 이 둘을 입력받아 예측값 y를 반환하는 함수였습니다.&lt;/p&gt;&lt;p&gt;손실함수 L_i는 예측함수f와 정답값 Y를 입력받아 이 W가 얼마나 구리게 예측하는지 정량화 시키는 함수라고 보시면 됩니다.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 372px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9980C5345E60BCC530&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9980C5345E60BCC530&quot; width=&quot;372&quot; height=&quot;87&quot; filename=&quot;3-2.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;최종Loss는 N개의 샘플들의 Loss의 평균값을 의미합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;결국 우리는 이 Loss함수를 이용해 Loss를 최소화하는 어떤 W를 찾아야 할것입니다.&lt;/p&gt;&lt;p&gt;positive와 negative로 분류하기만 하는 SVM 모델을 일반화 시켜 여러개의 클레스를 다룰 수 있도록 하는 Loss함수입니다.&lt;/p&gt;&lt;p&gt;Loss함수를 구하는 방식을 살펴보겠습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 360px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991817345E60BCC622&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991817345E60BCC622&quot; width=&quot;360&quot; height=&quot;187&quot; filename=&quot;3-3.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;우선 &quot;정답인 카테고리의 스코어 (True score)&quot;와 &quot;나머지 카테고리의 스코어(False score)&quot;들을 나누고 True score - False score 를 봐서 safety margin 이상이라면 Loss는 0이 됩니다. (예제에서는 safety margin을 1로 설정했습니다.)&lt;/p&gt;&lt;p&gt;그 차이가 safety margin보다 작다면, (즉 False score가 True score보다 크거나, True가 False보다 크지만 그 차이가 safety margin보다 작다면 ) 그것은 잘못된 경우니까 Loss가 생기고 여기서 Loss는 False score - True score + safety margin으로 구할 수 있습니다.&lt;/p&gt;&lt;p&gt;아래의 예제를 보시면 이해가 더 잘될 겁니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span style=&quot;text-align: left;&quot;&gt;&lt;b&gt;ex 1&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CB00345E60BCC724&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CB00345E60BCC724&quot; width=&quot;500&quot; height=&quot;252&quot; filename=&quot;3-4.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;b&gt;ex 2&lt;/b&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9971FD345E60BCC720&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9971FD345E60BCC720&quot; width=&quot;500&quot; height=&quot;256&quot; filename=&quot;3-5.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: left; clear: none; float: none;&quot;&gt;&lt;span style=&quot;text-align: start;&quot;&gt;이렇게 Loss를 구할 수 있고, 최종 Loss는 각 Loss값을 더한것에 input의 갯수(3개)를 나누어서 구할 수 있습니다.&lt;/span&gt;&lt;/p&gt;&lt;p&gt;즉 정리를 하자면, 우리는 정답인 카테고리의 스코어가 다른 스코어에 비해 얼마나 더 큰 스코어를 가지고 있는지, 그 상대적인 차이가 궁금한것이고 그 차이를 보여주는게 Loss함수라고 볼 수 있을것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;여기 흥미로운 사실이 있습니다. 손실함수라는 것이 분류기에서 우리가 어떤 W를 찾고있는지를 말해주는 것이라면, Loss가 0인것을 선택하는 것은 모순이 아닐까요?&lt;/p&gt;&lt;p&gt;왜냐하면 우리는 오직 데이터의 loss만 신경쓰고 있고, 분류기에게 트레이닝 데이터에 꼭 맞는 W를 찾으라는 말과 같아 보입니다. 그러니 분류기에게 트레이닝 데이터의 loss에만 신경쓰게 한다면 우리가 원하는 값을 찾지 못할 수도 있을 것입니다.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 360px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9987CC345E60BCC826&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9987CC345E60BCC826&quot; width=&quot;360&quot; height=&quot;198&quot; filename=&quot;3-6.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;여기 예시가 있습니다. 파란점(train set)들에 피팅되게 선을 예측한다면 초록네모(test set)에 들어왔을때 원하지 않는 결과 값을 얻을 수 있을 것입니다. 오히려 의도했던 것은 초록색 선일 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 보통 이를 해결하는 방법을 통틀어 Regularizaion이라고 합니다.&lt;/p&gt;&lt;p&gt;이는 모델이 더 단순한 W를 선택하도록 도와줍니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/991517345E60BCC81C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F991517345E60BCC81C&quot; width=&quot;500&quot; height=&quot;183&quot; filename=&quot;3-7.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 Regularizaion은 모델이 더 복잡해지지 않도록 도와주며, 모델에 soft한 제약을 추가한다고 볼 수 있습니다. &quot;만약 너가 복잡한 모델을 계속 쓰고싶으면, 이 패널티를 감수해야 할꺼야!&quot;라고 하는것과 같은거죠.&lt;/p&gt;&lt;p&gt;Regularizaion에는 다양한 종류가 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 500px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99108D345E60BCC928&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99108D345E60BCC928&quot; width=&quot;500&quot; height=&quot;255&quot; filename=&quot;3-8.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;가장 보편적인것은 L2 Regularizaion(Weight decay)입니다. L2 Regularization은 Euclidean Norm에 패널티를 주는 것입니다.&lt;/p&gt;&lt;p&gt;또다른 방식으로는 L1 Regularization도 있습니다. 이것은 W를 희소행렬이 될 수 있도록 합니다. Elastic net이라고 L1과 L2 를 짬뽕해둔 것도 있으며, Max Norm도 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 Regularization기법중 특히 딥러닝에 관련된 기법들을 더 배우게 될 것입니다. Dropout이나 Batch Normalization, Stochastic depth와 같은 최근의 멋있는 기법들 말입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;L1과 L2는 어떻게 모델이 복잡하다고 인지하는 걸까요?&lt;/p&gt;&lt;p&gt;여기 예시가 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99CB1D365E60BE5430&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99CB1D365E60BE5430&quot; width=&quot;820&quot; height=&quot;403&quot; filename=&quot;3-9.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;트레이닝데이터 x가 있고, 서로다른 W행렬 w1과 w2가 있습니다.&lt;/p&gt;
&lt;p&gt;이걸가지고 Linear classification을 할때 우리는 x와 w의 내적을 구합니다.&lt;/p&gt;
&lt;p&gt;Linear classification의 관점에서는 w1과 w2는 같습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;하지만 L2에서는 w1과 w2 중 어느것이 더 좋은 W라고 인지할까요?&lt;/p&gt;
&lt;p&gt;L2에서는 w2를 선호합니다. 왜냐하면 L2는 분류기의 복잡도를 각 값들이 얼마나 차이가 없는지로 비교합니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;Linear classificaion에서 W는 얼마나 x가 output class와 비슷한지를 계산합니다.&lt;/p&gt;&lt;p&gt;따라서 L2는 변동이 심한 어떤 입력 x 가 있고 그 특정요소에 의존하기 보다는 모든 x의 요소가 골고루 영향을 미치길 원할때 사용합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;L1은 어떨까요? L1은 w1을 선호합니다. 왜냐하면 L1은 행렬에서 0이 아닌 요소가 많을때 복잡하다고 생각합니다.&lt;/p&gt;&lt;p&gt;따라서 우리가 어떤 문제를 가지고 있고, 우리가 그 문제에서 '복잡하다'를 어떻게 정의할 것인지를 고민하여 적절한 Regularizaion 을 사용해야할 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Softmax는 스코어를 가지고 클래스별 확률 분포를 계산하는 방식입니다.&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 617px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9957E2365E60BE5422&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9957E2365E60BE5422&quot; width=&quot;617&quot; height=&quot;329&quot; filename=&quot;3-10.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;스코어를 모두 이용하고, 각 스코어에 지수를 취해 양수가 되게 만든 후, 지수들의 합으로 정규화 시킵니다. 그래서 softmax 함수를 거치게 되면 결국 확률분포를 얻을 수 있고 그것이 바로 해당 클래스일 확률이 되는 것입니다.&lt;/p&gt;&lt;p&gt;확률이기 때문에 0에서 1사이의 값이고, 모든 확률들의 합은 1이 되겠죠&lt;/p&gt;&lt;p&gt;그러면 우리가 원하는 것은 정답 클래스에 해당하는 클래스의 확률이 1에 가깝게 계산되는 것입니다. 그렇게 되면 Loss는 -log(정답클래스 확률) 이 될 것입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center;&quot;&gt;&lt;/p&gt;&lt;p&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px; text-align: center;; height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999E49365E60BE5519&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999E49365E60BE5519&quot; width=&quot;820&quot; height=&quot;206&quot; filename=&quot;3-11.PNG&quot; filemime=&quot;image/jpeg&quot; style=&quot;text-align: center;&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;손실함수는 &quot;얼마나 좋은지&quot;가 아니라 &quot;얼마나 구린지&quot;를 측정하는 것이기 때문에 log에 -를 붙이는 겁니다. 그러면 0에 가까울수록 loss값은 무한대로 커질거고 1에 가까울수로 loss는 0에 가까워 지겠죠. 우리는 이것을 Softmax 또는 Multinomial Logistic Regressison (다항 로지스틱 회귀) 라고 합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그렇다면 softmax의 최댓값과 최솟값은 얼마일까요? 이론적으로는 최댓값은 무한대, 최솟값은 0이 될 것입니다. 하지만 컴퓨터는 무한대 연산을 잘 못하기 때문에(유한 정밀도 때문에) Loss가 0인경우는 절대 없을 것입니다.&lt;/p&gt;&lt;p&gt;만약 스코어들이 모두 0근처에 모여있는 작은 수 일때 Loss는 어떻게 될까요? 디버깅할때 이 사실은 매우 유용한데요. 스코어들이 매우 비슷하다면 -log ( 1/class갯수) 가 되겠죠. log는 분자와 분모를 뒤집을 수 있으니까 log ( class의 갯수 )가 될 것입니다. 그렇지 않으면 뭔가 잘못된 것이겠죠?&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;그렇다면 지금까지 배운 두 손실함수를 한번 비교해 보겠습니다.&lt;/p&gt;
&lt;p&gt;이 두 손실함수의 가장 큰 차이점은 &quot;얼마나 구린지&quot;를 측정하기 위해 스코어를 해석하는 방식이 조금 다르다는 것입니다.&lt;/p&gt;
&lt;p&gt;SVM에서는 정답 스코어와, 정답이 아닌 스코어 간의 마진(margin)을 신경썼습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;반면 Softmax는 확률을 구해서 -log(정답클래스의 확률)에 신경을 썼습니다.&lt;/p&gt;
&lt;p&gt;그러면 이전 예제에서 car클래스에서 car의 스코어는 다른 클래스보다 훨씬 높았습니다.&lt;/p&gt;
&lt;p&gt;그래서 car스코어가 조금 변한다고 해서 SVM Loss가 변하거나 하진 않았죠, 왜냐하면 SVM은 정답과 그 외의 클래스의 margin만 관심 있기 때문이죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;이런점에서 softmax는 상당히 다릅니다. softmax는 언제나 확률을 1로 만들려고 노력할 것이기 때문에 정답 스코어가 충분히 높고 다른 클래스 스코어가 충분히 낮아도 최대한 정답 클래스에 확률을 몰아 넣으려고 함으로써 정답 클래스는 무한대로, 그외의 클래스는 음의 무한대로 보내려고 할 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;즉, SVM은 일정 margin만 넘기면 더이상 성능 개선에 신경을 쓰지 않지만, softmax는 성능을 계속해서 좋게 만들려고 노력할 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;이것이 매우 흥미로운 차이점인 것이죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;실제 딥러닝에서는 이 두 손실함수간의 성능차이는 엄청나게 크지는 않지만 그래도 차이를 알고 있다는 것은 유용할 것입니다.&lt;/p&gt;
&lt;p&gt;자, 그럼 이제는 어떻게 실제 Loss를 줄이는 W를 찾을 수 있는걸까요?&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우리는 이 방법을 '최적화 (Optimization)' 이라고 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;최적화에 대한 것은 다음 게시물에서 이어집니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
      <category>Study/Vision</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/111</guid>
      <comments>https://doromi.tistory.com/111#entry111comment</comments>
      <pubDate>Thu, 5 Mar 2020 17:57:50 +0900</pubDate>
    </item>
    <item>
      <title>CS231n 한글 정리 | Lecture 2 | Image Classification</title>
      <link>https://doromi.tistory.com/110</link>
      <description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;Stanford University에서 2017년에 강의한 영상을 보며 정리한 자료입니다.&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Link&lt;/strong&gt; : &lt;a href=&quot;https://www.youtube.com/playlist?list=PL3FW7Lu3i5JvHM8ljYj-zLfQRF3EO8sYv&quot;&gt;&lt;/a&gt;&lt;a href=&quot;https://www.youtube.com/playlist?list=PL3FW7Lu3i5JvHM8ljYj-zLfQRF3EO8sYv&quot;&gt;https://www.youtube.com/playlist?list=PL3FW7Lu3i5JvHM8ljYj-zLfQRF3EO8sYv&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;자료출처&lt;/b&gt; :&amp;nbsp;&lt;a href=&quot;http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture2.pdf&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;http://cs231n.stanford.edu/slides/2017/cs231n_2017_lecture2.pdf&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;참조&lt;/b&gt; :&amp;nbsp;&lt;a href=&quot;https://github.com/insurgent92/CS231N_17_KOR_SUB/blob/master/kor/Lecture%202%20%20%20Image%20Classification.ko.srt&quot; target=&quot;_blank&quot; class=&quot;tx-link&quot;&gt;https://github.com/insurgent92/CS231N_17_KOR_SUB/blob/master/kor/Lecture%202%20%20%20Image%20Classification.ko.srt&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Image Classification 은 어떻게 할 수 있을까요?&lt;/p&gt;&lt;p&gt;우선 이미지를 입력받아 어떤 카테고리에 속할지 판단하면 되겠죠&lt;/p&gt;&lt;p&gt;우리의 시각체계는 매우 고도화 되어있기 때문에 물체를 보자마자 바로 분류가 가능하지만 컴퓨터에게 이미지는 큰 격자모양의 숫자들의 집합이기 때문에 쉽게 분류하기가 어렵죠.&lt;/p&gt;&lt;ul&gt;
&lt;li&gt;ViewPoint variation → 보는 방향의 변화&lt;/li&gt;
&lt;li&gt;Iiiumiation → 조명에 따른 변화&lt;/li&gt;
&lt;li&gt;Deformaion → 형태의 변화&lt;/li&gt;
&lt;li&gt;Occlusion → 물체가 가려져 일부만 보여지는 경우&lt;/li&gt;
&lt;li&gt;Background Clutter →  배경과 비슷한 경우&lt;/li&gt;
&lt;li&gt;Interclass variation →  하나의 클레스에 속하는 물체들의 다양성&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;여러 문제들 때문에 인식의 어려움이 있을 수 있습니다.&lt;/p&gt;&lt;p&gt;*이전에도 이미지를 분류하기 위한 다양한 시도가 있었다&lt;/p&gt;&lt;p&gt;Huble과 Wiesel의 연구덕분에 Edges가 중요하다는 사실을 알게 되었고&lt;/p&gt;&lt;p&gt;Corner와 Edges를 이용하여 명시적인 규칙 집합을 만들어 분류하는 방식을 시도한 적이 있다.&lt;/p&gt;&lt;p&gt;이미지를 분류하는 방법에는 다양한 방식이 있지만 가장 첫번째로 생각해 볼 수 있는 방법은 NN입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;NN ( Nearest Neighbor )&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;가장 가까운 경우를 찾아서 그 레이블로 추측하는 방식입니다.&lt;/p&gt;&lt;p&gt;이를 위해서는 두가지 함수가 필요합니다. &quot;Train&quot; 과 &quot;Predict&quot;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Train&lt;/strong&gt; : 모든 training 데이터에 lable을 달아 저장하는 기능&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Predict&lt;/strong&gt; :  가장 유사한 training 데이터로 예측하는 기능&lt;/p&gt;&lt;p&gt;그렇다면 어떻게 유사도를 구할 수 있을까요?&lt;/p&gt;&lt;p&gt;














&lt;/p&gt;&lt;p&gt;여러 비교방법들이 있지만, 가장 단순한 방법은 L1 distance를 이용하는 것입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E60E3B5E60B14521&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E60E3B5E60B14521&quot; width=&quot;820&quot; height=&quot;333&quot; filename=&quot;2-1.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;L1 distance는 같은 자리의 픽셀값을 서로 빼고 절댓값을 취하여 모두 더하는 방식입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;*Image classification 문제에서 이 방법이 별로인 것 같지만 연습용으로는 매우 좋습니다 :)&lt;/p&gt;&lt;p&gt;왜냐하면 Train에 소요되는 시간은 O(1)이지만, Test시에는 N개의 학습데이터를 모두 비교해야하기 때문에 O(N)이 소요됩니다.&lt;/p&gt;&lt;p&gt;실제로 우리는 Train에서는 조금 느려도 되지만, Test 시에는 빠르게 동작하기를 원합니다.&lt;/p&gt;&lt;p&gt;따라서 그런 관점에서는 image classification에서 NN은 적합하지 않은 방법입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;




&lt;/p&gt;&lt;p&gt;( 앞으로 다루게될 CNN같은 모델은 소요시간적 관점에서 반대입니다! )&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 519px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/994C2D3B5E60B1451F&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F994C2D3B5E60B1451F&quot; width=&quot;519&quot; height=&quot;381&quot; filename=&quot;2-2.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;이 방법을 적용한다면 이러한 모양이 나올 것입니다.&lt;/p&gt;&lt;p&gt;위의 사진을 보면 이 분류방식은 그리 적절하지 않음을 알 수 있습니다.&lt;/p&gt;&lt;p&gt;NN은 가장 가까운 이웃만을 보기때문에 녹색구역 가운데에 노란색구역이 생긴 것을 볼 수 있습니다.&lt;/p&gt;&lt;p&gt;이부분또한 노란색이 아니라 녹색이어야 테스트시 더 좋은 성능을 낼 수 있을 것입니다.&lt;/p&gt;&lt;p&gt;( 그 노란색은 아마 noise거나 spurious일 것이기 때문이죠 )&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이러한 문제를 위해&lt;b&gt; K-NN 알고리즘&lt;/b&gt;이 탄생했습니다.&lt;/p&gt;&lt;p&gt;&lt;b&gt;K-NN 알고리즘&lt;/b&gt;은 가까운 이웃을 K개만큼 찾아 자신의 lable을 예측하는 방식입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;






&lt;/p&gt;&lt;p&gt;거리별 가중치를 가지고 예측할수도 있지만, 가장 단순하면서도 잘 동작하는 방식은 각 이웃들의 lable의 갯수만을 고려하는 것입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/999C573B5E60B14622&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F999C573B5E60B14622&quot; width=&quot;820&quot; height=&quot;242&quot; filename=&quot;2-3.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;이 사진을 보면 K가 달라지면서 경계가 더 부드러워 지는 것을 볼 수 있습니다.&lt;/p&gt;&lt;p&gt;하지만 사이사이에 생기는 흰색 영역은 어떻게 처리할 수 있을까요?&lt;/p&gt;&lt;p&gt;흰색영역은 k-nn에서 결정할 수 없는 지역입니다.&lt;/p&gt;&lt;p&gt;따라서 어떤식으로든 추론을 해보거나, 임의로 정할 수도 있을 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이번에도 비교함수를 어떤 것을 사용할지 결정해보아야 할 것입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;




&lt;/p&gt;&lt;p&gt;지금까지는&lt;b&gt; L1 distance&lt;/b&gt;를 이용했지만 &lt;b&gt;L2 distance&lt;/b&gt;를 이용할 수도 있을 것입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996F633B5E60B1461E&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996F633B5E60B1461E&quot; width=&quot;820&quot; height=&quot;362&quot; filename=&quot;2-4.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;L2 distance는 Euclidean distance 입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 두가지 척도간에는 아주 흥미로운 차이점이 있습니다.&lt;/p&gt;&lt;p&gt;&lt;u&gt;L1은 좌표 시스템에 따라 영향을 받습니다.&lt;/u&gt;&lt;/p&gt;&lt;p&gt;가령, 좌표시스템을 회전시키면 L1 distance도 변화합니다.&lt;/p&gt;&lt;p&gt;&lt;u&gt;L2는 영향을 받지 않습니다.&lt;/u&gt;&lt;/p&gt;&lt;p&gt;따라서 예컨데 특징 벡터의 각 요소들이 개별적 의미를 가지고 있다면 ( e.g. 키, 몸무게 )  L1이 더 잘 맞을 수 있겠죠.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;





&lt;/p&gt;&lt;p&gt;하지만 각 요소간의 실질적인 의미를 잘 모르는 경우에는 L2가 좋을 수 있을 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;K나 L1/L2 같은 것들 처럼 학습전에 미리 선택해야하는 변수들을 &quot;&lt;u&gt;하이퍼 파라미터&lt;/u&gt;&quot;라고 부릅니다.&lt;/p&gt;&lt;p&gt;이런 값들은 어떤것이 가장 좋은 성능을 낼 지 모르기 때문에 각 값들을 모두 시행해 보면서 실험하며 가장 적절한 값을 찾는 경우 도 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;

&lt;/p&gt;&lt;p&gt;하지만 test를 할때 유의해야 할 점이 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9986533B5E60B14724&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9986533B5E60B14724&quot; width=&quot;820&quot; height=&quot;411&quot; filename=&quot;2-5.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;training set에서의 정확도를 최대화 하는 것이 아니라 training set에 없는 데이터에 대해 높은 정확도를 가지도록 해야한다는 것입니다.&lt;/p&gt;&lt;p&gt;따라서 K=1인 경우가 training set에서 정확도가 가장 높겠지만 그 특정 training set에만 정확한 분류기가 될 가능성이 높습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그러면 가지고 있는 data set에서 일부를 training set으로 사용하고 일부를 test set으로 나눠서 사용하는건 어떨까요?&lt;/p&gt;&lt;p&gt;이 방법도 매우 위험합니다. 그 특정 test set에서만 잘 동작하는 분류기가 될 수 있기 때문입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그래서 더 일반적으로는 데이터를 3개로 쪼개는 방식을 사용합니다.&lt;/p&gt;&lt;p&gt;train, validation , test 로 데이터셋을 분리합니다.&lt;/p&gt;&lt;p&gt;training set으로 학습하고 validation으로 검증하고 test로 test를 진행하는것이죠.&lt;/p&gt;&lt;p&gt;검증시 가장 좋았던 분류기로 test는 딱 한번만 진행하는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;아래 보이는 사진은  Cross-Validation 방식입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;








&lt;/p&gt;&lt;p&gt;*이 방법은 데이터셋이 작은 경우에 많이 쓰입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/9958F23B5E60B14725&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F9958F23B5E60B14725&quot; width=&quot;820&quot; height=&quot;290&quot; filename=&quot;2-6.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;테스트셋을 제외한 데이터를 N개로 나누고 (여기서는 5개로 나누었습니다 )&lt;/p&gt;&lt;p&gt;4개의 fold에서 테스트를 하고 나머지 한개에서 validation을 진행하는 방식을 반복합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;

&lt;/p&gt;&lt;p&gt;각 하이퍼 파라미터에 대해서 이런식으로 테스트를 할 수 있을 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 이렇게 K-NN에 대해 열심히 배웠으나 이미지의 경우에서는 잘 사용하지 않습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;첫번째 문제점은, 앞서 말한대로 너무 느리다는 점입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;두번째 문제점은, L1/L2 Distance가 이미지간의 거리를 측정하기에 적절하지 않다는 점입니다.&lt;/p&gt;&lt;p&gt;


&lt;/p&gt;&lt;p&gt;아래의 사진에서 왼쪽의 한 여성이 있고 나머지 세개의 사진은 왜곡된 이미지입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99F18A3B5E60B14709&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99F18A3B5E60B14709&quot; width=&quot;820&quot; height=&quot;237&quot; filename=&quot;2-7.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 이들은 모두 같은 L2 Distance를 갖습니다. 즉, L2 Distance가 지각적 유사도를 측정하기에 적합하지 않다는 의미가 되겠죠&lt;/p&gt;&lt;p&gt;이미지들이 모두 같은 사람이므로 distance가 같으면 좋은것이 아닐까요?&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이 예시에서는 그럴 수 있지만, 예컨데 다른 두개의 이미지가 있는데 어떤 적절한 위치에 박스를 놓거나 색을 더하거나 한 경우에 두 이미지가 다름에도 불구하고 Distance를 매우 근접하게 만들 수 있는 경우가 생길 수 있겠죠.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;세번째 문제점은, 차원의 저주입니다. K-NN은 트레이닝 데이터를 이용하여 공간을 분할합니다.&lt;/p&gt;&lt;p&gt;그말은 즉, K-NN이 잘 동작하려면 전체 공간을 조밀하게 커버할 만큼 충분한 트레이닝 샘플이 필요하다는 말입니다.  하지만 차원이 증가하면서 필요한 데이터의 양은 기하급수적으로 증가합니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;




&lt;/p&gt;&lt;p&gt;따라서 K-NN은 잘 쓰이지 않습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;다음은&lt;span style=&quot;font-size: 12pt;&quot;&gt; &lt;/span&gt;&lt;b&gt;&lt;span style=&quot;font-size: 12pt;&quot;&gt;Linear Classification&lt;/span&gt;&lt;/b&gt;입니다.&lt;/p&gt;&lt;p&gt;
&lt;/p&gt;&lt;p&gt;&lt;b&gt;Linear Classification&lt;/b&gt; 은 NN과 CNN의 기반 알고리즘이며 &quot;parametric model&quot;의 가장 기본적인 모습입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99E5BC3B5E60B14821&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99E5BC3B5E60B14821&quot; width=&quot;820&quot; height=&quot;347&quot; filename=&quot;2-8.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;왼쪽의 고양이는 입력이미지 입니다.&lt;/p&gt;&lt;p&gt;입력이미지는 일반적으로 &quot;X&quot;로 사용합니다.&lt;/p&gt;&lt;p&gt;우리는 데이터 &quot;X&quot;와 parameter &quot;W&quot;를 가지고 10개의 숫자를 출력할 것입니다.&lt;/p&gt;&lt;p&gt;여기서 W는 가중치, &quot;W&quot;라고도 하고 theta(세타)라고도 합니다.&lt;/p&gt;&lt;p&gt;10개의 숫자는 학습을 위해 사용할 데이터인 CIFAR-10의 각 10개의 카테고리 스코어입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;




&lt;/p&gt;&lt;p&gt;여기서 스코어란, &quot;고양이&quot;의 스코어가 높다면 X가 고양이일 가능성이 높다는 뜻으로 해석될 것입니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;우리는 어떤식으로 W와 데이터를 조합할지 여러가지 방법을 생각해 볼 수 있지만 가장 단순한 방법은 둘을 곱하는 것입니다.&amp;nbsp;&lt;/p&gt;&lt;p&gt;그리고 그것이 Linear Classificaion입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이제 이들의 차원을 보겠습니다. 입력이미지는 32 * 32 * 3 입니다.&lt;/p&gt;&lt;p&gt;이 이미지를 길게 펴면 3072 벡터가 됩니다.&lt;/p&gt;&lt;p&gt;이제 이 3072벡터가 10개의 스코어로 되어야합니다.&lt;/p&gt;&lt;p&gt;따라서 행렬 W은 10*3072가 되어야 합니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;그리고 가끔 b (Bias)를 보게 될 텐데 이것은 데이터와 무관하게 특정 클레스에 우선권을 부여합니다.&lt;/p&gt;&lt;p&gt;예를들어, 데이터 셋이 불균형한 경우 (고양이&amp;lt;개 인경우) 고양이의 바이어스가 더 커지게 됩니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;






&lt;/p&gt;&lt;p&gt;이제 이 함수가 어떻게 동작하는지 보겠습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99B6BE3E5E60B1481C&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99B6BE3E5E60B1481C&quot; width=&quot;820&quot; height=&quot;374&quot; filename=&quot;2-9.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;*이 예제에서는 3가지 클레스로의 분류만 보도록 하겠습니다.&lt;/p&gt;&lt;p&gt;왼쪽의 2*2 고양이 이미지가 있습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;이미지를 4-dim 열벡터로 펼칩니다.&lt;/p&gt;&lt;p&gt;3개의 분류를 할 것이므로 가중치 W는 4*3행렬이 될 것이고, bias는 3-dim 열이 되겠죠&lt;/p&gt;&lt;p&gt;그러면 W와  4-dim 열벡터 (data)를 내적하고 , bias를 더해주면 각 분류에 맞는 스코어가 나오겠죠.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;




&lt;/p&gt;&lt;p&gt;(내적은 클래스간 탬플릿의 유사도를 측정하는 것과 유사하다고 보면 좋습니다. )&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 380px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/996D363E5E60B14923&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F996D363E5E60B14923&quot; width=&quot;380&quot; height=&quot;271&quot; filename=&quot;2-11.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Linear Classification은 고차원의 공간에서 NN처럼 일종의 &quot;결정경계&quot;를 학습한다고 볼 수 있습니다.&lt;/p&gt;&lt;p&gt;그 공간의 차원은 이미지의 픽셀 값에 해당되는 것입니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;하지만 이미지가 고차원의 공간의 하나의 점이라는 관점에서 생각하면 Linear Classification이 직면할 수 있는 문제가 있습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;


&lt;/p&gt;&lt;p&gt;아래와 같은 케이스는 분류하기 매우 까다롭습니다.&lt;/p&gt;&lt;p style=&quot;text-align: center; clear: none; float: none;&quot;&gt;&lt;span class=&quot;imageblock&quot; style=&quot;display: inline-block; width: 820px;  height: auto; max-width: 100%;&quot;&gt;&lt;img src=&quot;https://t1.daumcdn.net/cfile/tistory/99C2DE3E5E60B14921&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Ft1.daumcdn.net%2Fcfile%2Ftistory%2F99C2DE3E5E60B14921&quot; width=&quot;820&quot; height=&quot;401&quot; filename=&quot;2-10.PNG&quot; filemime=&quot;image/jpeg&quot;/&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;하지만 Linear Classification은 매우 쉽게 이해하고 해석할 수 있는 알고리즘 입니다.&lt;/p&gt;&lt;p&gt;여기서는 W행렬을 어떻게 구하는 지에서는 아직 다루지 않았습니다.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;

&lt;/p&gt;&lt;p&gt;다음 강의에서는 가중치 행렬 W를 구하는 방법과 다양한 알고리즘에 대해 다루겠습니다.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;</description>
      <category>Study/Vision</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/110</guid>
      <comments>https://doromi.tistory.com/110#entry110comment</comments>
      <pubDate>Thu, 5 Mar 2020 17:07:02 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]376. Wiggle Subsequence</title>
      <link>https://doromi.tistory.com/108</link>
      <description>&lt;p&gt;376.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Wiggle Subsequence&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A sequence of numbers is called a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;wiggle sequence&lt;/b&gt;if the differences between successive numbers strictly alternate between positive and negative. The first difference (if one exists) may be either positive or negative. A sequence with fewer than two elements is trivially a wiggle sequence.&lt;/p&gt;
&lt;p&gt;For example,&lt;span&gt;&amp;nbsp;&lt;/span&gt;[1,7,4,9,2,5]&lt;span&gt;&amp;nbsp;&lt;/span&gt;is a wiggle sequence because the differences&lt;span&gt;&amp;nbsp;&lt;/span&gt;(6,-3,5,-7,3)&lt;span&gt;&amp;nbsp;&lt;/span&gt;are alternately positive and negative. In contrast,&lt;span&gt;&amp;nbsp;&lt;/span&gt;[1,4,7,2,5]&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;[1,7,4,5,5]&lt;span&gt;&amp;nbsp;&lt;/span&gt;are not wiggle sequences, the first because its first two differences are positive and the second because its last difference is zero.&lt;/p&gt;
&lt;p&gt;Given a sequence of integers, return the length of the longest subsequence that is a wiggle sequence. A subsequence is obtained by deleting some number of elements (eventually, also zero) from the original sequence, leaving the remaining elements in their original order.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;&lt;span&gt;[1,7,4,9,2,5]&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;6 &lt;b&gt;Explanation:&lt;/b&gt; &lt;/span&gt;The entire sequence is a wiggle sequence.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;&lt;span&gt;[1,17,5,10,13,15,10,5,16,8]&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;7 &lt;/span&gt;&lt;span&gt;&lt;b&gt;Explanation: &lt;/b&gt;&lt;/span&gt;There are several subsequences that achieve this length. One is [1,17,10,13,10,16,8].&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;&lt;span&gt;[1,2,3,4,5,6,7,8,9]&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;2&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Follow up:&lt;/b&gt;&lt;br /&gt;Can you do it in O(&lt;i&gt;n&lt;/i&gt;) time?&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565880898604&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def wiggleMaxLength(self, nums):
        TurnNeg = None
        if nums ==[] :
            return 0
        cnt =0
        for i, num in enumerate(nums[:-1]):
            if TurnNeg is None and nums[i]-nums[i+1] !=0:
                TurnNeg  = nums[i]-nums[i+1]&amp;gt;0
                cnt +=1
            if (TurnNeg and nums[i]-nums[i+1]&amp;lt;0 ) or (not TurnNeg and nums[i]-nums[i+1]&amp;gt;0):
                #print(nums[i])
                cnt +=1
                TurnNeg = not TurnNeg
        return cnt+1&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/108</guid>
      <comments>https://doromi.tistory.com/108#entry108comment</comments>
      <pubDate>Thu, 15 Aug 2019 23:55:03 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]134. Gas Station</title>
      <link>https://doromi.tistory.com/107</link>
      <description>&lt;p&gt;134.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Gas Station&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;There are&lt;span&gt;&amp;nbsp;&lt;/span&gt;N&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas stations along a circular route, where the amount of gas at station&lt;span&gt;&amp;nbsp;&lt;/span&gt;i&lt;span&gt;&amp;nbsp;&lt;/span&gt;is&lt;span&gt;&amp;nbsp;&lt;/span&gt;gas[i].&lt;/p&gt;
&lt;p&gt;You have a car with an unlimited gas tank and it costs&lt;span&gt;&amp;nbsp;&lt;/span&gt;cost[i]&lt;span&gt;&amp;nbsp;&lt;/span&gt;of gas to travel from station&lt;span&gt;&amp;nbsp;&lt;/span&gt;i&lt;span&gt;&amp;nbsp;&lt;/span&gt;to its next station (i+1). You begin the journey with an empty tank at one of the gas stations.&lt;/p&gt;
&lt;p&gt;Return the starting gas station's index if you can travel around the circuit once in the clockwise direction, otherwise return -1.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If there exists a&amp;nbsp;solution, it is guaranteed to be unique.&lt;/li&gt;
&lt;li&gt;Both input arrays are non-empty and have the same length.&lt;/li&gt;
&lt;li&gt;Each element in the input arrays is a non-negative integer.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; gas = [1,2,3,4,5] cost = [3,4,5,1,2] &lt;b&gt;Output:&lt;/b&gt; 3 &lt;b&gt;Explanation: &lt;/b&gt;Start at station 3 (index 3) and fill up with 4 unit of gas. Your tank = 0 + 4 = 4 Travel to station 4. Your tank = 4 - 1 + 5 = 8 Travel to station 0. Your tank = 8 - 2 + 1 = 7 Travel to station 1. Your tank = 7 - 3 + 2 = 6 Travel to station 2. Your tank = 6 - 4 + 3 = 5 Travel to station 3. The cost is 5. Your gas is just enough to travel back to station 3. Therefore, return 3 as the starting index.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; gas = [2,3,4] cost = [3,4,3] &lt;b&gt;Output:&lt;/b&gt; -1 &lt;b&gt;Explanation: &lt;/b&gt;You can't start at station 0 or 1, as there is not enough gas to travel to the next station. Let's start at station 2 and fill up with 4 unit of gas. Your tank = 0 + 4 = 4 Travel to station 0. Your tank = 4 - 3 + 2 = 3 Travel to station 1. Your tank = 3 - 3 + 3 = 3 You cannot travel back to station 2, as it requires 4 unit of gas but you only have 3. Therefore, you can't travel around the circuit once no matter where you start.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565879729520&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def canCompleteCircuit(self, gas, cost):
        
        start = 0
        l_path = len(gas)
        while start&amp;lt;l_path:
            if gas[start] &amp;lt; cost[start]:
                start +=1
                continue
            far = 0
            cur_gas = 0
            while far &amp;lt; l_path and cur_gas&amp;gt;=0 :
                pos = (start+far)%l_path
                cur_gas += gas[pos] - cost[pos]
                far +=1
                
            if far == l_path and cur_gas &amp;gt;=0:
                return start
            start +=1
        return -1
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565879910999&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def canCompleteCircuit(self, gas, cost):
        start = 0
        if sum(gas) &amp;lt; sum(cost):
            return -1
        
        cur_gas =0
        for i in range(len(gas)):
            cur_gas += gas[i]-cost[i]
            if cur_gas &amp;lt;0:
                start = i+1
                cur_gas = 0
        return start&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/107</guid>
      <comments>https://doromi.tistory.com/107#entry107comment</comments>
      <pubDate>Thu, 15 Aug 2019 23:38:35 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]43. Multiply Strings</title>
      <link>https://doromi.tistory.com/106</link>
      <description>&lt;p&gt;43.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Multiply Strings&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given two non-negative integers&lt;span&gt;&amp;nbsp;&lt;/span&gt;num1&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;num2represented as strings, return the product of&lt;span&gt;&amp;nbsp;&lt;/span&gt;num1and&lt;span&gt;&amp;nbsp;&lt;/span&gt;num2, also represented as a string.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; num1 = &quot;2&quot;, num2 = &quot;3&quot; &lt;b&gt;Output:&lt;/b&gt; &quot;6&quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; num1 = &quot;123&quot;, num2 = &quot;456&quot; &lt;b&gt;Output:&lt;/b&gt; &quot;56088&quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The length of both&lt;span&gt;&amp;nbsp;&lt;/span&gt;num1&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;num2&lt;span&gt;&amp;nbsp;&lt;/span&gt;is &amp;lt; 110.&lt;/li&gt;
&lt;li&gt;Both&lt;span&gt;&amp;nbsp;&lt;/span&gt;num1&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;num2&lt;span&gt;&amp;nbsp;&lt;/span&gt;contain&amp;nbsp;only digits&lt;span&gt;&amp;nbsp;&lt;/span&gt;0-9.&lt;/li&gt;
&lt;li&gt;Both&lt;span&gt;&amp;nbsp;&lt;/span&gt;num1&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;num2&amp;nbsp;do not contain any leading zero, except the number 0 itself.&lt;/li&gt;
&lt;li&gt;You&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;must not use any built-in BigInteger library&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;or&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;convert the inputs to integer&lt;/b&gt;directly.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565878094248&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def multiply(self, num1, num2):
        if num1 ==&quot;0&quot; or num2 ==&quot;0&quot;:
            return &quot;0&quot;
        partialMult = []
        for i in range(len(num2)-1,-1,-1):
            cur_mult = [0 for _ in range(len(num2)-1-i)]
            n2 = int(num2[i])
            carry = 0
            
            for j in range(len(num1)-1,-1,-1):
                mult = n2 * int(num1[j]) + carry 
               
                carry = mult/10
                r = mult%10
                cur_mult.append(r)
            if carry &amp;gt;0:
                cur_mult.append(carry)
            partialMult.append(cur_mult)
        
       
        multSum = partialMult[0]
        for part in partialMult[1:]:
            carry = 0
            i = 0
            while i&amp;lt;len(multSum) or i&amp;lt;len(part) or carry&amp;gt;0:
                curSum = carry
                if i&amp;lt;len(multSum):
                    curSum +=multSum[i]
                if i&amp;lt;len(part):
                    curSum +=part[i]
                carry = curSum/10
                r = curSum%10
                if i &amp;lt; len(multSum):
                    multSum[i] = r
                else :
                    multSum.append(r)
                i+=1
        multSum.reverse()
        return ''.join(map(str,multSum))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;차근차근 풀면 풀리는 문제지만&lt;/p&gt;
&lt;p&gt;덜렁대면 절대 못푸는 문제이다.&lt;/p&gt;
&lt;p&gt;우선 가장 오른쪽끝부터 계산해야한다는 점을 기억해야한다. 그래서 뒤에서부터 계산하는 연산과정을 넣어야하고&lt;/p&gt;
&lt;p&gt;0을 체워넣을때에도 인덱스로 바로 하면안되고 뒤집어 있기때문에 len(num2)-1-i로 해서 체워넣어야한다.&lt;/p&gt;
&lt;p&gt;그리고나서 partialMult를 처리할때에도 while문 을 or로 처리했기 때문에 i가 범위를 초과하는지를 꼭 체크해야하고&lt;/p&gt;
&lt;p&gt;join은 문자열만 하기때문에 multSum이 integer로 이루어져있는것을 str로 변경후 concat해야한다.&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/106</guid>
      <comments>https://doromi.tistory.com/106#entry106comment</comments>
      <pubDate>Thu, 15 Aug 2019 23:10:31 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]1140. Stone Game II</title>
      <link>https://doromi.tistory.com/105</link>
      <description>&lt;p&gt;1140.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Stone Game II&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Alex&amp;nbsp;and Lee continue their&amp;nbsp;games with piles of stones.&amp;nbsp; There are a number of&amp;nbsp;piles&amp;nbsp;&lt;b&gt;arranged in a row&lt;/b&gt;, and each pile has a positive integer number of stones&amp;nbsp;piles[i].&amp;nbsp; The objective of the game is to end with the most&amp;nbsp;stones.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Alex and Lee take turns, with Alex starting first.&amp;nbsp; Initially,&lt;span&gt;&amp;nbsp;&lt;/span&gt;M = 1.&lt;/p&gt;
&lt;p&gt;On each player's turn, that player&amp;nbsp;can take&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;all the stones&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;in the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;first&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;X&lt;span&gt;&amp;nbsp;&lt;/span&gt;remaining piles, where&lt;span&gt;&amp;nbsp;&lt;/span&gt;1 &amp;lt;= X &amp;lt;= 2M.&amp;nbsp; Then, we set&amp;nbsp;M = max(M, X).&lt;/p&gt;
&lt;p&gt;The game continues until all the stones have been taken.&lt;/p&gt;
&lt;p&gt;Assuming Alex and Lee play optimally, return the maximum number of stones Alex can get.&lt;/p&gt;
&lt;pre id=&quot;code_1565863528830&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def stoneGameII(self, piles):
        n = len(piles)
        for i in range(n-2,-1,-1):
            piles[i] += piles[i+1]
        cache ={}
        def dfs(i, m):
            if (i,m) in cache:
                return cache[(i,m)]
            
            if i+2*m &amp;gt;=n:
                cache[(i,m)] = piles[i]
                return cache[(i,m)]
            
            max_piles = piles[i] - min([dfs(i+x,max(x,m)) for x in range(1,2*m+1)])
            cache[(i,m)] = max_piles
            return cache[(i,m)]
        return dfs(0,1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;minmax알고리즘 쓰는 문제 처음풀어본다...&lt;/p&gt;
&lt;p&gt;너무신기하다&lt;/p&gt;
&lt;p&gt;너무어려다&lt;/p&gt;
&lt;p&gt;여기에다가 dp 메모이제이션을 추가한 코드이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;와우 와우와우&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/105</guid>
      <comments>https://doromi.tistory.com/105#entry105comment</comments>
      <pubDate>Thu, 15 Aug 2019 19:06:06 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]1143. Longest Common Subsequence</title>
      <link>https://doromi.tistory.com/104</link>
      <description>&lt;p&gt;1143.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Longest Common Subsequence&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given two strings&lt;span&gt;&amp;nbsp;&lt;/span&gt;text1&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;text2, return the length of their longest common subsequence.&lt;/p&gt;
&lt;p&gt;A&lt;span&gt;&amp;nbsp;&lt;/span&gt;subsequence&lt;span&gt;&amp;nbsp;&lt;/span&gt;of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, &quot;ace&quot; is a subsequence of &quot;abcde&quot; while &quot;aec&quot; is not).&amp;nbsp;A&lt;span&gt;&amp;nbsp;&lt;/span&gt;common subsequence&amp;nbsp;of two strings is a subsequence that is common to both strings.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If there is no common subsequence, return 0.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; text1 = &quot;abcde&quot;, text2 = &quot;ace&quot; &lt;b&gt;Output:&lt;/b&gt; 3 &lt;b&gt;Explanation:&lt;/b&gt; The longest common subsequence is &quot;ace&quot; and its length is 3.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; text1 = &quot;abc&quot;, text2 = &quot;abc&quot; &lt;b&gt;Output:&lt;/b&gt; 3 &lt;b&gt;Explanation:&lt;/b&gt; The longest common subsequence is &quot;abc&quot; and its length is 3.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; text1 = &quot;abc&quot;, text2 = &quot;def&quot; &lt;b&gt;Output:&lt;/b&gt; 0 &lt;b&gt;Explanation:&lt;/b&gt; There is no such common subsequence, so the result is 0.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Constraints:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1 &amp;lt;= text1.length &amp;lt;= 1000&lt;/li&gt;
&lt;li&gt;1 &amp;lt;= text2.length &amp;lt;= 1000&lt;/li&gt;
&lt;li&gt;The input strings consist of lowercase English characters only.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1565859810883&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def longestCommonSubsequence(self, text1, text2):
        l1 , l2 = len(text1), len(text2)
        
        pre = [0]*(l2+1)
        cur = [0]*(l2+1)
        for i in range(1, l1+1):
            for j in range(1, l2+1):
                if text1[i-1] == text2[j-1]:
                    cur[j] = pre[j-1]+1
                else :
                    cur[j] = max(cur[j-1], pre[j])
            pre, cur = cur, pre
            
        return pre[-1]
        &lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 41.3271%; height: 95px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;t&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;e&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;n&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;t&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;h&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;e&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%; height: 19px;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;여기서 [t,t]를 보면 't'와 't' 사이에 가장긴 subsequence의 길이를 의미하는거다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음 [t,n]은 ' t'와 'ten'사이에 가장 긴 subsequence의 길이를 의미하는거다&lt;/p&gt;
&lt;p&gt;순차적으로 문자가 포함됬을경우를 확인하며 subsequence길이를 업데이트 해주는 것인데&lt;/p&gt;
&lt;p&gt;두 문자열의 글자가 같다면 두 문자열에서 그 글자가 포함되지 않은 경우 즉, 왼쪽 위 대각선부분의 값+1을 해주어야 한다.&lt;/p&gt;
&lt;p&gt;같지 않다면 현재 단어가 포함되지 않은 상황 즉 , [h,e]에 서 h가 포함되지 않은 상황 (위쪽 값), e가 포함되지 않은 값 (왼쪽 값)중에 큰 값을&amp;nbsp;&lt;/p&gt;
&lt;p&gt;가지도록 하여 현재 상황에서 최대길이를 가지고 있도록 한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;만약 이 상황에서 subsequence를 구하고 싶다면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;배열의 가장끝부터 체크하면서 큰값의 가장 작은 인덱스를 확인하고 현재 열보다 인덱스가 작은 열에서 다시 확인하고 반복하여 체크하면 된다. 처음에는 e가 있는 열 (3번)에서 2가 끝나는 지점인 (2번행)을 확인하고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그다음에 h가 있는 열 (2번)에서 (2번행)부터 체크하여 가장 큰값이 언제 끝나는지 확인하고 (1번행)이라는 것을 확인하여 &quot;t,e&quot;라는 것을 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 42.9569%; height: 97px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;t&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;e&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;n&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&amp;nbsp;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;t&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;h&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #f41a18;&quot;&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;e&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;&lt;span style=&quot;color: #f41a18;&quot;&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 12.5%;&quot;&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/104</guid>
      <comments>https://doromi.tistory.com/104#entry104comment</comments>
      <pubDate>Thu, 15 Aug 2019 18:28:13 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]31. Next Permutation</title>
      <link>https://doromi.tistory.com/103</link>
      <description>&lt;p&gt;31.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Next Permutation&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Implement&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;next permutation&lt;/b&gt;, which rearranges numbers into the lexicographically next greater permutation of numbers.&lt;/p&gt;
&lt;p&gt;If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).&lt;/p&gt;
&lt;p&gt;The replacement must be&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/In-place_algorithm&quot;&gt;in-place&lt;/a&gt;&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;and use only constant&amp;nbsp;extra memory.&lt;/p&gt;
&lt;p&gt;Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.&lt;/p&gt;
&lt;p&gt;1,2,3&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1,3,2&lt;br /&gt;3,2,1&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1,2,3&lt;br /&gt;1,1,5&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;rarr;&lt;span&gt;&amp;nbsp;&lt;/span&gt;1,5,1&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565854321303&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def sort(self, nums, start ):
        for i in range(start, len(nums)-1):
            min_index = i
            for j in range(i+1, len(nums)):
                if nums[j] &amp;lt; nums[min_index]:
                    min_index =j
            if min_index != i :
                nums[min_index] , nums[i] = nums[i], nums[min_index]
        
        
    def getNext(self, nums, start ):
        if start &amp;gt;= len(nums)-1:
            return False
        
        IsChanged = self.getNext(nums, start+1)
        if IsChanged:
            return True
        nextNum = -1 
        for i in range(start+1,len(nums)):
            if nums[start]&amp;lt;nums[i] and (nextNum &amp;lt;0  or nums[nextNum] &amp;gt; nums[i]):
                nextNum = i 
        if nextNum &amp;lt; 0 :
            return False
        else :
            nums[start], nums[nextNum] = nums[nextNum], nums[start]
            self.sort(nums, start+1)
        return True
        
    
    def nextPermutation(self, nums):
        IsChanged = self.getNext(nums, 0)
        if IsChanged :
            return 
        else :
            nums.sort()
            return &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;getNext를 통해서 현재 위치보다 오른쪽에 있는 것들중에 더 큰 수가 잇는지 확인하고, 그 큰수들 중에 가장 작은 수와 현재 위치를 바꾸고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;현재 위치 다음부분을 정렬한다. in-place라서 선택정렬로 정렬을 할 수 있도록 했다.&lt;/p&gt;
&lt;p&gt;BigO(N^2)일 것같다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;하지만 좋은 코드를 보고 큰 깨달음을 얻었는데,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;사실 현재 위치보다 오른쪽에 자신보다 큰수가 없다는 것은 현재 위치로부터 오른쪽으로 내림차순 정렬 되어있다는 것이고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그것을 반복적으로 하다가 현재 위치보다 오른쪽에 큰수가 있을때에는 그 오른쪽은 이미 내림차순 정렬 되어있다고 가정해도 좋다는 것이다.&amp;nbsp; 그러면 현재 위치의 숫자와 가장 오른쪽 끝 숫자부터 비교하다가 현재 위치 숫자보다 큰 수를 발견하고 교환을 한다는 것은 오른쪽에 있는 수중에 현재 숫자보다는 크면서 오른쪽에 있는 숫자중에서는 작은편에 속하는 숫자를 선택했다는 것을 보장할 수 있다.&lt;/p&gt;
&lt;p&gt;그러면 그 두 수를 교환하고 나서도 원래 현재숫자는 오른쪽에 있던 숫자보다는 더 작으므로 자리가 바뀌여도 내림차순 정렬 되어있다는 것을 보장 할 수 있으며, 그말은 즉 오른쪽 부분을 reverse하면 오름차순으로 정렬된다는 것과 같은 의미가 될 것이다.&lt;/p&gt;
&lt;p&gt;WOW 정말 대단하다.&lt;/p&gt;
&lt;pre id=&quot;code_1565855393579&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    
    def nextPermutation(self, nums):
        i = len(nums)-1
        
        while i&amp;gt;0 and nums[i] &amp;lt;= nums[i-1]:
            i -=1
        if i==0:
            nums.reverse()
            return
        changePoint = i-1
        j = len(nums)-1
        
        while j&amp;gt;=0 and nums[changePoint] &amp;gt;= nums[j]:
            j -=1
        nums[changePoint], nums[j] = nums[j], nums[changePoint]
        l = changePoint+1
        r = len(nums)-1
        
        while l &amp;lt; r:
            nums[l] , nums[r] = nums[r], nums[l]
            l +=1
            r -=1
        
        return &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 이 코드에서 신경써야 할 점은 &amp;lt;=&amp;nbsp; 과 &amp;lt; 어떤 선택을 할 지이다.&lt;/p&gt;
&lt;p&gt;nums[i] &amp;lt; nums[i-1]: 인 경우에는&lt;/p&gt;
&lt;p&gt;num[i]== nums[i-1]에도 멈추고 변경하려고 하므로 &amp;lt;= 해야한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/103</guid>
      <comments>https://doromi.tistory.com/103#entry103comment</comments>
      <pubDate>Thu, 15 Aug 2019 16:51:19 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]29. Divide Two Integers</title>
      <link>https://doromi.tistory.com/102</link>
      <description>&lt;p&gt;29.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Divide Two Integers&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given two integers&lt;span&gt;&amp;nbsp;&lt;/span&gt;dividend&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;divisor, divide two integers without using multiplication, division and mod operator.&lt;/p&gt;
&lt;p&gt;Return the quotient after dividing&lt;span&gt;&amp;nbsp;&lt;/span&gt;dividend&lt;span&gt;&amp;nbsp;&lt;/span&gt;by&lt;span&gt;&amp;nbsp;&lt;/span&gt;divisor.&lt;/p&gt;
&lt;p&gt;The integer division should truncate toward zero.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; dividend = 10, divisor = 3 &lt;b&gt;Output:&lt;/b&gt; 3&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; dividend = 7, divisor = -3 &lt;b&gt;Output:&lt;/b&gt; -2&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565849648999&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def divide(self, dividend, divisor):
        if dividend == 0: return 0

        # initialize
        i, result, p, q = map(abs, (0, 0, dividend, divisor))

        # phase 1
        while q &amp;lt;&amp;lt; i &amp;lt;= p: i += 1

        # phase 2
        for j in reversed(range(i)):
            if q &amp;lt;&amp;lt; j &amp;lt;= p: p, result = p - (q &amp;lt;&amp;lt; j), result + (1 &amp;lt;&amp;lt; j)

        # stupid leetcode restrictions
        if (dividend &amp;gt; 0) != (divisor &amp;gt; 0) or result &amp;lt; -1 &amp;lt;&amp;lt; 31: result = -result
        return min(result, (1 &amp;lt;&amp;lt; 31) - 1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이거는 손계산할때 나눗셈하는 것과 같은 원리이다.&lt;/p&gt;
&lt;p&gt;phase 1은&amp;nbsp;&lt;/p&gt;
&lt;p&gt;divisor을 왼쪽으로 몇번 쉬프트 할때까지 dividend보다 작은지를 체크한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그말은 몫이 2진수로 몇자리가 되는지를 체크하는것&lt;/p&gt;
&lt;p&gt;그다음 큰수부터 나누면서 dividend를 나눈만크 줄여주고, 결과는 나눈 수 만큼 더해준다.&lt;/p&gt;
&lt;p&gt;그리고 음수거나 , 음수범위보다 더 크면 부호를 바꿔서&amp;nbsp;&lt;/p&gt;
&lt;p&gt;dividend나 divisor중에 하나라도 음수면 음수의 결과가 나올 수 있도록 하고,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;음수 범위보다 더 크면 부호를 바꿔서 양수이면서 integer범위보다 더 큰 수가 될것이고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러면 return시에 min에서 1&amp;lt;&amp;lt;31 -1보다 크므로 1&amp;lt;&amp;lt;31 -1이 나올 수 있도록 처리된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;어려웠다.... 개념적으로는 알겠는데&lt;/p&gt;
&lt;p&gt;이걸 구현하려니까 어떻게 해야할지 잘 모르겠었고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2진수로 만들려니까 어렵다........&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/102</guid>
      <comments>https://doromi.tistory.com/102#entry102comment</comments>
      <pubDate>Thu, 15 Aug 2019 15:25:15 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]120. Triangle</title>
      <link>https://doromi.tistory.com/101</link>
      <description>&lt;p&gt;120.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Triangle&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.&lt;/p&gt;
&lt;p&gt;For example, given the following triangle&lt;/p&gt;
&lt;p&gt;[ [&lt;b&gt;2&lt;/b&gt;], [&lt;b&gt;3&lt;/b&gt;,4], [6,&lt;b&gt;5&lt;/b&gt;,7], [4,&lt;b&gt;1&lt;/b&gt;,8,3] ]&lt;/p&gt;
&lt;p&gt;The minimum path sum from top to bottom is&lt;span&gt;&amp;nbsp;&lt;/span&gt;11(i.e.,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;2&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;3&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;5&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;+&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;1&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 11).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Bonus point if you are able to do this using only&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(n) extra space, where&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;is the total number of rows in the triangle.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565846504189&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def minimumTotal(self, triangle):
        curMinList = triangle[-1]
        
        for level in range(len(triangle)-2,-1,-1):
            nextList = curMinList
            curMinList = []
            curList = triangle[level]
            for i , num in enumerate(curList):
                curMinList.append( min(num+nextList[i],num+nextList[i+1]))
        
        return curMinList[0]
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;더 깔끔한 코드&lt;/p&gt;
&lt;pre id=&quot;code_1565846730306&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def minimumTotal(self, triangle):
        for i in range(len(triangle)-1,0, -1):
            for j in range(i):
                triangle[i-1][j] += min(triangle[i][j] ,triangle[i][j+1])
        return triangle[0][0]
        &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/101</guid>
      <comments>https://doromi.tistory.com/101#entry101comment</comments>
      <pubDate>Thu, 15 Aug 2019 14:25:34 +0900</pubDate>
    </item>
    <item>
      <title>16.11 다이빙 보드</title>
      <link>https://doromi.tistory.com/100</link>
      <description>&lt;p&gt;문제&lt;/p&gt;
&lt;p&gt;다량의 널빤지를 이어 붙여서 다이빙 보드를 만들려고 한다. 널빤지는 길이가 긴 것과 짧은 것 두가지 종류가 있는데 정확히 K개의 널빤지를 사용하여 다이빙 보드를 만들어야 한다. 가능한 다이빙 보드의 길이를 모두 구하는 메서드를 작성하라&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해결법&lt;/p&gt;
&lt;p&gt;1. 재귀적 해법&lt;/p&gt;
&lt;p&gt;재귀적으로 K번의 널빤지를 선택하면 다이빙 보드를 완성할 수 있고 완성된 보드를 리스트에 추가하면 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;+ 메모이제이션&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565757237853&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def getAllLengths(k, long, short):
    memo = set()
    lengths = set()

def allLengths(k, lengths , total, long, short, memo):
    if k == 0:
        lengths.add(total)
    key = (total, k)
    if key in memo :
        return
    allLengths(k-1, lengths, total+long, long, short, memo)
    allLengths(k-1, lengths, total-short, long, short, memo)
    memo.add(key)
    return
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. 수열의 합만을 구하기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;어쩌피 널빤지는 2가지종류밖에 없으니 나올수 있는 경우의 수는 K+1밖에 없다.&lt;/p&gt;
&lt;p&gt;K = 7이면 long이 0개일때 shourt는 7,&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;long이 1개일때 shourt는 6, ... 이런식으로&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그러면 그냥 loop를 이용해서 구할 수 있다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp;하지만 한가지 생각해야할 부분이 있다. 두 판자의 길이가 같은 경우를 생각해야한다&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그런경우에는 원소가 하나인 배열을 반환하면 된다!!&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1565757369869&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def getAllLengths(k, long, short):

    lengths = []
    cnt_s = k
    if long != short:
        while cnt_s &amp;gt;=0 :
            cnt_l = k - cnt_s
            length = long*cnt_l + short*cnt_s
            lengths.add(length)
            cnt_s -=1
    else :
        return [long*k]
    return lengths
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/100</guid>
      <comments>https://doromi.tistory.com/100#entry100comment</comments>
      <pubDate>Wed, 14 Aug 2019 13:36:57 +0900</pubDate>
    </item>
    <item>
      <title>16.10 살아있는 사람</title>
      <link>https://doromi.tistory.com/99</link>
      <description>&lt;p&gt;문제&amp;nbsp;&lt;/p&gt;
&lt;p&gt;사람의 태어난 연도와 사망한 연도가 리스트로 주어졌을때, 가장 많은 사람이 동시에 살았던 연도를 찾는 메서드를 작성하라. 모든사람이 1900년도에서 2000년도 사이에서 태어났다고 가정해도 좋다. 또한 해당 연도의 일부만 살았더라도 해당 년도에 살아있었다고 봐야한다. 예르르들어 어떤 사람이 1908년에 태어나서 1909년에 사망했다면 이 사람은 1908년과 1909년 모두에 삶을 살았던 사람이된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해결법&lt;/p&gt;
&lt;p&gt;1. 무식한 방법&lt;/p&gt;
&lt;p&gt;각 년도를 순회하면서 각 년도에 살아있는 사람들을 카운트한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;R이 가능한 연도의 범위이고 P가 사람의 수라고 했을때 시간 복잡도는 O(RP)가 된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. 무식하지만 조금 나은 방법&lt;/p&gt;
&lt;p&gt;해마다 태어난 인구수를 기록하는 배열을 만들고, 사람을 순회하면서 배열에 기록한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;(배열을 잡을때 1900-2000 = 100개로 잡으면안되고 101개로 잡아야한다. 1900과 2000이 포함되기 때문)&lt;/p&gt;
&lt;p&gt;R이 가능한 연도의 범위이고 P가 사람의 수라고 하고 그사람이 살았던 구간을 Y라고 하면&amp;nbsp;&lt;/p&gt;
&lt;p&gt;O(PY + R) 이 된다. 하지만, Y=R이면 1번방법과 크게 달라지지 않는다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. 더 최적화&amp;nbsp;&lt;/p&gt;
&lt;p&gt;어쩌피 사람들의 정보 (태어난시간, 사망한시간)을 그대로 보존할 필요가 없다는 사실을 안다면 정렬을 해도좋다.&lt;/p&gt;
&lt;p&gt;태어난 시간끼리 정렬, 사망한 시간끼리 정렬을 한 다음에 하나씩 읽어들어가면서 사람이 태어났을때 +1 죽었을때는 -1을 하면서 최대 시간을 확인하면된다.&lt;/p&gt;
&lt;pre id=&quot;code_1565754120557&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def maxAliveYear(births, deaths, min, max):
    births.sort()
    deaths.sort()

    maxAlive = 0
    maxYear = 0
    curAlive = 0
    
    birthIndex = 0
    deathIndex = 0
    len_peoples = len(births)
    while deathsIndex != len_peoples:
        if birth[birthIndex] &amp;lt;= deaths[deathIndex] :
            curAlive +=1
            if maxAlive &amp;lt; curAlive :
                maxAlive = curAlive
                maxYear = births[birthIndex]
            birthIndex +=1
        else :
            curAlive -=1
            deathIndex +=1

    return maxYear&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이코드를 짤때에 주의해야할 점은 바로 birth[birthIndex] &amp;lt;= deaths[deathIndex] 이다.&lt;/p&gt;
&lt;p&gt;&amp;lt;= 인지 &amp;lt; 인지를 결정할때 태어난 년도에 사망한 사람이 있는 경우를 어떻게 처리할지에 대해 생각하면 답이 나온다.&lt;/p&gt;
&lt;p&gt;누군가가 해당 년도에 태어났고 누군가는 사망했다면 먼저 태어난것을 먼저 체크하고 그다음에 사망을 체크해주어야한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러려면 같은 경우에도 살아있는 사람 +1을 먼저 해야할 것이다.&lt;/p&gt;
&lt;p&gt;이경우의 Time complexity 는 사람들의 명수가 P일때 O(PlogP)일 것이다. sort가 있기 때문에&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. 더 최적화!&lt;/p&gt;
&lt;p&gt;PlogP보다 더 빨라지려면 정렬을 하지 말아야한다. 정렬을 안하면서도 최대 명수를 알기 위해서는 각 년도에 몇명이 태어났고 죽었는지를 미리 체크해두면 알 수 있을 것이다.&lt;/p&gt;
&lt;pre id=&quot;code_1565754215813&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def getPopulation(populationYears, births, deaths, min):
    for birth in births:
        populationYears[birth-min] +=1
    for death in deaths:
        populationYears[death-min+1] -=1



def maxAlive(births, deaths, min, max):
    populationYears = [0]*(max-min+1)
    getPopulation(populationYears, births, deaths , min)
    
    maxAlive = 0
    maxYear  = 0
    curAlive = 0
    for i, p in enumerate(populationYears):
        curAlive +=p
        if curAlive &amp;gt; maxAlive:
            maxAlive = curAlive
            maxYear = min+i

    return maxYear&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 경우에 조심해야할 부분은 사람이 태어난 년도에 인구+1을 하는 것은 맞지만 사망한 년도에 -1을 하게되면 해당년도에 누군가가 태어나고 누군가가 사망한경우는 상쇄되어 0으로 저장되어진다. 그러면 태어난 것을 카운트 할 수 없기 때문에 이런경우에는 사망년도 다음 년도에 -1을 하게 되면 간단하게 해결이 가능하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/99</guid>
      <comments>https://doromi.tistory.com/99#entry99comment</comments>
      <pubDate>Wed, 14 Aug 2019 12:49:50 +0900</pubDate>
    </item>
    <item>
      <title>16.1 숫자 교환</title>
      <link>https://doromi.tistory.com/98</link>
      <description>&lt;p&gt;문제&amp;nbsp;&lt;/p&gt;
&lt;p&gt;임시 변수를 사용하지 않고 숫자를 교환하는 함수를 작성하라.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해법&lt;/p&gt;
&lt;p&gt;이 문제는 두 수중 하나의 수에 그 둘의 '차이'를 가지고 있도록 하면 해결할 수 있는 문제이다.&lt;/p&gt;
&lt;p&gt;숫자 a, b가 있다면 a = a-b 를 통해 a가 차이를 가지고 있도록 하고, b = a&amp;nbsp; +b&amp;nbsp; 를 통해 a가 된다.&lt;/p&gt;
&lt;p&gt;그리고 다시 a = b -a를 통해 a 는 b가 된다.&lt;/p&gt;
&lt;p&gt;a = 9 b = 4라고 할때&lt;/p&gt;
&lt;p&gt;a = a- b ( a = 9 - 4 =5)&lt;/p&gt;
&lt;p&gt;b = a+b (b = 5+4 =9)&amp;nbsp;&lt;/p&gt;
&lt;p&gt;a = b-a ( a = 9-5 =4)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;비트로도 같은 연산이 가능하다. 이러면 정수 이외의 자료형에서도 동작한다는 이점이 있다.&lt;/p&gt;
&lt;p&gt;a&amp;nbsp; = a^b&lt;/p&gt;
&lt;p&gt;b = a^b&lt;/p&gt;
&lt;p&gt;a = a^b&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/98</guid>
      <comments>https://doromi.tistory.com/98#entry98comment</comments>
      <pubDate>Wed, 14 Aug 2019 10:34:43 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]300. Longest Increasing Subsequence</title>
      <link>https://doromi.tistory.com/97</link>
      <description>&lt;p&gt;300.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Longest Increasing Subsequence&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given an unsorted array of integers, find the length of longest increasing subsequence.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; [10,9,2,5,3,7,101,18] &lt;b&gt;Output: &lt;/b&gt;4 &lt;b&gt;Explanation: &lt;/b&gt;The longest increasing subsequence is [2,3,7,101], therefore the length is 4.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There may be more than one LIS combination, it is only necessary for you to return the length.&lt;/li&gt;
&lt;li&gt;Your algorithm should run in O(&lt;i&gt;n2&lt;/i&gt;) complexity.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Follow up:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Could you improve it to O(&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;log&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;) time complexity?&lt;/p&gt;
&lt;pre id=&quot;code_1565513262171&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def lengthOfLIS(self, nums):
        sub =[]
        def binarySearch(sub, num):
            l,r = 0, len(sub)-1
            while l&amp;lt;=r:
                mid = (l+r)//2
                if sub[mid] == num :
                    return mid
                elif sub[mid] &amp;lt; num:
                    l = mid+1
                else :
                    r = mid-1
            return l
        
        for n in nums:
            pos = binarySearch(sub, n)
            #print(pos)
            if len(sub)== pos:
                sub.append(n)
            else:
                sub[pos] = n
        return len(sub)
            
                &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/97</guid>
      <comments>https://doromi.tistory.com/97#entry97comment</comments>
      <pubDate>Sun, 11 Aug 2019 17:47:45 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]322. Coin Change</title>
      <link>https://doromi.tistory.com/96</link>
      <description>&lt;p&gt;322.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Coin Change&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You are given coins of different denominations and a total amount of money&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;amount&lt;/i&gt;. Write a function to compute the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;-1.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;coins = [1, 2, 5], amount = 11 &lt;b&gt;Output: &lt;/b&gt;3 &lt;b&gt;Explanation:&lt;/b&gt; 11 = 5 + 5 + 1&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;coins = [2], amount = 3 &lt;b&gt;Output: &lt;/b&gt;-1&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note&lt;/b&gt;:&lt;br /&gt;You may assume that you have an infinite number of each kind of coin.&lt;/p&gt;
&lt;pre id=&quot;code_1565507805849&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def coinChange(self, coins, amount):
        dp = [0]*(amount+1)
        for i in range(1, amount+1):
            if i in coins:
                dp[i] = 1
                continue
            min_coins = float(&quot;inf&quot;)
            for coin in coins:
                if i-coin &amp;gt;= 0:
                    min_coins = min(dp[i-coin], min_coins)
            dp[i] = min_coins+1
        if dp[-1] == float(&quot;inf&quot;):
            return -1
        return dp[-1]&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/96</guid>
      <comments>https://doromi.tistory.com/96#entry96comment</comments>
      <pubDate>Sun, 11 Aug 2019 16:16:51 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]62. Unique Paths</title>
      <link>https://doromi.tistory.com/95</link>
      <description>&lt;p&gt;62.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Unique Paths&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A robot is located at the top-left corner of a&lt;span&gt;&amp;nbsp;&lt;/span&gt;m&lt;span&gt;&amp;nbsp;&lt;/span&gt;x&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;grid (marked 'Start' in the diagram below).&lt;/p&gt;
&lt;p&gt;The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).&lt;/p&gt;
&lt;p&gt;How many possible unique paths are there?&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMaka9/btqxmw2aZuP/JScRnf0rGpmeNFNjDLyW11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMaka9/btqxmw2aZuP/JScRnf0rGpmeNFNjDLyW11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMaka9/btqxmw2aZuP/JScRnf0rGpmeNFNjDLyW11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMaka9%2Fbtqxmw2aZuP%2FJScRnf0rGpmeNFNjDLyW11%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Above is a 7 x 3 grid. How many possible unique paths are there?&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;m&lt;span&gt;&amp;nbsp;&lt;/span&gt;and&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;will be at most 100.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; m = 3, n = 2&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; 3&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt; From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:&lt;/p&gt;
&lt;p&gt;1. Right -&amp;gt; Right -&amp;gt; Down&amp;nbsp; &amp;nbsp;2. Right -&amp;gt; Down -&amp;gt; Right&amp;nbsp; &amp;nbsp; 3. Down -&amp;gt; Right -&amp;gt; Right&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; m = 7, n = 3&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; 28&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Solution 1 :&lt;/p&gt;
&lt;p&gt;중학교때 배운 최단거리 경우의수 구하는방식&lt;/p&gt;
&lt;pre id=&quot;code_1565499103544&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def uniquePaths(self, m, n):
        paths = [[0]*m for _ in range(n)]
        paths[0][0] = 1
        for i in range(n):
            for j in range(m):
                if i==0 and j ==0 :
                    continue
                paths[i][j] += paths[i-1][j] if i&amp;gt;0 else 0
                paths[i][j] += paths[i][j-1] if j&amp;gt;0 else 0
        
        return paths[i][j]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Solution 2:&lt;/p&gt;
&lt;p&gt;순열을 이용한 방법&lt;/p&gt;
&lt;p&gt;같은 것 p개 q개 r개 있는 n개의 것을 순서를 생각하며 나열하는 경우의 수는&amp;nbsp;&lt;/p&gt;
&lt;p&gt;n! /(p! * q! * n!)&lt;/p&gt;
&lt;pre id=&quot;code_1565499228863&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def uniquePaths(self, m, n):
        return self.factorial(m+n-2) / (self.factorial(m-1) * self.factorial(n-1))
    
    def factorial(self, n):
        num = 1
        while n &amp;gt;= 1:
            num = num * n
            n = n - 1
        return num&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/95</guid>
      <comments>https://doromi.tistory.com/95#entry95comment</comments>
      <pubDate>Sun, 11 Aug 2019 13:54:37 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]55. Jump Game</title>
      <link>https://doromi.tistory.com/94</link>
      <description>&lt;p&gt;55.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Jump Game&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given an array of non-negative integers, you are initially positioned at the first index of the array.&lt;/p&gt;
&lt;p&gt;Each element in the array represents your maximum jump length at that position.&lt;/p&gt;
&lt;p&gt;Determine if you are able to reach the last index.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; [2,3,1,1,4]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; true&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt; Jump 1 step from index 0 to 1, then 3 steps to the last index.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; [3,2,1,0,4]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; false&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt; You will always arrive at index 3 no matter what. Its maximum &amp;nbsp; jump length is 0, which makes it impossible to reach the last index.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;DFS + memorization 으로 풀었더니 Time limit exceeded 에러가 발생해서&lt;/p&gt;
&lt;p&gt;Discussion참고한 Solution&lt;/p&gt;
&lt;pre id=&quot;code_1565498083412&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def canJump(self, nums) :
        last = len(nums) - 1
        for i in range(len(nums)-1, -1, -1):
            if i + nums[i] &amp;gt;= last:
                last = i
        return nums[0] &amp;gt;= last&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/94</guid>
      <comments>https://doromi.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 11 Aug 2019 13:36:30 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]33. Search in Rotated Sorted Array</title>
      <link>https://doromi.tistory.com/93</link>
      <description>&lt;p&gt;33.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Search in Rotated Sorted Array&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.&lt;/p&gt;
&lt;p&gt;(i.e.,&lt;span&gt;&amp;nbsp;&lt;/span&gt;[0,1,2,4,5,6,7]&lt;span&gt;&amp;nbsp;&lt;/span&gt;might become&lt;span&gt;&amp;nbsp;&lt;/span&gt;[4,5,6,7,0,1,2]).&lt;/p&gt;
&lt;p&gt;You are given a target value to search. If found in the array return its index, otherwise return&lt;span&gt;&amp;nbsp;&lt;/span&gt;-1.&lt;/p&gt;
&lt;p&gt;You may assume no duplicate exists in the array.&lt;/p&gt;
&lt;p&gt;Your algorithm's runtime complexity must be in the order of&amp;nbsp;O(log&amp;nbsp;n).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; nums = [4,5,6,7,0,1,2], target = 0&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; 4&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; nums = [4,5,6,7,0,1,2], target = 3&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; -1&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565423355457&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def search(self, nums, target):
        l, r = 0 , len(nums)-1
        while l&amp;lt;=r :
            mid = (l+r)//2
            if nums[mid]== target:
                return mid
            elif nums[l] &amp;lt;= nums[mid] :
                if nums[mid] &amp;lt; target or (nums[mid] &amp;gt; target and nums[l] &amp;gt; target):
                    l = mid+1
                else :
                    r = mid-1
            else :
                if nums[mid] &amp;gt; target or(nums[mid] &amp;lt; target and nums[r] &amp;lt; target):
                    r = mid-1
                else :
                    l = mid +1
        return -1
                   &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/93</guid>
      <comments>https://doromi.tistory.com/93#entry93comment</comments>
      <pubDate>Sat, 10 Aug 2019 16:49:21 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode] 56. Merge Intervals</title>
      <link>https://doromi.tistory.com/92</link>
      <description>&lt;p&gt;56.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Merge Intervals&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a collection of intervals, merge all overlapping intervals.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[[1,3],[2,6],[8,10],[15,18]]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[[1,6],[8,10],[15,18]]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[[1,4],[4,5]]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[[1,5]]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Intervals [1,4] and [4,5] are considered overlapping.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;N&lt;/b&gt;&lt;b&gt;OTE:&lt;/b&gt;&amp;nbsp;input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565421290897&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def merge(self, intervals):
        intervals.sort()
        if len(intervals) &amp;lt;2:
            return intervals
        
        first = intervals[0]
        result = []
        for interval in intervals:
            if interval[0] &amp;gt; first[1]:
                result.append(first)
                first = interval
            else :
                first[1]= max(first[1],interval[1])
        result.append(first)
        return result&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/92</guid>
      <comments>https://doromi.tistory.com/92#entry92comment</comments>
      <pubDate>Sat, 10 Aug 2019 16:15:01 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]34. Find First and Last Position of Element in Sorted Array</title>
      <link>https://doromi.tistory.com/91</link>
      <description>&lt;p&gt;34.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Find First and Last Position of Element in Sorted Array&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given an array of integers&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums&lt;span&gt;&amp;nbsp;&lt;/span&gt;sorted in ascending order, find the starting and ending position of a given&lt;span&gt;&amp;nbsp;&lt;/span&gt;target&lt;span&gt;&amp;nbsp;&lt;/span&gt;value.&lt;/p&gt;
&lt;p&gt;Your algorithm's runtime complexity must be in the order of&lt;span&gt;&amp;nbsp;&lt;/span&gt;O(log&lt;span&gt;&amp;nbsp;&lt;/span&gt;n).&lt;/p&gt;
&lt;p&gt;If the target is not found in the array, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;[-1, -1].&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; nums = [5,7,7,8,8,10], target = 8&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; [3,4]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; nums = [5,7,7,8,8,10], target = 6&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; [-1,-1]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565420069297&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def searchRange(self, nums, target):
        l, r= 0 ,len(nums)-1
     
        while l&amp;lt;=r :
            mid = (l+r)//2
            if nums[mid] == target:
                l,r = mid, mid
                while l&amp;gt;=0 and nums[l]==target:
                    l-=1
                while r &amp;lt;len(nums) and nums[r]==target:
                    r+=1
                return [l+1, r-1]
            elif nums[mid] &amp;lt; target:
                l = mid+1
            else :
                r = mid-1
                
        return [-1,-1]
                &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/&quot;&gt;https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/91</guid>
      <comments>https://doromi.tistory.com/91#entry91comment</comments>
      <pubDate>Sat, 10 Aug 2019 15:54:52 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]162. Find Peak Element</title>
      <link>https://doromi.tistory.com/90</link>
      <description>&lt;p&gt;162.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Find Peak Element&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A peak element is an element that is greater than its neighbors.&lt;/p&gt;
&lt;p&gt;Given an input array&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums, where&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums[i] &amp;ne; nums[i+1], find a peak element and return its index.&lt;/p&gt;
&lt;p&gt;The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.&lt;/p&gt;
&lt;p&gt;You may imagine that&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums[-1] = nums[n] = -&amp;infin;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; &lt;b&gt;nums&lt;/b&gt; = [1,2,3,1] &lt;b&gt;Output:&lt;/b&gt; 2&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt; 3 is a peak element and your function should return the index number 2.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; &lt;b&gt;nums&lt;/b&gt; = [1,2,1,3,5,6,4] &lt;b&gt;Output:&lt;/b&gt; 1 or 5&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Explanation:&lt;/b&gt; Your function can return either index number 1 where the peak element is 2, &amp;nbsp; or index number 5 where the peak element is 6.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Your solution should be in logarithmic complexity.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;solution 1&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;좌우 살피기 pick인지&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;souluton 2&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;사실 내려가는 점만 찾으면 됨&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1565418488168&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def findPeakElement(self, nums):
        if len(nums) &amp;lt; 2: return 0
        n = len(nums)
        for i in range(n):
            if i &amp;lt; n -1 and nums[i + 1] &amp;lt; nums[i]: return i
        return n - 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;solution 3&lt;/p&gt;
&lt;p&gt;logarithmic coplexity를 위한 이진탐색법&amp;nbsp;&lt;/p&gt;
&lt;p&gt;while &amp;lt;=잊지말기&lt;/p&gt;
&lt;pre id=&quot;code_1565419075687&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def findPeakElement(self, nums):
        len_nums = len(nums)
        if len_nums &amp;lt;2:
            return 0
        if nums[0]&amp;gt;nums[1]:
            return 0
        if nums[-1]&amp;gt;nums[-2]:
            return len_nums -1
        l = 1
        r = len_nums-2
        while l &amp;lt;= r:
            mid = (l+r)//2
            if nums[mid] &amp;gt;= nums[mid-1] and nums[mid]&amp;gt;= nums[mid+1]:
                return mid
            if nums[mid-1] &amp;lt; nums[mid+1]:
                l = mid+1
            else :
                r = mid-1
        return -1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/find-peak-element&quot;&gt;https://leetcode.com/problems/find-peak-element&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/90</guid>
      <comments>https://doromi.tistory.com/90#entry90comment</comments>
      <pubDate>Sat, 10 Aug 2019 15:38:39 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]347. Top K Frequent Elements</title>
      <link>https://doromi.tistory.com/89</link>
      <description>&lt;p&gt;347.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Top K Frequent Elements&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a non-empty array of integers, return the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;i&gt;k&lt;/i&gt;&lt;/b&gt;most frequent elements.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;nums = &lt;span&gt;[1,1,1,2,2,3]&lt;/span&gt;, k = &lt;span&gt;2&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;[1,2]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;nums = &lt;span&gt;[1]&lt;/span&gt;, k = &lt;span&gt;1&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;[1]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may assume&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;k&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is always valid, 1 &amp;le;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;k&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;le; number of unique elements.&lt;/li&gt;
&lt;li&gt;Your algorithm's time complexity&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;must be&lt;/b&gt;better than O(&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;log&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;), where&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is the array's size.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;1 solution&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565415330023&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def topKFrequent(self, nums, k):
        cnt = {}
        for n in nums:
            cnt[n] = cnt.get(n,0)+1
            
        items = cnt.items()
        items.sort(key=lambda k: k[1], reverse=True)
        return [item[0] for item in items[:k]]
 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2 solution&lt;/p&gt;
&lt;pre id=&quot;code_1565416979550&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import random
class Solution(object):
    def findKthLargest(self, nums, k):
        pivot = random.randint(0,len(nums)-1)
        nums[0], nums[pivot] = nums[pivot], nums[0]
        bigger = [n for n in nums[1:] if n &amp;gt; nums[0]]
        
        if len(bigger) == k-1 :
            return nums[0]
        elif len(bigger) &amp;gt; k-1 :
            return self.findKthLargest(bigger, k)
        
        smaller = [n for n in nums[1:]  if n&amp;lt;= nums[0]]
        return self.findKthLargest(smaller, k-1-len(bigger))
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/kth-largest-element-in-an-array/&quot;&gt;https://leetcode.com/problems/kth-largest-element-in-an-array/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/89</guid>
      <comments>https://doromi.tistory.com/89#entry89comment</comments>
      <pubDate>Sat, 10 Aug 2019 15:03:46 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]347. Top K Frequent Elements</title>
      <link>https://doromi.tistory.com/88</link>
      <description>&lt;p&gt;347.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Top K Frequent Elements&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a non-empty array of integers, return the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;i&gt;k&lt;/i&gt;&lt;/b&gt;most frequent elements.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;nums = &lt;span&gt;[1,1,1,2,2,3]&lt;/span&gt;, k = &lt;span&gt;2&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;[1,2]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;nums = &lt;span&gt;[1]&lt;/span&gt;, k = &lt;span&gt;1&lt;/span&gt; &lt;b&gt;Output: &lt;/b&gt;&lt;span&gt;[1]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may assume&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;k&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is always valid, 1 &amp;le;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;k&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;le; number of unique elements.&lt;/li&gt;
&lt;li&gt;Your algorithm's time complexity&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;must be&lt;/b&gt;better than O(&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;log&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;), where&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;is the array's size.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1565408286134&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def topKFrequent(self, nums, k):
        cnt = {}
        for n in nums:
            cnt[n] = cnt.get(n,0)+1
            
        items = cnt.items()
        items.sort(key=lambda k: k[1], reverse=True)
        return [item[0] for item in items[:k]]
            &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span&gt;&lt;a href=&quot;https://leetcode.com/problems/top-k-frequent-elements/&quot;&gt;https://leetcode.com/problems/top-k-frequent-elements/&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/88</guid>
      <comments>https://doromi.tistory.com/88#entry88comment</comments>
      <pubDate>Sat, 10 Aug 2019 12:38:14 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]75. Sort Colors</title>
      <link>https://doromi.tistory.com/87</link>
      <description>&lt;p&gt;75.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Sort Colors&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given an array with&lt;span&gt;&amp;nbsp;&lt;/span&gt;n&lt;span&gt;&amp;nbsp;&lt;/span&gt;objects colored red, white or blue, sort them&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/In-place_algorithm&quot;&gt;in-place&lt;/a&gt;&amp;nbsp;&lt;/b&gt;so that objects of the same color are adjacent, with the colors in the order red, white and blue.&lt;/p&gt;
&lt;p&gt;Here, we will use the integers 0, 1, and 2 to represent the color red, white, and blue respectively.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&amp;nbsp;You are not suppose to use the library's sort function for this problem.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; [2,0,2,1,1,0] &lt;b&gt;Output:&lt;/b&gt; [0,0,1,1,2,2]&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Follow up:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A rather straight forward solution is a two-pass algorithm using counting sort.&lt;br /&gt;First, iterate the array counting number of 0's, 1's, and 2's, then overwrite array with total number of 0's, then 1's and followed by 2's.&lt;/li&gt;
&lt;li&gt;Could you come up with a&amp;nbsp;one-pass algorithm using only constant space?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;첫번째 solution:&lt;/p&gt;
&lt;p&gt;two-pass algorithm using counting sort.&lt;/p&gt;
&lt;pre id=&quot;code_1565405199093&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def sortColors(self, nums):
        count = [0]*3
        for n in nums:
            count[n] += 1
        index = 0
        for i in range(len(nums)):
            while count[index] == 0:
                index +=1
            nums[i] = index
            count[index]-=1
        
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;두번째 solution:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;one-pass algorithm using only constant space&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1565407177158&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def sortColors(self, nums):
        red_point = 0
        blue_point = len(nums)-1
        
        
        for i in range(len(nums)):
            while nums[i] != 1 :
                if nums[i] == 0:
                    if i == red_point :
                        red_point +=1
                        break
                    else :
                        nums[red_point], nums[i] = nums[i], nums[red_point]
                        red_point +=1
                elif nums[i]==2:
                    if i&amp;gt; blue_point :
                        return
                    nums[blue_point], nums[i] = nums[i], nums[blue_point]
                    blue_point -=1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;세번째 solution:&lt;/p&gt;
&lt;p&gt;두번째 솔루션을 더 간단하게!&lt;/p&gt;
&lt;pre id=&quot;code_1565407235102&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def sortColors(self, nums):			 
        l=len(nums)
        left=0
        right=l-1
        i=0
        while i&amp;lt;=right:
            if nums[i]==0:
                nums[i],nums[left]=nums[left],nums[i]
                left+=1
            elif nums[i]==2:
                nums[i],nums[right]=nums[right],nums[i]
                right-=1
                i-=1
            i+=1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/sort-colors/&quot;&gt;https://leetcode.com/problems/sort-colors/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/87</guid>
      <comments>https://doromi.tistory.com/87#entry87comment</comments>
      <pubDate>Sat, 10 Aug 2019 12:35:37 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]79. Word Search</title>
      <link>https://doromi.tistory.com/86</link>
      <description>&lt;p&gt;79.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Word Search&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a 2D board and a word, find if the word exists in the grid.&lt;/p&gt;
&lt;p&gt;The word can be constructed from letters of sequentially adjacent cell, where &quot;adjacent&quot; cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;board = [ ['A','B','C','E'], ['S','F','C','S'], ['A','D','E','E'] ]&lt;/p&gt;
&lt;p&gt;Given word = &quot;&lt;b&gt;ABCCED&lt;/b&gt;&quot;, return &lt;b&gt;true&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Given word = &quot;&lt;b&gt;SEE&lt;/b&gt;&quot;, return &lt;b&gt;true&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Given word = &quot;&lt;b&gt;ABCB&lt;/b&gt;&quot;, return &lt;b&gt;false&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565403547330&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def dfs(self, board, word, point):
        if not word:
            return True

        direct = [[-1,0,1,0],[0,-1,0,1]]
        for i in range(4):
            cur_y = point[0]+ direct[0][i]
            cur_x = point[1]+ direct[1][i]
            if cur_y &amp;gt;=0 and cur_y &amp;lt; len(board) and cur_x &amp;gt;=0 and cur_x &amp;lt; len(board[0]) and board[cur_y][cur_x]== word[0]:
                origin = board[cur_y][cur_x]
                board[cur_y][cur_x] = '0'
                result = self.dfs(board, word[1:], (cur_y, cur_x))
                if result : 
                    return True
                board[cur_y][cur_x] = origin 
        return False

    def exist(self, board, word):
        if len(board) == 0 or len(board[0])== 0:
            return False
        
        for i in range(len(board)):
            for j in range(len(board[0])):
                if board[i][j] == word[0]:
                    origin = board[i][j]
                    board[i][j] = '0'
                    result = self.dfs(board, word[1:], (i,j))
                    if result:
                        return True
                    board[i][j] = origin 
        return False
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/word-search/&quot;&gt;https://leetcode.com/problems/word-search/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/86</guid>
      <comments>https://doromi.tistory.com/86#entry86comment</comments>
      <pubDate>Sat, 10 Aug 2019 11:19:15 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]78. Subsets</title>
      <link>https://doromi.tistory.com/85</link>
      <description>&lt;p&gt;78.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Subsets&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a set of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;distinct&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;integers,&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums, return all possible subsets (the power set).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;The solution set must not contain duplicate subsets.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;nums = [1,2,3]&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;[ [3], &amp;nbsp; [1], &amp;nbsp; [2], &amp;nbsp; [1,2,3], &amp;nbsp; [1,3], &amp;nbsp; [2,3], &amp;nbsp; [1,2], &amp;nbsp; [] ]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565402069818&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def subsets(self, nums):
        index = 0
        curs = [[]]
        len_nums = len(nums)
        
        while index &amp;lt; len_nums:
            next_step =[]
            for cur in curs:
                next_step.append([i for i in cur])
                next_step.append([i for i in cur]+[nums[index]])
            index +=1
            curs = next_step
        return next_step
                &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/subsets/&quot;&gt;https://leetcode.com/problems/subsets/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/85</guid>
      <comments>https://doromi.tistory.com/85#entry85comment</comments>
      <pubDate>Sat, 10 Aug 2019 10:54:52 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]46. Permutations</title>
      <link>https://doromi.tistory.com/84</link>
      <description>&lt;p&gt;46.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Permutations&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a collection of&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;distinct&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;integers, return all possible permutations.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; [1,2,3] &lt;b&gt;Output:&lt;/b&gt; [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]&lt;/p&gt;
&lt;pre id=&quot;code_1565400967935&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def Permute(self, cur ,nums, len_nums, result):
        if not nums:
            result.append([i for i in cur])
            return
        
        for i in range(len(nums)) :
            cur.append(nums[i])
            self.Permute(cur, nums[:i]+nums[i+1:], len_nums, result)
            cur.pop()
        return 
    
    def permute(self, nums):
        result = []
        len_nums = len(nums)
        self.Permute([] , nums, len_nums, result)
        return result        
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/permutations/&quot;&gt;https://leetcode.com/problems/permutations/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/84</guid>
      <comments>https://doromi.tistory.com/84#entry84comment</comments>
      <pubDate>Sat, 10 Aug 2019 10:36:12 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]22. Generate Parentheses</title>
      <link>https://doromi.tistory.com/83</link>
      <description>&lt;p&gt;22.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Generate Parentheses&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;pairs of parentheses, write a function to generate all combinations of well-formed parentheses.&lt;/p&gt;
&lt;p&gt;For example, given&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;n&lt;/i&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;= 3, a solution set is:&lt;/p&gt;
&lt;p&gt;[ &quot;((()))&quot;, &quot;(()())&quot;, &quot;(())()&quot;, &quot;()(())&quot;, &quot;()()()&quot; ]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565334657742&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def makeCombi(self, prefix, n , openp, closep, result):
        #print(prefix)
        if openp &amp;lt; closep :
            return 
        if openp+ closep == 2*n :
            result.append(prefix)
            
        if openp &amp;lt; n:
            self.makeCombi(prefix+&quot;(&quot;, n, openp+1, closep, result)
        if closep &amp;lt; openp:
            self.makeCombi(prefix+&quot;)&quot;,n, openp, closep+1, result)
        return 
        
    def generateParenthesis(self, n):
        result = []
        self.makeCombi(&quot;&quot;, n , 0, 0, result)
        return result
        &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/83</guid>
      <comments>https://doromi.tistory.com/83#entry83comment</comments>
      <pubDate>Fri, 9 Aug 2019 16:11:09 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]17. Letter Combinations of a Phone Number</title>
      <link>https://doromi.tistory.com/82</link>
      <description>&lt;p&gt;17.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Letter Combinations of a Phone Number&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a string containing digits from&lt;span&gt;&amp;nbsp;&lt;/span&gt;2-9&lt;span&gt;&amp;nbsp;&lt;/span&gt;inclusive, return all possible letter combinations that the number could represent.&lt;/p&gt;
&lt;p&gt;A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not map to any letters.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oFYx0/btqxnlEXiwI/gUhqMkZb5bi6nC4lQVJik0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oFYx0/btqxnlEXiwI/gUhqMkZb5bi6nC4lQVJik0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oFYx0/btqxnlEXiwI/gUhqMkZb5bi6nC4lQVJik0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoFYx0%2FbtqxnlEXiwI%2FgUhqMkZb5bi6nC4lQVJik0%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;&quot;23&quot; &lt;b&gt;Output:&lt;/b&gt; [&quot;ad&quot;, &quot;ae&quot;, &quot;af&quot;, &quot;bd&quot;, &quot;be&quot;, &quot;bf&quot;, &quot;cd&quot;, &quot;ce&quot;, &quot;cf&quot;].&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Although the above answer is in lexicographical order, your answer could be in any order you want.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565333343799&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def makeCombi(self, digits, prefix, numberdict,result ):
        if digits == &quot;&quot;:
            result.append(''.join(prefix))
            return 
        
        charlist = numberdict[digits[0]]
        for c in charlist:
            prefix.append(c)
            self.makeCombi(digits[1:], prefix, numberdict, result)
            prefix.pop()
        return 
    
    def letterCombinations(self, digits):
        result = []
        
        if digits == &quot;&quot;:
            return result
        
        numberdict ={'2': ['a','b','c'],
                    '3' : ['d','e','f'],
                    '4' : ['g','h','i'],
                    '5' : ['j','k','l'],
                    '6' : ['m','n','o'],
                    '7' : ['p','q','r','s'],
                    '8' : ['t','u','v'],
                    '9' : ['w','x','y','z']}
        
      
        self.makeCombi(digits,[],numberdict,result)
        return result&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/letter-combinations-of-a-phone-number/&quot;&gt;https://leetcode.com/problems/letter-combinations-of-a-phone-number/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/82</guid>
      <comments>https://doromi.tistory.com/82#entry82comment</comments>
      <pubDate>Fri, 9 Aug 2019 15:49:12 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode] 200. Number of Islands</title>
      <link>https://doromi.tistory.com/81</link>
      <description>&lt;p&gt;200.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Number of Islands&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a 2d grid map of&lt;span&gt;&amp;nbsp;&lt;/span&gt;'1's (land) and&lt;span&gt;&amp;nbsp;&lt;/span&gt;'0's (water), count the number of islands. An island is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;11110&lt;/p&gt;
&lt;p&gt;11010&lt;/p&gt;
&lt;p&gt;11000&lt;/p&gt;
&lt;p&gt;00000&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt;&amp;nbsp;1&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;11000&lt;/p&gt;
&lt;p&gt;11000&lt;/p&gt;
&lt;p&gt;00100&lt;/p&gt;
&lt;p&gt;00011&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output: &lt;/b&gt;3&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BFS 또는 DFS로 풀면 되는 문제&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BFS로 풀었다.&lt;/p&gt;
&lt;pre id=&quot;code_1565323468791&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def numIslands(self, grid):
        cnt_land = 0
        q = []
        d = [[-1,0,1,0],[0,-1,0,1]]
        len_y = len(grid)
        if len_y ==0 :
            return 0
        len_x = len(grid[0])
        if len_x == 0:
            return 0
        for i in range(len_y):
            for j in range(len_x):
                if grid[i][j] == &quot;1&quot;:
                    grid[i][j] = &quot;-1&quot;
                    q.append((i,j))
                    while q :
                        cur = q.pop(0)
                        for k in range(4):
                            next_y = cur[0]+d[0][k]
                            next_x = cur[1]+d[1][k]
                            if next_y &amp;gt;= 0 and next_y &amp;lt;len_y and next_x &amp;gt;=0 and next_x &amp;lt;len_x and grid[next_y][next_x] == &quot;1&quot;:
                                grid[next_y][next_x] =&quot;-1&quot;
                                q.append((next_y, next_x))
                    cnt_land +=1
        return cnt_land
                        
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/number-of-islands/&quot;&gt;https://leetcode.com/problems/number-of-islands/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/81</guid>
      <comments>https://doromi.tistory.com/81#entry81comment</comments>
      <pubDate>Fri, 9 Aug 2019 13:05:49 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]230. Kth Smallest Element in a BST</title>
      <link>https://doromi.tistory.com/80</link>
      <description>&lt;p&gt;230.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Kth Smallest Element in a BST&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a binary search tree, write a function&lt;span&gt;&amp;nbsp;&lt;/span&gt;kthSmallest&lt;span&gt;&amp;nbsp;&lt;/span&gt;to find the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;k&lt;/b&gt;th smallest element in it.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;You may assume k is always valid, 1 &amp;le; k &amp;le; BST's total elements.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; root = [3,1,4,null,2]&lt;/p&gt;
&lt;p&gt;k = 1&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;3&lt;/p&gt;
&lt;p&gt;&amp;nbsp; / \&lt;/p&gt;
&lt;p&gt;&amp;nbsp;1&amp;nbsp; 4&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;\&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 2&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; 1&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; root = [5,3,6,2,4,null,null,1], k = 3&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;5&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; / \&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; 3&amp;nbsp; &amp;nbsp;6&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;/ \&lt;/p&gt;
&lt;p&gt;&amp;nbsp;2&amp;nbsp; 4&amp;nbsp; &amp;nbsp;&lt;/p&gt;
&lt;p&gt;/&lt;/p&gt;
&lt;p&gt;1&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Output:&lt;/b&gt; 3&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Follow up:&lt;/b&gt;&lt;br /&gt;What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 나의 첫번째 solution&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BST 를 inorder하면 정렬된 숫자를 갖는다는 점에서 착안하여 순차적으로 data를 넣고 그중에 i 번째 원소&amp;nbsp; return&lt;/p&gt;
&lt;p&gt;TimeComplexity = O(N)&amp;nbsp; SpaceComplextiy = O(N)&lt;/p&gt;
&lt;pre id=&quot;code_1565321830051&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def kthSmallest(self, root, k):
        li = []
        self.inorder(root, li)
        return li[k-1]
    
    def inorder(self, root, li):
        if root is None:
            return
        
        self.inorder(root.left,li)
        li.append(root.val)
        self.inorder(root.right,li)
        return
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2번째 솔루션 : leetcode의 다른 사람 코드를 보고 배움&lt;/p&gt;
&lt;p&gt;재귀를 없애고 반복적으로 inorder탐색을 하고 k번째에서 바로 리턴하기&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565322244098&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def kthSmallest(self, root, k):
        stk =[]
        while True:
            while root:
                stk.append(root)
                root = root.left
            root = stk.pop()
            k -=1
            if k ==0 :
                return root.val
            root = root.right
                &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/kth-smallest-element-in-a-bst/&quot;&gt;https://leetcode.com/problems/kth-smallest-element-in-a-bst/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/80</guid>
      <comments>https://doromi.tistory.com/80#entry80comment</comments>
      <pubDate>Fri, 9 Aug 2019 12:44:11 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]116. Populating Next Right Pointers in Each Node</title>
      <link>https://doromi.tistory.com/79</link>
      <description>&lt;p&gt;116.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Populating Next Right Pointers in Each Node&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You are given a&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;perfect binary tree&lt;/b&gt;&amp;nbsp;where&amp;nbsp;all leaves are on the same level, and every parent has two children. The binary tree has the following definition:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;box&quot;&gt;struct Node{&lt;br /&gt;int val;&lt;br /&gt;Node *left;&lt;br /&gt;Node *right;&lt;br /&gt;Node *next; }&lt;/blockquote&gt;
&lt;p&gt;Populate each next pointer to point to its next right node.&lt;/p&gt;
&lt;p&gt;If there is no next right node, the next pointer should be set to&lt;span&gt;&amp;nbsp;&lt;/span&gt;NULL.&lt;/p&gt;
&lt;p&gt;Initially, all next pointers are set to&lt;span&gt;&amp;nbsp;&lt;/span&gt;NULL.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565321201026&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;&quot;&quot;
# Definition for a Node.
class Node(object):
    def __init__(self, val, left, right, next):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
&quot;&quot;&quot;
class Solution(object):
    def connect(self, root):
        parents =[]
        currents = []
        if root : 
            currents.append(root)
        
        while currents:
            parents = currents
            currents = []
            for p in parents:
                if p.left :
                    currents.append(p.left)
                if p.right:
                    currents.append(p.right)
            len_p = len(parents)
            for i in range(len_p):
                if i &amp;lt; len_p-1 :
                    parents[i].next = parents[i+1]
                else :
                    parents[i].next = None
        return root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;같은 알고리즘&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;더&amp;nbsp; 간단한 코드&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1565321464865&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&quot;&quot;&quot;
# Definition for a Node.
class Node(object):
    def __init__(self, val, left, right, next):
        self.val = val
        self.left = left
        self.right = right
        self.next = next
&quot;&quot;&quot;
class Solution(object):
    def connect(self, root):
        nodes = [root] if root else []
        
        while nodes:
            next_nodes = []
            last = None
            for node in nodes:
                if last :
                    last.next = node
                if node.left :
                    next_nodes.append(node.left)
                if node.right:
                    next_nodes.append(node.right)
                last = node
            nodes = next_nodes
        return root&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/populating-next-right-pointers-in-each-node/&quot;&gt;https://leetcode.com/problems/populating-next-right-pointers-in-each-node/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/79</guid>
      <comments>https://doromi.tistory.com/79#entry79comment</comments>
      <pubDate>Fri, 9 Aug 2019 12:31:44 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]105. Construct Binary Tree from Preorder and Inorder Traversal</title>
      <link>https://doromi.tistory.com/78</link>
      <description>&lt;p&gt;105.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Construct Binary Tree from Preorder and Inorder Traversal&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given preorder and inorder traversal of a tree, construct the binary tree.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Note:&lt;/b&gt;&lt;br /&gt;You may assume that duplicates do not exist in the tree.&lt;/p&gt;
&lt;p&gt;For example, given&lt;/p&gt;
&lt;p&gt;preorder =&amp;nbsp;[3,9,20,15,7] inorder = [9,3,15,20,7]&lt;/p&gt;
&lt;p&gt;Return the following binary tree:&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;3&lt;/p&gt;
&lt;p&gt;&amp;nbsp; / \&lt;/p&gt;
&lt;p&gt;&amp;nbsp;9 20&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; / \&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;15 7&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565320072150&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution(object):
    def buildTree(self, preorder, inorder):
        if not inorder:
            return None
        
        root_index = 0
        for i in range(len(inorder)):
            if inorder[i] == preorder[0]:
                root_index = i
        root = TreeNode(preorder.pop(0))
        root.left = self.buildTree(preorder,inorder[:root_index])
        root.right = self.buildTree (preorder, inorder[root_index+1:])
        return root         
        
        
        
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/&quot;&gt;https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/&lt;/a&gt;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/78</guid>
      <comments>https://doromi.tistory.com/78#entry78comment</comments>
      <pubDate>Fri, 9 Aug 2019 12:08:15 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]103. Binary Tree Zigzag Level Order Traversal</title>
      <link>https://doromi.tistory.com/77</link>
      <description>&lt;p&gt;103.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Binary Tree Zigzag Level Order Traversal&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a binary tree, return the&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;i&gt;zigzag level order&lt;/i&gt;traversal of its nodes' values. (ie, from left to right, then right to left for the next level and alternate between).&lt;/p&gt;
&lt;p&gt;For example:&lt;br /&gt;Given binary tree&lt;span&gt;&amp;nbsp;&lt;/span&gt;[3,9,20,null,null,15,7],&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 3&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;/ \&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;9&amp;nbsp; 20&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; / \&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;15&amp;nbsp; &amp;nbsp;7&lt;/p&gt;
&lt;p&gt;return its zigzag level order traversal as:&lt;/p&gt;
&lt;p&gt;[ [3], [20,9], [15,7] ]&lt;/p&gt;
&lt;pre id=&quot;code_1565318357797&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def zigzagLevelOrder(self, root):
        level = 0
        result = []
        parents = []
        currents = []
        if root :
            currents.append(root)
        while currents:
            tmp =[]
            parents = currents
            currents = []
            for p in parents:
                tmp.append(p.val)
                if p.left :
                    currents.append(p.left)
                if p.right :
                    currents.append(p.right)
           
            result.append(tmp if level %2 ==0 else tmp[::-1] )
            level +=1
            
        return result&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/77</guid>
      <comments>https://doromi.tistory.com/77#entry77comment</comments>
      <pubDate>Fri, 9 Aug 2019 11:40:45 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]94. Binary Tree Inorder Traversal</title>
      <link>https://doromi.tistory.com/76</link>
      <description>&lt;p&gt;94.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Binary Tree Inorder Traversal&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Given a binary tree, return the&lt;span&gt;&amp;nbsp;&lt;/span&gt;inorder&lt;span&gt;&amp;nbsp;&lt;/span&gt;traversal of its nodes' values.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt; [1,null,2,3]&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; 1&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; \&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; 2&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;/&lt;/p&gt;
&lt;p&gt;&amp;nbsp;3&lt;/p&gt;
&lt;p&gt;&lt;b&gt;O&lt;/b&gt;&lt;b&gt;utput:&lt;/b&gt; [1,3,2]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565315292021&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def inorderTraversal(self, root):
        &quot;&quot;&quot;
        :type root: TreeNode
        :rtype: List[int]
        &quot;&quot;&quot;
        if not root:
            return []
        else:
            return self.inorderTraversal(root.left) + [root.val] + self.inorderTraversal(root.right)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/76</guid>
      <comments>https://doromi.tistory.com/76#entry76comment</comments>
      <pubDate>Fri, 9 Aug 2019 10:48:15 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode]160. Intersection of Two Linked Lists</title>
      <link>https://doromi.tistory.com/75</link>
      <description>&lt;p&gt;160.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Intersection of Two Linked Lists&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Write a program to find the node at which the intersection of two singly linked lists begins.&lt;/p&gt;
&lt;p&gt;For example, the following two linked lists:&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b1t6Ee/btqxj0VvWZE/DHzTZ2OX7K6HZv2qdvzQF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b1t6Ee/btqxj0VvWZE/DHzTZ2OX7K6HZv2qdvzQF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b1t6Ee/btqxj0VvWZE/DHzTZ2OX7K6HZv2qdvzQF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb1t6Ee%2Fbtqxj0VvWZE%2FDHzTZ2OX7K6HZv2qdvzQF0%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;begin to intersect at node c1.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 1:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/belcjJ/btqxiM4M8Kx/YORDXzY1rvJvkwFaHsepnk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/belcjJ/btqxiM4M8Kx/YORDXzY1rvJvkwFaHsepnk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/belcjJ/btqxiM4M8Kx/YORDXzY1rvJvkwFaHsepnk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbelcjJ%2FbtqxiM4M8Kx%2FYORDXzY1rvJvkwFaHsepnk%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3 &lt;b&gt;Output:&lt;/b&gt; Reference of the node with value = 8 &lt;b&gt;Input Explanation:&lt;/b&gt; The intersected node's value is 8 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [4,1,8,4,5]. From the head of B, it reads as [5,0,1,8,4,5]. There are 2 nodes before the intersected node in A; There are 3 nodes before the intersected node in B.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 2:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IdJf2/btqxhyFV20N/QFi6b318qDXQQG2ohJkw70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IdJf2/btqxhyFV20N/QFi6b318qDXQQG2ohJkw70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IdJf2/btqxhyFV20N/QFi6b318qDXQQG2ohJkw70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIdJf2%2FbtqxhyFV20N%2FQFi6b318qDXQQG2ohJkw70%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;intersectVal&amp;nbsp;= 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1 &lt;b&gt;Output:&lt;/b&gt; Reference of the node with value = 2 &lt;b&gt;Input Explanation:&lt;/b&gt;&amp;nbsp;The intersected node's value is 2 (note that this must not be 0 if the two lists intersect). From the head of A, it reads as [0,9,1,2,4]. From the head of B, it reads as [3,2,4]. There are 3 nodes before the intersected node in A; There are 1 node before the intersected node in B.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example 3:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ds9mHO/btqxjgYQu5i/fqx9EThkwiP12ePGJHReg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ds9mHO/btqxjgYQu5i/fqx9EThkwiP12ePGJHReg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ds9mHO/btqxjgYQu5i/fqx9EThkwiP12ePGJHReg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fds9mHO%2FbtqxjgYQu5i%2Ffqx9EThkwiP12ePGJHReg1%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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input: &lt;/b&gt;intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2 &lt;b&gt;Output:&lt;/b&gt; null &lt;b&gt;Input Explanation:&lt;/b&gt; From the head of A, it reads as [2,6,4]. From the head of B, it reads as [1,5]. Since the two lists do not intersect, intersectVal must be 0, while skipA and skipB can be arbitrary values. &lt;b&gt;Explanation:&lt;/b&gt; The two lists do not intersect, so return null.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Notes:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If the two linked lists have no intersection at all, return&lt;span&gt;&amp;nbsp;&lt;/span&gt;null.&lt;/li&gt;
&lt;li&gt;The linked lists must retain their original structure after the function returns.&lt;/li&gt;
&lt;li&gt;You may assume there are no cycles anywhere in the entire linked structure.&lt;/li&gt;
&lt;li&gt;Your code should preferably run in O(n) time and use only O(1) memory.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;나의 solution :&lt;/p&gt;
&lt;p&gt;우선 한번 순회를 통해 A, B의 길이와 각 끝점이 만나는지를 확인한다.&lt;/p&gt;
&lt;p&gt;만나지 않으면 둘의 intersection은 없기 때문에 None을 반환한다.&lt;/p&gt;
&lt;p&gt;그리고 길이가 긴쪽의 포인터를 차이만큼 움직여서 같은 길이에서 탐색을 시작해서 같은 점을 발견하면 그점이 intersection!&lt;/p&gt;
&lt;pre id=&quot;code_1565234644225&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    
    def changeStart(self,head, cnt):
        while cnt &amp;gt;0:
            head = head.next
            cnt -=1
        return head
        
    def getIntersectionNode(self, headA, headB):
        tailA, tailB = headA, headB
        cntA, cntB = 0, 0
        while tailA :
            tailA = tailA.next
            cntA +=1
        while tailB :
            tailB = tailB.next
            cntB +=1
        if tailA != tailB :
            return None 
        
        if cntA &amp;gt; cntB :
            headA = self.changeStart(headA, cntA-cntB)
        elif cntB &amp;gt; cntA :
            headB = self.changeStart(headB, cntB-cntA)
            
        while headA != headB:
            headA = headA.next
            headB = headB.next
            
        return headA
            
            
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;신기한 솔루션&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565234916104&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def getIntersectionNode(self, headA, headB):
        
        a, b = headA, headB
        while a != b:
            if a is None:
                a = headB
            else:
                a = a.next
            if b is None:
                b = headA
            else:
                b = b.next
        return a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/75</guid>
      <comments>https://doromi.tistory.com/75#entry75comment</comments>
      <pubDate>Thu, 8 Aug 2019 12:39:54 +0900</pubDate>
    </item>
    <item>
      <title>[leetcode] 2. add two numbers</title>
      <link>https://doromi.tistory.com/74</link>
      <description>&lt;p&gt;2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;Add Two Numbers&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You are given two&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;non-empty&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;linked lists representing two non-negative integers. The digits are stored in&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;reverse order&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;and each of their nodes contain a single digit. Add the two numbers and return it as a linked list.&lt;/p&gt;
&lt;p&gt;You may assume the two numbers do not contain any leading zero, except the number 0 itself.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Input:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;(2 -&amp;gt; 4 -&amp;gt; 3) + (5 -&amp;gt; 6 -&amp;gt; 4)&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Output:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;7 -&amp;gt; 0 -&amp;gt; 8&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;Explanation:&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;342 + 465 = 807.&lt;/p&gt;
&lt;pre id=&quot;code_1565166326638&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def addTwoNumbers(self, l1, l2): 
        result = None
        tail = None
        carry = 0
        while l1 is not None or l2 is not None or carry != 0 :
            l1_num = l1.val if l1 else 0
            l2_num = l2.val if l2 else 0
            if result is None :
                result = ListNode((l1_num + l2_num + carry)%10)
                tail = result
            else :
                tail.next = ListNode((l1_num + l2_num + carry)%10)
                tail = tail.next
            carry = 0 if l1_num + l2_num + carry &amp;lt; 10 else 1
            l1 = l1.next if l1 else None
            l2 = l2.next if l2 else None
        return result
        &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;* 실수한 부분&lt;/p&gt;
&lt;p&gt;l1 과 l2가 없어도 carry가 있으면 연산을 해야하는데 그부분을 간과함&lt;/p&gt;
&lt;p&gt;carry 만들때도 l1_num + l2_num + carry를 해야했는데 carry를 빠뜨렸음.&lt;/p&gt;</description>
      <category>Study/Algorithm</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/74</guid>
      <comments>https://doromi.tistory.com/74#entry74comment</comments>
      <pubDate>Wed, 7 Aug 2019 17:26:29 +0900</pubDate>
    </item>
    <item>
      <title>10.11 Peak과 Valley</title>
      <link>https://doromi.tistory.com/73</link>
      <description>&lt;p&gt;문제&amp;nbsp;&lt;/p&gt;
&lt;p&gt;정수 배열에서 peak란 현재 원소가 인접한 정수보다 크거나 같을 때를 말하고, 'valley'란 현재 원소가 인접한 정수보다 작거나 같을 때를 말한다. 예를 들어 {5,8,6,2,3,4,6}이 있으면, {8,6}은&amp;nbsp; peak고 {5,2}는 valley인 것이다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;정수배열이 주어졌을때 'peak'와 'valley'가 번갈아 등장하도록 정렬하는 알고리즘을 작성하라.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해법&lt;/p&gt;
&lt;p&gt;1. 부분 최적 해법&lt;/p&gt;
&lt;p&gt;&amp;nbsp;배열을 정렬하고 위치를 바꿈으로써 peak와 valley를 순차적으로 나올 수 있도록 만들 수 있을 것이다.&lt;/p&gt;
&lt;p&gt;정렬된 배열 0 1 4 7 8 9 가 있다고 하자.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;0은 올바른 위치고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1은 잘못 놓였다 0과 4중에 자리를 바꿀 수 있으나 0와 바꿔보자&amp;nbsp;&lt;/p&gt;
&lt;p&gt;7도 잘못 놓였다. 4과 8중에 자리를 바꿀 수 있으나 4과 바꿔보자&amp;nbsp;&lt;/p&gt;
&lt;p&gt;9도 잘못 놓였다 8과 자리를 바꿀 수 있으니 8과 바꿔보자&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러면 0 4 1 8 7 9로 peak와 valley가 번갈아 나타나는 배열이 나타난다.&lt;/p&gt;
&lt;p&gt;이 알고리즘의 TimeComplexity = O(NlogN)이다.&lt;/p&gt;
&lt;pre id=&quot;code_1565157090685&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def sortValleyPeak(array):
    array.sort()
    for i in range(1,len(array)):
        array[i] , array[i+1] = array[i+1] , array[i]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. 최적 해법&lt;/p&gt;
&lt;p&gt;저 알고리즘보다 더 최적이되려면 정렬을 하지 말아야한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그냥 배열을 가지고는 peak와 valley가 번갈아 나오도록 만들 수 없는 걸까?&lt;/p&gt;
&lt;p&gt;9 1 0 4 8 7 이라는 배열이 있다고 가정하자.&lt;/p&gt;
&lt;p&gt;그전에 더 짧은 배열을 통해 규칙을 확인해보자&amp;nbsp;&lt;/p&gt;
&lt;p&gt;0 1 2 라는 배열이 있을때&amp;nbsp;&lt;/p&gt;
&lt;p&gt;0 2 1&amp;nbsp; -&amp;gt;peak&lt;/p&gt;
&lt;p&gt;1 0 2&lt;/p&gt;
&lt;p&gt;1 2 0&amp;nbsp; -&amp;gt;peak&lt;/p&gt;
&lt;p&gt;2 1 0&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2 0 1&lt;/p&gt;
&lt;p&gt;나머지 배열도 수정해서 peak가 되게 할 수 있을까?&lt;/p&gt;
&lt;p&gt;가운데 원소와 인접한 원소 중에 가장 큰수와 바꾸면 된다.&lt;/p&gt;
&lt;p&gt;&quot;두 원소를 맞바꿨을때 이전에 처리했던 수열의 규칙이 깨지는 경우가 있지는 않을까?&quot; -&amp;gt; 이문제에서 중간값과 왼쪽 값을 바꾼다고 했을때 왼쪽값은 여전히 valley일 것이다 중간 값이 왼쪽 값보다 작으므로 더 작은 수를 놓게 되기 때문이다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565157098641&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def bigIndex(array, a,b,c):
    len_a = len(array)
    a = array[a] if a&amp;gt;=0 and a &amp;lt; len_a else - int('inf')
    b = array[b] if b&amp;gt;=0 and b &amp;lt; len_a else - int('inf')
    c = array[c] if c&amp;gt;=0 and c &amp;lt; len_a else - int('inf')

    max_num = max(a,b,c)
    if array[a] == max_num :
        return a
    elif array[b] == max_num :
        return b
    else :
        return c&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Interview준비</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/73</guid>
      <comments>https://doromi.tistory.com/73#entry73comment</comments>
      <pubDate>Wed, 7 Aug 2019 14:51:43 +0900</pubDate>
    </item>
    <item>
      <title>10.10 스트림에서의 순위</title>
      <link>https://doromi.tistory.com/72</link>
      <description>&lt;p&gt;문제&amp;nbsp;&lt;/p&gt;
&lt;p&gt;정수 스트림을 읽는다고 하자. 주기적으로 어떤 수 x의 랭킹(x보다 같거나 작은 수의 갯수)를 확인하고 싶다. 해당 연산을 지원하는 자료구조와 알고리즘을 구현하라. 수 하나를 읽을 때마다 호출되는 메서드 track(int x)와, x보다 작거나 같은 수의 갯수( x자신을 제외)를 반환하는 메서드 getRankOfNumber(int x)를 구현하라&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;입력 : 5,1,4,4,5,9,7,13,3&lt;/p&gt;
&lt;p&gt;출력 :&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;getRankOfNumber(1) = 0&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;getRankOfNumber(3 ) = 1&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;getRankOfNumber(4 ) = 3&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;해법 &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;모든 원소를 정렬된 상태로 보관하는 배열을 사용하면 구현하기가 상대적으로 간단해진다. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;새로운 원소를 삽입할때마다 다른 원소들을 옆으로 옮겨 공간을 확보해야하는데 그렇다보면 track() 호출시 효율성이 떨어진다. 원소간의 상대적 순서를 유지할 수 있으면서도 새로운 원소를 삽입하기에 도 효율적인 자료구조가 필요하다 -&amp;gt; 이진 탐색 트리가 적당할 것같다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;원소들을 배열에 보관하는 대신 이진 탐색 트리에 삽입하며 track()은 O(logN)시간에 가능하고, 각 노드가 자신의 왼쪽에 있는 자식 노드의 수를 알고있도록 하면 중위 탐색을 모두 하지 않고도 최소한의 탐색으로 랭킹을 확인할 수 있을 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;스크린샷 2019-08-07 오후 1.57.32.png&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfLgKM/btqxkV6SyVM/dkhGkR3wlh3OKdZKiIUpn0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfLgKM/btqxkV6SyVM/dkhGkR3wlh3OKdZKiIUpn0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfLgKM/btqxkV6SyVM/dkhGkR3wlh3OKdZKiIUpn0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfLgKM%2FbtqxkV6SyVM%2FdkhGkR3wlh3OKdZKiIUpn0%2Fimg.png&quot; data-filename=&quot;스크린샷 2019-08-07 오후 1.57.32.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;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;이런식으로 트리가 구성되어 있다고 가정해보자 그러면 만약 24의 랭킹은 어떻게 구할 수 있을까?&amp;nbsp;&lt;/p&gt;
&lt;p&gt;각 노드의 옆에 있는 작은 숫자는 왼쪽 노드의 갯수이다. 루트 20과 24를 비교해보면 24는 오른쪽에 있어야 하기때문에 20의 왼쪽 노드의 갯수인 4 + 1 (20을 포함) = counter은 5개가 된다. 그다음, 25와 비교해보자 24는 25의 왼쪽에 잇어야하므로 갱신하지 않는다.&lt;/p&gt;
&lt;p&gt;다음 23과 비교해보자 23보다는 24는 오른쪽에 있어야하므로 23의 왼쪽 노드의 갯수인 0 + 1 (23을 포함) = 1 만큼을 counter에 더해준다.&lt;/p&gt;
&lt;p&gt;그다음 오른쪽으로 가면 24와 만나기 때문에 24의 counter인 6을 반환하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1565155314166&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;
class Ranknode :
    def __init__(self, data):
        self.data = data
        self.right = None
        self.left = None
        self.leftcount = 0

    def insert(d):
        if d &amp;lt;= data :
            if self.left is None :
                self.left = Node(d)
            else :
                self.left.insert(d)
            leftcount +=1
        else :
            if self.right is None :
                self.right = Node(d)
            else :
                self.right.insert(d)

    def getRank(d):
        if d == self.data :
            return leftcount
        elif d &amp;lt; self.data :
            if self.left is None :
                return -1
            else :
                self.left.getRank(d)
        else :
            rightrank = right.getRank(d) if self.right is not None else -1
            if rightrank == -1 :
                return -1
            else :
                return leftcount + 1 + rightrank


Root = None

def track(number):
    if Root is None :
        Root = Ranknode(number)
    else :
        Root.insert(number)

def getRank(number):
    return Root.getRank(number)

&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Study/Interview준비</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/72</guid>
      <comments>https://doromi.tistory.com/72#entry72comment</comments>
      <pubDate>Wed, 7 Aug 2019 14:21:57 +0900</pubDate>
    </item>
    <item>
      <title>10.9 정렬된 행렬 탐색</title>
      <link>https://doromi.tistory.com/71</link>
      <description>&lt;p&gt;문제&amp;nbsp;&lt;/p&gt;
&lt;p&gt;각 행과 열이 오름차순으로 정렬된 MXN 행렬이 주어졌을대, 특정한 원소를 찾는 메서드를 구현하라&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해결법&lt;/p&gt;
&lt;p&gt;첫번째 : 행마다 이진탐색을 할 수있다.&lt;/p&gt;
&lt;p&gt;M개의 행이 있고 각 행을 탐색하는데 O(logN)이 걸리기 떄문에 O(MlogN)이 될 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;두번재 해결법을 생각해보기 전에 규칙을 찾아보자&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 23.2591%; height: 76px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;15&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;20&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;40&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;85&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;20&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;35&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;80&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;95&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;30&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;55&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;95&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;105&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;40&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;80&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;100&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;200&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;이런 행렬이 주어졌을때 55를 찾아보자.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;행의 시작점이나 열의 시작점을 보면 위치를 유추해 볼 수 있다. 열의 시작점 원소의 값이 55보다 크다면 탐색할 필요가 없고, 마찬가지로 행의 시작점 원소의 값이 55보다 크다면 탐색할 필요가 없을 것이다.&lt;/p&gt;
&lt;p&gt;그러면 행이나 열의 마지막점에서도 똑같이 적용할 수 있다. 어떤 행이나 열의 값이 x보다 작으면 다음 행이나 열로 이동해야한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- 어떤 열의 시작점 열의 원소보다 x가 크면 x는 해당 열 왼쪽에 있다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;- 어떤 열의 마지막 원소 값이 x보다 작으면, x는 해당열 오른쪽에 있다.&lt;/p&gt;
&lt;p&gt;- 어떤 행의 시작점 행의 원소가 x보다 크면 x는 해당 행 위쪽에 있다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- 어떤 행의 시작점 행의 원소가 x보다 작으면 x는 해당 행 아래쪽 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;가장 큰 값을 가지는 열부터 시작해서 좌측으로 진행할 필요ㅏ 있다. 즉, 첫번째 비교대상 원소는 array[0][c-1] =85이다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 25.1455%; height: 76px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;15&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;20&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;40&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #9eb1c7; color: #ffffff;&quot;&gt;&lt;b&gt;85&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;20&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;35&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;80&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #72889c; color: #ffffff;&quot;&gt;95&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;30&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;55&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;95&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #72889c; color: #ffffff;&quot;&gt;105&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;40&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;80&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;100&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%; height: 19px;&quot;&gt;&lt;span style=&quot;background-color: #72889c; color: #ffffff;&quot;&gt;200&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;여기서 c는 열의 갯수이다. 열의 시작점 원소들을 x(55)와 비교해보면 x는 0,1,2열에 있을 수 있다는 사실을 알 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;따라서 array[0][2]에서 진행을 멈춘다.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 25.0291%; height: 137px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #72889c; color: #ffffff;&quot;&gt;15&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #72889c; color: #ffffff;&quot;&gt;20&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #9eb1c7; color: #ffffff;&quot;&gt;40&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #36424d; color: #ffffff;&quot;&gt;85&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;20&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;35&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;80&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #36424d; color: #ffffff;&quot;&gt;95&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;30&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;55&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;95&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #36424d; color: #ffffff;&quot;&gt;105&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;40&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;80&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #ffcd00;&quot;&gt;100&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 25%;&quot;&gt;&lt;span style=&quot;background-color: #36424d; color: #ffffff;&quot;&gt;200&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그다음은 array[0][2]는 40으로 55보다는 작으니까 아래쪽으로 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;이런식으로 범위를 줄여가면서 정답을 찾을 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1565152963699&quot; class=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;def findElement(matrix, elem):
    row =0
    col =matrix[0].length -1
    while row &amp;lt;matrix.length and col &amp;gt;=0 :
        if matrix[row][col] == elem:
            return (row, col)
        elif matrix[row][col] &amp;gt; elem :
            col -=1
        else :
            row +=1
    return None
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Study/Interview준비</category>
      <author>DoRoMii</author>
      <guid isPermaLink="true">https://doromi.tistory.com/71</guid>
      <comments>https://doromi.tistory.com/71#entry71comment</comments>
      <pubDate>Wed, 7 Aug 2019 13:42:47 +0900</pubDate>
    </item>
  </channel>
</rss>