<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>라이징개발자</title>
        <link>https://velog.io/</link>
        <description>개발자기 되기 위해선 무엇이든!</description>
        <lastBuildDate>Thu, 11 Apr 2024 13:16:59 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>라이징개발자</title>
            <url>https://velog.velcdn.com/images/rising_developer/profile/b0d9322b-4e9e-40a1-a3d7-a06458d2a90c/image.jpeg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. 라이징개발자. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/rising_developer" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[[알고리즘] 백준 11048 이동하기 ]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-11048-%EC%9D%B4%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-11048-%EC%9D%B4%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 11 Apr 2024 13:16:59 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/14b396eb-a284-4b1e-a703-6ea13b83b85b/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>처음에는 bfs로 푸려고 했으나 당연히 메모리 및 시간 초과... 배열의 크기가 클때는 완전탐색은 하지말자 ㅠㅠ...다이나믹 프로그래밍을 사용하는 경우를 정리를 잘 해놔야할 것 같다. 배열의 크기가 크고 누적값을 구하거나 기존 값의 영향을 받는거면 사용한다!</p>
<p>그래서 다이나믹 프로그래밍으로 풀어주었다. (r+1, c), (r, c+1), (r+1, c+1) 이런 방식으로만 이동할 수 있으니 반대로 (r-1, c), (r, c-1), (r-1, c-1)을 확인해주면서 가장 큰 값을 가져오게 했다.</p>
<pre><code>import sys
from collections import deque


n, m = map(int, input().split())
lst =[[0]*(m+1)] + [[0]+list(map(int, input().split()))+[0] for i in range(n)] + [[0]*(m+1)]

dp = [[0]*(m+2) for _ in range(n+2)]
dp[1][1] = lst[1][1]


for i in range(1, n+1):
    for j in range(1, m+1):
        dp[i][j] = lst[i][j] +max(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])

print(dp[n][m])</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘]백준 17141 연구소2]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%B0%B1%EC%A4%80-17141-%EC%97%B0%EA%B5%AC%EC%86%8C2</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%B0%B1%EC%A4%80-17141-%EC%97%B0%EA%B5%AC%EC%86%8C2</guid>
            <pubDate>Thu, 11 Apr 2024 12:31:21 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/d8005885-48f9-4b6e-82b4-bc82da2549d2/image.png" alt=""></p>
<p>처음에 dfs를 통해 바이러스가 들어갈 자리를 구하다가 시간초과가 나서 파이썬 라이브러리 combination을 통해서 풀어주었다. 해결과정에서 선택되지 않은 바이러스를 놓을 수 있는자리를 어떻게 처리할까 싶어서 바이러스가 놓인 자리를 3으로 만들어주고 그 외에 바이러스가 놓일 수 있는 자리들을 같이 바꿔주었다.</p>
<pre><code>import sys
from collections import deque
from itertools import combinations


n,m = map(int, input().split())

lst = [list(map(int, input().split())) for _ in range(n)]

dx = [-1,1,0,0]
dy = [0,0,-1,1]

visited = [[False] * n for _ in range(n)]
t = []
for i in range(n):
    for j in range(n):
        if lst[i][j] ==2:
            t.append((i,j,3))

if(not t) :
    print(0)
    exit()
answer = int(1e9)
def bfs(array, visited, row):
    global answer
    q = deque(array)
    while q:
        x, y, count = q.popleft()
        visited[x][y] == True
        if count &gt;= answer:
            return int(1e9)
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx &lt; 0 or ny &lt; 0 or nx &gt;=n or ny &gt;= n or visited[nx][ny] == True:
                continue
            if row[nx][ny] == 0 or row[nx][ny] == 2  :
                visited[nx][ny] = True
                row[nx][ny] = count+1
                q.append((nx,ny,count+1))
    for ddd in row:
        if 0 in ddd or 2 in ddd:
            count = int(1e9)
    return count

combination = list(combinations(t, m))

for i in combination:
    v = [[False] * n for _ in range(n)]
    br = [row[:] for row in lst]
    for (x,y,z) in i:
        br[x][y] = 3

    answer = min(answer, bfs(i, v, br))

if answer != int(1e9):
    print(answer-3)
else:
    print(-1)
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[기타] 리눅스 기본 명령어 15가지]]></title>
            <link>https://velog.io/@rising_developer/%EA%B8%B0%ED%83%80-%EB%A6%AC%EB%88%85%EC%8A%A4-%EA%B8%B0%EB%B3%B8-%EB%AA%85%EB%A0%B9%EC%96%B4-15%EA%B0%80%EC%A7%80</link>
            <guid>https://velog.io/@rising_developer/%EA%B8%B0%ED%83%80-%EB%A6%AC%EB%88%85%EC%8A%A4-%EA%B8%B0%EB%B3%B8-%EB%AA%85%EB%A0%B9%EC%96%B4-15%EA%B0%80%EC%A7%80</guid>
            <pubDate>Thu, 11 Apr 2024 08:53:42 GMT</pubDate>
            <description><![CDATA[<h2 id="📌서론">📌서론</h2>
<p>AWS로 배포를 하고 프로젝트를 진행하면서 리눅스의 명령을 사용할때가 정말 많다. 그래서 기본적인 리눅스 명령어를 공부하고자 정리한다.</p>
<h2 id="📌ls">📌ls</h2>
<p>List의 약자로 windows 명력 프롬프트의 dir 명령과 같은 역할을 한다. 즉 해당 디렉터리에 있는 파일의 목록을 나열하는 명령어.
[예시]
<img src="https://velog.velcdn.com/images/rising_developer/post/ac39c6a6-7963-4af1-804d-67d5aa7d65c5/image.png" alt=""></p>
<h2 id="📌cd">📌cd</h2>
<p>Change Directory의 약자로 디렉터리를 이동하는 명령어
[예시]
<img src="https://velog.velcdn.com/images/rising_developer/post/a2dbe3f4-76da-4b5d-830c-e5d1bf95c76f/image.png" alt=""></p>
<h2 id="📌pwd">📌pwd</h2>
<p>Pring Working Directory의 약자로 현재 디렉터리의 전체 경로를 화면에 표시
<img src="https://velog.velcdn.com/images/rising_developer/post/ae198dc0-6502-4b83-80a2-3d907fe02981/image.png" alt=""></p>
<h2 id="📌rm">📌rm</h2>
<p>ReMove의 약자로 파일이나 디렉터리를 삭제. 당연히 파일이나 디렉터리를 삭제할 권한이 있어야 해당 명령을 실행할 수 있다. 단 root 사용자는 모든 권한이 있으므로 rm 명령 사용에 제약이 없음
<img src="https://velog.velcdn.com/images/rising_developer/post/bfa8d820-3b73-4bab-b01d-218ce6eeb721/image.png" alt=""></p>
<h2 id="📌cp">📌cp</h2>
<p>CoPy의 약자로 파일이나 디렉터리를 복사한다. 새로 복사한 파일은 복사한 사용자의 소유가 되므로 명령을 실행하는 사용자는 해당 파일의 읽기 권한이 필요하다.
<img src="https://velog.velcdn.com/images/rising_developer/post/f32430e1-89ab-4aef-ac6d-a361cbad7321/image.png" alt=""></p>
<h2 id="📌touch">📌touch</h2>
<p>크기가 0인 새 파일을 생성하거나 생성된 파일이 존재한다면 파일의 최종 수정 시간을 변경
<img src="https://velog.velcdn.com/images/rising_developer/post/fd8d6530-7de7-427f-af32-7754a6726ca6/image.png" alt=""></p>
<h2 id="📌mv">📌mv</h2>
<p>move의 약자로 파일이나 디렉터리의 이름을 변경하거나 다른 디렉터리로 옮길 때 사용한다.
<img src="https://velog.velcdn.com/images/rising_developer/post/9a8778bc-6883-4792-b8d3-874022e43a82/image.png" alt=""></p>
<h2 id="📌rmdir">📌rmdir</h2>
<p>ReMove DIRectory의 약자로 디렉터리를 삭제한다. 해당 디렉터리의 삭제 권한이 있어야 하며 디렉터리는 비어 있어야 함. 파일이 있는 디렉터리를 삭제하려면 rm -r 명령을 실행
<img src="https://velog.velcdn.com/images/rising_developer/post/009d4534-34cd-4ec7-955a-2cac3ea71036/image.png" alt=""></p>
<h2 id="📌rmdir-1">📌rmdir</h2>
<p>conCATenate의 약자로 파일 내용을 화면에 출력한다 여러 파일을 나열하면 파일을 연결해서 출력
<img src="https://velog.velcdn.com/images/rising_developer/post/6c4da9ab-d378-4a3f-a950-22316fc9eed7/image.png" alt=""></p>
<h2 id="📌head-tail">📌head, tail</h2>
<p>텍스트 형식으로 작성된 파일의 앞 10행 또는 마지막 10행만 화면에 출력
<img src="https://velog.velcdn.com/images/rising_developer/post/8d6232f5-a23c-478c-8a5f-c7aaa67506bb/image.png" alt=""></p>
<h2 id="📌more">📌more</h2>
<p>텍스트 형식으로 작성된 파일을 페이지 단위로 화면에 출력. [Space]를 누르면 다음 페이지로 이동하며, [B]를 누르면 앞 페이지로 이동한다. [Q]를 누르면 명령을 종료
<img src="https://velog.velcdn.com/images/rising_developer/post/29005055-6e8f-4ba6-8ee9-02f503953fe4/image.png" alt=""></p>
<h2 id="📌less">📌less</h2>
<p>more 명령과 용도가 비슷하지만, 기능이 더 확장되어 있다. more에서 사용하는 키와 더불어 화살표 키나 [PageUp], [PageDown]도 사용할 수 있음.
<img src="https://velog.velcdn.com/images/rising_developer/post/0f83392e-463c-40b8-b7b6-c7d1ba573a21/image.png" alt=""></p>
<h2 id="📌file">📌file</h2>
<p>파일의 종류를 표시
<img src="https://velog.velcdn.com/images/rising_developer/post/55fd1349-991d-41ab-ac30-ca577e673fa6/image.png" alt=""></p>
<h2 id="📌clear">📌clear</h2>
<p>현재 사용 중인 터미널 화면을 깨끗하게 지운다.
<img src="https://velog.velcdn.com/images/rising_developer/post/26b96c1b-9450-4a14-8fb4-005d0757a7d5/image.png" alt=""></p>
<p>출처 . <a href="https://m.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS6390061632">https://m.hanbit.co.kr/channel/category/category_view.html?cms_code=CMS6390061632</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 1600 말이 되고픈 원숭이]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1600-%EB%A7%90%EC%9D%B4-%EB%90%98%EA%B3%A0%ED%94%88-%EC%9B%90%EC%88%AD%EC%9D%B4</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1600-%EB%A7%90%EC%9D%B4-%EB%90%98%EA%B3%A0%ED%94%88-%EC%9B%90%EC%88%AD%EC%9D%B4</guid>
            <pubDate>Mon, 08 Apr 2024 12:55:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/8ac29408-a4c2-4695-88d3-055320f64535/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>말처럼 이동하는 부분과 변사이를 이동할때를 두개 다 넣어주되, k번을 넘지 않도록 해준다.
k번 넘은 여부는 이전에 벽 부수고 이동하기 처럼 visited배열을 3차원으로 만들어줘서 넘은 여부를 확인해준다.
3차원 배열 기억하기 -&gt; [[[False] * (k+1) for _ in range(201)] for _ in range(201]</p>
<pre><code>import sys
from collections import deque

k = int(input())
w, h = map(int, input().split())
lst = [list(map(int, input().split())) for _ in range(h)]
visited = [[[0] * (k+1) for _ in range(201)] for _ in range(201)]
# visited = [[False]* 201 for _ in range(201)]
visited[0][0][0] == True
dx = [-1,1,0,0]
dy = [0,0,-1,1]

hx = [2,2,-2,-2,1,1,-1,-1]
hy = [1,-1,1,-1,2,-2,2,-2]

def bfs(k, lst):
    q = deque()
    q.append((0,0,0,0))
    while q:
        x,y,count,horse = q.popleft()
        if count &gt; w*h:
            return -1
        if x == h-1 and y == w-1:
            return count
        if horse &lt; k:
            for i in range(8):
                xx = x + hx[i]
                yy = y + hy[i]
                if xx &lt; 0 or yy &lt; 0 or xx &gt;= h or yy &gt;= w:
                    continue
                if lst[xx][yy] != 1 and visited[xx][yy][horse+1] == False:
                    visited[xx][yy][horse+1] = True
                    q.append((xx,yy,count+1, horse+1))
        for i in range(4):
            nx = x + dx[i]
            ny = y + dy[i]
            if nx &lt; 0 or ny &lt; 0 or nx &gt;= h or ny &gt;= w:
                continue
            if lst[nx][ny] == 0 and visited[nx][ny][horse] == False:
                visited[nx][ny][horse] = True
                q.append((nx,ny,count+1, horse))

    return -1

print(bfs(k, lst))
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 5014 스타트링크]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-5014-%EC%8A%A4%ED%83%80%ED%8A%B8%EB%A7%81%ED%81%AC</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-5014-%EC%8A%A4%ED%83%80%ED%8A%B8%EB%A7%81%ED%81%AC</guid>
            <pubDate>Mon, 08 Apr 2024 11:57:22 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/7cdff4ce-6431-4d77-8bb0-dd58318d9d37/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>해당문제는 bfs문을 짜는데는 어렵지 않지만 가지치기 즉 시간을 줄이는 곳에서 고민이 필요하다.</p>
<pre><code>import sys
from collections import deque

f, s, g, u, d = map(int, input().split())
visited = [False] * (f+1)

def bfs(f,s,g,u,d):
    q = deque()
    q.append((s, 0))

    while q:
        now, count  = q.popleft()
        if count &gt; 1000000:
            return &#39;use the stairs&#39;
        if now == g:
            return count
        # 위층을 누르는 경우
        if now+u &lt;= f and u != 0 and visited[now+u] == False:
            visited[now+u] = True
            q.append((now+u, count+1))
        # 아래층을 누르는 경우
        if now-d &gt;= 1 and d != 0 and visited[now - d] == False:
            visited[now - d] = True
            q.append((now-d, count+1))

    return &#39;use the stairs&#39;

print(bfs(f,s,g,u,d))
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 1644 소수의 연속합]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1644-%EC%86%8C%EC%88%98%EC%9D%98-%EC%97%B0%EC%86%8D%ED%95%A9</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1644-%EC%86%8C%EC%88%98%EC%9D%98-%EC%97%B0%EC%86%8D%ED%95%A9</guid>
            <pubDate>Mon, 08 Apr 2024 11:27:27 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/e075f320-849f-498d-918b-7ecfea0763e6/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>먼저 주어진 n보다 작거나 같은 소수들을 리스트로 만들어주고 투포인터로 찾아주면 간단하게 풀린다.</p>
<pre><code>import sys
from collections import deque

n = int(input())

def prime_sieve(n):
    sieve = [True] * (n+1)
    sieve[0] = sieve[1] = False
    for i in range(2, int(n**0.5)+1):
        if sieve[i]:
            for j in range(i*i, n+1, i):
                sieve[j] = False
    primes = [i for i in range(2, n+1) if sieve[i]]
    return primes


def c(lst, target):
    right = 0
    left = 0
    count = 0
    sum = 0
    while right &lt;= len(lst):
        if sum == target:
            count +=1
            sum -= lst[left]
            left += 1
        elif sum &lt; target :
            if right == len(lst):
                break
            sum += lst[right]
            right += 1
        elif sum &gt; target:
            sum -= lst[left]
            left +=1

    return count
lst = prime_sieve(n)
print(c(lst, n))

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 2003 수들의 합2]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-2003-%EC%88%98%EB%93%A4%EC%9D%98-%ED%95%A92</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-2003-%EC%88%98%EB%93%A4%EC%9D%98-%ED%95%A92</guid>
            <pubDate>Sun, 07 Apr 2024 11:08:11 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/da0fe5b3-1511-4a91-91f5-6287157dd69d/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>1차원 배열에서 연속된 배열이나 특정 값을 구하는 문제에서는 투포인터를 사용해서 시간복잡도를 줄일 수 있다.</p>
