<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Hwani velog</title>
        <link>https://velog.io/</link>
        <description>개발자될거야</description>
        <lastBuildDate>Thu, 22 Aug 2024 15:36:02 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>Hwani velog</title>
            <url>https://velog.velcdn.com/images/hwani_/profile/92d399f5-aeeb-48b2-96db-41d2b3c2c7d5/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. Hwani velog. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hwani_" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[React - 기초 문법]]></title>
            <link>https://velog.io/@hwani_/React-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95</link>
            <guid>https://velog.io/@hwani_/React-%EA%B8%B0%EC%B4%88-%EB%AC%B8%EB%B2%95</guid>
            <pubDate>Thu, 22 Aug 2024 15:36:02 GMT</pubDate>
            <description><![CDATA[<h2 id="리액트-시작하기">리액트 시작하기</h2>
<p>React는 Node.js 가 설치되어 있어야 사용 가능하다.</p>
<pre><code class="language-javascript">npm install -g create-react-app // 리액트 앱을 만드는 명령어
create-react-app 프로젝트명 // 리액트 앱의 이름을 설정하는 명령어</code></pre>
<h2 id="리액트-기본-구조">리액트 기본 구조</h2>
<p><img src="https://velog.velcdn.com/images/hwani_/post/a7e9c18a-f8be-43ee-bbb3-fe4abe71429a/image.png" alt=""></p>
<p>위의 사진은 리액트를 설치하면 기본적으로 생성되는 파일/폴더 구조이다.
하나씩 뜯어보며 각각 어떤 역할을 하는지 알아보자.</p>
<h3 id="node_modules-디렉토리">node_modules 디렉토리</h3>
<p><strong>설명 :</strong> 이 디렉토리는 프로젝트에서 사용하는 모든 패키지들이 저장되는 곳이다.
&#39;npm&#39;, &#39;yarn&#39;을 사용해 설치한 외부 라이브러리들이 이 폴더에 저장된다.</p>
<p><strong>기능 :</strong> 이 디렉토리는 프로젝트의 의존성을 관리하며, 코드에서 라이브러리를 불러올 때 사용된다. 사용자가 직접 관리하지 않아도 자동으로 관리를 해준다.</p>
<h3 id="public-디렉토리">public 디렉토리</h3>
<p><strong>설명 :</strong> 이 디렉토리는 정적 파일들이 위치하는 곳이다. 주로 HTML 파일, 이미지, favicon 등이 들어있다.
이 디렉토리 안의 파일들은 빌드 시 그대로 복사되어 최종적으로 배포되는 애플리케이션에 포함된다.</p>
<pre><code class="language-html">index.html
&lt;div id=&quot;root&quot;&gt;&lt;/div&gt;</code></pre>
<p>React애플리케이션은 이 <strong>&#39;root&#39;</strong> 요소에 마운트된다.</p>
<h3 id="src-디렉토리">src 디렉토리</h3>
<p>*<em>설명 : *</em> 실제 React 애플리케이션의 소스 코드가 포함된 디렉토리. 이곳에서 모든 컴포넌트, 스타일시트, 이미지 등이 관리된다.</p>
<p>*<em>App.js : *</em> React 애플리케이션의 메인 컴포넌트 파일. 
이 파일은 애플리케이션의 기본적인 구조와 UI를 정의한다.
보통 이곳에서 여러 하위 컴포넌트를 불러오고 조합하여 화면에 렌더링을 한다.</p>
<p>*<em>App.css : *</em> &#39;App.js&#39; 에서 사용하는 스타일을 정의하는 CSS 파일.</p>
<p>*<em>App.test.js : *</em> &#39;App.js&#39;와 관련된 테스트 코드를 작성하는 파일.
&#39;Jest&#39;와 같은 테스트 프레임워크를 사용해 컴포넌트를 테스트할 수 있다.</p>
<p>*<em>index.js : *</em> React 애플리케이션의 진입점 파일. 이 파일에서 ReactDOM.render()를 사용해 App 컴포넌트를 index.html의 root 요소에 마운트한다.</p>
<p>*<em>index.css : *</em> 전체 애플리케이션에 적용될 수 있는 전역 스타일을 정의하는 CSS 파일</p>
<p>*<em>logo.svg : *</em> React 애플리케이션에서 사용되는 SVG 포맷의 로고 파일</p>
<p>*<em>serviceWorker.js : *</em> Progressive Web App(PWA) 기능을 제공하기 위해 사용되는 파일, 오프라인 캐시 및 백그라운드에서 작업을 처리할 수 있게 해주는 파일.
기본적으로 비활성화 되어있지만, 필요시 이 파일을 설정한다.</p>
<p>*<em>setupTests.js : *</em> 테스트 환경을 설정하는 파일.</p>
<h2 id="프로젝트-루트-파일">프로젝트 루트 파일</h2>
<p>*<em>package.json : *</em> 프로젝트의 메타데이터와 의존성, 스크립트 명령어 등을 정의하는 파일.
이 파일을 통해 프로젝트에서 사용하는 패키지들을 관리할 수 있으며, 
npm start, npm build 등의 명령어가 정의되어있다.</p>
<p>*<em>yarn.lock 또는 package-lock.json : *</em> 프로젝트의 의존성 리트를 관리하는 파일.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[React란?]]></title>
            <link>https://velog.io/@hwani_/React%EB%9E%80</link>
            <guid>https://velog.io/@hwani_/React%EB%9E%80</guid>
            <pubDate>Thu, 22 Aug 2024 15:04:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/hwani_/post/5d431e6b-64e5-43a7-af68-73dd9acf22d9/image.png" alt=""></p>
<h2 id="react란">React란?</h2>
<ul>
<li>React는 Facebook에서 개발한 오픈소스 자바스크립트 라이브러리로, <strong>사용자 인터페이스(UI)를 구축하는 데 중점</strong>을 둡니다.</li>
</ul>
<h2 id="react의-특징">React의 특징</h2>
<ul>
<li><strong>컴포넌트 기반 구조:</strong> React는 UI를 독립적이고 재사용 가능한 컴포넌트 단위로 분리하여 개발합니다. 이를 통해 코드의 유지보수성과 재사용성을 크게 향상시킬 수 있습니다.</li>
<li><strong>단방향 데이터 흐름:</strong> React는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 단방향 데이터 흐름을 채택하여, 애플리케이션의 상태 관리와 디버깅을 쉽게 만듭니다.</li>
<li><em>- Virtual DOM:*</em> React는 Virtual DOM을 사용하여 실제 DOM 조작을 최소화하고, 성능을 최적화합니다. 변경 사항을 Virtual DOM에 먼저 반영한 후, 실제 DOM에 필요한 부분만 업데이트하는 방식으로 동작합니다.</li>
</ul>
<h2 id="react를-사용해야-하는-이유">React를 사용해야 하는 이유</h2>
<p><strong>1. 성능 최적화</strong>
React의 <strong>Virtual DOM은 UI 업데이트를 최적화하여, 빠르고 효율적인 렌더링을 제공</strong>합니다. 이로 인해 대규모 애플리케이션에서도 우수한 성능을 유지할 수 있습니다.</p>
<p><strong>2. 높은 생산성</strong>
<strong>컴포넌트 기반 개발 방식을 통해 코드를 모듈화하고, 복잡한 UI를 쉽게 관리</strong>할 수 있습니다. 이로 인해 개발자들이 보다 효율적으로 코드를 작성하고 유지보수할 수 있습니다.</p>
<p><strong>3. 풍부한 생태계</strong>
React는 방대한 생태계를 자랑합니다. Redux, React Router, Styled Components 등 다양한 서드파티 라이브러리와 도구들이 React와 함께 사용되며, 개발 속도를 더욱 높여줍니다.</p>
<p><strong>4. 대기업 및 커뮤니티의 지원</strong>
React는 Facebook을 비롯한 많은 대기업에서 사용되며, 커뮤니티도 매우 활발합니다. 풍부한 자료와 튜토리얼이 제공되며, 다양한 문제를 해결할 수 있는 지원을 쉽게 받을 수 있습니다.</p>
<hr>
<p>백엔드 개발자를 지망하지만, 프론트엔드를 안다고 나쁠 건 하나도 없고
React를 할 줄 알면 우대하는 기업이 굉장히 많기에 이번에 인강을 보며 공부중이다.
블로그에 정리하며 공부를 할 예정이다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프레임워크, 라이브러리, API]]></title>
            <link>https://velog.io/@hwani_/%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-API</link>
            <guid>https://velog.io/@hwani_/%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC-API</guid>
            <pubDate>Tue, 06 Aug 2024 06:34:09 GMT</pubDate>
            <description><![CDATA[<p>개발을 하다보면 프레임워크, 라이브러리, API를 모두 사용하게 된다.
하지만 이 3개의 용어의 정의를 헷갈려서 정확히 정리해보려고 한다.</p>
<h2 id="프레임워크-framework">프레임워크 (FrameWork)</h2>
<p><strong>Frame(틀) + work(일)이라는 단어의 합성어</strong>입니다. 
일 구조, 혹은 작업 구조라는 뜻과 같이 <strong>프레임워크는 어떠한 일을 처리하기 위한 구조를 제공</strong>합니다.
프레임워크는 개발자들이 <strong>애플리케이션을 개발하는 데 사용되는 구조를 제공</strong>한다. 프레임워크는 일련의 규칙과 구조를 정의하고, 개발자가 애플리케이션을 작성할 때 이러한 규칙과 구조를 따르도록 한다. 프레임워크는 보통 여러 컴포넌트와 라이브러리를 포함하며, 개발자가 특정 기능을 구현하기 위해 이를 조합하여 사용한다.</p>
<h3 id="프레임워크-예시">프레임워크 예시</h3>
<ul>
<li><strong>Spring Framework</strong> - Java 기반의 엔터프라이즈 애플리케이션을 위한 강력한 프레임워크입니다.
Spring은 종속성 주입(Dependency Injection)과 같은 디자인 패턴을 통해 애플리케이션의 유연성과 모듈성을 향상시키는 것을 목표로 합니다.
Spring Boot는 Spring을 더 쉽게 사용할 수 있도록 초기 설정 작업을 최소화한 프로젝트입니다.</li>
<li><strong>Django</strong> - Django는 Python으로 작성된 고수준의 웹 프레임워크입니다. 
Django는 &quot;배터리가 포함된&quot; 접근 방식을 취하며, 데이터베이스 관리, 인증, 파일 관리 등 웹 애플리케이션 개발에 필요한 대부분의 공통 기능을 내장하고 있습니다. 
개발자는 Django의 구조와 규칙에 맞추어 애플리케이션을 구축하게 됩니다. 예를 들어, URL 라우터, 뷰, 모델 등이 이에 해당합니다.</li>
</ul>
<h2 id="라이브러리-library">라이브러리 (Library)</h2>
<p>라이브러리(Library)는 개발을 진행할 때 <strong>자주 사용하는 기능들은 개발자들이 필요와 목적에 따라 사용할 수 있도록 모듈화된 프로그램 모음</strong>이다.</p>
<p>라이브러리는 사전적 의미로는 도서관으로, <strong>도서관에 있는 책들을 꺼내 읽는 것 처럼 프로그래밍할 때 모듈화된 프로그램을 라이브러리에서 꺼내 사용 가능하다.</strong></p>
<p>파이썬(Python)의 경우 라이브러리가 잘 활성화 되어있어 인기가 아주 많아 졌다.</p>
<h3 id="라이브러리-예시">라이브러리 예시</h3>
<p><strong>Python</strong></p>
<ul>
<li><strong>Numpy</strong> 파이썬을 이용해 다양한 수학 계산을 할 수 있도록 해준다.</li>
<li><strong>SymPy:</strong> NumPy가 수치해석에 더 적합하다면, SymPy는 기호해석에 더 적합한 방식이다. 대부분의 경우에는 NumPy와 scipy의 조합으로 해결이 가능하지만, SymPy까지 사용하면 더 효율적이고 수월한 계산이 가능하다</li>
<li><strong>Pandas:</strong> 데이터 분석 라이브러리.</li>
<li><strong>matplotlib:</strong> 데이터 시각화 라이브러리.</li>
</ul>
<p><strong>Java</strong></p>
<ul>
<li><strong>Lombok:</strong> 자동으로 생성자 및 Getter/Setter 메소드를 추가해주는 라이브러리.</li>
<li><strong>JSTL:</strong> JSP 표준 태그 라이브러리.</li>
</ul>
<p><strong>JavaScript</strong></p>
<ul>
<li><strong>jQuery:</strong> 자바스크립트 라이브러리 중 가장 인지도가 높다.</li>
<li><strong>React:</strong> 페이스북에서 만든 라이브러리. UI 개발에 사용된다.</li>
<li><strong>Jindo:</strong> 네이버에서 만든 라이브러리. 스마트에디터에서 쓰인다.</li>
<li><strong>axios:</strong> 크로스 플랫폼 HTTP 클라이언트 라이브러리.</li>
</ul>
<h2 id="api-application-programming-interface">API (Application Programming Interface)</h2>
<p>Application Programming Interface(애플리케이션 프로그램 인터페이스)의 약자로, <strong>소프트웨어 응용 프로그램에서 다른 소프트웨어 구성 요소 또는 서비스와 상호 작용하기 위한 인터페이스를 제공하는 프로그래밍 기술</strong>이다.</p>
<h3 id="api-예시">API 예시</h3>
<ul>
<li>*<em>SPOTIFY API : *</em> Spotify API는 Spotify의 음악 카탈로그에 접근하고, 사용자의 플레이리스트를 관리하며, 음악을 스트리밍하는 기능을 제공한다.</li>
<li>*<em>NAVERPAY API : *</em> 네이버페이 API는 네이버페이의 결제 기능을 외부 웹사이트나 애플레케이션에 통합할 수 있도록 해주는 인터페이스이다.</li>
<li>*<em>KAKAO API : *</em> 카카오 API는 카카오 로그인, 카카오맵, 카카오메시지 등 여러 서비스를 제공하며, 앱 내에서 소셜 로그인, 위치 기반 서비스를 쉽게 통합할 수 있다.</li>
</ul>
<h2 id="정리">정리</h2>
<p>프레임워크, 라이브러리, API는 모두 개발 과정에서 중요한 역할을 수행한다. 
프레임워크는 애플리케이션의 전체적인 구조를 제공하며 라이브러리는 필요한 기능을 모듈화하여 제공하고
API는 다른 소프트웨어 또는 서비스와의 상호작용을 가능하게하는 인터페이스를 제공한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Cookie, Session, JWT]]></title>
            <link>https://velog.io/@hwani_/Cookie-Session-JWT</link>
            <guid>https://velog.io/@hwani_/Cookie-Session-JWT</guid>
            <pubDate>Mon, 05 Aug 2024 06:19:16 GMT</pubDate>
            <description><![CDATA[<h1 id="쿠키cookie-세션session-jwtjson-web-token의-차이점">쿠키(Cookie), 세션(Session), JWT(JSON Web Token)의 차이점</h1>
<p>웹 애플리케이션에서 인증과 상태 관리를 위한 방법에는 쿠키, 세션, 그리고 JWT가 있고, 보통 많이 사용되는데 정확히 구분하고자 정리 해보자!</p>
<h2 id="쿠키cookie">쿠키(Cookie)</h2>
<h3 id="정의">정의</h3>
<p>쿠키는 사용자의 웹 브라우저에 저장되는 작은 데이터 조각. 
서버가 클라이언트에게 전송하며, 클라이언트는 이 데이터를 저장하고 이후 요청에 포함시켜 서버로 보낸다.</p>
<h3 id="특징">특징</h3>
<ul>
<li><strong>클라이언트 측 저장</strong>: 데이터는 클라이언트의 브라우저에 저장된다.</li>
<li><strong>만료 기간</strong>: 쿠키는 만료 날짜를 설정할 수 있다.</li>
<li><strong>보안</strong>: 민감한 정보는 저장하지 않는 것이 좋습니다. <code>HttpOnly</code>와 <code>Secure</code> 플래그를 사용해 보안을 강화할 수 있습니다.</li>
</ul>
<h3 id="사용-예시">사용 예시</h3>
<ul>
<li><strong>로그인 상태 유지</strong>: 사용자가 웹사이트에 로그인한 상태를 유지하는 데 사용</li>
<li><strong>사용자 선호도</strong>: 테마나 언어 설정과 같은 사용자 선호도를 저장</li>
</ul>
<h3 id="장단점">장단점</h3>
<ul>
<li><strong>장점</strong>: 쉽게 구현 가능하며, 서버에 부하를 주지 않는다.</li>
<li><strong>단점</strong>: 보안 취약점이 있을 수 있으며, 데이터 저장 용량이 제한적이다.</li>
</ul>
<h2 id="세션session">세션(Session)</h2>
<h3 id="정의-1">정의</h3>
<p>세션은 서버 측에서 관리되는 사용자 상태 정보.
각 사용자는 고유한 세션 ID를 할당받으며, 이 ID를 통해 상태 정보를 식별한다.</p>
<h3 id="특징-1">특징</h3>
<ul>
<li><strong>서버 측 저장</strong>: 클라이언트는 세션 ID만을 보유하고, 실제 데이터는 서버에 저장한다.</li>
<li><strong>보안</strong>: 데이터가 서버에 저장되므로 보안이 상대적으로 더 높다.</li>
</ul>
<h3 id="사용-예시-1">사용 예시</h3>
<ul>
<li><strong>사용자 인증</strong>: 사용자가 로그인한 상태를 서버 측에서 관리.</li>
<li><strong>쇼핑 카트</strong>: 전자 상거래 사이트에서 사용자의 쇼핑 카트 상태를 유지한다.</li>
</ul>
<h3 id="장단점-1">장단점</h3>
<ul>
<li><strong>장점</strong>: 보안성이 높고, 데이터 저장 용량이 크다.</li>
<li><strong>단점</strong>: 서버 리소스를 소비하며, 확장성이 제한적일 수 있다.</li>
</ul>
<h2 id="jwt-json-web-token">JWT (JSON Web Token)</h2>
<h3 id="정의-2">정의</h3>
<p>JWT는 JSON 객체를 사용하여 양쪽 간에 정보를 안전하게 전송하기 위한 개방형 표준 방식이다. 
자체적으로 정보를 포함하고 있어 상태 비저장(stateless) 방식으로 작동한다.</p>
<h3 id="특징-2">특징</h3>
<ul>
<li><strong>자체 포함 토큰</strong>: 필요한 모든 정보를 포함하고 있어 서버에서 별도의 상태 저장이 필요 없다.</li>
<li><strong>서명과 암호화</strong>: JWT는 서명되어 있어 무결성을 검증할 수 있으며, 필요에 따라 암호화할 수 있다.</li>
</ul>
<h3 id="사용-예시-2">사용 예시</h3>
<ul>
<li><strong>OAuth2 인증</strong>: API 인증 및 권한 부여에 사용.</li>
<li><strong>정보 교환</strong>: 두 시스템 간의 안전한 정보 교환에 사용.</li>
</ul>
<h3 id="장단점-2">장단점</h3>
<ul>
<li><strong>장점</strong>: 확장성이 높고, 클라이언트 간에 쉽게 전달 가능하다.</li>
<li><strong>단점</strong>: 클라이언트에 노출되므로, 민감한 정보를 포함해서는 안된다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hwani_/post/5ac14876-f3b4-4b81-b1f7-9768b4080601/image.png" alt=""></p>
<p><strong>Header:</strong> JWT의 헤더는 알고리즘과 토큰의 타입을 지정합니다. 
이 예에서는 &#39;HS256&#39; 알고리즘과 &#39;JWT&#39; 타입이 사용되었습니다.</p>
<p><strong>Payload:</strong> 페이로드는 토큰에 담길 클레임(claim) 정보를 포함합니다.
여기에는 주제(&#39;sub&#39;)로 &#39;1234567890&#39;, 사용자 이름(&#39;name&#39;)으로 &#39;John Doe&#39;, 
그리고 토큰이 발급된 시간(&#39;iat&#39;)으로 1516239022가 포함되어 있습니다.</p>
<p><strong>Verify Signature:</strong> 서명 부분은 토큰의 보안을 담당한다.
헤더와 페이로드를 합친 후 비밀키를 이용하여 HMAC SHA256 알고리즘으로 서명이 생성됩니다.
이 서명을 통해 토큰이 변조되지 않았는지 검증할 수 있습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers Queue - 다리를 지나는 트럭]]></title>
            <link>https://velog.io/@hwani_/programmers-Queue-%EB%8B%A4%EB%A6%AC%EB%A5%BC-%EC%A7%80%EB%82%98%EB%8A%94-%ED%8A%B8%EB%9F%AD</link>
            <guid>https://velog.io/@hwani_/programmers-Queue-%EB%8B%A4%EB%A6%AC%EB%A5%BC-%EC%A7%80%EB%82%98%EB%8A%94-%ED%8A%B8%EB%9F%AD</guid>
            <pubDate>Fri, 26 Jul 2024 07:26:15 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---다리를-지나는-트럭-span">💡 <span style="color : orange"> 문제 - 다리를 지나는 트럭 </span></h2>
<h3 id="문제-설명">문제 설명</h3>
<h1 id="문제-설명-1">문제 설명</h1>
<p>트럭 여러 대가 강을 가로지르는 일차선 다리를 정해진 순서로 건너려 합니다.
모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 알아내야 합니다.
다리에는 트럭이 최대 <code>bridge_length</code>대 올라갈 수 있으며, 
다리는 <code>weight</code> 이하까지의 무게를 견딜 수 있습니다. 
단, 다리에 완전히 오르지 않은 트럭의 무게는 무시합니다.</p>
<p>예를 들어, 트럭 2대가 올라갈 수 있고 무게를 10kg까지 견디는 다리가 있습니다. 
무게가 [7, 4, 5, 6]kg인 트럭이 순서대로 최대 시간 안에 다리를 건너려면 다음과 같이 건너야 합니다.</p>
<table>
<thead>
<tr>
<th>경과 시간</th>
<th>다리를 지난 트럭</th>
<th>다리를 건너는 트럭</th>
<th>대기 트럭</th>
</tr>
</thead>
<tbody><tr>
<td>0</td>
<td>[]</td>
<td>[]</td>
<td>[7,4,5,6]</td>
</tr>
<tr>
<td>1~2</td>
<td>[]</td>
<td>[7]</td>
<td>[4,5,6]</td>
</tr>
<tr>
<td>3</td>
<td>[7]</td>
<td>[4]</td>
<td>[5,6]</td>
</tr>
<tr>
<td>4</td>
<td>[7]</td>
<td>[4,5]</td>
<td>[6]</td>
</tr>
<tr>
<td>5</td>
<td>[7,4]</td>
<td>[5]</td>
<td>[6]</td>
</tr>
<tr>
<td>6~7</td>
<td>[7,4,5]</td>
<td>[6]</td>
<td>[]</td>
</tr>
<tr>
<td>8</td>
<td>[7,4,5,6]</td>
<td>[]</td>
<td>[]</td>
</tr>
</tbody></table>
<p>따라서, 모든 트럭이 다리를 지나려면 최소 8초가 걸립니다.</p>
<p>solution 함수의 매개변수로 다리에 올라갈 수 있는 트럭 수 <code>bridge_length</code>,
다리가 견딜 수 있는 무게 <code>weight</code>, 트럭 별 무게 <code>truck_weights</code>가 주어집니다. 
이때 모든 트럭이 다리를 건너려면 최소 몇 초가 걸리는지 return 하도록 solution 함수를 완성하세요.</p>
<h2 id="제한-조건">제한 조건</h2>
<ul>
<li><code>bridge_length</code>는 1 이상 10,000 이하입니다.</li>
<li><code>weight</code>는 1 이상 10,000 이하입니다.</li>
<li><code>truck_weights</code>의 길이는 1 이상 10,000 이하입니다.</li>
<li>모든 트럭의 무게는 1 이상 <code>weight</code> 이하입니다.</li>
</ul>
<h2 id="입출력-예">입출력 예</h2>
<table>
<thead>
<tr>
<th>bridge_length</th>
<th>weight</th>
<th>truck_weights</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>2</td>
<td>10</td>
<td>[7, 4, 5, 6]</td>
<td>8</td>
</tr>
<tr>
<td>100</td>
<td>100</td>
<td>[10]</td>
<td>101</td>
</tr>
<tr>
<td>100</td>
<td>100</td>
<td>[10, 10, 10, 10, 10, 10, 10, 10, 10, 10]</td>
<td>110</td>
</tr>
</tbody></table>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">public int solution(int bridge_length, int weight, int[] truck_weights) {
        int time = 0; // 다리를 건너는 데 걸린 시간
        int current_weight = 0; // 현재 다리 위에 있는 트럭들의 무게 합
        Queue&lt;Integer&gt; bridge = new LinkedList&lt;&gt;(); // 다리 위의 트럭들을 관리할 큐

        // 각 트럭에 대해 처리
        for (int truck : truck_weights) {
            while (true) {
                // 다리에 올라간 트럭 수가 다리 길이와 같으면 트럭이 다리를 다 건넜다는 의미
                if (bridge.size() == bridge_length) {
                    current_weight -= bridge.poll(); // 다리에서 트럭을 내리고 무게를 갱신
                }

                // 현재 트럭을 다리에 올릴 수 있는지 확인
                if (current_weight + truck &lt;= weight) {
                    bridge.add(truck); // 트럭을 다리에 올림
                    current_weight += truck; // 현재 무게를 갱신
                    time++; // 시간을 증가
                    break; // 다음 트럭으로 넘어가기 위해 루프 탈출
                } else {
                    // 무게 초과로 트럭을 올릴 수 없을 때는 시간을 1초 추가하고
                    // 다리에 0을 추가하여 트럭이 지나가도록 함
                    bridge.add(0); // 무게 초과이므로 빈 공간을 추가
                    time++; // 시간을 증가
                }
            }
        }

        // 마지막 트럭이 다리를 완전히 건너는 시간 추가
        time += bridge_length;

        return time;
    }</code></pre>
<h2 id="문제-접근-방식">문제 접근 방식</h2>
<p>이 문제는 트럭들이 순서대로 다리를 건너는 동안 각 트럭의 무게와 다리의 최대 무게, 다리의 길이를 고려하여 최소 시간을 계산하는 문제입니다. 
트럭들은 큐(Queue)를 사용하여 다리 위에 올라가고, 다리의 길이와 무게 제한을 넘지 않도록 주의해서 푸는 문제.</p>
<p><strong>Queue를 사용하는 이유</strong>
선입선출(FIFO, First-In-First-Out) 구조를 가지는 자료구조로, 
가장 먼저 삽입된 요소가 가장 먼저 제거됩니다. </p>
<p><strong>주요 특징</strong>
<strong>선입선출(FIFO) 원칙 :</strong> 가장 먼저 삽입된 요소가 가장 먼저 제거됨.</p>
<p><strong>기본 연산:</strong>
enqueue: 요소를 큐의 뒤에 삽입.
dequeue: 요소를 큐의 앞에서 제거.
peek: 큐의 앞에 있는 요소를 제거하지 않고 조회.
사용 예: 트럭이 다리를 건너는 순서 관리, 프로세스 스케줄링, 너비 우선 탐색(BFS) 등</p>
<p>문제에서 먼저 다리에 올라간 트럭이 다리를 건너야한다. (선입선출)
그러므로 Stack(후입선출)은 사용할 수 없다.</p>
<h2 id="풀이-설명">풀이 설명</h2>
<p><strong>1. 변수 설정:</strong></p>
<p>time은 트럭들이 다리를 건너는 데 걸리는 총 시간을 저장한다.
current_weight은 현재 다리 위에 있는 트럭들의 무게 합을 저장한다.
bridge는 다리 위의 트럭들을 관리하기 위해 큐(Queue)로 선언한다.</p>
<p><strong>2. 트럭 처리:</strong></p>
<p>각 트럭을 순차적으로 처리하며, 트럭을 다리에 올릴 수 있는지 확인합니다.
트럭을 다리에 올릴 수 있는 경우, 트럭을 다리에 추가하고 무게를 갱신합니다.
트럭을 올릴 수 없는 경우, 시간을 1초 추가하고 큐에 0을 추가하여 트럭이 다리를 건널 수 있도록 합니다.</p>
<p><strong>3. 마지막 트럭 처리:</strong></p>
<p>모든 트럭이 다리를 건넌 후, 마지막 트럭이 다리를 완전히 건너는 시간을 추가합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[데이터베이스]]></title>
            <link>https://velog.io/@hwani_/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</link>
            <guid>https://velog.io/@hwani_/%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%B2%A0%EC%9D%B4%EC%8A%A4</guid>
            <pubDate>Sun, 21 Jul 2024 05:22:03 GMT</pubDate>
            <description><![CDATA[<h2 id="데이터베이스란">데이터베이스란?</h2>
<p>일정한 규칙, 혹은 규약을 통해 구조화되어 저장되는 데이터의 모음.
해당 데이터베이스를 제어, 관리하는 통합 시스템을 DBMS라고 하며, 데이터베이스 안에 있는 데이터들은 특정 DBMS마다 정의된 쿼리 언어를 통해 삽입, 삭제, 수정, 조회 등을 수행하며 데이터베이스는 실시간 접근, 동시 공유가 가능하다.</p>
<h3 id="엔터티">엔터티</h3>
<p>사람, 장소, 물건, 사건, 개념 등 여러 개의 속성을 지닌 명사를 의미한다.</p>
<h3 id="릴레이션">릴레이션</h3>
<p>데이터베이스에서 정보를 구분하여 저장하는 기본 단위</p>
<p><strong>테이블과 컬렉션</strong>
MySQL의 구조는 레코드-테이블-데이터베이스
NoSQL의 구조는 도큐먼트-컬렉션-데이터베이스 (MongoDB)</p>
<h3 id="속성">속성</h3>
<p>릴레이션에서 관리하는 구체적이며 고유한 이름을 갖는 정보</p>
<h3 id="도메인">도메인</h3>
<p>릴레이션에 포함된 각각의 속성들이 가질 수 있는 값의 집합</p>
<h3 id="필드와-레코드">필드와 레코드</h3>
<p>필드와 레코드 사진</p>
<h2 id="관계">관계</h2>
<p>여러 개의 테이블이 있고 이러한 테이블은 서로의 관계가 정의되어 있다.</p>
<p><strong>1:1 관계</strong></p>
<p><strong>1:N 관계</strong></p>
<p><strong>N:M 관계</strong></p>
<h2 id="키">키</h2>
<p>테이블 간의 관계를 조금 더 명확하게 하고 테이블 자체의 인덱스를 위해 설정된 장치</p>
<h3 id="기본키">기본키</h3>
<p>기본키는 줄여 PK 또는 프라이머리키라고 부르며, 유일성과 최소성을 만족하는 키</p>
<h3 id="외래키">외래키</h3>
<p>외래키는 FK라고도 하며, 다른 테이블의 기본키를 그대로 참조하는 값으로 개체와의 관계를 식별하는데 사용한다.
외래키는 중복되어도 괜찮다.</p>
<h3 id="후보키">후보키</h3>
<p>기본키가 될 수 있는 후보들이며 유일성과 최소성을 동시에 만족하는 키</p>
<h3 id="대체키">대체키</h3>
<p>후보키가 두 개 이상일 경우 어느 하나를 기본키로 지정하고 남은 후보키</p>
<h3 id="슈퍼키">슈퍼키</h3>
<p>각 레코드를 유일하게 식별할 수 있는 유일성을 갖춘 키</p>
<h2 id="정규화-과정">정규화 과정</h2>
<p>릴레이션 간의 잘못된 종속 관계로 인해 데이터베이스 이상 현상이 일어나서 이를 해결하거나, 저장 공간을 효율적으로 사용하기 위해 릴레이션을 여러 개로 분리하는 과정</p>
<h3 id="제1정규형">제1정규형</h3>
<p>릴레이션의 모든 도메인이 더 이상 분해될 수 없는 원자 값만으로 구성되어야 한다.
릴레이션의 속성 값 중에서 한 개의 기본키에 대해 두 개 이상의 값을 가지는 반복 집합이 있어서는 안된다. 반복 집합이 있다면 제거!</p>
<h3 id="제2정규형">제2정규형</h3>
<p>릴레이션이 제1정규형이며 부분 함수의 종속성을 제거한 형태를 말한다.
부분 함수의 종속성 제거란 기본키가 아닌 모든 속성이 기본키에 완전 함수 종속적인 것을 말한다.</p>
<h3 id="제3정규형">제3정규형</h3>
<p>제2정규형이고 기본키가 아닌 모든 속성이 이행적 함수 종속을 만족하지 않는 상태</p>
<h3 id="보이스코드-정규형">보이스/코드 정규형</h3>
<p>제3정규형이고, 결정자가 후보키가 아닌 함수 종속 관계를 제거하여 릴레이션의 함수 종속 관계에서 모든 결정자가 후보키인 상태</p>
<h2 id="트랜잭션">트랜잭션</h2>
<p>데이터베이스에서 하나의 논리적 기능을 수행하기 위한 작업의 단위를 말하며 데이터베이스에 접근하는 방법은 쿼리이므로, 즉 여러 개의 쿼리들을 하나로 묶는 단위를 말한다.</p>
<h3 id="원자성">원자성</h3>
<p>트랜잭션과 관련된 일이 모두 수행되었거나 되지 않았거나를 보장하는 특징
예를 들어 트랜잭션을 커밋했는데, 문제가 발생하여 롤백하는 경우 그 이후에 모두 수행되지 않음을 보장하는 것을 말한다.</p>
<h3 id="일관성">일관성</h3>
<p>&#39;허용된 방식&#39;으로만 데이터를 변경해야 하는 것을 의미한다.</p>
<h3 id="격리성">격리성</h3>
<p>트랜잭션 수행 시 서로 끼어들지 못하는 것을 말한다. 
복수의 병렬 트랜잭션은 서로 격리되어 마치 순차적으로 실행되는 것처럼 작동되어야 하고, 데이터베이스는 여러 사용자가 같은 데이터에 접근할 수 있어야한다.</p>
<h3 id="지속성">지속성</h3>
<p>성공적으로 수행된 트랜잭션은 영원히 반영되어야 하는 것을 의미한다.
이는 데이터베이스에 시스템 장애가 발생해도 원래 상태로 복구하는 회복 기능이 있어야 함을 뜻하며, 데이터베이스는 이를 위해 체크섬, 저널링, 롤백 등 기능을 제공한다.</p>
<h2 id="무결성">무결성</h2>
<p>데이터의 정확성, 일관성, 유효성을 유지하는것을 말하며, 무결성이 유지되어야 데이터베이스에 저장된 데이터 값과 그 값에 해당하는 현실 세계의 실제 값이 일치하는지에 대한 신뢰가 생긴다.</p>
<p>개체,참조,고유,NULL 무결성 테이블 사진</p>
<h2 id="데이터베이스의-종류">데이터베이스의 종류</h2>
<h3 id="관계형-데이터베이스">관계형 데이터베이스</h3>
<p>관계형 데이터베이스(RDBMS)는 행과 열을 가지는 표 형식 데이터를 저장하는 형태의 데이터베이스를 가리키며 SQL이라는 언어로 조작한다.
MySQL, PostgreSQL, 오라클, SQL Server, MSSQL 등이 있다.</p>
<p><strong>PostgreSQL</strong>
MySQL 다음으로 개발자들이 선호하는 데이터베이스
디스크 조각이 차지하는 영역을 회수할 수 있는 장치인 VACUUM이 특징.
최대 테이블의 크기는 32TB이며 SQL뿐만 아니라 JSON을 이용해서 데이터에 접근할 수 있으며 지정 시간에 복구하는 기능, 로깅, 접근 제어, 중첩된 트랜잭션, 백업 등을 할 수 있다.</p>
<h3 id="nosql-데이터베이스">NoSQL 데이터베이스</h3>
<p>NoSQL(Not only SQL)이라는 슬로건에서 생겨난 데이터베이스
SQL을 사용하지 않는 데이터베이스를 말하며, 대표적으로 MongoDB, Redis가 있다.</p>
<p><strong>MongoDB</strong>
JSON을 통해 데이터에 접긍할 수 있고, 키-값 데이터 모델에서 확장된 도큐먼트 기반의 데이터베이스이다.
확장성이 뛰어나며 빅데이터를 저장할 때 성능이 좋고, 고가용성과 샤딩, 레플리카셋을 지원한다.
스키마를 정해놓지 않고 데이터를 삽입할 수 있어 다양한 도메인의 데이터베이스를 기반으로 분석하거나 로깅 등을 구현할 때 강점을 보인다.</p>
<p><strong>Redis</strong>
인메모리 데이터베이스이자 키-값 데이터 모델 기반의 데이터베이스이다.
기본적인 데이터 타입은 문자열(String)이며 최대 512MB까지 저장가능하다.
이외에도 셋(Set), 해시(Hash) 등을 지원한다.</p>
<h2 id="인덱스">인덱스</h2>
<h3 id="인덱스의-필요성">인덱스의 필요성</h3>
<p>인덱스는 데이터를 빠르게 찾을 수 있는 하나의 장치</p>
<h3 id="b-트리">B-트리</h3>
<p>인덱스는 보통 B-트리라는 자료 구조로 이루어져 있다.
이는 루트 노드, 리프 노드, 루트 노드와 리프 노드 사이에 있는 브랜치 노드로 나뉜다.</p>
<p>위에 대한 사진으로 설명</p>
<h3 id="인덱스-만드는-방법">인덱스 만드는 방법</h3>
<p><strong>MySQL</strong></p>
<ul>
<li>클리스터형 인덱스는 테이블당 하나를 설정할 수 있다.
primary key 옵션으로 기본키로 만들면 클리스터형 인덱스를 생성할 수 있고,
기본키로 만들지 않고 unique not null 옵션을 붙여도 클리스터형 인덱스로 만들 수 있다.</li>
<li>create index.. 명령어를 기반으로 만들면 세컨더리 인덱스를 만들 수 있다. </li>
</ul>
<p>하나의 인덱스만 생성한다면 클리스터형 인덱스를 만드는 것이 세컨더리 인덱스보다 성능이 좋다!</p>
<p>세컨더리 인덱스는 보조 인덱스로 여러 개의 필드 값을 기반으로 쿼리를 많이 보낼 때 생성해야 하는 인덱스이다.</p>
<p><strong>MongoDB</strong></p>
<ul>
<li>도큐먼트를 만들면 자동으로 ObjectID가 형성되며, 해당 키가 기본키로 설정된다.</li>
<li>세컨더리키도 부가적으로 설정해서 기본키와 세컨더리키를 같이 쓰는 복합 인덱스를 설정할 수 있다.</li>
</ul>
<h2 id="인덱스-최적화-기법">인덱스 최적화 기법</h2>
<ol>
<li>인덱스는 비용이다.</li>
<li>항상 테스팅하라</li>
<li>복합 인덱스는 같음, 정렬, 다중 값, 카디널리티 순이다.</li>
</ol>
<h2 id="조인의-종류">조인의 종류</h2>
<ul>
<li>*<em>내부 조인(Inner Join) : *</em> 왼쪽 테이블과 오른쪽 테이블의 두 행이 모두 일치하는 행이 있는 부부만 표기합니다.</li>
<li>*<em>왼쪽 조인(Left Outer Join) : *</em> 왼쪽 테이블의 모든 행이 결과 테이블에 표기됩니다.</li>
<li>*<em>오른쪽 조인(Right Outer Join) : *</em> 오른쪽 테이블의 모든 행이 결과 테이블에 표기됩니다.</li>
<li>*<em>합집합 조인(Full Outer Join) : *</em> 두 개의 테이블을 기반으로 조인 조건에 만족하지 않는 행까지 모두 표기합니다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[운영체제와 컴퓨터]]></title>
            <link>https://velog.io/@hwani_/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%BB%B4%ED%93%A8%ED%84%B0</link>
            <guid>https://velog.io/@hwani_/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9C%EC%99%80-%EC%BB%B4%ED%93%A8%ED%84%B0</guid>
            <pubDate>Fri, 19 Jul 2024 14:56:30 GMT</pubDate>
            <description><![CDATA[<h2 id="운영체제">운영체제</h2>
<p>사용자가 컴퓨터를 쉽게 다루게 해주는 인터페이스이다.
한정된 메모리나 시스템 자원을 효율적으로 분배하여 사용한다.</p>
<h2 id="운영체제의-역할">운영체제의 역할</h2>
<p><strong>1. CPU 스케줄링과 프로세스 관리 :</strong> 
CPU 소유권을 어떤 프로세스에 할당할지, 프로세스의 생성과 삭제, 자원 할당 및 반환을 관리한다.</p>
<p><strong>2. 메모리 관리 :</strong> 
한정된 메모리를 어떤 프로세스에 얼만큼 할당해야 하는지 관리한다.</p>
<p><strong>3. 디스크 파일 관리 :</strong> 
디스크 파일을 어떠한 방법으로 보관할지 관리한다.</p>
<p><strong>4. I/O 디바이스 관리 :</strong> 
I/O 디바이스들인 마우스, 키보드와 컴퓨터 간에 데이터를 주고받는 것을 관리한다.</p>
<h2 id="운영체제의-구조">운영체제의 구조</h2>
<p>운영체제 구조 그림</p>
<h2 id="컴퓨터의-요소">컴퓨터의 요소</h2>
<p>컴퓨터의 요소 그림</p>
<h3 id="cpu">CPU</h3>
<p>산술논리연산장치, 제어장치, 레지스터로 구성되어 있는 컴퓨터 장치를 말하며, 인터럽트에 의해 단순히 메모리에 존재하는 명령어를 해석해서 실행한다.</p>
<p><strong>제어장치란?</strong>
프로세스 조작을 지시하는 CPU의 한 부품이다.
입출력장치 간 통신을 제어하고 명령어들을 읽고 해석하며 데이터 처리를 위한 순서를 결정한다.</p>
<p><strong>레지스터란?</strong>
CPU 안에 있는 매우 빠른 임시기억장치이다. 
CPU와 직접 연결되어 있어 연산 속도가 메모리보다 수십 배에서 수백 배까지 빠르며
CPU는 자체적으로 데이터를 저장할 방법이 없기 때문에 레지스터를 거쳐 데이터를 전달한다.</p>
<p><strong>산술논리연산장치란?</strong>
덧셈, 뺄셈 같은 두 숫자의 산술 연산과 배타적 논리합, 논리곱 같은 논리 연산을 계산하는 디지털 회로이다.</p>
<h2 id="메모리">메모리</h2>
<p>전자회로에서 데이터나 상태, 명령어 등을 기록하는 장치
보통 RAM을 메모리라고 한다. CPU는 계산을 담당하고 메모리는 기억을 담당한다.</p>
<h3 id="메모리-계층">메모리 계층</h3>
<ul>
<li><strong>레지스터 :</strong> CPU 안에 있는 작은 메모리, 휘발성, 속도 가장 빠름, 기억 용량이 가장 적다.</li>
<li><strong>캐시 :</strong> L1, L2 캐시를 지칭한다. 휘발성, 속도 빠름, 기억 용량이 적다.</li>
<li><strong>주기억장치 :</strong> RAM을 가리킨다. 휘발성, 속도 보통, 기억 용량이 보통이다.</li>
<li><strong>보조기억장치 :</strong> HDD,SDD를 일컬으며 휘발성, 속도 낮음, 기억 용량이 많다.</li>
</ul>
<h2 id="메모리-관리">메모리 관리</h2>
<h3 id="가상-메모리">가상 메모리</h3>
<p>메모리 관리 기법의 하나로 컴퓨터가 실제로 이용 가능한 메모리 자원을 추상화하여 이를 사용하는 사용자들에게 매우 큰 메모리로 보이게 만드는 것을 말합니다.</p>
<p><strong>스와핑이란?</strong>
만약 가상 메모리에는 존재하지만 실제 메모리인 RAM에는 현재 없는 데이터나 코드에 접근할 경우 페이지 폴트가 발생한다. 이를 방지하기 위해 당장 사용하지 않는 영역을 하드디스크로 옮겨 필요할 때 다시 RAM으로 불러와 올리고, 사용하지 않으면 다시 하드디스크로 내림을 반복하여 RAM을 효과적으로 관리하는 것.</p>
<p><strong>페이지 폴트란?</strong>
프로세스의 주소 공간에는 존재하지만 지금 이 컴퓨터의 RAM에는 없는 데이터에 접근했을 경우에 발생한다.
이 때 운영체제는 다음 과정으로 해당 데이터를 메모미로 가져와서 마치 페이지 폴트가 전혀 발생하지 않은 것처럼 프로그램이 작동하게 해준다.</p>
<h3 id="스레싱">스레싱</h3>
<p>메모리의 페이지 폴트율이 높은것을 의미하며, 이는 컴퓨터의 심각한 성능 저하를 초래한다.
스레싱은 메모리에 너무 많은 프로세스가 동시에 올라가게 되면 스와핑이 많이 일어나서 발생한다. 페이지 폴트가 일어나면 CPU 이용률이 낮아진다. 낮아지게 되면 운영체제는 &quot;CPU가 한가한가?&quot;라고 생각하여 가용성을 더 높이기 위해 더 많은 프로세스를 메모리에 올리게 된다. 이와 같은 악순환이 반복되고 스레싱이 일어나게 된다.
해결하기 위한 방법은 메모리를 늘리거나, HDD-&gt;SSD로 교체하는 방법이다.</p>
<h2 id="프로세스와-스레드">프로세스와 스레드</h2>
<p>프로세스는 컴퓨터에서 실행되고 있는 프로그램을 말하며 CPU 스케줄링의 대상이 되는 작업(task)이라는 용어와 거의 같은 의미로 쓰인다.
스레드는 프로세스의 실행 가능한 가장 작은 단위이다.
프로세스는 여러 스레드를 가질 수 있다.</p>
<h2 id="프로레스의-상태">프로레스의 상태</h2>
<p>생성 -&gt; 대기 -&gt; 대기 중단 -&gt; 실행 -&gt; 중단 -&gt; 일시 중단 -&gt; 종료</p>
<h2 id="프로세스의-메모리-구조">프로세스의 메모리 구조</h2>
<p><strong>스택</strong></p>
<ul>
<li>지역변수, 매개변수, 함수가 저장되고 컴파일 시에 크기가 결정되며 <strong>동적</strong>인 특징을 갖는다.</li>
<li>함수가 함수를 재귀적으로 호출하면서 동적으로 크기가 늘어날 수 있는데, 이때 힙과 스택의 메모리 영역이 겹치면 안 되기 때문에 힙과 스택 사이의 공간을 비워 놓는다.</li>
</ul>
<p><strong>힙</strong></p>
<ul>
<li>동적 할당할 때 사용되며 런타임 시 크기가 결정된다.</li>
<li>예를 들어 벡터 같은 동적 배열은 당연히 힙에 동적 할당된다. 힙은 <strong>동적</strong>인 특징을 가진다.</li>
</ul>
<p><strong>데이터 영역</strong></p>
<ul>
<li>전역변수, 정적변수가 저장되며, 정적인 특징을 갖는 프로그램이 종료되면 사라지는 변수가 들어 있는 영역이다.</li>
</ul>
<p><strong>코드 영역</strong></p>
<ul>
<li>프로그램에 내장되어 있는 소스 코드가 들어가는 영역이다.</li>
<li>이 영역은 수정 불가능한 기계어로 저장되어 있으며 정적인 특징을 갖는다.</li>
</ul>
<h2 id="공유-자원과-임계-영역">공유 자원과 임계 영역</h2>
<p><strong>공유 자원이란?</strong>
시스템 안에서 각 프로세스, 스레드가 함께 접근할 수 있는 모니터, 프린터, 메모리, 파일, 데이터 등의 자원이나 변수 등을 의미한다.
이 공유자원을 두 개 이상의 프로세스가 동시에 읽거나 쓰는 상황을 경쟁 상태라고 한다.
동시에 접근을 시도할 때 접근의 타이밍이나 순서 등이 결괏값에 영향을 줄 수 있는 상태이다.</p>
<p><strong>임계 영역이란?</strong>
공유 자원에 접근할 때 순서 등의 이유로 결과가 달라지는 영역을 임계 영역이라고 한다.
임계 영역을 해결하기 위한 방법은 크게 뮤텍스, 세마포어, 모니터 세 가지가 있다.
이 방법 모두 상호 배제, 한정 대기, 융퉁성이란 조건을 만족한다.</p>
<p>상호 배제</p>
<ul>
<li>한 프로세스가 임계 영역에 들어갔을 때 다른 프로세스는 들어갈 수 없다.</li>
</ul>
<p>한정 대기</p>
<ul>
<li>특정 프로세스가 영원히 임계 영역에 들어가지 못하면 안 된다.</li>
</ul>
<p>융퉁성</p>
<ul>
<li>한 프로세스가 다른 프로세스의 일을 방해해서는 안 된다.</li>
</ul>
<p>뮤텍스</p>
<ul>
<li>공유 자원을 사용하기 전에 설정하고 사용한 후에 해제하는 잠금이다.
잠금이 설정되면 다른 스레드는 잠긴 코드 영역에 접근할 수 없다.
또한 뮤텍스는 하나의 상태(잠금 또는 잠금 해제)만 가진다.</li>
</ul>
<p>세마포어</p>
<ul>
<li>세마포어는 일반화된 뮤텍스이다.</li>
<li>간단한 정수 값과 두 가지 함수 wait 및 signal로 공유 자원에 대한 접근을 처리한다.</li>
</ul>
<p>모니터</p>
<ul>
<li>모니터는 둘 이상의 스레드나 프로세스가 공유 자원에 안전하게 접근할 수 있도록 공유 자원을 숨기고 해당 접근에 대해 인터페이스만 제공한다.</li>
</ul>
<p>모니터는 세마포어보다 구현하기 쉬우며 모니터에서 상호 배제는 자동인 반면에, 세마포어에서는 상호 배제를 명시적으로 구현해야 하는 차이점이 있다.</p>
<h2 id="교착-상태">교착 상태</h2>
<h3 id="교착-상태의-원인">교착 상태의 원인</h3>
<ul>
<li><strong>상호 배제 :</strong> 한 프로세스가 자원을 독점하고 있으며 다른 프로세스들은 접근이 불가능하다.</li>
<li><strong>점유 대기 :</strong> 특정 프로세스가 점유한 자원을 다른 프로세스가 요청하는 상태</li>
<li><strong>비선점 :</strong> 다른 프로세스의 자원을 강제적으로 가져올 수 없다.</li>
<li><strong>환형 대기 :</strong> 프로세스 A는 프로세스 B의 자원을 요구하고, 프로세스 B는 프로세스 A의 자원을 요구하는 등 서로가 서로의 자원을 요구하는 상황을 말한다.</li>
</ul>
<h3 id="교착-상태의-해결-방법">교착 상태의 해결 방법</h3>
<ol>
<li>자원을 할당할 때 애초에 조건이 성립되지 않도록 설계한다.</li>
<li>교착 상태 가능성이 없을 때만 자원 할다외며, 프로세스당 요청할 자원들의 최대치를 통해 자원 할당 가능 여부를 파악하는 &#39;은행원 알고리즘&#39;을 사용한다.</li>
<li>교착 상태가 발생하면 사이클이 있는지 찾아보고 이에 관련된 프로세스를 한 개씩 지운다.</li>
</ol>
<h2 id="예상-질문">예상 질문</h2>
<p><strong>Q. 운영체제의 역할은 무엇인가요?</strong>
A. 운영체제의 역할은 크게 네 가지가 있다.</p>
<ol>
<li>CPU 스케줄링과 프로세스 관리 : CPU 소유권을 어떤 프로세스에 할당할지, 프로세스의 생성과 삭제, 자원 할당 및 반환을 관리한다.</li>
<li>메모리 관리 : 한정된 메모리를 어떤 프로세스에 얼만큼 할당해야 하는지 관리한다.</li>
<li>디스크 파일 관리 : 디스크 파일을 어떠한 방법으로 보관할지 관리한다.</li>
<li>I/O 디바이스 관리 : I/O 디바이스들인 마우스, 키보드 등과 컴퓨터 간에 데이터를 주고받는 것을 관리한다.</li>
</ol>
<p><strong>Q. 메모리 계층에 대해 설명해보세요.</strong>
A. 메모리 계층은 레지스터, 캐시, 메모리, 저장장치로 구성되어있다.
레지스터는 CPU 안에 있는 작은 메모리, 휘발성, 속도 가장 빠름, 기억 용량이 가장 낮습니다.
캐시로는 L1, L2 캐시를 지칭하며 휘발성, 속도 빠름, 기억 용량이 낮습니다.
주기억장치로는 RAM을 가리키며 휘발성, 속도 보통, 기억 용량이 보통입니다.
보조기억장치로는 HDD, SSD를 일컬으며 휘발성, 속도 낮음, 기억 용량이 높습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[네트워크]]></title>
            <link>https://velog.io/@hwani_/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</link>
            <guid>https://velog.io/@hwani_/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC</guid>
            <pubDate>Fri, 19 Jul 2024 14:07:03 GMT</pubDate>
            <description><![CDATA[<h2 id="네트워크">네트워크</h2>
<p>네트워크란 노드(node) 와 링크(link)가 서로 연결되어 있거나 연결되어 있지 않은 집합체를 의미한다.
여기서 노드란 서버, 라우터, 스위치 등 네트워크 장치를 의미하고
링크는 유선 또는 무선을 의미한다.</p>
<h3 id="처리량">처리량</h3>
<p>처리량이란 링크를 통해 전달되는 단위 시간당 데이터양을 말한다.
처리량은 사용자들이 많이 접속할 때마다 커지는 트래픽, 네트워크 장치 간의 대역폭, 
네트워크 중간에 발생하는 에러, 장치의 하드웨어 스펙에 영향을 받는다.</p>
<h3 id="지연시간">지연시간</h3>
<p>지연 시간은 요청이 처리되는 시간을 말하며 어떤 메시지가 두 장치 사이를 왕복하는데 걸린 시간을 말한다.
지연 시간은 매체 타입(무선,유선), 패킷 크기, 라우터의 패킷 처리 시간에 영향을 받는다.</p>
<h2 id="네트워크-토폴로지">네트워크 토폴로지</h2>
<p>네트워크 토폴로지는 노드와 링크가 어떻게 배치되어 있는지에 대한 방식이자 연결 형태를 의미한다.</p>
<p><strong>1. 트리 토폴로지</strong></p>
<ul>
<li>계층형 토폴로지라고 하며 트리 형태로 배치한 네트워크 구성을 말한다.</li>
<li>노드의 추가, 삭제가 쉬우며 특정 노드에 트래픽이 집중될 때 하위 노드에 영향을 끼칠 수 있다.</li>
</ul>
<p><strong>2. 버스 토폴로지</strong></p>
<ul>
<li>중앙 통신 회선 하나에 여러 개의 노드가 연결되어 공유하는 네트워크 구성을 말하며 근거리 통신망(LAN)에서 사용한다.</li>
<li>설치 비용이 적고 신뢰성이 우수하며 중앙 통신 회선에 노드를 추가하거나 삭제하기 쉽다. 
하지만 스푸핑이 생기는 문제가 있다.</li>
</ul>
<p><strong>스푸핑이란?</strong>
LAN상에서 송신부의 패킷을 송신과 관련 없는 다른 호스트에 가지않도록 하는 
스위칭 기능을 마비시키거나 속여서 특정 노드에 해당 패킷이 오도록 처리하는 것을 말한다.</p>
<p><strong>3. 스타 토폴로지</strong></p>
<ul>
<li>중앙에 있는 노드에 모두 연결된 네트워크 구성을 말한다.</li>
<li>노드를 추가하거나 에러를 탐지하기 쉽고 패킷의 충돌 발생 가능성이 적다.</li>
<li>노드에 장애가 발생해도 쉽게 에러를 발견할 수 있으며 장애 노드가 중앙 노드가 아닐 경우 다른 노드에 영향 끼치는 것이 적다.</li>
<li>하지만 중앙 노드에 장애가 발생하면 전체 네트워크를 사용할 수 없고 설치 비용이 비싸다는 단점이 있다.</li>
</ul>
<p><strong>4. 링형 토폴로지</strong></p>
<ul>
<li>각각의 노드가 양 옆의 두 노드와 연결하여 전체적으로 고리처럼 하나의 연속된 길을 통해 통신을 하는 망 구성 방식이다.</li>
<li>데이터는 노드-&gt;노드로 이동하며, 각각의 노드는 고리 모양의 길을 통해 패킷을 처리한다.</li>
<li>노드 수가 증가되어도 네트워크상의 손실, 충돌 가능성이 적고 노드의 고장 발견을 쉽게 찾을 수 있다.</li>
<li>네트워크 구성 변경이 어렵고 회선에 장애가 발생하면 전체 네트워크에 영향을 크게 끼치는 단점이 있다.</li>
</ul>
<p><strong>5. 메시 토폴로지</strong></p>
<ul>
<li>메시 토폴로지는 망형 토폴로지라고도 하며 그물망 처럼 연결되어 있는 구조이다.</li>
<li>한 단말 장치에 장애가 발생해도 여러 개의 경로가 존재하므로 
네트워크를 계속 사용가능하며 트래픽도 분산 처리가 가능하다.</li>
<li>노드의 추가가 어렵고 구축 비용과 운용 비용이 고가인 단점이 있다.</li>
</ul>
<p><strong>병목현상이란?</strong>
전체 시스템의 성능이나 용량이 하나의 구성 요소로 인해 제한을 받는 현상</p>
<h2 id="네트워크-분류">네트워크 분류</h2>
<p><strong>LAN</strong>
근거리 통신망을 의미하며 같은 건물이나 캠퍼스 같은 좁은 공간에서 운영되며,
전송 속도가 빠르고 혼잡하지 않다.</p>
<p><strong>MAN</strong>
대도시 지역 네트워크를 나타내며 도시 같은 넓은 지역에서 운영되며,
전송 속도는 평균이며 LAN보다는 더 많이 혼잡하다.</p>
<p><strong>WAN</strong>
광역 네트워크를 의미하며 국가 또는 대륙 같은 더 넓은 지역에서 운영되며,
전송 속도는 낮으면 MAN보다 더 혼잡하다.</p>
<h2 id="tcpip-4계층-모델">TCP/IP 4계층 모델</h2>
<p>TCP/IP OSI 7계층 그림</p>
<h3 id="애플리케이션-계층">애플리케이션 계층</h3>
<p>FTP, HTTP, SSH, SMTP, DNS 등 응용 프로그램이 사용되는 프로토콜 계층이며 웹 서비스, 이메일 등 서비스를 실질적으로 사람들에게 제공하는 층입니다.</p>
<h3 id="전송-계층">전송 계층</h3>
<p>송신자와 수신자를 연결하는 통신 서비스를 제공하며 연결 지향 데이터 스트림 지원, 신뢰성, 흐름 제어를 제공하며, 애플리케이션과 인터넷 계층 사이의 데이터가 전달될 때 중계 역할을 한다.
대표적으로 TCP, UDP 등이 있다.</p>
<p><strong>TCP란?</strong></p>
<ul>
<li>패킷 사이의 순서를 보장하고 연결지향 프로토콜을 사용해서 연결을 하여 신뢰성을 구축해서 수신 여부를 확인하며 <strong>가상회선 패킷 교환 방식</strong>을 사용한다.</li>
</ul>
<p><strong>UDP란?</strong></p>
<ul>
<li>순서를 보장하지 않고 수신 여부를 확인하지 않으며 단순히 데이터만 주는 <strong>데이터그램 패킷 교환 방식</strong>을 사용한다.</li>
</ul>
<p><strong>가상회선 패킷 교환 방식이란?</strong>
각 패킷에는 가상회선 식별자가 포함되며 모든 패킷을 전송하면 가상회선이 해제되고 패킷들은 <strong>전송된 순서대로 도착하는 방식</strong>을 말한다.</p>
<p><strong>데이터그램 패킷 교환 방식이란?</strong>
패킷이 독립적으로 이동하며 최적의 경로를 선택하여 가는데, 하나의 메시지에서 분할된 여러 패킷은 서로 다른 경로로 전송될 수 있으며 *<em>도착한 순서가 다를 수 *</em> 있는 방식을 뜻한다.</p>
<h3 id="tcp-연결-성립-과정">TCP 연결 성립 과정</h3>
<p>TCP는 신뢰성을 확보할 때 &#39;3-way-handshake&#39;라는 작업을 진행한다.
쓰리웨이 핸드셰이크 그림</p>
<p><strong>1. SVN 단계</strong>
<strong>2. SVN + ACK 단계</strong>
<strong>3. ACK 단계</strong></p>
<h3 id="tcp-연결-해제-과정">TCP 연결 해제 과정</h3>
<p>TCP가 연결을 해제할 때는 &#39;4-way-handshake&#39; 과정이 발생한다.</p>
<h3 id="인터넷-계층">인터넷 계층</h3>
<p>장치로부터 받은 네트워크 패킷을 IP 주소로 지정된 목적지로 전송하기 위해 사용되는 계층이다.
IP, ARP, ICMP 등이 있으며 패킷을 수신해야 할 상대의 주소를 지정하여 데이터를 전달한다.
상대방이 제대로 받았는지에 대해 보장하지 않는 비연결형적인 특징을 가지고 있다.</p>
<h3 id="링크-계층">링크 계층</h3>
<p>전선, 광섬유, 무선 등으로 실질적으로 데이터를 전달하며 장치 간에 신호를 주고받는 <strong>&#39;규칙&#39;</strong>을 정하는 계층이다.
네트워크 접근 계층이라고도 한다.</p>
<h2 id="예상-질문">예상 질문</h2>
<p><strong>Q. OSI 7계층과 TCP/IP 4계층의 차이점은 무엇인가요?</strong>
A. TCP/IP 계층과 달리 OSI 계층은 애플리케이션 계층을 세 개로 쪼개고 링크 계층을 데이터 링크 계층, 물리 계층으로 나눠서 설명하는 것이 다르며, 인터넷 계층을 네트워크 계층으로 부른다는 점이 다르다.</p>
<p><strong>Q. HTTP/2를 설명하고 장점 두 가지를 설명하세요.</strong>
A. HTTP/2는 HTTP/1.x보다 지연 시간을 중리고 응답 시간을 더 빠르게 할 수 있으며 멀티플렉싱, 헤더 압축, 서버 푸시, 요청의 우선순위 처리를 지원하는 프로토콜이다.
장점 두 가지로는 멀티플렉싱, 서버 푸시가 있다.
멀티플렉싱이란 여러 개의 스트림을 사용하여 송수신한다는 것이다. 이를 ㅌ오해 특정 스트림의 패킷이 손실되었다고 하더라도 해당 스트림에만 영향을 미치고 나머지 스트림은 멀쩡하게 동작할 수 있다.
서버 푸시란 HTTP/1.1에서는 클라이언트가 서버에 요청을 해야 파일을 다운로드 받을 수 있었다면, HTTP/2 클라이언트 요청 없이 서버가 바로 리소스를 푸시하는 것을 말한다. html에는 css나 js 파일이 포함되기 마련인데 html을 읽으면서 그 안에 들어있던 css 파일을 서버에서 푸시하여 클라이언트에 먼저 줄 수 있다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래밍 패러다임]]></title>
            <link>https://velog.io/@hwani_/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84</link>
            <guid>https://velog.io/@hwani_/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%8C%A8%EB%9F%AC%EB%8B%A4%EC%9E%84</guid>
            <pubDate>Wed, 17 Jul 2024 14:44:04 GMT</pubDate>
            <description><![CDATA[<h2 id="프로그래밍-패러다임">프로그래밍 패러다임</h2>
<p>프로그래밍 패러다임은 프로그래머에게 프로그래밍의 관점을 갖게 해주는 역할을 하는 개발 방법론입니다.
예를 들어 객체지향 프로그래밍은 프로그래머들이 프로그램을 상호 작용하는 객체들의 집합으로 볼 수 있게 하는 반면에, 함수형 프로그래밍은 상태 값을 지니지 않는 함수 값들의 연속으로 생각할 수 있게 해줍니다.
프로그래밍 패러다임은 크게 선언형, 명령형으로 나누며, 선언형은 함수형이라는 하위 집합을 갖습니다. 또한, 명령형은 다시 객체지향, 절차지향으로 나눕니다.</p>
<h3 id="객체지향-프로그래밍">객체지향 프로그래밍</h3>
<p>객체지향 프로그래밍은 객체들의 집합으로 프로그램의 상호 작용을 표현하며 데이터를 객체로 취급하여 객체 내부에 선언된 메서드를 활용하는 방식을 말한다. 설계에 많은 시간이 소요되며 처리 속도가 다른 프로그래밍 패러다임에 비해 상대적으로 느리다.</p>
<h3 id="객체지향-프로그래밍-특징">객체지향 프로그래밍 특징</h3>
<p><strong>추상화</strong>
추상화란 복잡한 시스템으로부터 핵심적인 개념 또는 기능을 간추려내는 것을 의미한다.
<strong>캡슐화</strong>
캡슐화는 객체의 속성과 메서드를 하나로 묶고 일부를 외부에 감추어 은닉하는 것을 말합니다.
<strong>상속성</strong>
상속성은 상위 클래스의 특성을 하위 클래스가 이어받아서 재사용하거나 추가, 확장하는 것을 말합니다. 코드의 재사용 측면, 계층적인 관계 생성, 유지 보수성 측면에서 중요하다.
<strong>다형성</strong>
다형성은 하나의 메서드나 클래스가 다양한 방법으로 동작하는 것을 말합니다. 대표적으로 오버로딩, 오버라이딩이 있다.</p>
<h4 id="오버로딩">오버로딩</h4>
<p>오버로딩은 같은 이름을 가진 메서드를 여러 개 두는 것을 말한다.
메서드의 타입, 매개변수의 유형, 개수 등으로 여러개를 둘 수 있으며 컴파일 중에 발생하는 &#39;정적&#39; 다형성입니다.</p>
<pre><code class="language-java">class Person {

    public void eat(String a) {
        System.out.println(&quot;I eat &quot; + a);
    }

    public void eat(String a, String b) {
        System.out.println(&quot;I eat &quot; + a &quot; and &quot; + b);
    }

    public class CalculateArea {

        public static void main(String[] args) {
            Person a = new Person();
            a.eat(&quot;apple&quot;);
            a.eat(&quot;tomato&quot;, &quot;phodo&quot;);
        }
    }
}

// 출력
I eat apple
I eat tomato and phodo</code></pre>
<p>앞의 코드를 보면 매개변수의 개수에 따라 다른 함수가 호출되는 것을 알 수 있다.</p>
<p><strong>오버라이딩</strong>
오버라이딩은 주로 메서드 오버라이딩을 말하며 상위 클래스로부터 상속받은 메서드를 하위 클래스가 재정의하는 것을 의미합니다.
이는 런타임 중에 발생하는 &#39;동적&#39; 다형성입니다.</p>
<pre><code class="language-java">class Animal {
    public void bark() {
        System.out.println(&quot;mumu! mumu!&quot;);
    }
}

class Dog extends Animal {
    @Override
    public void bark() {
        System.out.println(&quot;wal!!! wal!!!&quot;);
    }
}

public class main {
    public static void main(String[] args) {
        Dog d = new Dog();
        d.bark();
     }
}

// 출력
wal!!! wal!!!</code></pre>
<p>앞의 코드를 보면 부모 클래스는 mumu! mumu! 로 짖게 만들었지만 자식 클래스에서 wal!!! wal!!!로 짖게 만들었더닌 자식 클래스 기반으로 메서드가 재정의됨을 알 수 있습니다.</p>
<h2 id="설계-원칙">설계 원칙</h2>
<p>객체지향 프로그래밍을 설계할 때는 SOLID 원칙을 지켜주어야 합니다.
S는 단일 책임 원칙, O는 개방-폐쇄 원칙, L은 리스코프 치환 원칙, I는 인터페이스 분리 원칙, D는 의존 역전 원칙을 의미한다.</p>
<p><strong>단일 책임 원칙</strong>
단일 책임 원칙은 모든 클래스는 각각 하나의 책임만 가져야 하는 원칙입니다.
예를 들어 A라는 로직이 존재한다면 어떠한 클래스는 A에 관한 클래스여야 하고 이를 수정한다고 했을 때도 A와 관련된 수정이어야 합니다.</p>
<p><strong>개방-폐쇄 원칙</strong>
개방-폐쇄 원칙은 유지 보수 사항이 생긴다면 코드를 쉽게 확장할 수 있도록 하고 수정할 때는 닫혀 있어야 하는 원칙입니다. 즉, 기존의 코드는 잘 변경하지 않으면서도 확장은 쉽게 할 수 있어야 합니다.</p>
<p><strong>리스코프 치환 원칙</strong>
리스코프 치환 원칙은 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어햐 하는 것을 의미한다. 클래스는 상속이 되기 마련이고 부모, 자식이라는 계층 관계가 만들어집니다. 이때 부모 객체에 자식 객체를 넣어도 시스템이 문제없이 돌아가게 만드는 것을 말합니다. 즉, 범석 객체가 홍철 객체의 자식 계층일 때 범석 객체를 홍철 객체와 바꿔도 문제가 없어야 하는 것을 말합니다.</p>
<p><strong>인터페이스 분리 원칙</strong>
인터페이스 분리 원칙은 하나의 일반적인 인터페이스보다 구체적인 여러 개의 인터페이스를 만들어야 하는 원칙을 말합니다.</p>
<p><strong>의존 역전 원칙</strong>
의존 역전 원칙은 자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 원칙을 말합니다. 예를 들어 타이어를 갈아끼울 수 있는 틀을 만들어 놓은 후 다양한 타이어를 교체할 수 있어야 한다. 즉, 상위 계층은 하위 계층의 변화에 대한 구현으로부터 독립해야 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[디자인 패턴]]></title>
            <link>https://velog.io/@hwani_/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@hwani_/%EB%94%94%EC%9E%90%EC%9D%B8-%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Tue, 09 Jul 2024 15:31:11 GMT</pubDate>
            <description><![CDATA[<h2 id="디자인-패턴이란">디자인 패턴이란?</h2>
<p>프로그램을 설계할 때 발생했던 문제점들을 객체 간의 상호 관계 등을 이용하여 해결할 수 있도록 하나의 <strong>규약</strong> 형태로 만들어 놓은 것을 의미한다.</p>
<h3 id="싱글톤-패턴">싱글톤 패턴</h3>
<p>싱글톤 패턴(singleton pattern)은 하나의 클래스에 오직 하나의 인스턴스만 가지는 패턴입니다. 
하나의 클래스를 기반으로 여러 개의 개별적인 인스턴스를 만들 수 있지만 그렇게 하지 않고 
하나의 클래스를 기반으로 단 하나의 인스턴스를 만들어 
이를 기반으로 로직을 만드는데 쓰이며 보통 데이터베이스 연결모듈에 많이 사용합니다.</p>
<p><span style='color : orange'><strong>인스턴스</strong></span> : 인스턴스는 어떤 클래스나 템플릿에 기반하여 생성된 특정한 개체를 의미</p>
<pre><code class="language-java">class singleton {
    private static class singleInstanceHodler {
        private static final singleton INSTANCE = new Singleton();
    }
    public static synchronized Singleton getInstance() {
        return singleInstanceHolder.INSTANCE;
    }
}

public class HelloWorld {
    public static void main(String[] args) {
        Singleton a = Singleton.getInstance();
        Singleton b = Singleton.getInstance();
        System.out.println(a.hashCode());
        System.out.println(b.hashCode());

        if (a == b) {
            System.out.println(true);
        }
    }
}

출력
705927765
705927765
true</code></pre>
<h3 id="싱글톤-패턴의-단점">싱글톤 패턴의 단점</h3>
<ul>
<li>TDD할 때 단위 테스트를 주로 하는데, 단위 테스트는 테스트가 서로 독립적이어야 하며 테스트를 어떤 순서로든 실행할 수 있어야한다. 
하지만 싱글톤 패턴은 미리 생성된 하나의 인스턴스를 기반으로 구현하는 패턴이므로 각 테스트마다 <strong>&#39;독립적인&#39;</strong> 인스턴스를 만들기가 어렵다.</li>
</ul>
<h3 id="의존성-주입">의존성 주입</h3>
<ul>
<li>싱글톤 패턴은 사용하기가 쉽고 굉장히 실용적이지만 모듈 간의 결합을 강하게 만들 수 있다는 단점이 존재한다.</li>
<li>이때 의존성 주입 (DI, Dependency Injection)을 통해 모듈 간의 결합을 조금 더 느슨하게 만들어 해결할 수 있다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hwani_/post/777b2f02-e175-48e4-86bd-d8c843e23b5c/image.png" alt=""></p>
<h3 id="의존성-주입-장점">의존성 주입 장점</h3>
<ul>
<li>모듈을 쉽게 교체할 수 있는 구조가 되어 테스트하기 쉽다.</li>
<li>구현할 때 추상화 레이어를 넣고 이를 기반으로 구현체를 넣어 애플리케이션 의존성 방향이 일관되며, 쉽게 추론하며 모듈 간의 관계들이 조금 더 명확해진다.</li>
</ul>
<h3 id="의존성-주입-단점">의존성 주입 단점</h3>
<ul>
<li>모듈들이 더욱 더 분리되므로 클래스 수가 늘어나 복잡성이 증가, 약간의 런타임 페널티가 생길 수 있다.</li>
</ul>
<h2 id="mvc-패턴">MVC 패턴</h2>
<p>Model, View, Controller 세가지 역할로 구분하여 개발 프로세스에서 각각의 구성 요소에만 집중해서 개발하는 방법
재사용성과 확장성이 용이하다는 장점이 있고,
애플리케이션이 복잡해질수록 모델과 뷰의 관계가 복잡해지는 단점이 있다.</p>
<h3 id="모델-model">모델 (Model)</h3>
<p>모델은 애플리케이션의 데이터인 데이터베이스, 상수, 변수 등을 뜻한다.
예를 들어 사각형 모양의 박스 안에 글자가 들어 있다면 그 사각형 모양의 박스 위치 정보, 글자 내용, 글자 위치, 글자 포맷에 관한 정보를 모두 가지고 있어야 합니다.
뷰에서 데이터를 생성하거나 수정하면 컨트롤러를 통해 모델을 생성하거나 갱신합니다.</p>
<h3 id="뷰-view">뷰 (View)</h3>
<p>뷰는 inputbox, checkbox, textarea 등 사용자 인터페이스 요소를 나타냅니다.
즉, 모델을 기반으로 사용자가 볼 수 있는 화면을 뜻한다. 
모델이 가지고 있는 정보를 따로 저장하지 않아야 하며 단순히 사각형 모양 등 화면에 표시하는 정보만 가지고 있어야 합니다.
또한, 변경이 일어나면 컨트롤러에 이를 전달해야 합니다.</p>
<h3 id="컨트롤러-controller">컨트롤러 (Controller)</h3>
<p>컨트롤러는 하나 이상의 모델과 하나 이상의 뷰를 잇는 다리역할을 하며 이벤트 등 메인 로직을 담당합니다.
또한, 모델과 뷰의 생명주기도 관리하며, 모델이나 뷰의 변경 통지를 받으면 이를 해석하여 각각의 구성 요소에 해당 내용에 대해 알려줍니다.</p>
<h2 id="mvp-패턴">MVP 패턴</h2>
<p>MVP 패턴은 MVC 패턴으로부터 파생되었으며 MVC에서 C에 해당하는 컨트롤러가 프레젠터로 교체된 패턴이다.
뷰와 프레젠터는 일대일 관계이기 때문에 MVC 패턴보다 더 강한 결합을 지닌 디자인 패턴이라고 볼 수 있다.</p>
<h2 id="mvvm-패턴">MVVM 패턴</h2>
<p>MVVM 패턴은 MVC의 C에 해당하는 컨트롤러가 뷰모델(View Model)로 바뀐 패턴이다.
여기서 뷰모델은 뷰를 더 추상화한 계층이며, MVVM 패턴은 MVC 패턴과는 다르게 커맨드와 데이터 바인딩을 가지는 것이 특징이다. 뷰와 뷰모델 사이의 양방향 데이터 바인딩을 지원하며 UI를 별도의 코드 수정 없이 재사용할 수 있고 단위 테스팅하기 쉽다는 장점이 있다.</p>
<h3 id="mvvm-패턴의-예--뷰">MVVM 패턴의 예 : 뷰</h3>
<p>MVVM 패턴을 가진 대표적인 프레임워크로는 뷰(Vue.js)가 있습니다.
Vue.js는 반응형이 특징인 프런트엔드 프레임워크입니다.
예를 들어 watch와 computed 등으로 쉽게 반응형적인 값들을 구축할 수 있습니다.
함수를 사용하지 않고 값 대입만으로도 변수가 변경되며 양방향 바인딩, html을 토대로 컴포넌트를 구축할 수 있다는 점이 특징입니다. 재사용 가능한 컴포넌트 기반으로 UI를 구축할 수 있으며 BMW, 구글, 루이비통 등에서 사용합니다.</p>
<ul>
<li>데이터 바인딩 : 화면에 보이는 데이터와 웹 브라우저의 메모리 데이터를 일치시키는 기법으로, 뷰모델을 변경하면 뷰가 변경된다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[배열과 리스트]]></title>
            <link>https://velog.io/@hwani_/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</link>
            <guid>https://velog.io/@hwani_/%EB%B0%B0%EC%97%B4%EA%B3%BC-%EB%A6%AC%EC%8A%A4%ED%8A%B8</guid>
            <pubDate>Fri, 05 Jul 2024 12:31:39 GMT</pubDate>
            <description><![CDATA[<h2 id="배열">배열</h2>
<ul>
<li>연속된 데이터를 저장하는 자료구조</li>
<li>인덱스와 대응하는 데이터를 저장하며, 인덱스는 첫번째로부터 상대적인 위치를 표현</li>
<li><strong>검색(조회) 연산은 빠르지만, 추가/삭제 연산이 느리다.</strong></li>
</ul>
<h2 id="배열-생성하기">배열 생성하기</h2>
<table>
  <tr>
    <th style="text-align: center;">index</th>
    <th style="text-align: center;">0</th>
    <th style="text-align: center;">1</th>
    <th style="text-align: center;">2</th>
    <th style="text-align: center;">3</th>
    <th style="text-align: center;">4</th>
    <th style="text-align: center;">5</th>
    <th style="text-align: center;">6</th>
  </tr>
  <tr>
    <td style="text-align: center;">value</td>
    <td style="text-align: center;">월</td>
    <td style="text-align: center;">화</td>
    <td style="text-align: center;">수</td>
    <td style="text-align: center;">목</td>
    <td style="text-align: center;">금</td>
    <td style="text-align: center;">토</td>
    <td style="text-align: center;">일</td>
  </tr>
</table>

<p>위와 같은 배열을 자바에서 생성하자면</p>
<pre><code class="language-java">String[] week = {&quot;월&quot;, &quot;화&quot;, &quot;수&quot;, &quot;목&quot;, &quot;금&quot;, &quot;토&quot;, &quot;일&quot;};
System.out.println(week[0]); // 출력: 월
System.out.println(week[6]); // 출력: 일</code></pre>
<p>길이는 7 이지만 인덱스 번호는 6까지 존재한다.</p>
<h3 id="배열의-길이와-인덱스-번호가-다른-이유">배열의 길이와 인덱스 번호가 다른 이유</h3>
<p>배열의 길이는 배열이 저장할 수 있는 요소의 총 개수를 나타낸다.
인덱스 번호는 배열의 각 요소에 접근하기 위한 위치를 나타내며, 0부터 시작한다.
따라서 인덱스 번호는 0에서 시작하여 배열의 길이보다 하나 작은 값까지 존재하게 된다.</p>
<p>여기서는, 길이가 7인 배열이지만 인덱스 번호는 0부터 6까지 존재한다.
이는 배열의 첫번째 요소에 접근할 때는 인덱스 0을 사용하고, 마지막 요소에 접근할 때는 인덱스 (길이-1)을 사용한다.</p>
<h2 id="배열의-특징">배열의 특징</h2>
<p><strong>1. 고정된 크기:</strong> 배열은 생성 시 크기가 고정되며, 한 번 생성된 배열의 크기는 변경할 수 없다. 
따라서 배열의 크기를 신중하게 결정해야 한다.</p>
<p><strong>2. 연속된 메모리 공간:</strong> 배열은 연속된 메모리 공간을 차지한다. 
이러한 특성 때문에 인덱스를 이용한 접근이 매우 빠르며, 시간 복잡도가 O(1)이다.</p>
<p><strong>3. 빠른 검색:</strong> 배열은 인덱스를 통해 빠르게 요소에 접근할 수 있어 검색(조회) 연산이 빠르다.</p>
<p><strong>4. 느린 추가/삭제:</strong> 배열의 중간에 요소를 추가하거나 삭제하는 경우, 
해당 요소 이후의 모든 요소를 이동시켜야 하기 때문에 시간 복잡도가 O(n)으로 느리다.</p>
<p><strong>5. 동일한 데이터 타입:</strong> 배열은 동일한 데이터 타입의 요소들만 저장할 수 있다. 
예를 들어, 정수형 배열은 정수만, 문자열 배열은 문자열만 저장할 수 있다.</p>
<p><strong>6. 인덱스를 이용한 접근:</strong> 배열의 각 요소는 인덱스를 통해 접근할 수 있으며, 인덱스는 0부터 시작한다.</p>
<h2 id="리스트">리스트</h2>
<ul>
<li>연속적으로 데이터를 저장하는 자료구조</li>
<li>각 요소는 노드로 구성되며, 노드는 데이터와 다음 노드를 가리키는 포인터를 포함</li>
<li><strong>추가/삭제 연산이 빠르지만, 검색(조회) 연산이 느리다.</strong></li>
</ul>
<h2 id="리스트-생성하기">리스트 생성하기</h2>
<table>
  <tr>
    <th style="text-align: center;">Node</th>
    <th style="text-align: center;">1</th>
    <th style="text-align: center;">2</th>
    <th style="text-align: center;">3</th>
    <th style="text-align: center;">4</th>
  </tr>
  <tr>
    <td style="text-align: center;">Value</td>
    <td style="text-align: center;">A</td>
    <td style="text-align: center;">B</td>
    <td style="text-align: center;">C</td>
    <td style="text-align: center;">D</td>
  </tr>
</table>

<p>위와 같은 리스트를 자바에서 생성하자면</p>
<pre><code class="language-java">public class Main {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add(&quot;A&quot;);
        list.add(&quot;B&quot;);
        list.add(&quot;C&quot;);
        list.add(&quot;D&quot;);

        System.out.println(list.get[0]); // 출력: A
        System.out.println(list.get[1]); // 출력: B
        System.out.println(list.get[2]); // 출력: C
        System.out.println(list.get[3]); // 출력: D
    }
}</code></pre>
<p>리스트의 각 노드는 다음 노드를 가리키는 포인터를 가지며, 마지막 노드는 null을 가리킨다.</p>
<h2 id="리스트의-특징">리스트의 특징</h2>
<p><strong>1. 동적인 크기:</strong> 리스트는 동적으로 크기를 조절할 수 있으며, 요소를 추가할 때마다 크기가 늘어난다.</p>
<p><strong>2. 링크를 통한 연결:</strong> 리스트의 각 요소(노드)는 다음 요소를 가리키는 포인터를 포함하며, 이를 통해 연결된다.</p>
<p><strong>3. 빠른 추가/삭제:</strong> 리스트의 중간에 요소를 추가하거나 삭제하는 경우, 포인터만 수정하면 되므로 시간 복잡도가 O(1)이다. 
(요소를 찾는 과정 제외)</p>
<p><strong>4. 느린 검색:</strong> 리스트는 순차적으로 탐색해야 하므로 특정 요소에 접근하기 위해서는 시간 복잡도가 O(n)이다.</p>
<p><strong>5. 다양한 데이터 타입:</strong> 리스트는 다양한 데이터 타입의 요소를 저장할 수 있다. 각 노드가 포인터를 통해 연결되므로 데이터 타입에 구애받지 않는다.</p>
<p><strong>6. 인덱스가 없음:</strong> 리스트는 배열과 달리 인덱스를 통해 요소에 접근할 수 없으며, 노드를 순차적으로 탐색해야 한다.</p>
<h3 id="리스트의-활용">리스트의 활용</h3>
<ul>
<li>요소의 추가/삭제가 빈번하게 일어나는 경우</li>
<li>데이터의 순서가 중요하고, 순차적으로 탐색이 필요한 경우</li>
<li>메모리 공간을 효율적으로 사용하고자 하는 경우</li>
</ul>
<p>리스트는 배열에 비해 검색이 느리지만, 동적인 크기와 빠른 추가/삭제 연산 덕분에 많은 상황에서 유용하게 사용될 수 있습니다. 
이러한 특성 때문에 다양한 데이터 구조와 알고리즘에서 기본적인 구성 요소로 사용됩니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[NoSQL이란?]]></title>
            <link>https://velog.io/@hwani_/NoSQL%EC%9D%B4%EB%9E%80</link>
            <guid>https://velog.io/@hwani_/NoSQL%EC%9D%B4%EB%9E%80</guid>
            <pubDate>Thu, 04 Jul 2024 15:00:28 GMT</pubDate>
            <description><![CDATA[<h2 id="nosql이란">NoSQL이란?</h2>
<p>Not Only SQL 혹은 Non-Relational Operational DataBase의 약자로 비관계형 데이터베이스를 지칭한다.
NoSQL 데이터베이스는 전통적인 관계형 데이터베이스 관리 시스템(RDBMS)과는 달리, 
데이터 저장 및 검색에 대해 보다 유연하고 확장 가능한 접근 방식을 제공합니다.
NoSQL 데이터베이스는 다양한 데이터 모델을 지원하며, 일반적으로 스키마가 고정되지 않고 동적입니다. 
주로 빅데이터, 분산 시스템 환경에서 대용량의 데이터를 처리하는데 적합하다.</p>
<h2 id="nosql의-특징">NoSQL의 특징</h2>
<p><strong>1. RDBMS와 달리 데이터 간의 관계를 정의하지 않는다.</strong>
RDBMS는 데이터 관계를 외래키 등으로 정의하고 JOIN 연산을 수행할 수 있지만, NoSQL은 JOIN 연산이 불가능하다.</p>
<p><strong>2. RDBMS에 비해 대용량의 데이터를 저장할 수 있다.</strong>
페타바이트 급의 대용량 데이터를 저장할 수 있다.</p>
<p><strong>3. 분산형 구조이다.</strong>
여러 곳의 서버에 데이터를 분산 저장해 특정 서버에 장애가 발생했을 때도 데이터 유실 혹은 서비스 중지가 발생하지 않도록 한다.</p>
<p><strong>4. 고정되지 않은 테이블 스키마를 갖는다.</strong>
RDBMS와 달리 테이블의 스키마가 유동적이다. 
데이터를 저장하는 칼럼이 각기 다른 이름과 다른 데이터 타입을 갖는 것이 허용된다.</p>
<h2 id="nosql의-장점">NoSQL의 장점</h2>
<p><strong>1. 유연한 스키마 (Flexible Schema):</strong>
NoSQL 데이터베이스는 사전 정의된 스키마가 없으며, 데이터 구조를 쉽게 변경할 수 있습니다. 
이는 데이터가 자주 변경되거나 확장되는 환경에서 유용합니다.</p>
<p><strong>2. 수평적 확장성 (Horizontal Scalability):</strong>
NoSQL 시스템은 데이터를 여러 서버에 분산 저장하여 확장할 수 있습니다. 
이는 대규모 데이터와 트래픽을 효율적으로 처리할 수 있도록 합니다</p>
<p><strong>3. 고성능 (High Performance):</strong>
NoSQL 데이터베이스는 특정 작업에 최적화되어 있어 대규모 데이터 처리와 빠른 읽기/쓰기 성능을 제공합니다. 
예를 들어, 캐싱, 실시간 분석 등에 유리합니다.</p>
<p><strong>4.다양한 데이터 모델 (Variety of Data Models):</strong>
문서 지향, 키-값, 그래프, 열 지향 등 다양한 데이터 모델을 지원하여, 다양한 데이터 요구 사항에 맞출 수 있습니다.</p>
<p><strong>5.데이터 중복 저장 (Data Redundancy):</strong>
NoSQL 데이터베이스는 데이터를 중복 저장하여 고가용성과 데이터 복원력을 제공합니다. 
이는 시스템의 장애를 최소화하는 데 도움이 됩니다.</p>
<h2 id="nosql의-단점">NoSQL의 단점</h2>
<p><strong>1. 일관성 부족 (Lack of Consistency):</strong>
많은 NoSQL 시스템은 ACID 특성 대신 CAP 이론을 따르기 때문에, 
일관성보다는 가용성이나 파티션 허용성을 우선할 수 있습니다. 
이는 데이터 일관성이 중요한 애플리케이션에는 적합하지 않을 수 있습니다.</p>
<p><strong>2. 복잡한 쿼리 (Complex Queries):</strong>
NoSQL 데이터베이스는 전통적인 SQL의 복잡한 쿼리와 조인(join) 연산을 지원하지 않거나 제한적으로 지원합니다. 
따라서 복잡한 데이터 분석이나 트랜잭션 관리에는 어려움이 있을 수 있습니다.</p>
<p><strong>3. 제한된 커뮤니티 지원 (Limited Community Support):</strong>
NoSQL 기술은 상대적으로 신기술이기 때문에 SQL에 비해 커뮤니티와 지원 자료가 부족할 수 있습니다. 
이는 문제 해결이나 학습에 어려움을 줄 수 있습니다.</p>
<p><strong>4. 표준화 부족 (Lack of Standardization):</strong>
각 NoSQL 데이터베이스는 고유한 쿼리 언어와 관리 도구를 사용하기 때문에, 
새로운 NoSQL 시스템을 배우고 사용하는 데 시간이 걸릴 수 있습니다.</p>
<p><strong>5. 데이터 중복 (Data Duplication):</strong>
NoSQL 데이터베이스는 데이터 중복 저장을 통해 성능을 향상시키지만, 
이는 저장 공간을 더 많이 차지하고 데이터 관리가 복잡해질 수 있습니다.</p>
<h2 id="대표적인-nosql-툴">대표적인 NoSQL 툴</h2>
<ol>
<li><p>MongoDB</p>
<ul>
<li>유형 : 문서 지향 데이터베이스</li>
<li>특징 : JSON과 유사항 BSON 형식으로 데이터를 저장하며, 동적 스키마를 지원한다.
높은 확장성과 성능을 제공하며, 복잡한 쿼리와 인덱싱을 지원한다.</li>
<li>사용 : 컨텐츠 관리 시스템, 실시간 분석, 전자 상거래 플랫폼</li>
</ul>
</li>
<li><p>Cassandra</p>
<ul>
<li>유형 : 열 지향 데이터베이스</li>
<li>특징 : 대규모 데이터 분산 처리에 적합하며, 높은 가용성과 무중단성을 제공한다.
데이터가 여러 데이터 센터에 걸쳐 분산되어도 성능이 유지된다.</li>
<li>사용 : IoT 애플리케이션, 시간 시리즈 데이터 저장, 소셜 네트워크 분석</li>
</ul>
</li>
<li><p>Redis</p>
<ul>
<li>유형 : 키-값 저장소</li>
<li>특징 : 메모리 내 데이터 구조 저장소로, 빠른 읽기/쓰기 성능을 제공한다.
캐싱, 세션 저장, 실시간 분석 등에 유용하다.</li>
<li>사용 : 세션 관리, 캐싱, 메시지 브로커, 실시간 데이터 분석</li>
</ul>
</li>
<li><p>Neo4j</p>
<ul>
<li>유형 : 그래프 데이터베이스</li>
<li>특징 : 데이터간의 관계를 그래프 구조로 저장하여 복잡한 관계를 효율적으로 표현하고 쿼리 할 수 있다.</li>
<li>사용 : 소셜 네트워크 분석, 추천 시스템, 사기 탐지</li>
</ul>
</li>
<li><p>CouchDB</p>
<ul>
<li>유형 : 문서 지향 데이터베이스</li>
<li>특징 : JSON 형식으로 데이터를 저장하며, HTTP와 Restful API를 통해 데이터 접근을 지원한다.
데이터 복제를 통해 고가용성을 제공한다.</li>
<li>사용 : 웹 애플리케이션, 모바일 앱 데이터 동기화, 분산 데이터 저장소</li>
</ul>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers greedy - 큰 수 만들기]]></title>
            <link>https://velog.io/@hwani_/programmers-%ED%81%B0-%EC%88%98-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@hwani_/programmers-%ED%81%B0-%EC%88%98-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Wed, 03 Jul 2024 05:06:19 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---큰-수-만들기-span">💡 <span style="color : orange"> 문제 - 큰 수 만들기 </span></h2>
<h3 id="문제-설명">문제 설명</h3>
<p>어떤 숫자에서 k개의 수를 제거했을 때 얻을 수 있는 가장 큰 숫자를 구하려 합니다.</p>
<p>예를 들어, 숫자 1924에서 수 두 개를 제거하면 [19, 12, 14, 92, 94, 24] 를 만들 수 있습니다. 
이 중 가장 큰 숫자는 94 입니다.</p>
<p>문자열 형식으로 숫자 number와 제거할 수의 개수 k가 solution 함수의 매개변수로 주어집니다. 
number에서 k 개의 수를 제거했을 때 만들 수 있는 수 중 가장 큰 숫자를 문자열 형태로 return 하도록 solution 함수를 완성하세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>number는 2자리 이상, 1,000,000자리 이하인 숫자입니다.</li>
<li>k는 1 이상 number의 자릿수 미만인 자연수입니다.</li>
</ul>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>number</th>
<th>k</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;1924&quot;</td>
<td>2</td>
<td>&quot;94&quot;</td>
</tr>
<tr>
<td>&quot;1231234&quot;</td>
<td>3</td>
<td>&quot;3234&quot;</td>
</tr>
<tr>
<td>&quot;4177252841&quot;</td>
<td>4</td>
<td>&quot;775841&quot;</td>
</tr>
</tbody></table>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">class Solution {
    public String solution(String number, int k) {
        // 결과를 저장할 StringBuilder 객체 생성
        StringBuilder result = new StringBuilder();
        // 최종 결과 문자열의 길이 계산
        int length = number.length() - k;

        // 주어진 숫자 문자열을 문자 배열로 변환하여 순회
        for (char digit : number.toCharArray()) {
            // 조건을 만족하는 동안 반복하여 문자를 제거
            while (k &gt; 0 &amp;&amp; result.length() &gt; 0 &amp;&amp; result.charAt(result.length() - 1) &lt; digit) {
                // 마지막 문자를 제거
                result.deleteCharAt(result.length() - 1);
                // 제거할 문자 수 감소
                k--;
            }
            // 현재 문자를 결과에 추가
            result.append(digit);
        }

        // 결과 문자열의 길이를 최종 길이로 잘라서 반환
        return result.substring(0, length).toString();
    }
}</code></pre>
<h2 id="풀이-설명">풀이 설명</h2>
<p><strong>1. 문자열 순회:</strong> 주어진 숫자 문자열을 문자 배열로 변환하여 순회합니다.</p>
<p><strong>2. 스택 사용:</strong> 숫자를 저장할 스택으로 StringBuilder를 사용합니다.</p>
<p><strong>3. 문자 제거 조건:</strong> 스택의 마지막 문자와 현재 문자를 비교하여, 현재 문자가 더 크면 스택의 마지막 문자를 제거합니다.
이 과정을 제거할 문자의 수 k가 0이 될 때까지 반복합니다.</p>
<p><strong>4. 문자 추가:</strong> 현재 문자를 스택에 추가합니다.</p>
<p><strong>5. 최종 결과 문자열:</strong> 스택에 남은 문자의 길이가 목표 길이보다 길 경우 앞에서부터 필요한 길이만큼 잘라서 반환합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers greedy - 조이스틱]]></title>
            <link>https://velog.io/@hwani_/programmers-greedy-%EC%A1%B0%EC%9D%B4%EC%8A%A4%ED%8B%B1</link>
            <guid>https://velog.io/@hwani_/programmers-greedy-%EC%A1%B0%EC%9D%B4%EC%8A%A4%ED%8B%B1</guid>
            <pubDate>Sat, 29 Jun 2024 03:08:34 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---조이스틱-span">💡 <span style="color : orange"> 문제 - 조이스틱 </span></h2>
<h3 id="문제-설명">문제 설명</h3>
<p>조이스틱으로 알파벳 이름을 완성하세요. 맨 처음엔 A로만 이루어져 있습니다.
ex) 완성해야 하는 이름이 세 글자면 AAA, 네 글자면 AAAA</p>
<p>조이스틱을 각 방향으로 움직이면 아래와 같습니다.</p>
<p>▲ - 다음 알파벳
▼ - 이전 알파벳 (A에서 아래쪽으로 이동하면 Z로)
◀ - 커서를 왼쪽으로 이동 (첫 번째 위치에서 왼쪽으로 이동하면 마지막 문자에 커서)
▶ - 커서를 오른쪽으로 이동 (마지막 위치에서 오른쪽으로 이동하면 첫 번째 문자에 커서)</p>
<p>예를 들어 아래의 방법으로 &quot;JAZ&quot;를 만들 수 있습니다.</p>
<ul>
<li>첫 번째 위치에서 조이스틱을 위로 9번 조작하여 J를 완성합니다.</li>
<li>조이스틱을 왼쪽으로 1번 조작하여 커서를 마지막 문자 위치로 이동시킵니다.</li>
<li>마지막 위치에서 조이스틱을 아래로 1번 조작하여 Z를 완성합니다.
따라서 11번 이동시켜 &quot;JAZ&quot;를 만들 수 있고, 이때가 최소 이동입니다.</li>
</ul>
<p>만들고자 하는 이름 name이 매개변수로 주어질 때, 
이름에 대해 조이스틱 조작 횟수의 최솟값을 return 하도록 solution 함수를 만드세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>name은 알파벳 대문자로만 이루어져 있습니다.</li>
<li>name의 길이는 1 이상 20 이하입니다.</li>
</ul>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>name</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>&quot;JEROEN&quot;</td>
<td>56</td>
</tr>
<tr>
<td>&quot;JAN&quot;</td>
<td>23</td>
</tr>
</tbody></table>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">class Solution {
    public int solution(String name) {
        int answer = 0; // 조이스틱 조작 횟수
        int len = name.length();
        int move = name.length() - 1; // 기본 최소 좌우이동 횟수 (좌, 우 커서)

        // 해당 커서 알파벳 변경 최솟값 (위, 아래 커서)
        for (int i = 0; i &lt; len; i++) {
            answer += Math.min(name.charAt(i) - &#39;A&#39;, &#39;Z&#39; - name.charAt(i) + 1);

            // 연속된 &#39;A&#39;가 끝나는 지점 찾기
            int next = i + 1;
            while(next &lt; len &amp;&amp; name.charAt(next) == &#39;A&#39;) {
                next++;
            }

            // 좌우이동 최소 횟수 구하기 (순서대로 가기 vs 뒤로 돌아가기)
            move = Math.min(move, (i * 2) + len - next);
            move = Math.min(move, (len - next) * 2 + i);
        }   
        answer += move;

        return answer;
    }
}</code></pre>
<h2 id="풀이-설명">풀이 설명</h2>
<p><strong>1. 정렬:</strong> 주어진 문자열에서 각 문자를 &#39;A&#39;로 만드는 데 필요한 조작 횟수를 계산합니다.</p>
<p><strong>2. 알파벳 변경 최솟값 계산:</strong> 각 문자에 대해 &#39;A&#39;에서 해당 문자로 가는 최소 조작 횟수를 계산합니다.
Math.min(name.charAt(i) - &#39;A&#39;, &#39;Z&#39; - name.charAt(i) + 1)을 사용하여 위 방향과 아래 방향 이동 중 최소값을 선택합니다.</p>
<p><strong>3. 좌우 이동 최소 횟수 계산:</strong> 각 위치에서 연속된 &#39;A&#39;가 끝나는 지점을 찾습니다.
순서대로 가는 경우와 뒤로 돌아가는 경우를 모두 고려하여 최소 이동 횟수를 계산합니다.
move = Math.min(move, (i * 2) + len - next)와 
move = Math.min(move, (len - next) * 2 + i)를 사용하여 좌우 이동 최소값을 갱신합니다.</p>
<p><strong>4. 결과 계산:</strong> 최소 알파벳 변경 횟수와 최소 좌우 이동 횟수를 더하여 최종 조작 횟수를 계산합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers Greedy - 체육복]]></title>
            <link>https://velog.io/@hwani_/programmers-Greedy-%EC%B2%B4%EC%9C%A1%EB%B3%B5</link>
            <guid>https://velog.io/@hwani_/programmers-Greedy-%EC%B2%B4%EC%9C%A1%EB%B3%B5</guid>
            <pubDate>Fri, 28 Jun 2024 14:55:23 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---체육복-span">💡 <span style="color : orange"> 문제 - 체육복 </span></h2>
