<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>heejae-l.log</title>
        <link>https://velog.io/</link>
        <description>그냥 하는 사람 @Heejae-L</description>
        <lastBuildDate>Sun, 06 Apr 2025 13:53:38 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>heejae-l.log</title>
            <url>https://velog.velcdn.com/images/heejae-l/profile/eb77fdaa-8d72-492e-adc9-9885a6ca0044/social_profile.png</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. heejae-l.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/heejae-l" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[프로그래머스] 체육복 문제]]></title>
            <link>https://velog.io/@heejae-l/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%B2%B4%EC%9C%A1%EB%B3%B5-%EB%AC%B8%EC%A0%9C</link>
            <guid>https://velog.io/@heejae-l/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%B2%B4%EC%9C%A1%EB%B3%B5-%EB%AC%B8%EC%A0%9C</guid>
            <pubDate>Sun, 06 Apr 2025 13:53:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/heejae-l/post/a11b7c85-be14-4f04-a8f9-56f81b015b1d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/cd0e0c60-931e-4edc-a804-85a0864d17e3/image.png" alt=""></p>
<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/42862">https://school.programmers.co.kr/learn/courses/30/lessons/42862</a>!
<a href="https://velog.velcdn.com/images/heejae-l/post/463ef207-f068-4431-a40b-4093c9d7d4a2/image.png"></a></p>
<p>탐욕법 문제로, 여분의 체육복을 가져온 학생이 체육복을 잃어버린 학생에게 빌려줘서 최대한 많은 학생이 체육수업에 참여할 수 있도록 하는 문제입니다.</p>
<h2 id="문제-정의">문제 정의</h2>
<p><strong>lost 배열</strong>: 체육복이 없는 학생 리스트
<strong>reserve 배열</strong> : 여벌의 체육복이 있는 학생 리스트
<strong>n</strong> : 전체 학생 수
<strong>결과</strong> : 체육 수업을 들을 수 있는 학생 수</p>
<p>*<em>제약조건: *</em></p>
<ol>
<li>체육복은 자신의 앞 또는 뒤 학생에게만 빌려줄 수 있다. </li>
<li>여벌 체육복을 가져온 학생이 체육복을 도난당했을 수 있지만, 이 학생은 체육복을 하나만 도난당했다고 가정하며, 남은 체육복이 하나이기에 다른 학생에게는 체육복을 빌려줄 수 없다.</li>
</ol>
<p>-&gt; 즉, lost와 reserve배열에 동일한 학생이 존재할 수 있지만, 이 학생은 다른 체육복을 빌릴 수도, 자신의 여분을 빌려줄 수도 없다는 의미입니다.</p>
<hr>
<h2 id="첫-번째-시도">첫 번째 시도</h2>
<h3 id="알고리즘">알고리즘</h3>
<p>lost를 순서대로 순회하면서 현재 학생의 앞 뒤 학생이 reserve에 있는지 확인하자!</p>
<p>위의 알고리즘을 C++로 작성했습니다</p>
<pre><code class="language-cpp">#include &lt;string&gt;
#include &lt;vector&gt;

using namespace std;

int solution(int n, vector&lt;int&gt; lost, vector&lt;int&gt; reserve) {
    int answer = n;
    int i=0, j=0; //lost 스캔 인덱스

    for(i=0; i&lt;lost.size() i++){
        if(lost[i]-1 == reserve[j]){
            j++;
        }
        else if(lost[i]-1&gt;reserve[j]){
            j++;
            i--;
        }
        else{
            if(lost[i]+1 == reserve[j]){
                j++;
            }
            else if(lost[i]+1&lt;reserve[j]){
                answer--;
            }
        }
    }

    return answer;
}</code></pre>
<h3 id="결과">결과</h3>
<p>위의 풀이는 제출했을 때 50%의 정확도만 받을 수 있었습니다.
분명 if문에서 잘못된게 없다고 생각했는데 낮은 점수를 받아서 gpt에게 피드백을 요청했습니다.</p>
<h3 id="gpt-피드백">gpt 피드백</h3>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/cc1c1b6b-cdbb-4e8d-84e5-fe39e6172c22/image.png" alt=""></p>
<p>이 피드백을 통해 제약조건을 확인하지 않았다는 것을 발견했습니다.</p>
<ol>
<li>lost와 reserve가 정렬되어있지 않으면 reserve와 lost를 크기비교하는 것이 의미가 없습니다.</li>
<li>여벌 옷이 있는 학생이 도난을 당한 케이스를 제외하지 못했습니다..(이거는 문제를 잘 안읽어서 생긴 문제) </li>
</ol>
<hr>
<h2 id="두번째-시도">두번째 시도</h2>
<p>피드백을 읽고 다시 알고리즘을 작성했습니다.</p>
<h3 id="알고리즘-1">알고리즘</h3>
<ol>
<li>두 배열의 <strong>교집합을 제거</strong>하기</li>
<li>교집합이 제거된 배열을 각각 <strong>정렬</strong>하기</li>
<li><strong>reserve를 순회</strong>하면서 앞이나 뒤 학생이 lost에 있다면 해당 학생을 lost에서 제거하기</li>
</ol>
<p>-&gt; reserve를 순회해야 앞과 뒤 두 학생에게 중복으로 빌려주는 일이 없음</p>
<p>이번에는 파이썬으로 코드를 작성했습니다.</p>
<pre><code class="language-python">def solution(n, lost, reserve):
    answer = 0

    lost = set(lost)
    reserve = set(reserve)

    both = lost&amp;reserve
    lost -= both
    reserve -= both

    lost = sorted(lost)
    reserve = sorted(reserve)

    for r in reserve:
        if r-1 in lost:
            lost.remove(r-1)
        elif r+1 in lost:
            lost.remove(r+1)

    answer = n - len(lost)
    return answer</code></pre>