<pre><code>import sys
input = sys.stdin.readline

n, s = map(int, input().split())
A = list(map(int, input().split()))

def two_sum(nums, target):
    s,e,count = 0,0,0
    sum = nums[0]

    while e &lt; n:
        if sum == target:
            count+=1
            sum -= A[s]
            s +=1
        elif sum &lt; target:
            e += 1
            if e &gt;= n:
                break
            sum += A[e]
        elif sum &gt; target:
            sum -= A[s]
            s +=1
    return count
print(two_sum(A, s))
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 1717 집합의 표현]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1717-%EC%A7%91%ED%95%A9%EC%9D%98-%ED%91%9C%ED%98%84</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1717-%EC%A7%91%ED%95%A9%EC%9D%98-%ED%91%9C%ED%98%84</guid>
            <pubDate>Mon, 01 Apr 2024 13:16:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/9e0e8718-599c-4138-9b78-3475dfd4eb83/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>union, find 함수를 이용해 연결된 부모 찾기를 통해 풀어주었다. 그러나 RecrusionErrorr가 떴는데 재귀 깊이 제한을 풀어주어야한다고 한다.</p>
<p>import sys
sys.setrecursionlimit(1000000)</p>
<pre><code>import sys
sys.setrecursionlimit(1000000) # 재귀 깊이 제한 늘리기
input = sys.stdin.readline

n, m = map(int, input().split())
parent = [i for i in range(n + 1)] # 자기 자신을 부모로 갖는 n + 1개 집합

# 찾기 연산(같은 집합에 속하는지 확인하기 위한 함수)
def find_parent(x):
    if parent[x] != x:
        parent[x] = find_parent(parent[x])
    return parent[x]

# 합집합 연산(두 집합을 합치기 위한 함수)
def union_parent(a, b):
    a = find_parent(a)
    b = find_parent(b)
    if a &lt; b: # 값이 더 작은 쪽을 부모로
        parent[b] = a
    else:
        parent[a] = b

for _ in range(m):
    opr, a, b = map(int, input().split())
    if opr == 0:
        union_parent(a, b)
    else:
        if find_parent(a) == find_parent(b):
            print(&quot;YES&quot;)
        else:
            print(&quot;NO&quot;)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 12865 평범한 배낭]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-12865-%ED%8F%89%EB%B2%94%ED%95%9C-%EB%B0%B0%EB%82%AD</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-12865-%ED%8F%89%EB%B2%94%ED%95%9C-%EB%B0%B0%EB%82%AD</guid>
            <pubDate>Mon, 01 Apr 2024 12:48:46 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/0a088ef0-5c32-4e09-b7c4-1455895515a4/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>유명한 냅색 알고리즘을 통해서 dp 를 활용해 풀어주어야한다.</p>
<pre><code>n,k = map(int, input().split())

lst = [list(map(int, input().split())) for _ in range(n)]
dp = [[0]*(k+1) for _ in range(n+1)]
mx = 0

for i in range(1, n+1):
    for j in range(1,k+1):
        if j &gt;= lst[i-1][0]:
            dp[i][j] = max(lst[i-1][1]+dp[i-1][j-lst[i-1][0]], dp[i-1][j])
        else:
            dp[i][j] = dp[i-1][j]