<h2 id="greedy탐욕-알고리즘이란">Greedy(탐욕) 알고리즘이란?</h2>
<p>Greedy의 뜻은 &#39;탐욕스러운&#39; 이라는 뜻이다.
그리디 알고리즘은 탐욕이란 뜻처럼 <span style="color : yellow"><strong>현재 상황에서 최적의 해</strong></span>만을 찾아야한다.
탐욕 알고리즘은 특정한 조건을 만족하는 문제들에 대해 매우 효율적이고 간단한 해결책을 제공한다.</p>
<h3 id="탐욕-알고리즘의-기본-원리">탐욕 알고리즘의 기본 원리</h3>
<p><strong>1. 선택 단계 :</strong> 현재 상태에서 최적이라고 판단되는 선택을 한다.
<strong>2. 검증 단계 :</strong> 현재 선택이 문제의 제약 조건을 만족하는지 확인한다.
<strong>3. 결정 단계 :</strong> 선택이 최종 해결책의 일부가 되는지 결정한다.
<strong>4. 반복 :</strong> 위의 단계를 반복해서 문제를 해결한다.</p>
<h3 id="탐욕-알고리즘의-문제-예시">탐욕 알고리즘의 문제 예시</h3>
<p>체육복, 거스름돈, 노드의 최소 신장 트리(MST)</p>
<h3 id="탐욕-알고리즘의-한계">탐욕 알고리즘의 한계</h3>
<p>탐욕 알고리즘은 항상 최적의 해를 보장하진 않고 <span style="color : yellow"><strong>현재 상황에서 최적의 해</strong></span>를 구한다.
이럴 경우, 동적 계획법이나 백트래킹 같은 다른 알고리즘을 사용해야한다.</p>
<h3 id="문제-설명">문제 설명</h3>
<p>점심시간에 도둑이 들어, 일부 학생이 체육복을 도난당했습니다. 
다행히 여벌 체육복이 있는 학생이 이들에게 체육복을 빌려주려 합니다. 
학생들의 번호는 체격 순으로 매겨져 있어, 바로 앞번호의 학생이나 바로 뒷번호의 학생에게만 체육복을 빌려줄 수 있습니다. 
예를 들어, 4번 학생은 3번 학생이나 5번 학생에게만 체육복을 빌려줄 수 있습니다. 
체육복이 없으면 수업을 들을 수 없기 때문에 체육복을 적절히 빌려 최대한 많은 학생이 체육수업을 들어야 합니다.</p>
<p>전체 학생의 수 n, 체육복을 도난당한 학생들의 번호가 담긴 배열 lost, 
여벌의 체육복을 가져온 학생들의 번호가 담긴 배열 reserve가 매개변수로 주어질 때, 
체육수업을 들을 수 있는 학생의 최댓값을 return 하도록 solution 함수를 작성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<ul>
<li>전체 학생의 수는 2명 이상 30명 이하입니다.</li>
<li>체육복을 도난당한 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.</li>
<li>여벌의 체육복을 가져온 학생의 수는 1명 이상 n명 이하이고 중복되는 번호는 없습니다.</li>
<li>여벌 체육복이 있는 학생만 다른 학생에게 체육복을 빌려줄 수 있습니다.</li>
<li>여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있습니다. 
이때 이 학생은 체육복을 하나만 도난당했다고 가정하며, 
남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없습니다.</li>
</ul>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>n</th>
<th>lost</th>
<th>reserve</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>5</td>
<td>[2, 4]</td>
<td>[1, 3, 5]</td>
<td>5</td>
</tr>
<tr>
<td>5</td>
<td>[2, 4]</td>
<td>[3]</td>
<td>4</td>
</tr>
<tr>
<td>3</td>
<td>[3]</td>
<td>[1]</td>
<td>2</td>
</tr>
</tbody></table>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>예제 #1
1번 학생이 2번 학생에게 체육복을 빌려주고, 3번 학생이나 5번 학생이 4번 학생에게 체육복을 빌려주면 학생 5명이 체육수업을 들을 수 있습니다.</p>
<p>예제 #2
3번 학생이 2번 학생이나 4번 학생에게 체육복을 빌려주면 학생 4명이 체육수업을 들을 수 있습니다.</p>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">import java.util.*;