<h3 id="결과-1">결과</h3>
<p><strong>성공!</strong>
저는 set을 이용해 집합으로 만들어서 교집합을 구했지만 다른 사람들의 코드를 살펴보니 for문을 이용하는 경우가 많았습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[블록체인] 솔리디티와 스마트 계약 개념정리1]]></title>
            <link>https://velog.io/@heejae-l/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EC%86%94%EB%A6%AC%EB%94%94%ED%8B%B0%EC%99%80-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EA%B3%84%EC%95%BD-%EA%B0%9C%EB%85%90%EC%A0%95%EB%A6%AC1</link>
            <guid>https://velog.io/@heejae-l/%EB%B8%94%EB%A1%9D%EC%B2%B4%EC%9D%B8-%EC%86%94%EB%A6%AC%EB%94%94%ED%8B%B0%EC%99%80-%EC%8A%A4%EB%A7%88%ED%8A%B8-%EA%B3%84%EC%95%BD-%EA%B0%9C%EB%85%90%EC%A0%95%EB%A6%AC1</guid>
            <pubDate>Thu, 07 Nov 2024 13:30:52 GMT</pubDate>
            <description><![CDATA[<p>블록체인을 이용한 프로젝트를 해보려하는데 개념이 헷갈리고 어려워서 정리 해보았다. </p>
<p>아래는 공부하면서 생각나는 것들과 궁금했던 점들에 대한 답변을 메모처럼 정리한 내용이다.</p>
<hr>
<h2 id="솔리디티란">솔리디티란?</h2>
<p>솔리디티란 스마트 계약 코드(contract)를 작성하기 위한 언어이다. 이렇게 작성된 스마트 계약 코드는 이더리움에 의해 컴파일되어 이더리움 블록체인에 배포, 실행된다.</p>
<h2 id="솔리디티-개발은-뭘로-하는데">솔리디티 개발은 뭘로 하는데?</h2>
<p>솔리디티 개발은 Remix IDE를 이용해 웹 상에서 개발하거나 truffle을 이용해 로컬 환경에서 개발할 수 있다.</p>
<h2 id="스마트-계약-코드contract가-배포되는-이더리움은-뭐지">스마트 계약 코드(=contract)가 배포되는 이더리움은 뭐지?</h2>
<p>이더리움이란 블록체인이 존재하는 네트워크이다.</p>
<p>이더리움 네트워크에는 종류가 있다.</p>
<ol>
<li>이더리움 메인넷: 이더리움의 주요 네트워크로 실제 거래와 스마트 계약이 실행된다. </li>
<li>테스트넷: 개발자가 스마트 계약을 테스트할 수 있도록 설계된 네트워크</li>
</ol>
<h2 id="erc-20은-뭐고-스마트-계약-코드는-어떻게--생겼지">ERC-20은 뭐고 스마트 계약 코드는 어떻게  생겼지?</h2>
<p>ERC-20은 이더리움 블록체인에서 토큰을 만들고 관리하기 위한 표준이다. 토큰이 어떻게 이동하고, 어떻게 토큰을 전송하는지 등을 정의한다. ERC-20표준을 따르는 토큰은 서로 호환된다.</p>
<p>ERC-20표준에 따른 contract 코드의 예시는 다음과 같다.</p>
<pre><code class="language-solidity">// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address recipient, uint256 amount) external returns (bool);
    function allowance(address owner, address spender) external view returns (uint256);
    function approve(address spender, uint256 amount) external returns (bool);
    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

    event Transfer(address indexed from, address indexed to, uint256 value);
    event Approval(address indexed owner, address indexed spender, uint256 value);
}

contract MyToken is IERC20 {
    string public constant name = &quot;MyToken&quot;;
    string public constant symbol = &quot;MTK&quot;;
    uint8 public constant decimals = 18;

    uint256 private _totalSupply;
    mapping(address =&gt; uint256) private _balances;
    mapping(address =&gt; mapping(address =&gt; uint256)) private _allowances;

    constructor(uint256 initialSupply) {
        _totalSupply = initialSupply;
        _balances[msg.sender] = _totalSupply;
        emit Transfer(address(0), msg.sender, _totalSupply);
    }

    function totalSupply() public view override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) public view override returns (uint256) {
        return _balances[account];
    }

    function transfer(address recipient, uint256 amount) public override returns (bool) {
        require(_balances[msg.sender] &gt;= amount, &quot;ERC20: transfer amount exceeds balance&quot;);
        _balances[msg.sender] -= amount;
        _balances[recipient] += amount;
        emit Transfer(msg.sender, recipient, amount);
        return true;
    }

    function approve(address spender, uint256 amount) public override returns (bool) {
        _allowances[msg.sender][spender] = amount;
        emit Approval(msg.sender, spender, amount);
        return true;
    }

    function allowance(address owner, address spender) public view override returns (uint256) {
        return _allowances[owner][spender];
    }

    function transferFrom(address sender, address recipient, uint256 amount) public override returns (bool) {
        require(_allowances[sender][msg.sender] &gt;= amount, &quot;ERC20: transfer amount exceeds allowance&quot;);
        _balances[sender] -= amount;
        _balances[recipient] += amount;
        _allowances[sender][msg.sender] -= amount;
        emit Transfer(sender, recipient, amount);
        return true;
    }
}
</code></pre>
<h2 id="contract가-배포되면-무슨-일이-일어나지">contract가 배포되면 무슨 일이 일어나지?</h2>
<ol>
<li><p><strong>컴파일</strong>: 이더리움은 contract를 바이트 코드로 컴파일한다.</p>
</li>
<li><p><strong>배포 트랜잭션 생성</strong>: 블록체인에 바이트 코드를 배포하기 위해 트랜잭션을 생성한다. 바이트 코드와 가스 비용(GAS)을 지정해야한다.</p>
</li>
<li><p><strong>트랜잭션 처리</strong>: 배포 트랜잭션이 이더리움 네트워크로 전송되어 네트워크의 노드들에 의해 검증되고 트랜잭션을 블록에 포함시켜 블록체인에 추가한다.</p>
</li>
<li><p><strong>계약 주소(contract address)할당</strong>: 배포(블록체인에 추가)에 성공하면, contract는 고유한 계약 주소를 할당받는다. 이 주소를 이용해 계약과 상호작용한다.</p>
</li>
<li><p><strong>상호작용</strong>: 계약주소를 이용해 contract에 작성된 함수를 호출하고 데이터를 조회할 수 있다.</p>
</li>
</ol>
<h2 id="계약과의-상호작용이-뭔데">계약과의 상호작용이 뭔데?</h2>
<p>contract 코드에 작성했던 함수를 호출하는 것이 상호작용이다. 크게 두 가지 종류가 있다.</p>
<ol>
<li><p>Transaction
블록체인의 상태를 변경하는 것. 토큰을 전송, 데이터를 기록, 계약 상태 변경 등. 블록체인에 기록되고 가스 비용이 발생한다.</p>
</li>
<li><p>call
블록체인의 상태를 변경하지 않고 데이터만 조회하는 것. 계약의 변수 값 확인 등. 블록체인에 기록되지 않고 가스 비용이 발생하지 않는다.</p>
</li>
</ol>
<h2 id="그래서-이걸-이용해서-뭘-할-수-있는-거지">그래서 이걸 이용해서 뭘 할 수 있는 거지?</h2>
<p>스마트 계약의 특징을 이용해서 다양한 서비스를 개발할 수 있다.</p>
<ol>
<li>스마트 계약은 자동 계약을 가능하게 해서 사람의 개입 없이 특정 조건이 충족되면 자동으로 작업을 실행한다. </li>
</ol>
<p>이를 이용해 특정 가격에 자동적으로 주식을 사고팔 수 있는 자동 주식 거래 프로그램을 만들 수도 있다.</p>
<ol start="2">
<li>작품을 토큰화하여 블록체인에 기록할 수 있다. = NFT</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AWS EC2에서 FastAPI 서버] 3. http 요청 처리하기]]></title>
            <link>https://velog.io/@heejae-l/AWS-EC2%EC%97%90%EC%84%9C-FastAPI-%EC%84%9C%EB%B2%84-3.-http%EC%9A%94%EC%B2%AD-%EB%B3%B4%EB%82%B4%EA%B8%B0</link>
            <guid>https://velog.io/@heejae-l/AWS-EC2%EC%97%90%EC%84%9C-FastAPI-%EC%84%9C%EB%B2%84-3.-http%EC%9A%94%EC%B2%AD-%EB%B3%B4%EB%82%B4%EA%B8%B0</guid>
            <pubDate>Thu, 15 Aug 2024 04:41:04 GMT</pubDate>
            <description><![CDATA[<p>이전에는 로컬에서 접속할 수 있는 서버를 만들었다.
이 서버를 다른 컴퓨터에서 접속하면 어떻게 될까?</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/0441ecd0-6881-48bf-b84c-32750067e726/image.png" alt=""></p>
<p>화면의 아래쪽을 보면 PublicIPs라고 써진 부분에 IP주소를 확인할 수 있다.
이 주소를 쳐서 접속해보기로 했다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/9344e598-28fc-4d1f-86c9-9cdbdf875b46/image.png" alt=""></p>
<p>접속이 되지 않는다.</p>
<p>그 이유는 <a href="http://54.180.150.169%EC%97%90">http://54.180.150.169에</a> 접속하면 포트80번으로 자동으로 연결되는데,
우리가 열어둔 포트는 8000번이기 때문이다.</p>
<p>이 문제를 해결하는 것이 Nginx이다.</p>
<h2 id="nginx란">Nginx란?</h2>
<p>nginx는 서버와 클라이언트 사이에 존재하는 프록시 서버로, 클라이언트의 요청을 서버로 대신 전달해주는 역할을 한다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/05434c27-ec87-40f5-bab9-1c6582a0b93b/image.png" alt=""></p>
<p> 출처: <a href="https://velog.io/@chickenfondue/nginx-docker-compose%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A6%AC%EB%B2%84%EC%8A%A4-%ED%94%84%EB%A1%9D%EC%8B%9C-%EA%B5%AC%EC%84%B1">https://velog.io/@chickenfondue/nginx-docker-compose%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A6%AC%EB%B2%84%EC%8A%A4-%ED%94%84%EB%A1%9D%EC%8B%9C-%EA%B5%AC%EC%84%B1</a></p>
<p>위의 그림처럼 80번 포트로 들어온 요청을 실제로 열려있는 포트로 전달해주는 것이 nginx이다.</p>
<h3 id="장점">장점</h3>
<ol>
<li>로드 밸런싱: 트래픽을 분산시킬 수 있다.</li>
<li>보안 강화: 웹 서버가 클라이언트에게 바로 노출되어있지 않아 위험한 요청을 차단할 수 있다.(DDOS등)</li>
</ol>
<h2 id="nginx-설치-및-설정">Nginx 설치 및 설정</h2>
<blockquote>
<p>sudo apt install nginx</p>
</blockquote>
<p>위의 명령어를 통해 간단히 설치할 수 있다.
<img src="https://velog.velcdn.com/images/heejae-l/post/d5a0e555-2b75-48a8-9f4e-b0ae45a9ed80/image.png" alt=""></p>
<p>설치가 되었다면 이제 8000번 포트로 링크할 수 있도록 설정해주어야 한다.</p>
<blockquote>
<p>sudo vi /etc/nginx/sites-enabled/default</p>
</blockquote>
<p>명령어를 입력하면 vi 편집기가 열린다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/1ec2b127-1a15-4cf0-9b14-3ea8897f3a00/image.png" alt="">
당황하지 말고 아래로 스크롤 해서 내려가면 location이라는 부분이 보인다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/7eedc1db-4d03-4c08-ac01-354e73e0f669/image.png" alt=""></p>
<p>location / 뒤에 붙은 중괄호 안의 내용을 변경해주면 된다.</p>
<p>변경할 때는 i를 눌러 INSERT모드로 바꾸고</p>
<blockquote>
<p>proxy_pass <a href="http://127.0.0.1:8000">http://127.0.0.1:8000</a>;
        proxy_set_header Host $http_host;
        proxy_set_header X-Real_IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Photo $scheme;</p>
</blockquote>
<p>이 내용을 중괄호 안에 넣어주면 된다.
<img src="https://velog.velcdn.com/images/heejae-l/post/6e0e77f6-ea9e-4945-b6f1-8272cc4e200b/image.png" alt=""></p>
<p>저장하고 나가기 위해서 esc를 누르고 :wq!를 치고 엔터를 치면 된다.</p>
<p>변경사항을 반영하기 위해 nginx를 재실행 해준다.</p>
<blockquote>
<p>실행하기
sudo service nginx start
재실행하기
sudo service nginx restart
종료하기
sudo service nginx stop</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/a153c080-1f53-4905-819f-52d4b7195e95/image.png" alt=""></p>
<p>그리고 -t옵션으로 설정 파일의 문법이 정확한지 검사할 수 있다.</p>
<blockquote>
<p>sudo nginx -t</p>
</blockquote>
<p><img src="blob:https://velog.io/cf345aee-a938-4019-bebc-4830f9c3e2ea" alt=""></p>
<p>문제가 없다고 떴으니 이제 다시 서버를 열고 테스트할 수 있다.</p>
<h2 id="테스트">테스트</h2>
<p>uvicorn main:app 명령어로 서버를 열어주고
<img src="https://velog.velcdn.com/images/heejae-l/post/816094e1-7cc5-444d-8d22-8e302556093d/image.png" alt=""></p>
<p>아까와 같은 IP주소를 통해 접속할 수 있다.
<img src="https://velog.velcdn.com/images/heejae-l/post/1cb59d26-8870-4fa0-b108-d5af03ee738a/image.png" alt=""></p>
<p>문제없이 잘 뜨는 것을 확인할 수 있다.</p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AWS EC2에서 FastAPI 서버] 2. 로컬 서버 열기]]></title>
            <link>https://velog.io/@heejae-l/AWS-EC2%EC%97%90%EC%84%9C-FastAPI-%EC%84%9C%EB%B2%84-2.-%EB%A1%9C%EC%BB%AC-%EC%84%9C%EB%B2%84-%EC%97%B4%EA%B8%B0</link>
            <guid>https://velog.io/@heejae-l/AWS-EC2%EC%97%90%EC%84%9C-FastAPI-%EC%84%9C%EB%B2%84-2.-%EB%A1%9C%EC%BB%AC-%EC%84%9C%EB%B2%84-%EC%97%B4%EA%B8%B0</guid>
            <pubDate>Thu, 15 Aug 2024 04:11:36 GMT</pubDate>
            <description><![CDATA[<p>이전 포스트에서는 EC2인스턴스를 만들고 실행해보았다. 이번에는 실제로 FastAPI서버를 여는 방법을 알아보겠다.</p>
<h2 id="python-fastapi-uvicorn-설치">Python, FastAPI, uvicorn 설치</h2>
<h3 id="파이썬-pip-설치">파이썬, pip 설치</h3>
<h4 id="python3-설치">python3 설치</h4>
<blockquote>
<p>sudo apt install python3</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/58c9ddc9-f465-4236-9fc1-eb4797f440bd/image.png" alt=""></p>
<blockquote>
<p>sudo apt install python3-pip</p>
</blockquote>
<h4 id="오류-python3-pip가-설치되지-않을-때">[오류] python3-pip가 설치되지 않을 때</h4>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/16b5347c-fd16-4089-8ffe-7a593e2b73ac/image.png" alt="">
이렇게 package &#39;python3-pip&#39; has no installation candidate 오류가 발생하면 </p>
<blockquote>
<p>sudo apt update</p>
</blockquote>
<p>위의 명령어로 업데이트 해준 후에 동일한 명령어로 설치하면 됩니다.</p>
<h4 id="이어서-pip-설치">이어서 pip 설치</h4>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/ee55a459-6c43-44ca-b189-c8c146ec180b/image.png" alt=""></p>
<p>중간에 y를 눌러서 계속해주면 됩니다.
잘 설치됩니다.</p>
<h3 id="fastapi-uvicorn-설치">FastAPI, Uvicorn 설치</h3>
<h4 id="fastapi-설치">fastAPI 설치</h4>
<blockquote>
<p>pip install fastapi
pip install uvicorn</p>
</blockquote>
<h4 id="오류-가상환경이-필요할-때">[오류] 가상환경이 필요할 때</h4>
<p>error: externally-managed-environment
<img src="https://velog.velcdn.com/images/heejae-l/post/e053acbe-1235-402a-a96b-b2da2d0d5a29/image.png" alt="">
이런 오류가 발생하면 가상환경을 실행하고 그 안에 fastAPI와 uvicorn을 다운받아줘야 합니다.</p>
<blockquote>
<p>sudo apt install python3-venv</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/a7a652ac-3fa9-4b77-a87f-48d85df62f8f/image.png" alt=""></p>
<p>설치해주고</p>
<blockquote>
<p>python3 -m venv (가상공간 이름)</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/715505be-b1c0-407a-8382-125c5b1c5eea/image.png" alt=""></p>
<p>가상공간을 만들어준다</p>
<blockquote>
<p>source (가상공간 경로/bin/activate)</p>
</blockquote>
<p>이렇게 가상공간을 활성화 할 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/7971ec16-9e4f-4493-ab38-e26af866dbe2/image.png" alt="">
pwd를 이용해 현재 경로를 확인하고 그 위에 /bin/activate를 붙여주면 된다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/a9b57bf3-7d3e-4d14-b3f4-27eeedcc8ed2/image.png" alt=""></p>
<h4 id="이어서-fastapi-uvicorn-설치">이어서 fastAPI, uvicorn 설치</h4>
<p>위에서 말했던 명령어로 다시 설치하면 된다.
<img src="https://velog.velcdn.com/images/heejae-l/post/f64dcf8e-8941-4fd8-9deb-1bc0f2cb5c9e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/b2fef582-d4ed-4e2e-9906-0f1424dc6210/image.png" alt=""></p>
<p>왼쪽 상단에 가상환경 이름이 떠있는 것을 확인할 수 있다.</p>
<h4 id="테스트">테스트</h4>
<p>두 개가 제대로 설치되었는지 확인하기 위해서 깃에 올려둔 간단한 fastAPI예제를 가져와서 실행해보기로 했다.</p>
<p><a href="https://github.com/Heejae-L/SimpleFastApi.git">https://github.com/Heejae-L/SimpleFastApi.git</a></p>
<blockquote>
<p>git clone <a href="https://github.com/Heejae-L/SimpleFastApi.git">https://github.com/Heejae-L/SimpleFastApi.git</a></p>
</blockquote>
<p>이 명령어로 리포지토리를 클론해서 가져온다.
<img src="https://velog.velcdn.com/images/heejae-l/post/9ff04d38-88b9-46d6-8ea8-9de714393952/image.png" alt=""></p>
<p>SimpleFastAPI폴더로 이동하여 uvicorn을 테스트해본다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/884729c7-459d-420f-8d4c-d35162bf9943/image.png" alt=""></p>
<p>이렇게 로컬호스트8000(127.0.0.1:8000)에서 서버가 열린 것을 확인할 수 있다.</p>
<p>외부에서 http를 이용해 접근하는 것은 다음 포스트에서 이어서 설명하겠다.</p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[AWS EC2에서 FastAPI 서버] 1. EC2인스턴스 만들기]]></title>
            <link>https://velog.io/@heejae-l/AWS-EC2%EC%97%90%EC%84%9C-FastAPI-%EC%84%9C%EB%B2%84-1.-EC2%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</link>
            <guid>https://velog.io/@heejae-l/AWS-EC2%EC%97%90%EC%84%9C-FastAPI-%EC%84%9C%EB%B2%84-1.-EC2%EC%9D%B8%EC%8A%A4%ED%84%B4%EC%8A%A4-%EB%A7%8C%EB%93%A4%EA%B8%B0</guid>
            <pubDate>Thu, 15 Aug 2024 03:15:51 GMT</pubDate>
            <description><![CDATA[<h2 id="인스턴스-생성">인스턴스 생성</h2>
<p>Fast API를 EC2에 올리기 위해서는 일단 EC2인스턴스를 생성해야한다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/9247c0b0-fc41-4e8d-8c17-18974514a8ea/image.png" alt=""></p>
<p>위의 화면에서 인스턴스 시작을 누른다</p>
<p>그러면 아래와 같은 화면이 뜨는데 자신이 사용할 OS를 선택해주면 된다.
<img src="https://velog.velcdn.com/images/heejae-l/post/13a93855-e5b5-4a3f-871f-053804c77305/image.png" alt=""></p>
<p>나는 Ubuntu를 선택했다.
프리티어에서 사용가능하다고 표시된 것을 선택하면 돈을 내지 않고도 일정한 시간동안 사용할 수 있다.</p>
<p>아래로 내려가서..
<img src="https://velog.velcdn.com/images/heejae-l/post/f99e6d69-6443-47e0-a5af-0c668b52a4e4/image.png" alt="">
인스턴스 유형은 기본을 그대로 선택하면 된다.
키페어는 없다면 <strong>생성해주고 선택</strong>하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/91cf1441-bab4-43b6-8ee7-5447a948e687/image.png" alt=""></p>
<p>다음으로 네트워크 설정인데 이거는 <strong>HTTP/HTTPS를 쓸지 말지에 따라서 선택</strong>해주면 된다.
나는 둘 다 체크해줬다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/2938e9b1-fb9a-4be3-962f-c7e4a5688bc5/image.png" alt="">
그 다음으로 스토리지 구성은 프리티어에서 최대 30GB이므로 <strong>30으로 설정</strong>해주면 된다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/fbcc509a-c81d-467a-9cd7-68cf2caf291b/image.png" alt=""></p>
<p>그리고 오른쪽에 <strong>인스턴스 시작</strong>을 눌러주면 된다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/b44a9210-c733-4483-90d0-de2bd55758fd/image.png" alt=""></p>
<p>성공적으로 잘 만들어졌고 이제 오른쪽 아래의 <strong>모든 인스턴스 보기</strong>를 누르면 만들어진 인스턴스를 확인할 수 있다.</p>
<h2 id="인스턴스-실행">인스턴스 실행</h2>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/1e1da7ba-5b2c-496e-ad4f-0d3425de19b2/image.png" alt="">
아래 있는 것이 방금 만든 인스턴스인데, 실행 중으로 나와있다. 
인스턴스 ID를 누르면 자세한 정보를 볼 수 있다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/7ade8c07-50d3-40c3-8f79-d6eff42fe165/image.png" alt=""></p>
<p>현재 이 인스턴스의 IP, 로컬 IP 등이 나와있다.</p>
<p><strong>퍼블릭 IPv4 주소는 인스턴스를 실행/중지 할 때마다 바뀌기 때문에 주의해야한다.</strong></p>
<p>이제 우리가 만든 ubuntu 컴퓨터를 직접 사용해 볼 수 있다.
아주 간단하게 오른쪽 위 <strong>연결</strong>을 누르면 된다.
<img src="https://velog.velcdn.com/images/heejae-l/post/f59b32f2-49c7-4f8c-970f-2ed512cd03ee/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/66f659b7-1774-4aba-ba62-1f3c26e39f1a/image.png" alt="">
그러면 이렇게 콘솔 화면이 나오게 된다.</p>
<p>이 화면을 통해 파일을 관리하고 코드를 작성하거나 서버를 띄우는 일을 할 수 있다.</p>
<p>이 다음 포스트에서는 FastAPI서버를 띄우는 법을 공부할 것이다.</p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[회고] 7월 회고]]></title>
            <link>https://velog.io/@heejae-l/%ED%9A%8C%EA%B3%A0-7%EC%9B%94-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@heejae-l/%ED%9A%8C%EA%B3%A0-7%EC%9B%94-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Tue, 06 Aug 2024 07:11:32 GMT</pubDate>
            <description><![CDATA[<p>이제 8월의 한 주가 지나가고 있는 시점에서 남은 방학을 더 의미있게 보내야겠다고 생각했다.
기록 해놓으면 나중에 무엇을 했는지, 어떤 것을 느꼈는지 명확할 것이다.
따라서 7월을 회고하고 8월을 계획하고자 한다.</p>
<h1 id="2024년-7월">2024년 7월</h1>
<h2 id="공개-sw-개발자-대회629">공개 SW 개발자 대회(6/29~)</h2>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/85a0de2f-d15d-4b76-ab2a-a041b65b33f0/image.png" alt=""></p>
<p>6월 18일에 학부의 날 행사에 다녀온 후 동기부여가 되어 함께 갔던 동기와 공개 sw 개발자 대회를 준비하게 되었다.</p>
<p>매 주 2번 이상 온라인으로 회의하며 진행하고 있다.</p>
<p>6월 말에 아이템 선정 완료, 7월 초 부터 개발을 시작하여 <strong>FastAPI, HTML, YOLOv8</strong>을 이용해 object tracking과제를 수행하는 중이다.</p>
<p>모델의 성능이 잘 나오지 않고 트랙킹을 최적화하기 위해 <strong>Deep sort</strong> 모델의 사용을 고민하는 중이다.</p>
<hr>
<h2 id="하계-딥러닝-단기-프로그램78711--715718">하계 딥러닝 단기 프로그램(7/8<del>7/11 , 7/15</del>7/18)</h2>
<p>딥러닝 기업 실무진을 초청하여 교육을 진행한다길래 빠르게 신청하였다.
<img src="https://velog.velcdn.com/images/heejae-l/post/1f71bc99-a98a-4496-a31e-4c822fab4a1a/image.png" alt=""></p>
<p>기초과정과 고급과정으로 나눠져있었는데, 기초 과정은 대부분 전공 수업인 AI수학, 데이터과학, 인공지능 개론에서 다뤘던 내용들이 주를 이뤘다.</p>
<p>고급 과정에서는 기초 수업의 내용을 바탕으로 실제 현장에서 물체에 띄지를 부착하거나, 불량품을 검출해내는 AI를 어떻게 학습시키는지 실습하였다.</p>
<p>바이오헬스의료기기융합전공에서 주최한 프로그램이기에 의료 데이터를 이용한 딥러닝 모델 학습을 주로 배우게 되었다. </p>
<p><strong>의료 데이터</strong> 분야 실무를 배웠기 때문에 computer vision 분야에서 실제로 사용되고 있는 모델과 새로 등장하는 모델을 알아가는 기회였다.</p>
<p><del>학교에서 배우는 모델은 아주 기초적이고 오래된 모델이라는 것도 배웠다..</del></p>
<hr>
<h2 id="백엔드-취준716-">백엔드 취준(7/16~ )</h2>
<p>가장 막막하고 큰 고민을 안겨준..</p>
<p><strong>취준!!</strong></p>
<p>백엔드 개발자로 노선을 정하고 나서 잠깐은 길이 보이는 기분에 이것저것 계획을 세웠었다.</p>
<p>하지만.. 공부를 시작하고 보니 알아야 할 기술이 너무나 많고 명확한 길도 없는 것처럼 느껴졌다.</p>
<p>물론 어떤 분야도 확실한 노선은 없는게 당연하지만, 나는 인공지능 전공이기에 학과 수업이 아닌 분야를 스스로 터득해야한다는 부담감이 존재했다.</p>
<p>7월에는 취준을 위해 두 가지를 진행했다.</p>
<h3 id="1-코딩테스트-준비">1. 코딩테스트 준비</h3>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/89e428d1-5b65-403f-98ba-467895adeace/image.png" alt=""></p>
<ul>
<li>이것이 취업을 위한 코딩테스트다 with 파이썬 책으로 알고리즘 개념을 잡고있다. </li>
<li>chapter 8 까지 완료</li>
<li>백준에서 문제를 찾아서 풀고 있다.</li>
</ul>
<h3 id="2-스프링-부트-강의-수강7">2. 스프링 부트 강의 수강(7/</h3>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/38f3e6aa-8127-40dc-9eaf-b7d3680e4283/image.png" alt="">
이 수업을 듣기 시작한것은 저번 학기 중반이었는데, 중간에 시간이 없다는 핑계로 미뤘다가 이번에 다시 듣고 있다.</p>
<h2 id="http-공부729731">HTTP 공부(7/29~7/31)</h2>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/981fd143-2a88-4fce-98c4-d85c6d34ad7a/image.png" alt=""></p>
<p>스프링 강의를 들으면서 기본적인 웹 지식이 부족함을 느끼고 http강의를 수강하였다.</p>
<p>TCP, UDP, IP나 PORT관련 내용은 학교 네트워크 수업을 바탕으로 이해할 수 있었다.
학교에서 다루지 않았던 HTTP 메서드들간의 차이와 상태코드를 정리할 기회도 됐다. 웹 개발자가 되려면 꼭 필요한 부분이라고 생각한다.</p>
<hr>
<h2 id="velog-작성--토이프로젝트622-">velog 작성 &amp; 토이프로젝트(6/22~ )</h2>
<p>벨로그를 한 주에 한 번은 작성하려고 노력했다.
6월 22일에 시작해서 5주 동안 10개를 썼으니까 일주일에 2개 정도 작성했다.</p>
<p>벨로그를 작성하면서 매번 ppt나 미리캔버스로 썸네일을 만드는게 귀찮아서 간단한 토이프로젝트를 진행했다.</p>
<p><strong>썸네일을 만들 수 있는 웹 서비스다</strong>. 이번 주 내로 프론트는 마무리해서 벨로그에 작성할 예정이다. 생성형ai의 api를 가져와서 추가하는 것도 생각중이다.</p>
<p><a href="https://github.com/Heejae-L/thumbnail-maker">https://github.com/Heejae-L/thumbnail-maker</a></p>
<hr>
<h2 id="기타">기타</h2>
<ul>
<li>깃허브 리드미 정리</li>
<li></li>
<li>건강 챙기기(탄수화물 줄이기 + 꾸준한 산책)</li>
<li>여름 휴가</li>
</ul>
<hr>
<h2 id="결론">결론...</h2>
<p>회고를 쓰게 된 계기는 이렇다.
방학이 끝나가는데 대체 어떤 일로 시간을 보냈는지 기억이 나지 않았다.
이상하게도 자꾸 취업시장과 IT시장이 얼어간다는 소식만 듣게 되면서 취업에 대해 막연한 걱정을 매일하는 지경이었다.</p>
<p>작성하면서 보니 꽤 알차다면 알차게 보낸 듯 하다. 너무 걱정하거나 비교하지 말고 스스로 반성하며 삶을 이끌어가는 것이 중요함을 느낀다.</p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백엔드] 자바 개념잡기 1]]></title>
            <link>https://velog.io/@heejae-l/%EB%B0%B1%EC%97%94%EB%93%9C-%EC%9E%90%EB%B0%94-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-1</link>
            <guid>https://velog.io/@heejae-l/%EB%B0%B1%EC%97%94%EB%93%9C-%EC%9E%90%EB%B0%94-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-1</guid>
            <pubDate>Thu, 01 Aug 2024 01:29:26 GMT</pubDate>
            <description><![CDATA[<p>스프링 부트 강의를 들으면서 애매한 개념들을 확실히 정리하기 위해 씁니다.</p>
<h2 id="상속">상속</h2>
<p>: (is-a관계) 한 클래스가 다른 클래스의 변수와 메소드를 받아오는 것. 자식 클래스가 부모클래스를 상속받는다. 필요한 변수나 메서드를 추가할 수 있다.</p>
<h3 id="특징">특징</h3>
<ul>
<li>일반적인 특성을 부모 클래스에서 구현하고 구체적인 부분은 자식 클래스에서 구현할 수 있다</li>
<li>클래스에 새로운 기능을 일관되게 넣어 일관성을 유지한다.</li>
<li>유지 보수 용이</li>
</ul>
<h3 id="사용">사용</h3>
<p>class [자식 클래스] <strong>extends</strong> [부모 클래스] {}</p>
<h3 id="예제">예제</h3>
<pre><code class="language-java">// 부모 클래스
class Vehicle {
    protected String brand; // 차량 브랜드
    protected int year;     // 제조 연도

    public Vehicle(String brand, int year) {
        this.brand = brand;
        this.year = year;
    }

    public void start() {
        System.out.println(&quot;Vehicle is starting&quot;);
    }

    public void stop() {
        System.out.println(&quot;Vehicle is stopping&quot;);
    }
}

// 자식 클래스 1: Car
class Car extends Vehicle {
    private int doors; // 차량의 문 개수

    public Car(String brand, int year, int doors) {
        super(brand, year); // 부모 클래스의 생성자 호출
        this.doors = doors;
    }

    // 추가 메소드 정의
    public void openTrunk() {
        System.out.println(&quot;Opening the trunk&quot;);
    }
}

// 자식 클래스 2: Truck
class Truck extends Vehicle {
    private double loadCapacity; // 적재 용량

    public Truck(String brand, int year, double loadCapacity) {
        super(brand, year); // 부모 클래스의 생성자 호출
        this.loadCapacity = loadCapacity;
    }

    // 추가 메소드 정의
    public void unload() {
        System.out.println(&quot;Unloading cargo&quot;);
    }
}

// 메인 클래스로 실행을 위한 코드
public class Main {
    public static void main(String[] args) {
        Car myCar = new Car(&quot;Toyota&quot;, 2021, 4);
        Truck myTruck = new Truck(&quot;Ford&quot;, 2019, 5.0);

        myCar.start();
        myCar.openTrunk();
        myCar.stop();

        myTruck.start();
        myTruck.unload();
        myTruck.stop();
    }
}</code></pre>
<h3 id="다중-상속-불가능">다중 상속 불가능</h3>
<p>: 한 클래스는 <strong>단 하나의 부모클래스</strong>를 가져야한다. </p>
<p>하지만 여러 클래스의 메서드가 필요한 경우가 있다. 이때, <strong>인터페이스</strong>를 이용하여 <strong>하나의 클래스가 여러 인터페이스를 구현</strong>함으로써 이 부분을 어느 정도 극복할 수 있다.</p>
<h4 id="예제-1">예제</h4>
<pre><code class="language-java">//인터페이스1 정의
public interface Sell {

    void sell();

}
//인터페이스2 정의
public interface Buy {

    void buy();

}
//인터페이스1,2를 모두 구현하는 클래스 정의
public class Customer implements Buy, Sell{

    @Override
    public void sell() {
        System.out.println(&quot;customer sell&quot;);
    }

    @Override
    public void buy() {
        System.out.println(&quot;customer buy&quot;);        
    }

    public void sayHello() {
        System.out.println(&quot;Hello&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Customer customer1 = new Customer();
        customer1.sell();  // 출력: customer sell
       customer1.buy(); //출력: customer buy
    }
}
</code></pre>
<hr>
<h2 id="인터페이스">인터페이스</h2>
<p>: 메소드의 이름, 파라미터 리스트, 반환 유형을 명시하지만 코드적인 구현은 포함하지 않은 <strong>껍데기 클래스</strong>. </p>
<h3 id="특징-1">특징</h3>
<ul>
<li>구현과 인터페이스를 분리해서 독립적인 개발이 가능하도록 한다.</li>
<li>다중 상속과 비슷한 기능을 지원한다. ➜ 상속 부분 참고</li>
</ul>
<h3 id="정의">정의</h3>
<p><strong>interface</strong> [인터페이스] {}</p>
<h3 id="사용-1">사용</h3>
<p>class [클래스] <strong>implements</strong> [인터페이스 이름] {}</p>
<p>class [클래스] <strong>implements</strong> [인터페이스1],[인터페이스2] {}</p>
<p>위와 같이 두 개의 인터페이스를 구현할 수 있다.</p>
<h3 id="예제-2">예제</h3>
<pre><code class="language-java">// Animal 인터페이스 정의
interface Animal {
    void speak();  // 모든 동물은 말할 수 있어야 함을 정의
}

// Dog 클래스가 Animal 인터페이스를 구현
class Dog implements Animal {
    // 인터페이스의 speak 메서드 구현
    @Override
    public void speak() {
        System.out.println(&quot;멍멍!&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Dog myDog = new Dog();
        myDog.speak();  // 출력: 멍멍!
    }
}
</code></pre>
<hr>
<h2 id="추상-클래스abstract-class">추상 클래스(abstract class)</h2>
<p>: 인터페이스와 유사한 역할. </p>
<h3 id="특징-2">특징</h3>
<p>인터페이스와의 차이점은 일부 메소드의 <strong>구현</strong>을 포함한다는 것이다. 또한 클래스 내에 변수(멤버 변수)를 가질 수 있다. </p>
<p>➜ 결과적으로 <strong>공통 부분을 추상 클래스에서 구현</strong>하여 코드의 중복을 줄인다.</p>
<h3 id="정의-1">정의</h3>
<p><strong>abstract class</strong> [추상 클래스 이름] {}</p>
<h3 id="사용-2">사용</h3>
<p>class [클래스 이름] <strong>extends</strong> [추상 클래스 이름] {}</p>
<h3 id="예제-3">예제</h3>
<pre><code class="language-java">// Vehicle 추상 클래스 정의
abstract class Vehicle {
    abstract void startEngine();  // 엔진을 시작하는 추상 메서드

    // 공통 기능을 제공하는 비추상 메서드
    void stopEngine() {
        System.out.println(&quot;엔진 정지!&quot;);
    }
}

// Car 클래스가 Vehicle 클래스를 상속받음
class Car extends Vehicle {
    // 추상 메서드 구현
    void startEngine() {
        System.out.println(&quot;엔진 시동!&quot;);
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car();
        myCar.startEngine();  // 출력: 엔진 시동!
        myCar.stopEngine();   // 출력: 엔진 정지!
    }
}
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 개념잡기] DFS를 구현하는 두 가지 방법]]></title>
            <link>https://velog.io/@heejae-l/%EC%BD%94%ED%85%8C-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-DFS%EB%A5%BC-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%91%90-%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95</link>
            <guid>https://velog.io/@heejae-l/%EC%BD%94%ED%85%8C-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-DFS%EB%A5%BC-%EA%B5%AC%ED%98%84%ED%95%98%EB%8A%94-%EB%91%90-%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95</guid>
            <pubDate>Wed, 24 Jul 2024 05:17:25 GMT</pubDate>
            <description><![CDATA[<p>오늘은 백준 1012번을 풀다가 막혀서 dfs에 대해서 더 공부해보려고 글을 씁니다.</p>
<h1 id="dfs란">DFS란?</h1>
<p>DFS는 깊이 우선 탐색 알고리즘입니다.
즉 한 노드를 탐색하면 그 노드와 연결된 노드 중 방문하지 않은 곳이 없을 때까지 타고타고 들어가며 탐색하는 알고리즘입니다.</p>
<p>스택으로 구현될 수 있는 알고리즘이기도 합니다.<img src="https://velog.velcdn.com/images/heejae-l/post/40e5a439-4bb3-4b1d-8747-c1cf8cc54b8f/image.gif" alt=""></p>
<p>위의 그림을 스택을 이용해 설명하면 이렇습니다.</p>
<ol>
<li><p>1을 방문처리한 후 스택에 넣습니다</p>
</li>
<li><p>1과 연결된 2를 방문처리하고 스택에 넣습니다.</p>
</li>
<li><p>2와 연결된 3을 방문처리하고 스택에 넣습니다.</p>
</li>
<li><p>3과 연결된 노드가 없으므로 3을 스택에서 꺼냅니다.</p>
</li>
<li><p>2와 연결된 노드 또한 없으므로 2를 스택에서 꺼냅니다.</p>
</li>
<li><p>1과 연결된 노드 4를 스택에 넣습니다.</p>
</li>
<li><p>반복</p>
</li>
</ol>
<p>이렇게 스택의 구조를 이용해서 구현할 수 있습니다.</p>
<p><strong>다시 말해 DFS는 한 길로 쭉 파고 들어가는 알고리즘이라고 할 수 있습니다.</strong></p>
<h1 id="dfs의-구현">DFS의 구현</h1>
<h2 id="재귀함수를-이용한-구현">재귀함수를 이용한 구현</h2>
<h3 id="코드">코드</h3>
<pre><code class="language-python">def dfs(graph, v, visited):
    visited[v] = True
    print(v,end=&#39; &#39;)
    for i in graph[v]:
        if not visited[i]:
            dfs(graph, i, visited)
graph = [
    [],
    [2, 3],
    [1, 4],
    [1, 3, 4],
    [2, 4]
]

visited = [False] * 5

dfs(graph, 1, visited)</code></pre>
<h3 id="코드-설명">코드 설명</h3>
<p><strong>graph</strong>배열은 각 노드에 연결된 노드를 나타냅니다.
예를 들어 graph[1]은 노드 1에 연결된 모든 노드를 리스트 형태로 확인할 수 있습니다.</p>
<p><strong>visited</strong> 배열은 각 노드가 방문되었는지 저장합니다.</p>
<p><strong>dfs</strong>함수는 graph, v(현재노드), visited를 인자로 받습니다.</p>
<pre><code class="language-python">visited[v] = True
print(v,end=&#39; &#39;)</code></pre>
<p>먼저 v에 방문처리를 해줍니다. 방문했으므로 출력도 해줍니다.</p>
<pre><code class="language-python">for i in graph[v]:
        if not visited[i]:
            dfs(graph, i, visited)</code></pre>
<p>자신과 연결된 모든 노드를 확인하기 위해서 graph[v]로 반복문을 실행합니다.
각 노드들이 방문되었는지 확인하고, 방문하지 않은 노드인 경우에만 dfs를 호출합니다.</p>
<h3 id="장점">장점</h3>
<p>재귀함수를 이용하였기 때문에 스택을 사용할 필요가 없습니다.
또한 이해가 아주 쉽습니다.</p>
<h3 id="단점">단점</h3>
<p>제가 부딪힌 한계이기도 한데, 파이썬에는 <strong>최대 재귀한도 깊이 에러</strong>(RecursionError: maximum recursion depth exceeded in comparison)가 존재합니다. 이는 재귀함수가 또 다른 재귀함수를 부르는 과정이 1000번 이상 반복되면 발생하는 오류입니다.</p>
<p>파이썬의 최대 재귀 한도는 <strong>1000</strong>입니다.
만약 1001개의 노드가 한 줄로 연결 되어있다면 오류가 발생하게 됩니다.</p>
<p>이 문제를 해결하는 방법은 </p>
<p><strong>1. 한도를 늘려주기
2. 반복문을 사용하기</strong></p>
<p>입니다.</p>
<p>저는 반복문과 스택을 이용해 dfs함수를 다시 만들어보겠습니다.</p>
<hr>
<h2 id="반복문-이용한-구현">반복문 이용한 구현</h2>
<h3 id="코드-1">코드</h3>
<pre><code class="language-python">def dfs(graph, v, visited):
    stack = [v]
    while stack:
        v = stack.pop()
        if not visited[v]:
            visited[v] = True
            print(v, end=&#39; &#39;)
            for node in graph[v]:
                if not visited[node]:
                    stack.append(node)

graph = [
    [],
    [2, 3],
    [1, 4],
    [1, 4],
    [2, 3]
]

visited = [False] * 5

dfs(graph, 1, visited)</code></pre>
<h3 id="코드-설명-1">코드 설명</h3>
<p>스택에 첫 노드를 추가합니다(초기화)</p>
<ol>
<li>스택에서 노드를 하나 빼냅니다.</li>
<li>그 노드가 방문된 것인지 확인하고 아니라면 방문표시를 합니다.</li>
<li>그 노드와 연결된 노드 중 방문하지 않은 노드를 모두 스택에 넣습니다.</li>
<li>스택이 모두 빌 때까지 반복합니다.</li>
</ol>
<hr>
<p>오늘은 dfs에 대해서 두 가지 방법으로 코드를 작성하고 정리해보았습니다.
아직 백준1012번을 풀지 못했지만... 풀게 되면 올리도록 하겠습니다!</p>
<p>끝.<img src="https://velog.velcdn.com/images/heejae-l/post/aad5e6a5-8687-4e8c-a5f9-050081f0a3d2/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[백준 2839] 설탕 배달]]></title>
            <link>https://velog.io/@heejae-l/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%B0%B1%EC%A4%80-2839-%EC%84%A4%ED%83%95-%EB%B0%B0%EB%8B%AC</link>
            <guid>https://velog.io/@heejae-l/%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EB%B0%B1%EC%A4%80-2839-%EC%84%A4%ED%83%95-%EB%B0%B0%EB%8B%AC</guid>
            <pubDate>Mon, 22 Jul 2024 02:50:29 GMT</pubDate>
            <description><![CDATA[<h2 id="문제">문제</h2>
<p>상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.</p>
<p>상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.</p>
<p>상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.</p>
<h2 id="입력">입력</h2>
<p>첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000)</p>
<h2 id="출력">출력</h2>
<p>상근이가 배달하는 봉지의 최소 개수를 출력한다. 만약, 정확하게 N킬로그램을 만들 수 없다면 -1을 출력한다.</p>
<h2 id="1-큰-수부터-차례대로-나누기실패">1) 큰 수부터 차례대로 나누기(실패)</h2>
<p>거스름돈 문제처럼 가장 큰 수 5로 최대한 나눈 후 나머지를 3으로 나눠서 해결하려고 하였다. </p>
<h3 id="알고리즘-">*<em>알고리즘 *</em></h3>
<ul>
<li>N 을 입력 받기</li>
<li>N 을 5로 나눠서 몫을 result에 저장하기</li>
<li>5로 나눈 나머지를 N에 다시 저장하기</li>
<li>N 을 3으로 나눈 몫을 result에 더하기</li>
<li>3으로 나눈 나머지가 있다면 result = -1</li>
<li>result 출력</li>
</ul>
<h3 id="코드"><strong>코드</strong></h3>
<pre><code class="language-python">N = int(input())
result=0
for i in [5,3]:
    result += N//i
    N = N % i
if N&gt;0 :
    print(-1)
else :
    print(result)</code></pre>
<h3 id="문제-발생">문제 발생</h3>
<p>입력이 11일 때,
5로 나눈 후 나머지는 1이 되어 결과가 -1로 나온다.</p>
<p>하지만, 실제로는 (5+3+3)으로 결과는 3이 나와야 한다.
무조건 큰 수로 먼저 나누는 것은 안되는 결과가 나왔다.</p>
<p>이유는 5가 3의 배수가 아니라서 3의 배수를 완전히 커버할 수 없기 때문이다. 
그리디 알고리즘 문제를 풀 때 가장 흔히 하는 실수다.</p>
<h3 id="해결">해결</h3>
<p>3을 하나씩 늘려가면서 5로 나누어 떨어지는지 확인하는 방법을 사용하기로 하였다.</p>
<hr>
<h2 id="2-3의-개수를-하나씩-늘려가기성공">2) 3의 개수를 하나씩 늘려가기(성공)</h2>
<h3 id="알고리즘"><strong>알고리즘</strong></h3>
<ul>
<li>N을 입력 받는다</li>
<li>N 에서 3 * i를 뺀다.(i는 0 ~ N//3)</li>
<li>뺀 결과가 0이거나 5로 나누어지는지 확인한다</li>
<li>맞다면 result에 i+(N-3*i)//5를 저장하고 출력, N = 0.</li>
<li>아니라면 i를 1늘려 반복한다.</li>
<li>반복이 끝나고 N&gt;0 이라면 -1출력</li>
</ul>
<h3 id="코드-1"><strong>코드</strong></h3>
<pre><code class="language-python">N = int(input())
result=0

for i in range(N//3 +1):
    if (N - 3*i)&lt;0:
        break
    if (N - 3*i)==0 or (N - 3*i)%5 == 0:
        result += (i+((N - 3*i)//5))
        N=0
        print(result)

if N&gt;0 :
    print(-1)</code></pre>
<h3 id="복잡도">복잡도</h3>
<p>이 코드의 복잡도는 반복문을 주목하면 되는데, 반복문이 N/3 번 반복되기 때문에 <strong>O(N)</strong> 이라고 할 수 있다.</p>
<hr>
<h2 id="결론">결론</h2>
<p>*<em>그리디 알고리즘 *</em> 카테고리에서 문제를 선택했기 때문에 당연히 가장 큰 수부터 나눠야 <img src="https://velog.velcdn.com/images/heejae-l/post/55b711ec-bacb-42d2-8969-e9db9ed3dde5/image.png" alt="">
할 것이라고 생각했다.
중간에 3과 5의 최소공배수로도 나눠보고, 5를 하나씩 늘리는 방법도 시도했으나 반례에 부딪혔다.</p>
<p>그리디 문제를 풀 때 <strong>배수관계</strong>에 대해서 주의깊게 살펴야겠다.
쉬운 문제지만 혼자 힘으로 풀어냈다는 점이 뿌듯하다.</p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 개념잡기] 배열 입력받기1]]></title>
            <link>https://velog.io/@heejae-l/%EC%BD%94%ED%85%8C-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-%EB%B0%B0%EC%97%B4-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B01</link>
            <guid>https://velog.io/@heejae-l/%EC%BD%94%ED%85%8C-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-%EB%B0%B0%EC%97%B4-%EC%9E%85%EB%A0%A5%EB%B0%9B%EA%B8%B01</guid>
            <pubDate>Mon, 22 Jul 2024 00:04:34 GMT</pubDate>
            <description><![CDATA[<h2 id="동기">동기</h2>
<pre><code class="language-python">
array = list(map(int, input().split()))
</code></pre>
<p>파이썬으로 코딩테스트를 준비하면서 가장 어려웠던 점은 C와의 자잘한 문법의 차이였습니다.
특히 입력이 헷갈렸는데, 모두들 당연하게 위의 방법을 사용하고 있었습니다. 
외우기보다는 이해하는 것이 더 손에 익을 것 같아 코드를 뜯어보기로 했습니다.</p>
<h2 id="input을-이용해-입력받기">input을 이용해 입력받기</h2>
<pre><code class="language-python">
array = list(map(int, input().split()))
</code></pre>
<p>위의 한 줄 중 어느 정도까지 이해가 되나요? 저는 map부터 막혔는데 이제는 설명할 수 있습니다. 같이 공부해봅시다!</p>
<h3 id="inputsplit이란">input().split()이란?</h3>
<p>input()은 문자열을 받아오는 메서드입니다.</p>
<blockquote>
<p>1 2 3 4 5</p>
</blockquote>
<p>위와 같이 입력이 들어왔다면 아래의 코드로 받아올 수 있습니다.</p>
<pre><code class="language-python">
in = input()
print(in)</code></pre>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/a2640c9c-03ce-4fff-b1b2-059e74cc0026/image.png" alt=""></p>
<p>하지만 input은 한 줄씩 읽어오기 때문에 &quot;1 2 3 4 5&quot; 라는 하나의 문자열을 반환하게 됩니다.</p>
<p>이때 split()메서드를 이용해 문자열을 공백을 기준으로 나누어줄 수 있습니다.</p>
<pre><code class="language-python">
in = input().split()
print(in)
</code></pre>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/bc3b0b35-20c5-44ea-8cb3-9317e8744cc9/image.png" alt=""></p>
<p>위처럼 리스트 형태로 반환된 것을 확인 할 수 있습니다.
또 하나 눈에 띄는 것은 리스트 안의 각각의 요소가 문자 형태라는 점입니다.</p>
<p>문자를 숫자로 변환해주기 위해서 map() 메서드를 사용할 수 있습니다.</p>
<h3 id="list-map-함수-리스트--이란">list( map( 함수, 리스트 ) )이란?</h3>
<p>map은 리스트의 요소를 지정된 함수로 처리해주는 메서드입니다.
다시 말해서 오른쪽의 입력된 리스트의 각각의 요소를 함수에 통과시켜서 그 결과로 다시 <strong>새로운</strong> 리스트를 만듭니다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/dcb14759-4069-4172-af5e-2eb8b6dbf0c9/image.png" alt="">
출처:<a href="https://dojang.io/mod/page/view.php?id=2286">https://dojang.io/mod/page/view.php?id=2286</a></p>
<p>왜 list를 이용하는지 궁금해졌기 때문에 map함수에 대해 알아보았습니다.
아래는 map의 결과를 찍어본 결과입니다.</p>
<pre><code class="language-python">a = map(int, input().split())
print(a)
print(type(a))</code></pre>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/5739311f-612c-406b-a294-b10db82c3475/image.png" alt="">
map()함수의 반환값은 map 객체입니다.
따라서 이를 리스트로 만들어주기 위해서 list()라는 메서드를 다시 이용하는 것입니다.</p>
<h2 id="결론">결론</h2>
<p>처음 코드로 돌아가보겠습니다.</p>
<pre><code class="language-python">
array = list(map(int, input().split()))
</code></pre>
<p>이 문장을 이제 완벽하게 이해할 수 있습니다.</p>
<blockquote>
<p>input으로 문자열을 받아서 split으로 공백 기준으로 나눠 리스트를 만들고 map을 이용해 요소 각각을 정수로 바꾼 다음 다시 리스트로 만드는 과정입니다.</p>
</blockquote>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[코테 개념잡기] 그리디 알고리즘(Greedy Algorithm))]]></title>
            <link>https://velog.io/@heejae-l/%EC%BD%94%ED%85%8C-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EB%94%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98Greedy-Algorithm</link>
            <guid>https://velog.io/@heejae-l/%EC%BD%94%ED%85%8C-%EA%B0%9C%EB%85%90%EC%9E%A1%EA%B8%B0-%EA%B7%B8%EB%A6%AC%EB%94%94-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98Greedy-Algorithm</guid>
            <pubDate>Fri, 19 Jul 2024 02:02:23 GMT</pubDate>
            <description><![CDATA[<h2 id="ch3-그리디-알고리즘">ch3. 그리디 알고리즘</h2>
<p>코딩 테스트 개념잡기 첫 번째로 그리디(greedy)알고리즘에 대해서 정리해보려합니다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/b735a80a-321f-4882-9f6c-a8945cf1b681/image.gif" alt="">
출처:<a href="https://commons.wikimedia.org/wiki/File:Greedy-search-path-example.gif">https://commons.wikimedia.org/wiki/File:Greedy-search-path-example.gif</a></p>
<p>그리디 알고리즘은 말 그대로 욕심쟁이 알고리즘입니다.
탐욕법이라고도 부르는데, 현재 상황에서 가장 좋은 것을 고르는 방법입니다.</p>
<p>위의 예시처럼 그리디 알고리즘을 이용해 그래프에서 가장 큰 수를 찾으려고 한다면, <strong>현재 위치(7)과 연결된 두 노드 중 큰 노드(12)를 고르는 것</strong>입니다. 
그리고 이동한 노드(12)에서 또 다시 가장 큰 수를 찾으면 결과적으로 6에 도달하게 됩니다.</p>
<hr>
<h2 id="단점">단점</h2>
<p><strong>전체 문제에 대한 최선의 결과가 아닐 수 있다.</strong></p>
<p>다시 말해서 위의 예시처럼 각 노드에서 가장 큰 수를 골랐지만 결과적으로 전체에서 가장 큰 수를 고르지는 못한 경우입니다.</p>
<h2 id="장점">장점</h2>
<p><strong>빠르게 최적해로 가는 근사치를 구할 수 있다</strong></p>
<p>하지만 위와 같은 단점이 있기 때문에 특정 조건에서만 사용 가능합니다.</p>
<hr>
<h2 id="그럼-어떨-때-사용할-수-있을까">그럼 어떨 때 사용할 수 있을까?</h2>
<p><strong>1. 탐욕적 선택 특성(Greedy choice property)
2. 최적 부분 구조(Optimal substructure)</strong></p>
<p>우리는 위의 두 가지 조건에서 그리디 알고리즘을 적용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/2ae19cac-15a0-4e17-958b-2cff06691fbd/image.png" alt="">
다시 위의 예시를 보겠습니다.
우리가 12를 고르게 되면서 3으로 가는 경우가 사라졌습니다. 이러면 12를 고른 결정이 최종 결과에 영향을 미치게 됩니다.</p>
<p>이는 <strong>탐욕적 선택 특성</strong>에 어긋납니다.</p>
<blockquote>
<p>탐욕적 선택 특성이란, 지금의 선택이 다음 선택에 영향을 주지 않는 것을 의미합니다.</p>
</blockquote>
<hr>
<p>유명한 다른 예시를 들어보겠습니다.
서울에서 대전을 거쳐서 부산으로 가장 빨리가는 방법을 찾는 문제입니다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/51c728f8-d98f-4d59-91bb-89d482ffc6d6/image.png" alt="">
출처:<a href="https://yganalyst.github.io/concept/algo_cc_book_1/">https://yganalyst.github.io/concept/algo_cc_book_1/</a></p>
<p>서울에서 대전까지의 경로가 대전에서 부산까지의 경로에 영향을 미치지 않습니다.</p>
<p>그래서 서울에서 대전까지 가장 빠른 경로 7,
대전에서 부산까지 가장 빠른 경로 22를 고르면
결과적으로 서울에서 부산까지 가장 빠른 경로를 찾을 수 있는 것입니다.</p>
<blockquote>
<p>각 부분의 최선의 선택의 합이 전체의 최선의 결과가 되는 것이 <strong>최적 부분 구조</strong>입니다.</p>
</blockquote>
<p>따라서 <strong>코딩테스트에서 특정 문제를 만났을 때 그리디 알고리즘을 사용하고 싶다면, 현재 상황의 최선의 선택의 조합으로 문제가 해결되는지 판단하는 것</strong>이 핵심입니다.</p>
<hr>
<h1 id="예제-종류">예제 종류</h1>
<ul>
<li><p>거스름돈 문제 : 가장 적은 수의 동전을 이용해 특정 값을 지불하는 문제입니다</p>
</li>
<li><p>1이 될 때까지 : 어떤 수 N이 1이 될 때까지 -1또는 %K를 반복 수행 하여 가장 적을 횟수로 1을 만드는 문제입니다.</p>
</li>
</ul>
<hr>
<p>위의 문제들은 제가 풀이하면 올리도록 하겠습니다
끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Spring Boot 프로젝트 생성 오류 해결]]></title>
            <link>https://velog.io/@heejae-l/Spring-Boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</link>
            <guid>https://velog.io/@heejae-l/Spring-Boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1-%EC%98%A4%EB%A5%98-%ED%95%B4%EA%B2%B0</guid>
            <pubDate>Sat, 13 Jul 2024 13:01:03 GMT</pubDate>
            <description><![CDATA[<h3 id="배경">배경</h3>
<p>김영한의 spring boot 강의를 들으면서 따라하던 중 spring boot 프로젝트 생성 부분에서 막혔습니다.</p>
<hr>
<h3 id="문제사항">문제사항</h3>
<p>Could not resolve all dependencies for configuration &#39;:compileClasspath&#39;.</p>
<p>Failed to calculate the value of task &#39;:compileJava&#39; property &#39;javaCompiler&#39;.</p>
<p>Cannot find a Java installation on your machine matching this tasks requirements: {languageVersion=17, vendor=any, implementation=vendor-specific} for MAC_OS on aarch64.</p>
<p>No locally installed toolchains match and toolchain download repositories have not been configured.</p>
<p>대충 해석해보면,
일치하는 java를 찾을 수 없다는 것인데요.<img src="https://velog.velcdn.com/images/heejae-l/post/0d38b4d0-9111-4de2-ba1d-7c31ea929596/image.png" alt=""></p>
<p>이렇게 17버전을 쓴다고 해놓고 정작 jdk버전 19로 설정되어있어서 그런 것 아닐까 하는 생각이 들었습니다.</p>
<hr>
<h3 id="자바-버전-확인">자바 버전 확인</h3>
<p>터미널에 아래 명령어를 실행해 현재 저의 자바 버전을 확인했습니다.</p>
<pre><code>&gt; java --version</code></pre><p>19버전이 메인 버전으로 설정되어있다는 것을 확인했습니다.</p>
<p>컴퓨터의 깔려있는 모든 sdk를 확인하기 위해서는 아래의 명령어를 실행하면 됩니다.</p>
<pre><code>&gt; /usr/libexec/java_home -V</code></pre><p>원하는 자바 버전이 없다면 brew를 통해 설치할 수 있습니다.</p>
<pre><code>&gt; brew info openjdk@17   </code></pre><p>저는 17버전을 깔았습니다.</p>
<hr>
<h3 id="자바-환경변수-설정">자바 환경변수 설정</h3>
<p>자바 17버전을 메인으로 설정해주기 위해서 환경변수를 설정해주었습니다.
꼭 메인으로 설정하지 않더라도 프로젝트 생성은 가능할 듯 합니다.</p>
<pre><code>&gt; vi ~/.zshrc</code></pre><p>위의 명령어로 vi를 열어줍니다
i를 눌러 INSERT(수정)모드로 바꿔주고</p>
<pre><code>export PATH=$HOME/bin:/usr/local/bin:$PATH
export JAVA_HOME=/Library/Java/JavaVirtualMachines/openjdk-17.jdk/Contents/Home</code></pre><p>이거를 추가해줍니다.
경로이름을 모르겠다 하시는 분은 직접 파인더를 열어</p>
<blockquote>
<p>Library/Java/JavaVirtualMachines</p>
</blockquote>
<p>들어가면 확인할 수 있습니다</p>
<p>변경하고 나면
esc 누르고 :wq를 입력해 저장하고 나가줍니다.</p>
<p>위에 변경한 내용을 적용해줘야합니다.</p>
<pre><code>&gt; source ~/.zshrc</code></pre><p>터미널에 입력해 환경변수를 적용해주면 됩니다.</p>
<hr>
<h3 id="버전-재확인">버전 재확인</h3>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/60ffa726-48c5-4296-81bf-ff8f86e10f26/image.png" alt=""></p>
<p>정상적으로 변경된 것을 확인할 수 있습니다.</p>
<hr>
<h3 id="해결">해결!</h3>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/caaad418-f6fc-4269-ae32-65f329b7ae36/image.png" alt=""></p>
<p>끝.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[백엔드 개념 공부/정리]]></title>
            <link>https://velog.io/@heejae-l/%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%85%90-%EA%B3%B5%EB%B6%80%EC%A0%95%EB%A6%AC</link>
            <guid>https://velog.io/@heejae-l/%EB%B0%B1%EC%97%94%EB%93%9C-%EA%B0%9C%EB%85%90-%EA%B3%B5%EB%B6%80%EC%A0%95%EB%A6%AC</guid>
            <pubDate>Sat, 13 Jul 2024 10:28:50 GMT</pubDate>
            <description><![CDATA[<p>백엔드를 처음 공부하고있기 때문에 헷갈리는 개념이 많아서 정리합니다.</p>
<h2 id="웹서버-vs-웹-어플리케이션-서버">웹서버 vs. 웹 어플리케이션 서버</h2>
<p><strong>웹서버</strong>(Web server): <strong>정적 컨텐츠</strong>를 처리. HTML, CSS, JavaScript파일. 처음 페이지가 실행됐을 때. 보통 http요청을 직접 받는(엔드포인트) 역할을 수행. 보안 등 http통신 관리. 어플리케이션 서버로 요청 전달.</p>
<p>예) apache, nginx</p>
<p><strong>어플리케이션 서버</strong>(WAS): <strong>동적 컨텐츠</strong> 처리. 정보 조회, 로그인 등등.</p>
<p>예) Node.js
<img src="https://velog.velcdn.com/images/heejae-l/post/1bcb9c92-e331-4fb5-8292-ea0ed29fdd10/image.png" alt=""></p>
<h2 id="http-요청이-처리되는-과정">http 요청이 처리되는 과정</h2>
<p>웹서버에게 http요청이 들어옴</p>
<p>→ 정적 컨텐츠일 경우 웹서버가 파일을 찾아 반환</p>
<p>→ 동적 컨텐츠일 경우 요청을 어플리케이션 서버로 전달</p>
<p>→어플리케이션 서버는 요청을 처리, 응답 생성</p>
<p>→응답을 웹서버에 전달</p>
<p>→웹 브라우저가 응답을 해석하고 화면에 표시(client side javascript가 처리)</p>
<p><strong>웹브라우저:</strong> 콘텐츠 렌더링, 사용자 인터페이스, 자바스트립트 파일 실행, http통신 관리, 세션 관리, 보안, 멀티미디어 재생 기능 수행</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[딥러닝]아나콘다 start error 고치는 여정]]></title>
            <link>https://velog.io/@heejae-l/%EB%94%A5%EB%9F%AC%EB%8B%9D%EC%95%84%EB%82%98%EC%BD%98%EB%8B%A4-start-error-%EA%B3%A0%EC%B9%98%EB%8A%94-%EC%97%AC%EC%A0%95</link>
            <guid>https://velog.io/@heejae-l/%EB%94%A5%EB%9F%AC%EB%8B%9D%EC%95%84%EB%82%98%EC%BD%98%EB%8B%A4-start-error-%EA%B3%A0%EC%B9%98%EB%8A%94-%EC%97%AC%EC%A0%95</guid>
            <pubDate>Fri, 21 Jun 2024 15:17:59 GMT</pubDate>
            <description><![CDATA[<p>딥러닝 프로젝트 1일차(ㅋㅋ) 코랩 무료버전에 한계를 느끼고 아나콘다와 주피터 노트북으로 개발하기로 결심했습니다.</p>
<p>아나콘다를 정상적으로 다운받았다고 생각했는데 아래 오류때문에 실행이 되지 않았습니다.</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/e69e2edd-2c9f-45b6-9647-f3a4ba0e4204/image.png" alt=""></p>
<h3 id="bytes-object-has-no-attribute-get-에러">&#39;bytes&#39; object has no attribute &#39;get&#39; 에러..</h3>
<p>터미널을 통해 접속해도 같은 문제가 발생했습니다.</p>
<p>구글에 검색했더니 같은 문제를 겪는 사람이 엄청(!!)많았습니다.
<a href="https://github.com/ContinuumIO/anaconda-issues/issues/13288">https://github.com/ContinuumIO/anaconda-issues/issues/13288</a></p>
<p>정리하자면 몇 가지 방법이 있는 것 같았습니다.</p>
<h2 id="1-아나콘다를-삭제-후-재설치">1. 아나콘다를 삭제 후 재설치</h2>
<p>답변 중 대부분은 다시 깔아보라는 내용이었습니다.</p>
<p>지우는 법은 간단합니다.
finder에서 Macintosh HD로 들어갑니다.
opt폴더를 찾습니다
(숨겨져있기 때문에 cmd+shift+. 로 숨김폴더를 확인해야합니다)
<img src="https://velog.velcdn.com/images/heejae-l/post/31d35516-bab6-4738-b265-689468f0a000/image.png" alt=""></p>
<p>위와 같이 opt폴더로 들어갔다면 anaconda3라는 폴더가 보일텐데 그냥 삭제해주면 됩니다. 
<img src="https://velog.velcdn.com/images/heejae-l/post/5f5c3453-be11-45b5-b2cb-f0fea2b8cede/image.png" alt="">
응용 프로그램에서도 anaconda-Navigator를 지워주면 됩니다.</p>
<p>이후 다운로드 파일을 이용해 다시 설치할 수 있습니다.</p>
<h3 id="결론적으로-저는-실패했습니다">결론적으로 저는 실패했습니다.</h3>
<p>미련이 남아서 3번이나 재설치했는데 안됐습니다.</p>
<h2 id="2-아나콘다-업데이트">2. 아나콘다 업데이트</h2>
<p>두번째는 아나콘다를 업데이트하는 방법입니다.
터미널을 통해 아래 명령어를 입력합니다.</p>
<pre><code>conda update anaconda-navigator</code></pre><p>파이썬의 버전과 아나콘다의 버전이 맞지 않아서 문제가 될 때 사용할 수 있는 코드인 듯 합니다.</p>
<p>근데 conda 명령어가 동작하지 않는 저로서는 같은 오류가 반복 될 뿐이었습니다.</p>
<p>하지만 한가지 수확이 있었는데, 에러 메시지에서 <strong>권한</strong> 관련 문제를 발견한 것입니다. </p>
<blockquote>
<p>PermissionError: [Errno 13] Permission denied: &#39;/Users/LeeHeejae/.config/conda/.condarc&#39;</p>
</blockquote>
<p><strong>그러면 sudo를 이용해 conda를 실행할 수 있지 않을까???</strong></p>
<h2 id="3-sudo-권한-이용하기">3. sudo 권한 이용하기</h2>
<pre><code>sudo conda</code></pre><p>일단 콘다가 실행됐습니다.
 <img src="https://velog.velcdn.com/images/heejae-l/post/fe0b64d0-1a06-48c5-bcd4-e07e0cd20458/image.png" alt=""></p>
<p>하지만 이런 방법은 터미널로만 아나콘다를 이용해야 하기 때문에 불편합니다. sudo를 매번 붙여주고 비밀번호도 써줘야해서 더더 불편합니다. </p>
<p>오기가 생겼습니다.
또한 예전부터 sudo로만 실행되는 오류가 항상 있어서 고쳐야겠다고 생각했습니다.</p>
<h1 id="최종-config에-대한-권한-얻기">최종 .config에 대한 권한 얻기</h1>
<p>이쯤 되니 미룬 구몬 숙제같은.. sudo를 해결하지 않았던 것에 대한 업보 청산에 가까웠습니다..</p>
<p>30분가량 구글링한 결과
<a href="https://apple.stackexchange.com/questions/320682/ownership-of-the-config-folder-in-home-directory">https://apple.stackexchange.com/questions/320682/ownership-of-the-config-folder-in-home-directory</a></p>
<pre><code>sudo chown -R &lt;username&gt; .config</code></pre><p>이런 간단한 코드로 해결할 수 있더군요</p>
<p><img src="https://velog.velcdn.com/images/heejae-l/post/475bba13-73d7-48b3-83bd-1afd15925903/image.png" alt="">
이거지예..</p>
<p>모든 &#39;bytes&#39; object has no attribute &#39;get&#39;에러가 이런 방식으로 해결될 수 있을지는 모르겠습니다. </p>
<p>에러 메시지도 좀 더 뜯어봐야겠지만 딥러닝 프로젝트를 시작할 수 있게 된 것 만으로 만족합니다.</p>
<p>뭘 하든 개발환경 만드는 게 제일 어렵네요.. 끝!![]</p>
]]></description>
        </item>
    </channel>
</rss>