print(dp[n][k])</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] JAVA]]></title>
            <link>https://velog.io/@rising_developer/CS-JAVA</link>
            <guid>https://velog.io/@rising_developer/CS-JAVA</guid>
            <pubDate>Mon, 01 Apr 2024 10:47:45 GMT</pubDate>
            <description><![CDATA[<p>Ref. <a href="https://mangkyu.tistory.com/94">https://mangkyu.tistory.com/94</a></p>
<p>[JAVA의 장점과 단점]
장점</p>
<ul>
<li>JVM 위에서 동작하기 때문에 운영체제에 독립적이다.</li>
<li>가비지컬렉터가 메모리를 관리해주기 때문에 편리하다.</li>
</ul>
<p>단점</p>
<ul>
<li>JVM 위에서 동작하기 때문에 실행 속도가 상대적으로 느리다.</li>
<li>다중 상속이나 타입에 업격하는 등 제약이 있는 것이 많다.</li>
</ul>
<p>[ 원시 타입과 참조 타입의 차이 ]
원시 타입은 실제 값을 저장하기 위한 타입입니다. 예를 들어 int a = 1과 같이 코드를 작성했다면, JVM의 스택 영역에 a라는 변수의 값이 할당됩니다.
참조 타입은 기본 타입을 제외한 타입으로, 객체의 주소를 저장하는 타입입니다. 예를 들어 Integer b = 1과 같이 코드를 작성했다면, JVM의 힙 영역에는 실제 객체가 저장되고, 스택에는 해당 객체의 주소를 저장한다. 그래서 객체를 사용할 때마다 참조 변수에 저장된 객체의 주소를 불러와 사용하게 됩니다.
즉, 원시 타입은 스택 영역에 생성되지만, 참조 타입은 힙 영역에 생성됩니다. 또한 원시 타입의 경우 메모리를 훨씬 적게 사용합니다. boolean은 1비트, byte는 8비트, short는 16비트, int는 32비트를 사용합니다. 그 외에도 원시 타입은 실제 값을 저장하기 때문에 null을 담을 수가 없습니다.</p>
<p>[ Java가 다중 상속을 지원하지 않는 이유 ]
다중 상속을 지원하면 다이아몬드 문제가 발생할 수 있기 때문입니다. 예를 들어 Human 클래스에 있는 walk() 메소드를 Female 클래스와 Male 클래스가 모두 구현하였다고 할 때, Female과 Male 클래스를 다중 상속 받은 Person 클래스의 입장에서는 코드의 충돌이 생기기 때문입니다.
<img src="https://velog.velcdn.com/images/rising_developer/post/fd3ce6ce-cd89-42a9-bf1a-87190afeeb9d/image.png" alt=""></p>
<p>[ 오버라이딩(Overriding)과 오버로딩(Overloading) ]</p>
<p>오버라이딩(Overriding): 상위 클래스가 가지고 있는 메소드를 하위 클래스에서 재정의하여 사용하는 기술
오버로딩(Overloading): 매개변수의 타입과 개수를 변경하면서 같은 이름의 메소드를 여러 개 사용하는 기술
<img src="https://velog.velcdn.com/images/rising_developer/post/ddb26ea9-915c-44e5-a924-a1c7a5010eba/image.png" alt=""></p>
<p>[ 클래스(Class), 객체(Object), 인스턴스(Instance)의 개념 ]</p>
<p>클래스(Class): 객체를 만들어내기 위한 설계도 혹은 틀
객체(Object): 설계도(클래스)를 기반으로 선언된 대상, 클래스의 인스턴스라고도 부름
인스턴스(Instance): 객체에 메모리가 할당되어 실제로 활용되는 실체
<img src="https://velog.velcdn.com/images/rising_developer/post/828f93a2-e633-4de4-8294-a846fa2da646/image.png" alt=""></p>
<p>[ 싱글톤 패턴(Singleton Pattern) 구현 및 사용 이유 ]
<img src="https://velog.velcdn.com/images/rising_developer/post/8f13dbf5-bcce-4596-af25-7d319c625e6e/image.png" alt="">
 
싱글톤 패턴은 단 하나의 인스턴스를 생성하여 사용하는 디자인패턴입니다. 싱글톤패턴은 아래의 경우에 사용합니다.</p>
<ul>
<li>해당 인스턴스가 절대적으로 1개만 존재한다는 것을 보증하고 싶은 경우</li>
<li>동일한 인스턴스를 자주 생성해주어야 하는 경우(메모리 낭비의 방지)</li>
</ul>
<p>하지만 이러한 싱글톤 패턴은 객체 지향 설계의 원칙에 적합하지 않으며, LifeCycle 제어가 힘들고, 멀티스레드 환경에서 여러 개의 객체가 생성되는 문제가 발생할 수 있습니다. 그러한 이유로 멀티스레드 환경이라면 static 앞에 synchronized 키워드를 붙여 동기화 작업을 추가해주어야 합니다.(당연히 성능이 저하됩니다).</p>
<p>[ 추상클래스와 인터페이스의 차이 ]</p>
<ul>
<li><p>추상클래스
단일 상속만이 가능하다.
모든 접근 제어자를 사용할 수 있다.
변수와 상수를 선언할 수 있다.
추상 메소드와 일반 메소드를 선언할 수 있다.</p>
</li>
<li><p>인터페이스
다중 구현이 가능하다.
public 접근 제어자만 사용할 수 있다.
상수만 선언할 수 있다.
추상메소드만 선언할 수 있다.</p>
</li>
</ul>
<p>[ Java의 List, Set, Map 차이 ]</p>
<ul>
<li><p>List
데이터를 순차적으로 저장한다.
데이터의 중복을 허용한다. 
데이터로 null을 허용한다.</p>
</li>
<li><p>Set
순서없이 Key로만 데이터를 저장한다.
Key의 중복을 허용하지 않는다.
Key로 null을 허용하지 않는다.</p>
</li>
<li><p>Map
순서없이 Key, Value로 데이터를 저장한다.
Value는 중복을 허용하지만 Key의 중복을 허용하지 않는다.
Key로 null을 허용하지 않는다.</p>
</li>
</ul>
<p>[ Java의 Vector와 ArrayList 차이 ]</p>
<p>Vector</p>
<p>동기화를 지원한다.
속도가 느리지만 병렬 상황에서 안전하다.
크기가 증가하는 경우, 2배 증가함(10 -&gt; 20)</p>
<p>ArrayList</p>
<p>동기화를 지원하지 않는다.
속도는 빠르지만 병렬 상황에서 안전하지 않다.
크기가 증가하는 경우, 1.5배 증가함(10 -&gt; 15)</p>
<p> 
 
[ Java의 StringBuffer와 StringBuilder 차이 ]</p>
<p>StringBuffer</p>
<p>동기화를 지원한다.
속도가 느리지만 병렬 상황에서 안전하다.</p>
<p>StringBuilder</p>
<p>동기화를 지원하지 않는다.
속도는 빠르지만 병렬 상황에서 안전하지 않다.</p>
<p> 
[ synchronized란? ]
Java에서 지원하는 synchronized 키워드는 여러 쓰레드가 하나의 자원을 이용하고자 할 때, 한 스레드가 해당 자원을 사용중인 경우, 데이터에 접근할 수 없도록 막는 키워드입니다. synchronized 키워드를 이용하면 병렬 상황에서 자원의 접근을 안전하게 하지만, 자원을 이용하지 않는 쓰레드는 락에 의한 병목현상이 발생하게 됩니다.</p>
<p>메소드 synchronized: 한 시점에 하나의 쓰레드만이 해당 메소드를 실행할 수 있다.
변수 synchronized: 한시점에 하나의 쓰레드만이 해당 변수를 참조할 수 있다.</p>
<p> 
[ Java의 String과 불변 ]
자바의 String은 불변성을 가지고 있습니다. 자바의 스트링이 불변으로 만들어진 이유는 다음과 같습니다.</p>
<p>보안
스레드 안정성
캐싱과 효율성
해시 맵 키로 사용 가능
메모리 관리 및 GC 효율성</p>
<p> 
만약 상수로 선언된 문자열이라면, 해당 문자열을 특정 공간에 하나만 복사해두고 사용하여 메모리를 최적화할 수 있는데, 이것을 interning이라고 한다. 이때 JVM이 상수로 선언된 String을 저장하는 곳이 바로 Constant Pool이다. Constant Pool은 힙 위에 올라가므로 GC의 대상이 된다. 저장하고, 해당 주소를 스택에 저장한다.
 
 
[ 자바의 동시성 처리 ]
Java8에서는 함수형 프로그래밍을 위해 함수형 인터페이스와 람다와 함께 stream API가 추가되었고, Null-safe한 작업을 위한 Optional API, Date와 Time을 함께 처리하기 위한 LocalDateTime API 등이 추가되었습니다. 
 
 
[ Java8 ]
기존의 Thread와 Runnable은 반환 타입을 받을 수 없고, 지나치게 저수준 API 코드를 작성해야 하며, 매번 쓰레드를 생성과 종료하는 오버헤드를 감당해야 했습니다.
따라서 이러한 문제를 해결한 Callable과 Future가 등장하게 되었습니다. 하지만 Future는 결과를 얻으려면 블로킹 방식으로 대기를 해야 한다는 단점이 있었고, 그 외에도 콜백의 사용이나 여러 작업들을 중첩시키는 것이 불가능했습니다. 따라서 이러한 부분들을 완전히 보완한 CompletableFuture가 등장하게 되었습니다.
 
 
[ try-with-resources ]
try-with-resources란 Java7 버전에 추가된 기능으로, 리소스를 다 사용한 객체를 자동으로 반납(close)해줍니다. try-with-resources를 사용하면 코드가 try-finally보다 유연해지며, try-finally에서와 달리 누락없이 모든 자원을 반납할 수 있습니다.
try-with-resources를 통해 객체가 자동으로 반납되기 위해서는 AutoCloseable 인터페이스를 구현하고 있어야 합니다. 
 
 
[ Stream API의 장점과 단점 ]</p>
<p>장점</p>
<p>코드를 간결하게 작성하여 가독성을 높일 수 있다.
병렬스트림과 같은 기술을 이용하면 처리 속도를 많이 높일 수 있다.</p>
<p>단점</p>
<p>잘못 사용하면 기존의 Java 방식보다 오히려 성능이 떨어질 수 있다.
코드들이 추상화되어 있어 실수가 발생할 수 있다.</p>
<p>[JAVA의 동작 과정]
<img src="https://velog.velcdn.com/images/rising_developer/post/865c3cf2-3045-4528-bdca-b45b322ec791/image.png" alt=""></p>
<ol>
<li>Java 소스 파일을 javac로 컴파일하여 class파일(Java 바이트 코드)을 생성함</li>
<li>클래스로더가 컴파일된 Java 바이트 코드를 런타임 데이터 영역(Runtime Data Areas)로 로드함</li>
<li>실행 엔진(Execution Engine)이 자바 바이트코드를 실행함</li>
</ol>
<p>[JVM의 구조]
<img src="https://velog.velcdn.com/images/rising_developer/post/099981e7-5e7c-412f-b66d-2deea53bf1ef/image.png" alt="">
JVM의 구조 중 메모리 구조는 다음과 같이 구성됩니다.</p>
<ul>
<li>Method Area(메소드 영역): 클래스 변수의 이름, 타입, 접근 제어자 등과 같은 클래스와 관련된 정보를 저장한다. 그 외에도 static 변수, 인터페이스 등이 저장된다.</li>
<li>Heap Area(힙 영역): new를 통해 생성된 객체와 배열의 인스턴스를 저장하는 곳이다. 가비지 컬렉터는 힙 영역을 청소하며 메모리를 확보한다.</li>
<li>Stack Area(스택 영역): 메소드가 실행되면 스택 영역에 메소드에 대한 영역이 1개 생긴다. 이 영역에 지역변수, 매개변수, 리턴값 등이 저장된다.</li>
<li>PC register(PC 레지스터): 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장한다.(CPU의 레지스터와 다르다.)</li>
<li>Native Method Stack(네이티브 메소드 스택): 자바 외의 언어(C, C++ 등)로 작성된 코드를 위한 메모리 영역이다. JNI를 통해 사용된다.</li>
</ul>
<p>[ OOM이란? ]
OOM은 JVM이 힙 메모리에 새로운 객체를 할당할 수 없을 때 발생하는 에러입니다.
자바 애플리케이션을 실행되면서 동적으로 만들어진 객체는 힙 메모리에 저장됩니다. 해당 객체들은 다른 객체나 메소드에 의해 참조될 수 있습니다. 그러다가 해당 객체에 대한 참조가 사라지면 해당 객체는 가비지로 인식되고, 가비지 컬렉터에 의해 청소됩니다.
그런데 가비지 컬렉터에 의해 힙 메모리가 청소되지 않으면 해당 메모리가 계속 쌓이고 , 새로운 객체를 힙 메모리에 할당하는 것이 불가능해집니다. 이러한 경우에 발생하는 것이 OOM입니다.
 
 
 
[ 가비지 컬렉터(Garbage Collector)란? ]
&#39;더이상 참조되지 않는 메모리&#39;인 가비지를 청소해주는 JVM의 실행 엔진의 한 요소입니다. JVM은 new와 같은 연산에 의해 새롭게 생성된 객체들 중에서 더이상 참조되지 않는 객체를 정리해줍니다. 가비지 컬렉터는 Heap 영역을 위주로 탐색하며 메모리를 정리해줍니다.</p>
<p>[ 가비지 컬렉션(Garbage Collection)의 과정 ]
가비지 컬렉션(GC)은 메모리를 정리하는 과정입니다. 그렇기 때문에 일반적으로 메모리의 사용을 중단한 채로 진행이 되어야 합니다. JVM은 GC를 실행하기 위해 애플리케이션의 실행을 멈추는 stop-the-world를 먼저 실행하게 됩니다. stop-the-world를 실행하면 GC를 실행하는 쓰레드를 제외한 모든 쓰레드가 작업을 멈춥니다. 그리고 GC가 끝나면 다시 작업을 재개합니다. GC의 작업은 Young 영역에 대한 Minor GC와 Old 영역에 대한 Major GC로 구분됩니다.
 </p>
<ul>
<li>Young 영역: 새롭게 생성한 객체들이 위치한다. 대부분의 객체는 금방 접근 불가능한 상태가 되기 때문에, 많은 객체가 Young 영역에 생성되었다가 사라진다.</li>
<li>Old 영역: Young 영역에서 계속 사용되어 살아남은 객체가 복사되는 영역이다. Young 영역보다 크게 할당되며, 더 적은 GC가 발생한다.
Young 영역은 또 1개의 Eden 영역과 2개의 Survivor 영역으로 구성되는데, Young 영역에 대한 GC는 다음과 같이 작동한다.</li>
</ul>
<p>새로운 객체가 Eden 영역에 생성됨
Eden 영역에 GC가 동작하고, 그 중에서 살아남은 객체가 Survivor0으로 이동함
2번의 동작이 반복되어 Survivor0이 꽉차게 됨
Survivor0 영역에 GC가 동작하고, 살아남은 객체들은 Survivor1으로 이동하고 Survivor0을 비우게 됨
(2개의 Survivor 영역 중 1개는 반드시 비어있어야 됨)
위의 동작들이 반복되어 특정 횟수만큼 살아남은 객체는 Old 영역으로 이동함</p>
<p>그리고 Old 영역이 가득차서 Survivor 영역에서 Old 영역으로 Promotion이 불가능할 때 Old 영역에 대한 GC(Major GC)가 실행됩니다.</p>
<p>[ 가비지 컬렉션(Garbage Collection) 알고리즘의 종류 ]</p>
<ul>
<li>Serial GC: mark-sweep-compact 알고리즘을 사용한다. Old영역에서 살아있는 객체를 식별(Mark)하고, 살아있는 객체만을 남긴다.(Sweep) 그리고 난 후에 객체들을 앞부분부터 채워 객체가 존재하는 부분과 존재하지 않는 부분으로 나눈다.(Compaction) </li>
<li>Parallel GC: 기본적인 알고리즘은 Serial GC와 같지만 여러 쓰레드를 이용하여 GC를 처리한다. </li>
<li>Parallel Old GC(Parallel Compacting GC): Serial GC의 Sweep 알고리즘 대신 Summary를 사용한다. Summary 단계는 앞서 GC를 수행한 영역에 대해서 별도로 살아있는 객체를 식별하며, Sweep보다 조금 더 복잡하다.</li>
<li>Concurrent Mark &amp; Sweep GC(이하 CMS): Initial Mark 단계에서는 살아 있는 객체를 찾는 것으로 끝낸다.(Stop-the-World 시간이 짧음) 그리고 찾은 객체에서 참조하는 객체를 Concurrent하게(여러 쓰레드가 동시에) 따라가는 Concurrent Mark 단계가 수행된다. 그 이후에 Stop-the-World가 실행되고 Concurrent하게 Remark)가 동작한다. 애플리케이션의 응답속도가 매우 중요할 때 사용한다.</li>
<li>G1(Garbage First) GC: 바둑판의 각 영역에 객체를 할당하고 GC를 실행한다. 위에서 설명한 Young영역과 Old영역에 대한 개념을 사용하지 않고, 객체를 할당한다.
<img src="https://velog.velcdn.com/images/rising_developer/post/e9633ef3-38b1-4a54-8bee-0b02dccc8bd1/image.png" alt=""></li>
</ul>
<p>[ 가비지 컬렉터(Garbage Collector) 작동의 문제를 진단하는 방법과 해결 하는 방법은? ]
위의 가비지 컬렉션의 동작 과정을 보면 알겠지만 Survivor 영역 중 하나는 반드시 비어 있는 상태로 남아 있어야 합니다. 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 두 영역 모두 사용량이 0이라면 시스템이 정상적인 상황이 아니라고 생각하면 됩니다.
추가적으로, GC에 대한 로그를 확인하여 옵션을 수정할 지 코드를 수정할 지 정해야 합니다.</p>
<p>[ 가비지 컬렉션(Garbage Collection)에 의한 시스템 중단 시간을 줄이는 방법 ]</p>
<ul>
<li>옵션을 변경하여 GC의 성능을 높이기<ul>
<li>young 영역과 old 영역의 힙 크기를 높여 GC의 빈도를 줄이는 것</li>
<li>객체의 할당과 promotion을 줄이는 것</li>
</ul>
</li>
</ul>
<p>위의 설명 중에서 힙 크기를 높여 GC의 빈도를 줄이는 해결책이 있습니다. 사실 논리적으로만 생각하면 힙의 크기를 높이면, GC 영역이 넓어져 실행시간이 길어지므로 무의미해진다고 생각이들 수 있습니다. 하지만 Minor GC의 실행시간은 힙의 크기보다는 살아남은 객체의 수에 의해 더욱 지연됩니다. 그렇기 때문에 short-lived 객체를 위한 young 영역의 크기를 높인다면 GC의 실행 시간과 호출 빈도를 모두 줄일 수 있습니다.(하지만 만약 애플리케이션에서 long-lived 객체를 많이 사용한다면, survivor영역으로 복제되는 객체가 많아져 GC에 의한 멈추는 시간이 증가할 수 있습니다.)</p>
<ul>
<li>설정을 변경하여 GC의 성능을 높이기<ul>
<li>애플리케이션을 중단시킨 후에 GC를 병렬로 동시에 진행시키는 것</li>
<li>애플리케이션과 GC작업을 동시에(concurrent) 진행시키는 것</li>
</ul>
</li>
</ul>
<p> </p>
<ul>
<li><p>개발자의 코드를 변경하여 GC의 성능을 높이기</p>
<ul>
<li><p>Collection 등을 활용할 때 사용할 객체의 크기를 명시해주기</p>
</li>
<li><p>스트림을 바로 사용하기</p>
<ul>
<li>변경 전: byte[] fileData = readFileToByteArray(new File(&quot;myfile.txt&quot;));</li>
<li>변경 후: FileInputStream fis = new FileInputStream(fileName);</li>
</ul>
</li>
<li><p>불변(Immutable) 객체 사용하기</p>
</li>
</ul>
</li>
</ul>
<p>위의 설명 중에서 불변의 객체를 사용하자는 해결책에 대해 설명하도록 하겠습니다.
<img src="https://velog.velcdn.com/images/rising_developer/post/71ec85b2-bb2e-40d0-b4ac-5eaeda96dbf2/image.png" alt="">
 
만약 위와 같은 MutableHolder가 있다라고 하면, MutableHolder는 계속 다른 값을 참조하여 생존하며 Old 영역으로 이동하게 됩니다. 하지만 Old 영역으로 가서도 참조하는 객체가 바뀌기 때문에, Minor GC를 수행할 때 Old 영역으로 와서 MutableHolder까지 검사하여 Young 영역을 정리해주어야 합니다. 즉, 검사해야 하는 범위가 늘어나게 되는 것입니다. 하지만, 불변의 객체 ImmutableHolder를 사용하게 된다면 상황이 달라집니다. 당연히 ImmutableHolder가 참조하는 값이 먼저 존재해야 ImmutableHolder가 존재할 수 있습니다. 그렇기 때문에 ImmutableHolder가 Old 영역으로 이동하게 되면 MutableHolder Minor GC에 대한 검사를 하지 않아도 되므로, 스캔의 범위를 줄여 성능을 높일 수 있는 것입니다.</p>
<p> </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 1654 랜선 자르기 파이썬]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1654-%EB%9E%9C%EC%84%A0-%EC%9E%90%EB%A5%B4%EA%B8%B0-%ED%8C%8C%EC%9D%B4%EC%8D%AC</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1654-%EB%9E%9C%EC%84%A0-%EC%9E%90%EB%A5%B4%EA%B8%B0-%ED%8C%8C%EC%9D%B4%EC%8D%AC</guid>
            <pubDate>Mon, 18 Mar 2024 13:04:18 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/0a3f0328-d701-4b03-a3bb-31af83c2df9c/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>이진탐색을 활용해 문제를 풀어준다. 이때 count()함수를 따로 만들어 생기는 전선의 갯수를 리턴하고 가장 큰 라인의 절반 값부터 1씩 줄어들게 만들어 값을 구한다</p>