class Solution {
    public int solution(int n, int[] lost, int[] reserve) {
        // 배열 정렬
        Arrays.sort(lost);
        Arrays.sort(reserve);

        // 체육복을 도난당한 학생들 중 여벌 체육복을 가진 학생 제거
        List&lt;Integer&gt; realLost = new ArrayList&lt;&gt;();
        List&lt;Integer&gt; realReserve = new ArrayList&lt;&gt;();

        // lost 배열과 reserve 배열의 중복을 제거
        for (int l : lost) {
            boolean hasReserve = false;
            for (int r : reserve) {
                if (l == r) {
                    hasReserve = true;
                    break;
                }
            }
            if (!hasReserve) {
                realLost.add(l);
            }
        }

        // reserve 배열의 학생이 실제로 여벌 체육복을 가진 경우
        for (int r : reserve) {
            if (!realLost.contains(r)) {
                realReserve.add(r);
            }
        }

        // 여벌 체육복을 다른 학생에게 빌려주는 경우 처리
        for (int r : realReserve) {
            if (realLost.contains(r - 1)) {
                realLost.remove((Integer) (r - 1));
            } else if (realLost.contains(r + 1)) {
                realLost.remove((Integer) (r + 1));
            }
        }

        // 체육복을 입을 수 있는 학생 수를 계산
        int answer = n - realLost.size();
        return answer;
    }
}</code></pre>
<h2 id="풀이-설명">풀이 설명</h2>
<p>문제는 n명의 학생 중 lost는 체육복을 잃어버린 학생이고,
다른 배열 reserve는 여분의 체육복을 가지고 있는 학생이다.
체육복을 잃어버린 학생의 앞번호,뒷번호의 학생에게만 체육복을 빌릴 수 있다.
가능한 최대한 많은 학생에게 빌려줄 수 있는 방법을 찾아야한다.</p>
<p><strong>1. 정렬 :</strong> 문제에 <strong>(학생들의 번호는 체격 순으로 매겨져 있어)</strong> 를 참고해 정렬해서 풀어야 하는 문제임을 알 수 있다.
<strong>2. 중복 제거 :</strong> 체육복을 잃어버렸지만 여분의 체육복을 가지고 있는 학생을 제거해 잃어버린 학생과 여분의 체육복이 있는 학생을 정확히 구분한다.
<strong>3. 빌려줄 수 있는지 확인 :</strong> 빌려줄 수 있는지 조건문을 작성해 처리한다.
<strong>4. 학생 수 계산 :</strong> n - realLost.size()로 학생 수를 계산한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers 정렬 - H-Index]]></title>
            <link>https://velog.io/@hwani_/programmers-%EC%A0%95%EB%A0%AC-H-Index</link>
            <guid>https://velog.io/@hwani_/programmers-%EC%A0%95%EB%A0%AC-H-Index</guid>
            <pubDate>Thu, 27 Jun 2024 07:50:55 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---h-index-span">💡 <span style="color : orange"> 문제 - H-Index </span></h2>
<h3 id="문제-설명">문제 설명</h3>
<p>H-Index는 과학자의 생산성과 영향력을 나타내는 지표입니다. 어느 과학자의 H-Index를 나타내는 값인 h를 구하려고 합니다. 
위키백과1에 따르면, H-Index는 다음과 같이 구합니다.</p>
<p>어떤 과학자가 발표한 논문 n편 중, h번 이상 인용된 논문이 h편 이상이고 나머지 논문이 h번 이하 인용되었다면 h의 최댓값이 이 과학자의 H-Index입니다.</p>
<p>어떤 과학자가 발표한 논문의 인용 횟수를 담은 배열 citations가 매개변수로 주어질 때, 
이 과학자의 H-Index를 return 하도록 solution 함수를 작성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<p>과학자가 발표한 논문의 수는 1편 이상 1,000편 이하입니다.
논문별 인용 횟수는 0회 이상 10,000회 이하입니다.</p>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>citations</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>[3, 0, 6, 1, 5]</td>
<td>3</td>
</tr>
</tbody></table>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>이 과학자가 발표한 논문의 수는 5편이고, 그중 3편의 논문은 3회 이상 인용되었습니다.
그리고 나머지 2편의 논문은 3회 이하 인용되었기 때문에 이 과학자의 H-Index는 3입니다.</p>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">import java.util.Arrays;