<pre><code>import sys

n, k = map(int, sys.stdin.readline().split())
lines = [int(sys.stdin.readline()) for _ in range(n)]

def count(lines, target):
    count = 0
    for i in lines:
        count+= i // target
    return count

def ejin(lines, t_c):
    start, end = 1, max(lines)
    result = 0
    while start &lt;= end:
        mid = (start + end) // 2
        if count(lines, mid) &gt;= t_c:
            result = mid
            start = mid + 1
        else: end = mid-1

    return result

print(ejin(lines, k))
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[CS] 백엔드]]></title>
            <link>https://velog.io/@rising_developer/CS-%EB%B0%B1%EC%97%94%EB%93%9C-yqhdp8qc</link>
            <guid>https://velog.io/@rising_developer/CS-%EB%B0%B1%EC%97%94%EB%93%9C-yqhdp8qc</guid>
            <pubDate>Mon, 18 Mar 2024 08:10:21 GMT</pubDate>
            <description><![CDATA[<p>[was와 ws의 차이]
    - was(web application server)
        - 비즈니스 로직을 넣을 수 있음
        - tomcat, php, ASP, .Net 등
    - ws(web server)
        - 비즈니스 로직을 넣을 수 없음
        - Nginx, Apache등</p>
<p>[많은 트래픽이 발생한 경우 대처하는 방법]</p>
<ul>
<li>스케일 업 :  서버에 cpu나 ram등을 추가하여 서버의 하드웨어 스펙을 향상시키는 방법</li>
<li>스케일 아웃 :  서버를 여러 대 추가하여 시스템을 증가시키는 방법</li>
</ul>
<p>[ CORS 란? ]
CORS(Cross-Origin-Resource-Sharing)란 도메인이 다른 2개의 사이트가 데이터를 주고 받을 때 발생하는 문제입니다. 예를 들어 mangkyu.com에서 mang.com으로 데이터를 요청한다고 하면, 따로 설정을 해주지 않는 한 CORS 에러를 만나게 됩니다.
CORS가 생기게 된 이유는 서버 내에서 요청이 허락된 도메인에만 데이터를 주기 위해서인데, 요청을 허락하기 위해서는 Access-Control-Alow-Origin: {도메인} 과 같은 내용을 Response의 헤더에 추가해주어야 합니다다. 만약 도메인을 *으로 설정하면 모든 도메인에 대해 요청을 허락할 수 있습니다. 그 외에도  Access-Control-Allow-Methods, Access-Control-Max-Age 등을 설정해줄 수 있습니다.</p>
<p>Access-Control-Allow-Orgin : 요청을 보내는 페이지의 출처 [ *, 도메인 ] 
Access-Control-Allow-Methods : 요청을 허용하는 메소드. Default : GET, POST
Access-Control-Max-Age : 클라이언트에서 preflight 요청 (서버의 응답 가능여부에 대한 확인) 결과를 저장할 시간
Access-Control-Allow-Headers : 요청을 허용하는 헤더</p>
<p>[ 아파치와 톰캣은 각각 멀티 프로세스인가 멀티 쓰레드인가? ]
아파치는 기본적으로 멀티 프로세스로 구현되어 있다. 하지만 설정에 따라 멀티 쓰레드를 같이 운용할 수 있다.
톰캣은 요청을 처리하기 위한 쓰레드 풀을 관리하고 있다. 그리고 요청이 오면 해당 쓰레드 풀에서 쓰레드를 꺼내 요청을 처리하도록 한다.</p>
<p>[ 디자인 패턴 ]</p>
<p>생성 패턴</p>
<p>팩토리 패턴: 객체를 생성하기 위한 디자인 패턴
추상 팩토리 패턴: 객체를 생성하는 팩토리를 생성하기 위한 디자인 패턴
빌더 패턴: 상황에 따라 동적인 인자를 필요로 하는 객체를 생성하기 위한 디자인 패턴
싱글톤 패턴: 객체를 1개만 생성하여 항상 참조가능하도록 고안된 디자인 패턴</p>
<p>구조 패턴</p>
<p>어댑터 패턴: 호환성이 맞지 않는 두 클래스를 연결하여 사용하기 위한 디자인 패턴
프록시 패턴: 어떤 객체에 접근 제어를 위해 대리인을 사용하는 디자인 패턴
데코레이터 패턴: 어떤 객체에 새로운 기능 추가를 위해 대리인을 사용하는 디자인 패턴
퍼사드 패턴: 어떤 복합적인 기능에 대해 간략화된 인터페이스를 제공하는 디자인 패턴</p>
<p>행위 패턴</p>
<p>전략 패턴: 상황에 따라 다른 전략을 사용하기 위한 디자인 패턴
옵저버 패턴: 값을 관찰하여 빠르게 반영하기 위한 디자인 패턴
커맨드 패턴: 실행될 기능을 캡슐화하여 재사용성이 높은 클래스를 설계하기 위한 디자인 패턴</p>
<p>DatabaseController=&gt; SingletonPattern을 사용하여 데이터베이스를 제어하는 하나의 인스턴스만을 생성
DatabasePool =&gt; ObjectPool Pattern을 사용하여 데이터베이스 객체를 미리 생성하여 Performance 향상
UnitFactory =&gt; FactoryPattern을 사용하여 객체 생성을 최적화 + Singleton Pattern을 사용하여 하나의 공장을 사용
BaseFrame =&gt; ObserverPattern을 사용하여 사용자의 정보가 생신되면 View의 값들도 갱신되게 함
PlayerInfo =&gt; StrategyPattern을 사용하여 상황에 따라 다른 스킬을 사용</p>
<p>[ Servlet(서블릿)이란? ]
서블릿이란 클라이언트의 요청을 처리하고, 그 결과를 반환하는 Servlet 클래스의 구현 규칙을 지킨 자바 웹 프로그래밍 기술입니다. Spring MVC에서 Controller로 이용되며, 사용자의 요청을 받아 처리한 후에 결과를 반환합니다.
 
 
[ Spring 기초지식(DI, DL, IoC, AOP) ]</p>
<p>DI(Dependency Injection): 한 객체에서 다른 객체를 필요로 하여 의존성을 갖게 하는 기술
DL(Dependency Look-up): 한 객체에서 필요로 하는 다른 객체를 찾아서 사용하는 기술
IoC(Inversion of Control): 직접 제어야하는 부분에 대한 권한을 프레임워크 등에 넘기는 기술
AOP(Aspect Oriented Programming): 공통의 관심 사항을 추출하여 원하는 곳에 적용하는 기술</p>
<p> 
 
[ VO와 DTO, BO, DAO란? ]</p>
<p>DAO(Data Access Object): DB에 접근하여 실제 데이터를 조회 또는 조작하는 클래스, Repository 또는 Mapper에 해당함
BO(Business Object): 여러 DAO를 활용해 비지니스 로직을 처리하는 클래스, Service에 해당함
DTO(Data Transfer Object): 데이터를 주고 받기 위해 사용하는 클래스
VO(Value Object): 실제 데이터만을 저장하는 클래스</p>
<p>[ 디스패처 서블릿(Dispatcher Servlet)이란? ]
디스패처 서블릿이란 톰캣과 같은 서블릿 컨테이너를 통해 들어오는 모든 요청을 제일 앞에서 받는 프론트 컨트롤러입니다. 디스패처 서블릿은 공통된 작업을 처리한 후에, 적절한 세부 컨트롤러로 작업을 위임해줍니다. 그리고 각각의 세부 컨트롤러는 처리할 부분을 처리하고 반환할 view를 Dispatcher Servlet에 넘기게 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/rising_developer/post/aa2a05ef-0777-4a5b-b78c-cb6f4fa536d3/image.png" alt=""></p>
<p>[ Spring에서의 싱글톤 패턴 ]
Java로 기본적인 싱글톤 패턴을 구현하고자 하면 다음과 같은 단점들이 발생한다.</p>
<p>private 생성자를 갖고 있어 상속이 불가능하다.
테스트하기 힘들다.
서버 환경에서는 싱글톤이 1개만 생성됨을 보장하지 못한다.
전역 상태를 만들 수 있기 때문에 바람직하지 못하다.</p>
<p>그래서 스프링은 컨테이너를 통해 직접 싱글톤 객체를 생성하고 관리하는데, 이를 통해 다음과 같은 장점을 얻을 수 있다.</p>
<p>static 메소드나 private 생성자 등을 사용하지 않아 객체지향적 개발을 할 수 있다.
테스트를 하기 편리하다.</p>
<p> 
 
[ MVC 패턴이란? ]
MVC(Model-View-Controller)패턴은 아키텍쳐를 설계하기 위한 디자인 패턴입니다. 
MVC 패턴은 애플리케이션을 개발할 때 그 구성요소를 3가지로 나눕니다.</p>
<p>Model: 데이터를 저장하는 컴포넌트
View: 사용자 인터페이스(UI) 컴포넌트
Controller: 사용자의 요청을 처리하고 Model과 View를 중개하는 컴포넌트
<img src="https://velog.velcdn.com/images/rising_developer/post/8d9ff8e0-a9c0-42b0-8817-8785e034afda/image.png" alt=""></p>
<p>[ Spring MVC란? ]
Spring MVC란 웹 애플리케이션 개발을 위한 MVC 패턴 기반의 웹 프레임워크입니다. Spring MVC는 애플리케이션의 구성요소를 Model, View, Controller로 분리합니다. 또한 Spring MVC는 아래와 같은 컴포넌트들로 구성됩니다.</p>
<p>Dispatcher Servlet: 클라이언트의 요청을 먼저 받아들이는 서블릿으로, 요청에 맞는 컨트롤러에게 요청을 전달함
Handler Mapping: 해당 요청이 어떤 컨트롤러에게 온 요청인지 검사함
Controller: 클라이언트의 요청을 받아 처리하여 결과를 디스패처 서블릿에게 전달함
ViewResolver: View의 이름을 통해 알맞은 View를 찾음
View: 사용자에게 보여질 UI 화면</p>
<p>[ Spring MVC 작동 원리 ]
<img src="https://velog.velcdn.com/images/rising_developer/post/f4981e90-7c85-402c-ab64-8795546485d1/image.png" alt="">
1.클라이언트는 URL을 통해 요청을 전송한다.
2.디스패처 서블릿은 핸들러 매핑을 통해 해당 요청이 어느 컨트롤러에게 온 요청인지 찾는다.
3.디스패처 서블릿은 핸들러 어댑터에게 요청의 전달을 맡긴다.
4.핸들러 어댑터는 해당 컨트롤러에 요청을 전달한다.
5.컨트롤러는 비지니스 로직을 처리한 후에 반환할 뷰의 이름을 반환한다.
6.디스패처 서블릿은 뷰 리졸버를 통해 반환할 뷰를 찾는다.
7.디스패처 서블릿은 컨트롤러에서 뷰에 전달할 데이터를 추가한다.
8.데이터가 추가된 뷰를 반환한다.   </p>
<p>[ Spring MVC의 장점과 단점 그리고 SpringBoot]</p>
<p>장점</p>
<p>의존성 주입을 통해 컴포넌트 간의 결합도를 낮출 수 있어 단위테스트가 용이함
제어의 역전을 통해 빈(객체)의 라이프싸이클에 관여하지 않고 개발에 집중할 수 있음</p>
<p>단점</p>
<p>XML을 기반으로 하는 프로젝트 설정은 너무 많은 시간을 필요로 함
톰캣과 같은 WAS를 별도로 설치해주어야 함</p>
<p>해결책(Spring Boot)</p>
<p>자주 사용되는 라이브러리들의 버전 관리 자동화
AutoConfig로 복잡한 설정 자동화
Tomcat과 같은 내장 웹서버 제공
실행 가능한 JAR로 개발 가능</p>
<p> 
 
[ Spring @Bean, @Configuration, @Component 어노테이션 ]</p>
<p>@Bean: 개발자가 직접 제어가 불가능한 외부 라이브러리 또는 설정을 위한 클래스를 수동으로 빈 등록할 때 사용
@Configuration: 1개 이상의 @Bean 메소드를 갖는 클래스의 경우에 반드시 명시해 주어야 함
@Component: 개발자가 직접 개발한 클래스를 컴포넌트 스캔 방식으로 자동으로 빈 등록할 때 사용</p>
<p> 
[ @SpringBootApplication ]</p>
<p>@SpringBootConfiguration: @Configuration을 포함하고 있으며, 테스트 등을 위한 자동 설정을 위한 하기 위해 찾아짐
@EnableAutoConfiguration: 필요한 설정들을 자동으로 해주는 자동 설정 기능을 활성화함
@ComponentScan: 빈을 찾아서 등록하기 위한 위치를 지정함</p>
<p>[ Spring AOP의 작동 원리(JDK 동적 프록시와 CGLib 프록시) ]</p>
<p>다이내믹 프록시 객체의 생성 요청
포인트컷을 통해 부가 기능 대상 여부 확인
어드바이스로 부가 기능 적용
실제 기능 처리</p>
<p> 
Spring AOP는 기본적으로 JDK 동적 프록시를 이용하며, 자바의 인터페이스와 스프링 컨테이너 외에는 특별한 기술이나 환경을 필요로 하지 않습니다. 하지만 이러한 프록시 방법은 다음과 같은 2가지 단점을 가지고 있습니다.</p>
<p>프록시 적용을 위해 반드시 인터페이스를 생성해야 함
구체 클래스로는 빈을 주입받을 수 없고, 반드시 인터페이스로만 주입받아야 함</p>
<p>그래서 이러한 문제를 해결하고자 클래스 상속을 기반으로 프록시를 구현하는 CGLib 프록시가 등장하게 되었습니다. CGLib 프록시는 상속을 기반으로 구현되므로 final 클래스나 final 메소드면 프록시 생성이 불가능한 제약이 있습니다.
 
 
[ AspectJ AOP의 작동 원리 ]
Spring AOP가 아닌 또 다른 강력한 AOP 프레임워크 중 하나인 AspectJ는 프록시를 이용하지 않았습니다. 대신 AspectJ는 타깃 클래스 파일의 바이트 코드를 조작하여 부가기능을 직접 넣어주는 방법(위빙)을 사용합니다. 그래서 우리가 만든 코드에서는 부가 기능이 분리되어 있지만 바이트 코드에서는 핵심 기능과 부가 기능이 섞여있는 구조입니다. AspectJ가 프록시를 사용하지 않고 어려운 복잡한 바이트 조작 방법을 사용하는 이유는 크게 2가지가 있습니다.</p>
<p>바이트 코드를 조작하면 Spring과 같은 컨테이너의 도움이 필요 없기 때문이다.
프록시 방식보다 훨씬 강력하고 유연한 AOP를 제공할 수 있다.</p>
<p> 
바이트 코드를 끼워넣는 시점은 컴파일 시점과 클래스 파일이 JVM 메모리로 올라가는 시점 총 2가지가 있습니다.
 
 
[ 쓰레드 로컬(Thread Local) ]
스프링 MVC는 멀티 쓰레드 기반으로 동작하는 웹 프레임워크이다. 매번 요청이 올 때마다 쓰레드를 만들어 실행하면 비용이 커지므로, 쓰레드를 미리 만들어두고 쓰레드 풀에 쓰레드를 넣어뒀다가 요청이 오면 꺼내서 사용하고 반환한다. 
ThreadLocal은 각 쓰레드에 할당되는 저장 공간인데, 스프링과 같은 멀티 쓰레드 프로그래밍 환경에서 쓰레드 로컬에 값을 저장하고 해제하지 않으면 문제가 발생한다. 왜냐하면 쓰레드가 재사용되기 때문이다. 
대표적으로 Spring Security에서 사용되는 SecurityContextHolder는 ThreadLocal을 사용된다.
 
 
[ Spring WebFlux란? ]
Spring WebFlux란 Blocking+동기 방식으로 동작하는 Spring MVC의 한계점을 극복하기 위해 Spring5에 처음 등장하게 되었습니다. 기존의 Spring MVC에서는 HTTP 요청들을 큐에 넣어두고, 멀티쓰레드를 기반으로 동작하고 있습니다. 하지만 이러한 방식은 응답성이 상대적으로 떨어지기 때문에 비동기적으로 요청을 처리하기 위한 방법이 필요하게 되었고, 리액티브 프로그래밍을 통해 비동기 데이터 스트림으로 Non-Blocking 애플리케이션을 개발하기 위한 Spring WebFlux 프레임워크가 등장하게 되었습니다.</p>
<p>[ CDN(Content Delivery Network)란? ]
CDN(Content Delivery Network)는 물리적으로 떨어져 있는 사용자에게 컨텐츠를 더 빠르게 제공하기 위해 고안된 기술입니다. 만약 우리나라에 있는 사람이 미국에 있는 서버로부터 이미지나 파일 등을 다운받으려고 하면 시간이 오래 걸립니다. 따라서 느린 응답속도와 다운로드 시간을 극복하기 위해 서버를 분산시켜 캐싱해두고, 빠르게 다운받을 수 있게 합니다.
CDN은 콘텐츠에 대한 요청이 발생하면 사용자와 가장 가까운 위치에 존재하는 서버로 매핑시켜, 요청된 파일의 캐싱된(사전 저장된) 버전으로 요청을 처리합니다. 서버가 파일을 찾는 데 실패하는 경우 CDN 플랫폼의 다른 서버에서 콘텐츠를 찾은 다음 엔드유저에게 응답을 전송합니다. </p>
<p>출처: <a href="https://mangkyu.tistory.com/95">https://mangkyu.tistory.com/95</a> [MangKyu&#39;s Diary:티스토리]</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 12015 가장 긴 증가하는 부분 수열2]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-12015-%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B42</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-12015-%EA%B0%80%EC%9E%A5-%EA%B8%B4-%EC%A6%9D%EA%B0%80%ED%95%98%EB%8A%94-%EB%B6%80%EB%B6%84-%EC%88%98%EC%97%B42</guid>
            <pubDate>Mon, 11 Mar 2024 11:48:02 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/b2a3aa10-0819-49ed-b823-8f18f5b9b646/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>가장 긴 증가하는 수열(LIS)는 기존풀이 방식(dp)과 이분탐색으로 풀어볼 수 있다.
문제와 같이 크기가 큰 수열은 시간초과가 뜨기 때문에 시간 복잡도가 O(nlog n)인 이분탐색을 사용해야한다.</p>
<pre><code>import sys
import heapq
input = sys.stdin.readline

n = int(input())

A = list(map(int, input().split()))

d = [0]

for x in A:
    if d[-1] &lt; x:
        d.append(x)
    else:
        start = 0
        end = len(d)

        while start &lt; end:
            mid = (start + end) //2
            if d[mid] &lt; x:
                start = mid + 1
            else:
                end = mid
        d[end] = x
print(len(d)-1)
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘]백준 2138]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%B0%B1%EC%A4%80-2138</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EB%B0%B1%EC%A4%80-2138</guid>
            <pubDate>Wed, 06 Mar 2024 12:09:07 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/e773b34e-eadf-4dfd-836d-a6da2c7ca041/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>그리디 알고리즘이라 하면 가장 큰 것부터, 가장 작은 것부터 이런 식으로 단순하게 생각했다. 그러나 난이도가 올라갈 수록 최적의 해를 찾는 것 또한 그리디의 일부라는 것을 알게 되었다. 이 문제에서 바꿔줄지 말지를 결정하는 것이 최적의 해고 , 또한 경우의 수도 생각해야했다. 바꿀지 말지를 결정하는 것은 본인의 순서가 아닌 본인 - 1 순서를 보고 정하는데 첫번째 전구는 그게 없기 때문에, 첫번째 전구를 바꿔주는 경우와 안바꿔주는 경우를 모두 생각해주어야해서 까다롭다.```
import sys
input = sys.stdin.readline</p>
<p>n = int(input())
A = list(map(int, input().rstrip()))
B = list(map(int, input().rstrip()))</p>
<p>def change(A, B):
    copy_A = A[:]
    press = 0
    for i in range(1,n):
        if copy_A[i-1] == B[i-1]:
            continue
        press += 1
        for j in range(i-1, i+2):
            if j &lt; n:
                copy_A[j] = 1 - copy_A[j]</p>
<pre><code>if copy_A == B:
    return press
else:return int(1e9)</code></pre><p>res = change(A,B)
A[0] = 1-A[0]
A[1] = 1-A[1]</p>
<p>res = min(res, change(A,B)+1)</p>
<p>if res == int(1e9):
    print(-1)
else:print(res)
```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 1080 행렬]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1080-%ED%96%89%EB%A0%AC</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-1080-%ED%96%89%EB%A0%AC</guid>
            <pubDate>Tue, 05 Mar 2024 12:28:49 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/bdbc3c1e-b0e6-4968-af30-2fd5c2523a55/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>풀이 방법을 생각하기 쉽지 않았다.
각 행을 돌면서 같지 않는 부분이 있으면 전환해준다. 이때 전환은 함수를 이용해서 작성해준다.
각 행을 다 돌았는데 리스트가 동일하지 않는 경우도 확인해준다.</p>
<pre><code>n,m = map(int, input().split())

A = [list(map(int, input())) for _ in range(n)]
B = [list(map(int, input())) for _ in range(n)]

if (n &lt; 3 or m &lt; 3) and A != B :
    print(-1)
    exit()

def rev(i,j):
    for x in range(i, i+3):
        for y in range(j, j+3):
            if A[x][y] == 0:
                A[x][y] = 1
            else:
                A[x][y] = 0

cnt = 0
if (n &lt; 3 or m &lt; 3) and A != B :
    cnt = -1
else:
    for i in range(n-2):
        for j in range(m-2):
            if A[i][j] != B[i][j]:
                cnt+=1
                rev(i,j)

if cnt!=-1:
    if A != B:
        cnt = -1
print(cnt)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 11399 ATM]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-11399-ATM</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-11399-ATM</guid>
            <pubDate>Tue, 05 Mar 2024 11:43:36 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/bdd96627-17b4-4a63-abbf-390afadcee21/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>그리디 알고리즘으로 풀 수 있는 매우 쉬운 문제이다. sort()를 통해 크기순으로 세워주고 그의 합을 지속적으로 구해주면 된다.</p>