class Solution {
    public int solution(int[] citations) {
        int answer = 0;

        Arrays.sort(citations);

        for(int i = 0; i &lt; citations.length; i++) {
            int h = citations.length - i; // 인용된 논문의 수

            if(citations[i] &gt;= h) {
                answer = h;
                break;
            }
        }

        return answer;
    }
}</code></pre>
<h2 id="풀이-설명">풀이 설명</h2>
<p>H-Index는 특정 과학자의 논문이 얼마나 자주 인용되었는지 나타내는 지표이다.
H-Index를 계산하기 위해서 다음 조건을 만족하는 최대 h값을 찾아야한다.</p>
<ul>
<li>h번 이상 인용된 논문이 h편 이상</li>
<li>나머지 논문은 h번 이하 인용됨.</li>
</ul>
<ol>
<li>** 정렬 :** 주어진 배열 citations을 정렬한다.</li>
<li>** H-Index 계산:** 정렬된 배열을 for문으로 순회하며 각 논문이 몇 번 인용되었는지 남은 논문의 개수를 비교</li>
</ol>
<ul>
<li>h는 배열의 길이에서 현재 인덱스를 뺀 값, 즉 현재 인덱스 이후에 남은 논문의 개수를 나타낸다.</li>
<li>citations[i]가 h 보다 크면, h가 H-Index의 조건을 만족</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers 정렬 - 가장 큰 수]]></title>
            <link>https://velog.io/@hwani_/programmers-%EC%A0%95%EB%A0%AC-%EA%B0%80%EC%9E%A5-%ED%81%B0-%EC%88%98</link>
            <guid>https://velog.io/@hwani_/programmers-%EC%A0%95%EB%A0%AC-%EA%B0%80%EC%9E%A5-%ED%81%B0-%EC%88%98</guid>
            <pubDate>Wed, 26 Jun 2024 14:47:49 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---가장-큰-수-span">💡 <span style="color : orange"> 문제 - 가장 큰 수 </span></h2>