<pre><code>n = int(input())

array = list(map(int, input().split()))

array.sort()

sum = 0
for i in range(len(array)):
    for j in range(i+1):
        sum+=array[j]

print(sum)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[기타] ElasticSearch]]></title>
            <link>https://velog.io/@rising_developer/%EA%B8%B0%ED%83%80-ElasticSearch</link>
            <guid>https://velog.io/@rising_developer/%EA%B8%B0%ED%83%80-ElasticSearch</guid>
            <pubDate>Tue, 05 Mar 2024 09:18:58 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-elasticsearch">📌 ElasticSearch</h1>
<p>Apache Lucene(아파치 루씬) 기반의 Java 오픈 소스 분산 검색 엔진이다. ElasticSearch를 통해 루씬 라이브러리를 단독으로 사용할 수 있으며, 방대한 양의 데이터를 신속하게 저장, 검색, 분석을 할 수 있다.
ELK(Elasticsearch / Logstash / Kibana) 스택으로 사용되기도 한다. ELK 스택은 다음과 같다.</p>
<ul>
<li>Logstash<ul>
<li>다양한 소스(DB, csv 파일 등)의 로그 또는 트랜잭션 데이터를 수집, 집계, 파싱하여 Elasticsearch로 전달</li>
</ul>
</li>
<li>Elasticsearch<ul>
<li>Logstash로부터 받은 데이터를 검색 및 집계하여 필요한 정보를 획득</li>
</ul>
</li>
<li>Kibana<ul>
<li>Elasticsearch의 빠른 검색을 통해 데이터를 시각화 및 모니터링</li>
</ul>
</li>
</ul>
<h1 id="📌-elasticsearch-vs-rdbms">📌 ElasticSearch VS RDBMS</h1>
<p><img src="https://velog.velcdn.com/images/rising_developer/post/470340f6-570b-4e03-8f2c-57710fb93ada/image.png" alt="">
<img src="https://velog.velcdn.com/images/rising_developer/post/6a27e40b-c2f4-44a3-875b-06c7a759a73a/image.png" alt=""></p>
<h1 id="📌-elasticsearch-핵심-개념">📌 ElasticSearch 핵심 개념</h1>
<h2 id="document">Document</h2>
<p>Elasticsearch에서 데이터의 최소 단위이다. RDBMS에서의 row와 비슷하다. Document는 JSON 객체이며, 다양한 필드를 포함하고, document안에 document가 필드로 존재할 수 있다.</p>
<h2 id="field">Field</h2>
<p>Document안에 들어가는 데이터이다. RDBMS에서의 column과 비슷하다.</p>
<h2 id="type">Type</h2>
<p>여러 document가 모여서 하나의 type을 이룬다. RDBMS에서의 table과 비슷하다. Elasticsearch 6.1 부터는 하나의 index(여러 type이 모인 것)당 하나의 type만을 가질수 있게 되었고, 7.0 부터는 type이 사라지고 대신 고정자 _doc 으로 접근해야 한다</p>
<h2 id="index">Index</h2>
<p>데이터가 검색될 수 있는 구조로 변경하기 위해 원본 문서를 검색어 토큰들로 변환(indexing)하여 저장한 것. 여러 type이 모여 한 개의 index를 이룬다. RDBMS에서의 database와 table의 역할을 한다. RDBMS에서는 여러 database의 데이터를 한번에 조회할 수 없지만 Elasticsearch에서는 가능하다 (multitenancy). index는 shard라는 단위로 분산되어 저장된다. Lucene에서 index 파일들은 immutable(불변)하다. Update 시에는 내부적으로 수정될 document를 삭제후 다시 insert한다. 따라서 수정이 잦은 문서를 elasticsearch에 저장하는 것은 비효율적이다.</p>
<h2 id="shard">Shard</h2>
<p>Index가 분산되어 처리되는 단위를 뜻한다. 각 shard는 물리적 노드들에 나뉘어서 저장된다. Shard는 두 종류로 나뉜다.</p>
<pre><code>- Primary shard: 모든 document들은 하나의 primary shard에 저장된다. Primary shard의 기본 개수는 5개이다.
- Replica shard: Primary shard의 복제본이다. 원본 데이터에 fault 발생시 복구하기 위해 사용된다 (fault tolerance). Replica shard의 기본 개수는 1개이다.</code></pre><h2 id="segment">Segment</h2>
<p>Segment는 shard가 물리적으로 나뉘어서 저장되는 단위이다. Document가 처음부터 segment에 저장되는 것은 아니다. Indexing된 document는 먼저 시스템의 메모리 버퍼에 저장되고, 이 때는 document가 검색되지 않는다. Elasticsearch의 refreash 과정을 거쳐야 segment 단위로 physically 저장되고 검색이 된다. Segment는 immutable 하며 document가 update 되면 새로운 segment가 생성된다. Segment가 많아질수록 search 할 때 성능이 낮아질 수 있다. 따라서 Elasticsearch 내부에서 background로 segment merging을 진행한다.</p>
<h2 id="mapping">Mapping</h2>
<p>Elasticsearch의 index에 들어가는 데이터의 type을 정의하는 것이다. RDBMS에서의 schema와 유사하다. Elasticsearch는 선 indexing 후 mapping을 지원하며, 새로운 필드가 추가되면 동적으로 해당 필드 indexing 후 mapping까지 해준다.</p>
<h1 id="📌-elasticsearch-이점">📌 Elasticsearch 이점</h1>
<p>신속한 가치 실현
Elasticsearch는 간단한 REST 기반 API, 간단한 HTTP 인터페이스를 제공하고 스키마 없는 JSON 문서를 사용해 다양한 사용 사례에서 쉽게 시작하고 빠르게 애플리케이션을 구축할 수 있습니다.</p>
<p>고성능
Elasticsearch의 분산 성질로 인해 대량 볼륨의 데이터를 병렬로 처리할 수 있어 쿼리에 최고의 일치 항목을 빠르게 찾을 수 있습니다.</p>
<p>무료 도구 및 플러그인
Elasticsearch는 유명 시각화 및 보고서 도구인 Kibana가 통합되어 제공됩니다. Beats 및 Logstash와의 통합도 제공하여 소스 데이터를 쉽게 전환하고 Elasticsearch 클러스터에 로드할 수 있습니다. 언어 분석기 및 제안자 등 다양한 오픈 소스 Elasticsearch 플러그인을 사용하여 애플리케이션에 풍부한 기능을 추가할 수도 있습니다.</p>
<p>실시간에 가까운 운영
데이터 읽기 및 쓰기와 같은 Elasticsearch 운영은 보통 1초도 안 걸려서 완료됩니다. 덕분에 애플리케이션 모니터링 및 이상 탐지와 같은 실시간에 가까운 사용 사례에 Elasticsearch를 사용할 수 잇습니다.</p>
<p>쉬운 애플리케이션 개발
Elasticsearch는 Java, Python, PHP, JavaScript, Node.js, Ruby 및 기타 여러 다양한 언어에 대한 지원을 제공합니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 백준 7576 토마토]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-7576-%ED%86%A0%EB%A7%88%ED%86%A0</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B0%B1%EC%A4%80-7576-%ED%86%A0%EB%A7%88%ED%86%A0</guid>
            <pubDate>Tue, 05 Mar 2024 08:26:14 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/76664f2d-9332-4944-874b-24b04f8fcaf2/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>bfs를 활용해서 풀었고, 현재 1로 되어있는 부분만 q에 넣는다. 이후 인접한 과일들을 먼저 +1씩해주고 가장 큰 숫자를 출력</p>
<pre><code>from collections import deque
m, n = map(int, input().split())

array = []
for i in range(n):
    array.append(list(map(int, input().split())))

q = deque()
for i in range(n):
    for j in range(m):
        if array[i][j] == 1:
            q.append((i, j , 1))

dx = [-1, 1, 0, 0]
dy = [0, 0, -1, 1]
def bfs(q):
    count = 0
    while q:
        x, y, count = q.popleft()
        for i in range(4):
            nx = x+dx[i]
            ny = y+dy[i]
            if nx &lt; 0 or ny &lt; 0 or nx &gt;= n or ny &gt;= m:
                continue
            if array[nx][ny] == 0:
                array[nx][ny] = count
                q.append((nx,ny,count+1))

    return count
mx = 0
count = bfs(q)
ans = True
for k in array:
    mx = max(mx, max(k))
    if 0 in k:
        ans = False
        break
if ans == True:
    if count == 1:
        print(0)
    else:print(mx)
else:
    print(-1)
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[알고리즘] 14888 연산자 끼워넣기]]></title>
            <link>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-14888-%EC%97%B0%EC%82%B0%EC%9E%90-%EB%81%BC%EC%9B%8C%EB%84%A3%EA%B8%B0</link>
            <guid>https://velog.io/@rising_developer/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-14888-%EC%97%B0%EC%82%B0%EC%9E%90-%EB%81%BC%EC%9B%8C%EB%84%A3%EA%B8%B0</guid>
            <pubDate>Tue, 05 Mar 2024 08:25:50 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/rising_developer/post/50d34b7e-be9e-405c-acd9-e5aff5d960c6/image.png" alt=""></p>