<h3 id="문제-설명">문제 설명</h3>
<p>0 또는 양의 정수가 주어졌을 때, 정수를 이어 붙여 만들 수 있는 가장 큰 수를 알아내 주세요.</p>
<p>예를 들어, 주어진 정수가 [6, 10, 2]라면 [6102, 6210, 1062, 1026, 2610, 2106]를 만들 수 있고, 이중 가장 큰 수는 6210입니다.</p>
<p>0 또는 양의 정수가 담긴 배열 numbers가 매개변수로 주어질 때, 순서를 재배치하여 만들 수 있는 가장 큰 수를 문자열로 바꾸어 return 하도록 solution 함수를 작성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<p>numbers의 길이는 1 이상 100,000 이하입니다.
numbers의 원소는 0 이상 1,000 이하입니다.
정답이 너무 클 수 있으니 문자열로 바꾸어 return 합니다.</p>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>numbers</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>[6, 10, 2]</td>
<td>&quot;6210&quot;</td>
</tr>
<tr>
<td>[3, 30, 34, 5, 9]</td>
<td>&quot;9534330&quot;</td>
</tr>
</tbody></table>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">import java.util.Arrays;

class Solution {
    public String solution(int[] numbers) {
        // 숫자를 문자열로 변환하여 저장할 배열 생성
        String[] arr = new String[numbers.length];

        // 배열의 각 정수를 문자열로 변환
        for (int i = 0; i &lt; numbers.length; i++) {
            arr[i] = String.valueOf(numbers[i]);
        }

        // 두 문자열을 연결했을 때 더 큰 숫자를 만든다.
        Arrays.sort(arr, (o1, o2) -&gt; (o2 + o1).compareTo(o1 + o2));

        // 만약 가장 큰 숫자가 0 이라면 0을 리턴
        if (arr[0].equals(&quot;0&quot;)) {
            return &quot;0&quot;;
        }

        // StringBuilder 생성
        StringBuilder answer = new StringBuilder();

        // 정렬된 문자열 배열을 순회하며 StringBuilder에 추가
        for (int i = 0; i &lt; arr.length; i++) {
            answer.append(arr[i]);
        }

        // StringBuilder에 저장된 문자열 변환
        return answer.toString();
    }
}</code></pre>
<h2 id="풀이-설명">풀이 설명</h2>
<p>배열 내의 숫자들을 재배열하여 만들 수 있는 가장 큰 숫자를 문자열 형태로 반환하는 문제</p>
<ol>
<li><p><strong>문자열 변환 :</strong> 배열에 있는 각 숫자를 문자열로 변환, 숫자들을 조합할 때, 문자열 연산을 통해 쉽게 비교하고 정렬하기 위해서이다.</p>
</li>
<li><p><strong>정렬 기준 설정 :</strong> 숫자들을 문자열로 변환 후, 두 문자열 &#39;o1&#39;과 &#39;o2&#39;를 이어붙였을 때 더 큰 값을 형성하는 순서대로 정렬한다.
즉, &#39;o2 + o1;이 &#39;o1 + o2&#39;보다 크면 &#39;o2&#39;가 &#39;o1&#39;보다 앞에 오도록 한다.
이 비교 기준은 두 문자열을 합쳤을 때 더 큰 숫자를 정렬한다.</p>
</li>
<li><p><strong>결과 :</strong> 정렬된 문자열 배열을 순회하며, &#39;StringBuilder&#39; 를 사용하여 최종 문자열을 만든다.</p>
</li>
<li><p><strong>0 값 처리 :</strong> 모든 숫자가 0인 경우는 정렬 후 첫 번째 문자열이 &quot;0&quot;인지 확인 후 맞다면 &quot;0&quot;을 리턴한다.</p>
</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers 정렬 - K번째수]]></title>
            <link>https://velog.io/@hwani_/programmers-%EC%A0%95%EB%A0%AC-K%EB%B2%88%EC%A7%B8%EC%88%98</link>
            <guid>https://velog.io/@hwani_/programmers-%EC%A0%95%EB%A0%AC-K%EB%B2%88%EC%A7%B8%EC%88%98</guid>
            <pubDate>Wed, 26 Jun 2024 14:38:22 GMT</pubDate>
            <description><![CDATA[<h2 id="💡-span-stylecolor--orange-문제---k번째수-span">💡 <span style="color : orange"> 문제 - K번째수 </span></h2>
<h3 id="문제-설명">문제 설명</h3>
<p>배열 array의 i번째 숫자부터 j번째 숫자까지 자르고 정렬했을 때, k번째에 있는 수를 구하려 합니다.</p>
<p>예를 들어 array가 [1, 5, 2, 6, 3, 7, 4], i = 2, j = 5, k = 3이라면</p>
<p>array의 2번째부터 5번째까지 자르면 [5, 2, 6, 3]입니다.
1에서 나온 배열을 정렬하면 [2, 3, 5, 6]입니다.
2에서 나온 배열의 3번째 숫자는 5입니다.
배열 array, [i, j, k]를 원소로 가진 2차원 배열 commands가 매개변수로 주어질 때, commands의 모든 원소에 대해 앞서 설명한 연산을 적용했을 때 나온 결과를 배열에 담아 return 하도록 solution 함수를 작성해주세요.</p>
<h3 id="제한사항">제한사항</h3>
<p>array의 길이는 1 이상 100 이하입니다.
array의 각 원소는 1 이상 100 이하입니다.
commands의 길이는 1 이상 50 이하입니다.
commands의 각 원소는 길이가 3입니다.</p>
<h3 id="입출력-예">입출력 예</h3>
<table>
<thead>
<tr>
<th>array</th>
<th>commands</th>
<th>return</th>
</tr>
</thead>
<tbody><tr>
<td>[1, 5, 2, 6, 3, 7, 4]</td>
<td>[2, 5, 3]</td>
<td>5</td>
</tr>
<tr>
<td></td>
<td>[4, 4, 1]</td>
<td>6</td>
</tr>
<tr>
<td></td>
<td>[1, 7, 3]</td>
<td>3</td>
</tr>
</tbody></table>
<h3 id="입출력-예-설명">입출력 예 설명</h3>
<p>[1, 5, 2, 6, 3, 7, 4]를 2번째부터 5번째까지 자른 후 정렬합니다. [2, 3, 5, 6]의 세 번째 숫자는 5입니다.
[1, 5, 2, 6, 3, 7, 4]를 4번째부터 4번째까지 자른 후 정렬합니다. [6]의 첫 번째 숫자는 6입니다.
[1, 5, 2, 6, 3, 7, 4]를 1번째부터 7번째까지 자릅니다. [1, 2, 3, 4, 5, 6, 7]의 세 번째 숫자는 3입니다.</p>
<h2 id="💡-span-stylecolor--orange-풀이-span">💡 <span style="color : orange"> 풀이 </span></h2>
<pre><code class="language-java">import java.util.*;

class Solution {
    public int[] solution(int[] array, int[][] commands) {
        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();

        for (int i = 0; i &lt; commands.length; i++) {
            // i,j,k 를 a,b,k로 변수 설정
            int a = commands[i][0]-1;
            int b = commands[i][1];
            int k = commands[i][2];

            // a~b까지 새로운 배열에 복사
            int[] subArray = Arrays.copyOfRange(array, a, b);

            // 배열을 정렬
            Arrays.sort(subArray);

            // 배열의 k 번째 숫자 list에 추가
            list.add(subArray[k-1]);
        }

        int[] answer = new int[list.size()];
        for (int i = 0; i &lt; list.size(); i++) {
            answer[i] = list.get(i);
        }
        return answer;
    }
}</code></pre>
<h2 id="풀이-설명">풀이 설명</h2>
<p>세 가지 수 i,j,k 에 대해서 매개변수 배열에서 i번부터 j까지 값을 구한 뒤 각각의 k번째의 값을 배열에 담는 문제</p>
<p><strong>1. 부분 배열 추출 :</strong> 주어진 i와 j를 사용해 원본 배열 array에서 필요한 부분을 추출한다.
배열의 인덱스는 0부터 시작하니까 i-1로 계산한다.</p>
<p><strong>2. 배열 정렬 :</strong> 추출된 부분 배열을 정렬해서 요소들이 순서대로 정렬한다.</p>
<p><strong>3. 결과 :</strong> 정렬된 배열에서 k번째 요소를 추출해서 list에 담아준다.
마찬가지로 배열 인덱스는 0부터 시작하니까 k-1로 계산한다.</p>
<p><strong>4. 결과 리턴:</strong> list에 담긴 값을 배열로 변환하여 리턴한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[programmers 기초 Day25]]></title>
            <link>https://velog.io/@hwani_/programmers-%EA%B8%B0%EC%B4%88-Day25</link>
            <guid>https://velog.io/@hwani_/programmers-%EA%B8%B0%EC%B4%88-Day25</guid>
            <pubDate>Tue, 25 Jun 2024 16:24:57 GMT</pubDate>
            <description><![CDATA[<h2 id="문제---정수를-나선형으로-배치하기">문제 - 정수를 나선형으로 배치하기</h2>
<p><img src="https://velog.velcdn.com/images/hwani_/post/d90f34c3-453e-4f5f-9a38-f44aba79305b/image.png" alt=""></p>
<h2 id="풀이">풀이</h2>
<pre><code class="language-java">class Solution {
    public int[][] solution(int n) {
        int[][] answer = new int[n][n];
        int value = 1; // 채워야 할 정수 값
        int row = 0; // 현재 행 위치
        int col = 0; // 현재 열 위치
        int direction = 0; // 이동 방향 (0: 오른쪽, 1: 아래, 2: 왼쪽, 3: 위)

        while (value &lt;= n * n) { // 모든 정수 값을 배열에 채우면 종료
            answer[row][col] = value++; // 현재 위치에 값을 채우고 다음 값으로 이동

            // 다음 이동할 위치 계산
            if (direction == 0) { // 오른쪽 방향으로 이동
                if (col == n - 1 || answer[row][col + 1] != 0) {
                    direction = 1;
                    row++;
                } else {
                    col++;
                }
            } else if (direction == 1) { // 아래쪽 방향으로 이동
                if (row == n - 1 || answer[row + 1][col] != 0) {
                    direction = 2;
                    col--;
                } else {
                    row++;
                }
            } else if (direction == 2) { // 왼쪽 방향으로 이동
                if (col == 0 || answer[row][col - 1] != 0) {
                    direction = 3;
                    row--;
                } else {
                    col--;
                }
            } else if (direction == 3) { // 위쪽 방향으로 이동
                if (row == 0 || answer[row - 1][col] != 0) {
                    direction = 0;
                    col++;
                } else {
                    row--;
                }
            }
        }

        return answer;
    }
}
</code></pre>
<h3 id="설명">설명</h3>
<h2 id="문제---특별한-이차원-배열-2">문제 - 특별한 이차원 배열 2</h2>
<p><img src="https://velog.velcdn.com/images/hwani_/post/8689d4c1-2916-48cf-ace4-cf093b61c151/image.png" alt=""></p>
<h2 id="풀이-1">풀이</h2>
<pre><code class="language-java">class Solution {
    public int solution(int[][] arr) {
        int n = arr.length;

        for (int i = 0; i &lt; n; i++) {
            for (int j = 0; j &lt; n; j++) {
                if (arr[i][j] != arr[j][i]) {
                    return 0;
                }
            }
        }

        return 1; 
    }
}</code></pre>
<h3 id="설명-1">설명</h3>
<h2 id="문제---정사각형으로-만들기">문제 - 정사각형으로 만들기</h2>
<p><img src="https://velog.velcdn.com/images/hwani_/post/69143417-1d43-44ff-8715-b35a7a860e87/image.png" alt=""></p>
<h2 id="풀이-2">풀이</h2>
<pre><code class="language-java">class Solution {
    public int[][] solution(int[][] arr) {
        int rows = arr.length;
        int cols = arr[0].length;

        if (rows &gt; cols) {
            // 행이 더 많을 경우
            int[][] answer = new int[rows][rows];
            for (int i = 0; i &lt; rows; i++) {
                for (int j = 0; j &lt; rows; j++) {
                    if (j &lt; cols) {
                        answer[i][j] = arr[i][j];
                    } else {
                        answer[i][j] = 0;
                    }
                }
            }
            return answer;
        } else if (cols &gt; rows) {
            // 열이 더 많을 경우
            int[][] answer = new int[cols][cols];
            for (int i = 0; i &lt; cols; i++) {
                for (int j = 0; j &lt; cols; j++) {
                    if (i &lt; rows) {
                        answer[i][j] = arr[i][j];
                    } else {
                        answer[i][j] = 0;
                    }
                }
            }
            return answer;
        } else {
            // 행과 열이 같을 경우
            return arr;
        }
    }
}</code></pre>
<h3 id="설명-2">설명</h3>
<h2 id="문제---이차원-배열-대각선-순회하기">문제 - 이차원 배열 대각선 순회하기</h2>
<p><img src="https://velog.velcdn.com/images/hwani_/post/adb1af63-2123-4fc3-afc4-1637e407624a/image.png" alt=""></p>
<h2 id="풀이-3">풀이</h2>
<pre><code class="language-java">class Solution {
    public int solution(int[][] board, int k) {
        int answer = 0;
        for(int i =0; i&lt;board.length; i++){
            for(int j=0; j&lt;board[0].length; j++) {
                if(i+j &lt;= k) {
                    answer += board[i][j];
                }
            }
        }
        return answer;
    }
}</code></pre>
<h3 id="설명-3">설명</h3>
]]></description>
        </item>
        <item>
            <title><![CDATA[WebSocket을 이용한 실시간 알림]]></title>
            <link>https://velog.io/@hwani_/WebSocket%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EC%95%8C%EB%A6%BC</link>
            <guid>https://velog.io/@hwani_/WebSocket%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EC%8B%A4%EC%8B%9C%EA%B0%84-%EC%95%8C%EB%A6%BC</guid>
            <pubDate>Tue, 25 Jun 2024 08:22:39 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>시작하며</p>
</blockquote>
<p>프로젝트 진행하며 WebSocke을 이용한 실시간 알림 기능을 만들어보고 싶었다.
찾아보니 생각보다 간단한? 기능인것 같아서 다행이지만 진행하면서 얼마나 삽질할지..</p>
<h4 id="시나리오">시나리오</h4>
<ol>
<li>B가 A가 등록한 플레이리스트에 좋아요 또는 댓글을 남긴다.</li>
<li>그러면 A에게 실시간 알림으로 B가 어느 글에 좋아요를 눌렀습니다. 알림을 보낸다.</li>
</ol>
<p>말은 간단하지만 직접 해보며 진행할 예정이다.</p>
<h3 id="세팅">세팅</h3>
<pre><code class="language-java">build.gradle
implementation &#39;org.springframework.boot:spring-boot-starter-websocket&#39;</code></pre>
<p>websocket 의존성 주입을한다.</p>
<pre><code class="language-java">@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker(&quot;/topic&quot;);  // 클라이언트가 구독하는 목적지 prefix
        config.setApplicationDestinationPrefixes(&quot;/app&quot;);  // 클라이언트가 메시지를 보낼 때 사용하는 prefix
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint(&quot;/ws&quot;).withSockJS();  // SockJS 폴백을 사용한 STOMP 엔드포인트
    }

    @Override
    public boolean configureMessageConverters(List&lt;MessageConverter&gt; messageConverters) {
        MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        converter.setObjectMapper(objectMapper);
        messageConverters.add(converter);
        return false;
    }
}</code></pre>
<p>** WebSocket 엔드포인트 등록:**</p>
<p>/ws 엔드포인트를 통해 클라이언트가 WebSocket 연결을 맺을 수 있습니다. 이 엔드포인트는 SockJS 폴백을 지원합니다.</p>
<p>** 메시지 브로커 구성:**</p>
<p>클라이언트는 /topic 경로로 메시지를 구독할 수 있습니다. 예를 들어, 클라이언트가 /topic/notifications를 구독하면, 서버에서 이 경로로 발행된 메시지를 받을 수 있습니다.
클라이언트는 /app 경로로 메시지를 보낼 수 있습니다. 서버 측에서 이 경로로 들어오는 메시지를 처리할 메서드는 @MessageMapping 어노테이션을 사용하여 정의합니다.</p>
<p>** 메시지 변환기 설정:**</p>
<p>메시지를 JSON 형식으로 변환하기 위해 MappingJackson2MessageConverter를 사용합니다. 이를 통해 객체를 JSON으로 직렬화하고, JSON을 객체로 역직렬화할 수 있습니다.</p>
<h2 id="로직">로직</h2>
<p>실시간 알림 로직은 댓글/좋아요를 했을 때 플레이리스트를 등록한 사람에게 알림이 가는 로직이다.</p>
<ol>
<li>댓글/좋아요 등록</li>
<li>플레이리스트 등록한 사람에게 알림 전송</li>
</ol>
<p>그래서 기존의 댓글과 좋아요를 저장 후 알림을 전송하기 위해 기존의 CommentService 파일에 로직을 추가한다.</p>
<pre><code class="language-java">public void saveComment(CommentRequest commentRequest, String playlistId, User loginUser) {
        // PlaylistService를 사용하여 Playlist 엔터티 가져오기
        Playlist playlist = playlistService.findById(Long.valueOf(playlistId));

        // Comments 엔터티 빌더를 사용하여 생성
        Comments comment = Comments.builder()
                .comments(commentRequest.getComment())
                .user(loginUser)
                .playlist(playlist)
                .build();

        commentRepository.save(comment);

        Notification notification = Notification.builder()
                .userId(loginUser.getId()) // 게시글 작성자 ID
                .username(loginUser.getUsername())
                .message(loginUser.getUsername() + &quot;님이 &#39;&quot; + playlist.getTitle() + &quot;&#39; 플레이리스트에 댓글을 달았습니다: &quot; + commentRequest.getComment())
                .type(&quot;comment&quot;)
                .read(false)
                .timestamp(LocalDateTime.now())
                .build();

        notificationService.saveNotification(notification);

        // 실시간 알림 전송
        String destination = &quot;/topic/notifications/&quot; + loginUser.getUsername();
        messagingTemplate.convertAndSend(destination, notification);
    }</code></pre>
<p>기존의 댓글 등록 로직 이후</p>
<ol>
<li>Notification 엔터티를 빌더 패턴을 사용하여 생성합니다.</li>
<li>loginUser의 ID와 사용자명을 각각 userId와 username 필드에 설정합니다.</li>
<li>알림 메시지를 생성하여 message 필드에 설정합니다. <strong>( 화면에 보일 message 설정 )</strong></li>
<li>알림의 타입을 &quot;comment&quot;로 설정합니다. 좋아요는 &quot;like&quot;로 설정!</li>
<li>알림이 읽히지 않은 상태(false)로 설정합니다.</li>
<li>알림 생성 시점을 timestamp 필드에 설정합니다.</li>
<li>notificationService의 saveNotification 메서드를 통해 DB에 저장합니다.</li>
<li>실시간 알림을 전송할 대상 경로를 설정합니다. 여기서는 /topic/notifications/ 경로 뒤에 loginUser의 사용자명을 붙여 알림을 보낼 경로를 결정합니다.</li>
<li>messagingTemplate를 사용하여 설정한 경로로 notification 객체를 전송합니다.</li>
</ol>
<p>이러면 백엔드 로직은 끝이나고 이제 화면에 표현해야한다.</p>
<h3 id="mainhtml">main.html</h3>
<pre><code class="language-java">&lt;script src=&quot;https://cdn.jsdelivr.net/sockjs/1/sockjs.min.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js&quot;&gt;&lt;/script&gt;
&lt;script th:inline=&quot;javascript&quot;&gt;
        var userId = /*[[${userId}]]*/ &#39;dummyUserId&#39;; // Thymeleaf 변수를 JavaScript 변수로 설정
&lt;/script&gt;</code></pre>
<p>실시간 통신을 위한 라이브러리 Sockjs와 stomp.js 를 추가한다.
추가적으로 js에서 변수를 동작해야하기 때문에 Thymeleaf 의 변수를 JavaScript 변수로 설정한다. ( 그래야 js 파일에서 인식을 해서 정상적으로 기능이 작동한다. )</p>
<h3 id="notificationjs">Notification.js</h3>
<pre><code class="language-javascript">$(document).ready(function() {
    // 웹소켓 연결 설정
    const socket = new SockJS(&#39;/ws&#39;);
    const stompClient = Stomp.over(socket);

    stompClient.connect({}, function(frame) {
        // 사용자 ID에 따라 알림을 구독
        const userId = window.userId;

        stompClient.subscribe(&#39;/topic/notifications/&#39; + userId, function(notification) {
            console.log(&quot;Notification received:&quot;, notification);
            const parsedNotification = JSON.parse(notification.body);
            const message = `${parsedNotification.username}님이 &#39;${parsedNotification.message}&#39;`;
            showNotification(parsedNotification);
        });
    });

    function showNotification(notification) {
        const notificationContent = $(&#39;#notificationContent&#39;);
        const timeAgo = new Date(notification.timestamp).toLocaleString();
        const message = `${notification.message}`;

        const notificationItem = `
            &lt;div class=&quot;notification-item&quot;&gt;
                &lt;img src=&quot;/static/images/${notification.type === &#39;comment&#39; ? &#39;comment_icon.png&#39; : &#39;red_heart.png&#39;}&quot; alt=&quot;profile&quot;&gt;
                &lt;span&gt;${message}&lt;/span&gt;
                &lt;span class=&quot;time&quot;&gt;${timeAgo}&lt;/span&gt;
            &lt;/div&gt;
        `;

        notificationContent.prepend(notificationItem);
    }
});</code></pre>
<p>이렇게 하면 알림이 전송됐을 경우 기존의 div class = &quot;notification-item&quot;의 화면이 알림의 내용이 보여지면서 사용자에게 보여지게 된다.</p>
<h3 id="구현-영상">구현 영상</h3>
<p><img src="https://velog.velcdn.com/images/hwani_/post/470ffc5d-f92d-45a3-b47d-50864047307c/image.gif" alt=""></p>
<blockquote>
<p>마치며</p>
</blockquote>
<p>실시간 알림 기능을 구현하면서 좀 간단해 보였지만 진행하면서 게시판의 댓글을 불러올 때 left join을 사용해서 불러오는데 댓글이 중복해서 불러오는 오류가 생겨서 그 과정을 또 해결하고 백엔드단에선 Message가 정상적으로 출력이되는데 화면단에 보여지지 않아서 좀 애를 먹었지만 그래도 빠르게 기능을 완성해서 다행이다.
새로운 기능을 추가할 때 이런저런 과정의 어려움을 겪지만 기능을 완성을 하면 너무 뿌듯하다!</p>
]]></description>
        </item>
    </channel>
</rss>