<h1 id="풀이">풀이</h1>
<p>dfs를 통해 쉽게 풀 수 있으나, 답이 계속 오류가 떴다. 그 이유는 max값이 음수가 나올 수도 있는데, 처음에 max = 0으로 지정해줘서 뜨는 오류</p>
<pre><code>n = int(input())

array = list(map(int, input().split()))
add, sub, mul, div = map(int, input().split())

mx = -int(1e9)
mi = int(1e9)
ans = array[0]
def dfs(result, count):
    global mx, mi, add, sub, mul, div
    if count == n-1:
        mx = max(result, mx)
        mi = min(result, mi)
        return

    if add &gt; 0 :
        add -= 1
        dfs(result+array[count+1], count+1)
        add += 1
    if sub &gt; 0 :
        sub -= 1
        dfs(result-array[count+1], count+1)
        sub += 1
    if mul &gt; 0 :
        mul -= 1
        dfs(result*array[count+1], count+1)
        mul += 1
    if div &gt; 0 :
        div -= 1
        dfs(int(result/array[count+1]), count+1)
        div += 1

dfs(ans, 0)
print(mx)
print(mi)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[기타] Jenkins란? CI/CD]]></title>
            <link>https://velog.io/@rising_developer/%EA%B8%B0%ED%83%80-Jenkins%EB%9E%80-CICD</link>
            <guid>https://velog.io/@rising_developer/%EA%B8%B0%ED%83%80-Jenkins%EB%9E%80-CICD</guid>
            <pubDate>Tue, 05 Mar 2024 08:25:38 GMT</pubDate>
            <description><![CDATA[<h1 id="📌-cicd">📌 CI/CD</h1>
<ol>
<li><p>CI</p>
<ul>
<li>Continuous Intergration을 의미 <ul>
<li>기본적으로 코드</li>
<li>여러 명의 많은 개발자들이 코드 베이스를 계속해서 통합하는 것이다.</li>
<li>여러 개발자들의 코드를 각각 가능한 빠르게 배포하는 것을 의미한다.</li>
<li>즉 코드를 통합하는 것이다.</li>
</ul>
</li>
</ul>
</li>
<li><p>CD</p>
<ul>
<li>Continuous Delivery<ul>
<li>내부 사용자든 , 사용자든 서비스를 지속적으로 배달한다.</li>
<li>즉 코드 베이스가 항상 배포 가능한 상태를 유지하는 것을 의미한다.<ul>
<li>Continuos Deployment</li>
</ul>
</li>
<li>코드 베이스를 사용자가 사용 가능한 환경에 배포하는 것을 자동화하는 것이다.</li>
<li>버전 1 쓰다가 끊기지 않고 배포하는 것</li>
</ul>
</li>
</ul>
</li>
</ol>
<p>-&gt; 즉, CI/CD란 각각의 개발자들이 개발을 하는 개발환경을 사용자가 사용 가능한 서비스로 전달하는 모든 과정을 지속 가능한 형태로 또 가능하다면 자동으로 해서 개발자와 사용자 사이의 격차를 없애는 것이다. 이러한 과정에는 코드를 빌드하고, 테스트하고 배포하는 활동이 있다.</p>
<h1 id="📌-젠킨스">📌 젠킨스</h1>
<ol>
<li><p>기본개념</p>
<ul>
<li>Java Runtime Environment에서 동작</li>
<li>다양한 플러그인들을 활용해서 각종 자동화 작업을 처리할 수 있다.</li>
<li>AWS배포, 테스트, 도커 빌드 등 할게 너무 많으니 각각의 컴포넌트들을 하나의 플러그인으로 모듈화해서 활용</li>
<li>가장 핵심적인 파이프라인, 시크릿키도 플러그인으로 동작 가능</li>
<li>일련의 자동화 작업의 순서들의 집합인 pipeline을 통해 CI/CD 파이프라인을 구축한다.</li>
<li>플러그인들을 잘 조합해서 돌아가게 하는 게 Pipeline이라고 할 수 있다.</li>
</ul>
</li>
<li><p>대표 Plugins</p>
<ul>
<li>Credentials Plugin<ul>
<li>jenkins는 그냥 단지 서버이기 때문에 배포에 필요한 각종 리소스에 접근하기 위해서는 여러가지 중요 정보들을 저장하고 있어야한다.</li>
<li>리소스에는 클라우드 리소스 혹은 베어메탈에 대한 ssh 접근 등을 의미한다.</li>
<li>베어메탈 : 어떠한 소프트웨어도 담겨 있지 않은 하드웨어를 가리킨다.</li>
<li>AWS token, Gin access token, secret key, ssh등의 정보들을 저장할 때 사용</li>
<li>중요한 정보들을 저장해주는 플러그인</li>
<li>private Network에 떠있기 때문에 보안상 안전하다.</li>
</ul>
</li>
<li>Git Plugin -&gt; jenkins에서 git에 대한 소스콛를 긁어와서 빌드할 수 있도록 도와줌</li>
<li>Pipeline -&gt; 핵심기능</li>
<li>Docker plugin and Docker Pipeline -&gt; Docker agent를 사용하고 jenkins에서 도커를 사용하기 위한 플러그인</li>
</ul>
</li>
</ol>
<h1 id="📌-젠킨스의-pipeline">📌 젠킨스의 PipeLine</h1>
<p><img src="https://velog.velcdn.com/images/rising_developer/post/7de93ffb-3f9e-4efa-99d7-3878b63cebe6/image.png" alt=""></p>
<ul>
<li><p>파이프라인</p>
<ul>
<li>파이프라인이란 CI/CD 파이프라인을 젠킨스에 구현하기 위한 일련의 플러그인들의 집합</li>
<li>여러 플러그인들을 파이프라인에서 용도에 맞게 사용하고 정의함으로써 파이프라인을 통한 서비스가 배포된다.</li>
<li>Pipeline DSL로 작성됨</li>
<li>젠킨스가 동작되기 위해서는 여러 플러그인들이 파이프라인을 통해 흘러가는 과정</li>
</ul>
</li>
<li><p>구성 요소</p>
<ul>
<li>두가지 형태의 Pipeline Syntax가 존재<ul>
<li>Declarative</li>
<li>Scripted Pipeline</li>
</ul>
</li>
</ul>
</li>
<li><p>Pipeline의 Section</p>
<ul>
<li><p>Agent section</p>
<ul>
<li><p>젠킨스는 많을 일을 해야 하기 때문에 혼자 하기 버겁다.</p>
</li>
<li><p>여러 slave node를 두고 일을 시킬 수 있는데, 이처럼 어떤 젠킨스가 일을 하게 할 것인지를 지정한다.</p>
</li>
<li><p>젠킨스 노드 관리에서 새로 노드를 띄우거나 혹은 docker이미지를 통해 처리할 수 있다.</p>
</li>
<li><p>쉽게 말하면 젠킨스를 이용하여 시종을 여러 명 둘 수 있는데 어떤 시종에게 일을 시킬 것이냐 하는 것을 결정하는 것이다.</p>
</li>
<li><p>예를 들어 젠킨스 인스턴스가 서버 2대에 각각 떠있는 경우, 마스터에서 시킬 것인지 slave에서 시킬 것인지를 결정할 수 있다.</p>
</li>
<li><p>젠킨스 노드만 넣을 수 있는 것이 아니라 젠킨스 안에 있는 docker container에 들어가서 일을 시킬 수도 있다.</p>
</li>
<li><p>&quot;nodejs안에서 뭔가를 해&quot;라고도 명령을 시킬 수 있다.</p>
</li>
<li><p>Post section</p>
<ul>
<li>스테이지가 끝난 이후의 결과에 따라서 후속 조치를 취할 수 있다.</li>
<li>각각의 단계별로 구별하면 다음과 같다.</li>
<li>성공 시에 성공 이메일, 실패하면 중단 혹은 건너뛰기 등등, 작업 결과에 따른 행동을 취할 수 있다.</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li><p>Stage Section</p>
<ul>
<li>어떤 일들을 처리할 것인지 일련의 stage를 정의한다.</li>
<li>일종의 카테고리라고 보면 됨.</li>
<li>ex) 프론트엔드 배포를 위한 스테이지, 등</li>
</ul>
</li>
<li><p>Steps Section</p>
<ul>
<li>한 스테이지 안에서의 단계로 일련의 스텝을 보여줌.</li>
<li>Steps 내부는 여러 가지 스텝들로 구성되며 여러 작업들을 실행 가능</li>
<li>플러그인을 깔면 사용할 수 있는 스텝들이 생겨남</li>
<li>빌드를 할 때 디렉터리를 옮겨서 빌드를 한다던가, 다른 플러그인을 깔아서 해당 플러그인의 메서드를 활용해서 일을 처리한다던지 하는 작업들을 할 수 있다.</li>
<li>플러그인을 설치하면 쓸 수 있는 Steps들이 많아진다.</li>
</ul>
</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>