diff --git a/Gemfile b/Gemfile
index 1291498971d7..4e61c3189c62 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,2 +1,3 @@
source "https://rubygems.org"
-gemspec
\ No newline at end of file
+gemspec
+gem "webrick", "~> 1.7"
diff --git a/_config.yml b/_config.yml
index 1da3e705de83..259929a27791 100644
--- a/_config.yml
+++ b/_config.yml
@@ -15,24 +15,24 @@
minimal_mistakes_skin : "default" # "air", "aqua", "contrast", "dark", "dirt", "neon", "mint", "plum", "sunrise"
# Site Settings
-locale : "en-US"
-title : "Site Title"
-title_separator : "-"
+locale : "ko-KR"
+title : "안녕,설리!"
+title_separator : "|"
subtitle : # site tagline that appears below site title in masthead
-name : "Your Name"
-description : "An amazing website."
-url : # the base hostname & protocol for your site e.g. "https://mmistakes.github.io"
+name : "Sulley"
+description : "안녕 설리! 블로그 입니다"
+url : "https://meang123.github.io"
baseurl : # the subpath of your site, e.g. "/blog"
repository : # GitHub username/repo-name e.g. "mmistakes/minimal-mistakes"
teaser : # path of fallback teaser image, e.g. "/assets/images/500x300.png"
logo : # path of logo image to display in the masthead, e.g. "/assets/images/88x88.png"
masthead_title : # overrides the website title displayed in the masthead, use " " for no title
-# breadcrumbs : false # true, false (default)
+breadcrumbs : true # true, false (default)
words_per_minute : 200
comments:
- provider : # false (default), "disqus", "discourse", "facebook", "staticman", "staticman_v2", "utterances", "giscus", "custom"
+ provider : "disqus" # false (default), "disqus", "discourse", "facebook", "staticman", "staticman_v2", "utterances", "giscus", "custom"
disqus:
- shortname : # https://help.disqus.com/customer/portal/articles/466208-what-s-a-shortname-
+ shortname : "Hi Sullivan"
discourse:
server : # https://meta.discourse.org/t/embedding-discourse-comments-via-javascript/31963 , e.g.: meta.discourse.org
facebook:
@@ -75,7 +75,7 @@ google:
# SEO Related
google_site_verification :
bing_site_verification :
-naver_site_verification :
+naver_site_verification : "030497dd1cc7a51bf72c69577c31500d29e3598b"
yandex_site_verification :
baidu_site_verification :
@@ -96,23 +96,23 @@ social:
# Analytics
analytics:
- provider : false # false (default), "google", "google-universal", "google-gtag", "custom"
+ provider : "google-gtag" # false (default), "google", "google-universal", "google-gtag", "custom"
google:
- tracking_id :
- anonymize_ip : # true, false (default)
+ tracking_id : "G-6FH90EBH5C"
+ anonymize_ip : false
# Site Author
author:
- name : "Your Name"
+ name : "Sulley"
avatar : # path of avatar image, e.g. "/assets/images/bio-photo.jpg"
- bio : "I am an **amazing** person."
- location : "Somewhere"
- email :
+ bio : "공부한 자료 정리하는 사이트입니다."
+ location : "Korea"
+ email : "meangsungjoo@naver.com"
links:
- label: "Email"
icon: "fas fa-fw fa-envelope-square"
- # url: "mailto:your.name@email.com"
+ url: "meangsungjoo@naver.com"
- label: "Website"
icon: "fas fa-fw fa-link"
# url: "https://your-website.com"
@@ -253,20 +253,21 @@ whitelist:
category_archive:
type: liquid
path: /categories/
+
tag_archive:
type: liquid
path: /tags/
-# https://github.com/jekyll/jekyll-archives
-# jekyll-archives:
-# enabled:
-# - categories
-# - tags
-# layouts:
-# category: archive-taxonomy
-# tag: archive-taxonomy
-# permalinks:
-# category: /categories/:name/
-# tag: /tags/:name/
+ #https://github.com/jekyll/jekyll-archives
+ jekyll-archives:
+ enabled:
+ - categories
+ - tags
+ layouts:
+ category: archive-taxonomy
+ tag: archive-taxonomy
+ permalinks:
+ category: /categories/:name/
+ tag: /tags/:name/
# HTML Compression
@@ -287,6 +288,7 @@ defaults:
layout: single
author_profile: true
read_time: true
- comments: # true
+ comments: true
share: true
related: true
+ show_date: true
diff --git a/_data/navigation.yml b/_data/navigation.yml
index 6f30866f3bed..463c47235537 100644
--- a/_data/navigation.yml
+++ b/_data/navigation.yml
@@ -1,7 +1,22 @@
# main links
main:
- - title: "Quick-Start Guide"
- url: https://mmistakes.github.io/minimal-mistakes/docs/quick-start-guide/
+ - title: "Category"
+ url: /categories/
+ - title: "Tag"
+ url: /tags/
+ - title: "Search"
+ url : /search/
+
+
+docs:
+ - title: "목차"
+ children:
+ - title: "Category"
+ url : /categories/
+ - title: "Tag"
+ url : /tags/
+
+
# - title: "About"
# url: https://mmistakes.github.io/minimal-mistakes/about/
# - title: "Sample Posts"
diff --git a/_pages/category-archive.md b/_pages/category-archive.md
new file mode 100644
index 000000000000..3cd6f6e06761
--- /dev/null
+++ b/_pages/category-archive.md
@@ -0,0 +1,7 @@
+---
+title: "Category"
+layout: categories
+permalink: /categories/
+author_profile: true
+sidebar_main: true
+---
\ No newline at end of file
diff --git a/_pages/search.md b/_pages/search.md
new file mode 100644
index 000000000000..c32ce00347d0
--- /dev/null
+++ b/_pages/search.md
@@ -0,0 +1,5 @@
+---
+title: Search
+layout : search
+permalink: /search/
+---
\ No newline at end of file
diff --git a/_pages/tag-archive.md b/_pages/tag-archive.md
new file mode 100644
index 000000000000..58ae8e76afc6
--- /dev/null
+++ b/_pages/tag-archive.md
@@ -0,0 +1,7 @@
+---
+title: "Tag"
+layout: tags
+permalink: /tags/
+author_profile: true
+sidebar_main: true
+---
\ No newline at end of file
diff --git a/_posts/2022-01-08-first.md b/_posts/2022-01-08-first.md
new file mode 100644
index 000000000000..c532dd33447b
--- /dev/null
+++ b/_posts/2022-01-08-first.md
@@ -0,0 +1,15 @@
+---
+layout: single
+title: "첫 포스팅 입니다"
+categories: introduction
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: false
+---
+# 안녕하세요
+
+공부한 자료를 정리하는 블로그입니다.
+
+감사합니다.
diff --git a/_posts/2022-01-26-algoIntro.md b/_posts/2022-01-26-algoIntro.md
new file mode 100644
index 000000000000..7cb6545214f8
--- /dev/null
+++ b/_posts/2022-01-26-algoIntro.md
@@ -0,0 +1,62 @@
+---
+layout: single
+title: "알고리즘 소개 및 방향"
+categories: introduction
+tag : Algorithm
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 소개글
+
+제가 공부한 내용을 정리하는 포스팅입니다.
+
+공부 진행할때 "코드없는 프로그래밍" 유튜브를 참고하면서 공부했습니다.
+
+
+[코드없는 프로그래밍](https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg)
+{: .notice--danger}
+
+
+
+### 알고리즘 카테고리의 방향성
+
+소개글에서 언급한 유튜버님의 영상을 기반으로 공부를 하였기 때문에 진행방식도 코드없는 프로그래밍님 방식을 따라갑니다. (하지만 문제에 대한 코드 흐름은 같지 않습니다.)
+
+알고리즘 개념에 초점이 맞추어져 있기보다 관련 문제를 풀어보고 리뷰하면서
+진행 할 예정입니다.
+
+사용 언어는 c++을 주로 사용합니다.
+그래서 개인적으로 c++을 이용한 문제 풀이 및 리뷰 그리고 개인적인 생각을 정리하는 방향으로 진행이 됩니다.
+
+"코드없는 프로그래밍" 유튜브로 들어가시면 colab에 파이썬 코드가 있습니다.
+파이썬 코드가 필요하신 분은 링크로 들어가셔서 보시면 좋을 것 같습니다.
+
+
+
+
+
+#### 정리
+
+* 정리
+ + 문제위주의 리뷰 블로그
+
+ + 사용어는 c++ , python
+
+ + 알고리즘 개념 설명도 간단하게 언급 될 예정
+
+ + 유튜브를 공부했다 하더라도 생각의 흐름과 코드는 다름
+
+
+
+
+
+### 마무리
+
+이 포스팅은 개인 공부한 자료를 정리하는 느낌입니다.
+그래서 내용이 정확하지 않거나 틀린 내용이 포함되어있을 수 있다는점 알려드립니다.
+혹시 보시다가 이러한 내용이 보인다면 댓글로 알려주세요 바로 고치도록 하겠습니다.
+감사합니다.
\ No newline at end of file
diff --git a/_posts/2022-01-26-array.md b/_posts/2022-01-26-array.md
new file mode 100644
index 000000000000..1f48de7835d0
--- /dev/null
+++ b/_posts/2022-01-26-array.md
@@ -0,0 +1,1706 @@
+---
+layout: single
+title: "배열관련 문제 "
+categories: Array
+tag: [c++,python,Algorithm,LeetCode,Array,moveZeros,Find pivot index,Minimum size subarray sum,Merge sorted Array,Find peak element,Merge intervals ,Shortest Unsorted continuout subArray ,Find duplicate number ,Two sum,Rotate Image 2D array ,search 2D matrix]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### Intro
+
+풀어볼 문제는 총 11한 문제입니다. 링크 달았으니까 참고 자세한 문제 설명은 참고하시면 될것같습니다.
+
+이번 포스트에서는 총 11한 문제에 대한 저의 코드와 생각들을 정리합니다.
+
+내용이 길어질수있으니 문제 목록을 참고하셔서 필요한 부분만 보는것을 추천합니다.
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 배열 정리
+
+읽기를 할때 가장 효율이 좋은 자료 구조인 것 같습니다.
+첫 주소를 알고 있으므로 index만 안다면 한 단계로 읽을수있다는 장점이 있습니다.
+
+삽입을 할 때 또한 마지막 요소에 삽입하는 경우 한 단계로 삽입할수있습니다.
+
+
+
+
+> 왜 마지막 요소에 삽입할때 O(1)인가 하면 배열에서 삽입하는 경우 요소들을 모두 복사 하는데 처음 요소에 삽입하는 경우 모든 요소 복사 해야 한다. 중간에 삽입하는 경우도 마찬가지로 중간 요소 부터 삽입 해야 한다 그러니 마지막 요소에 삽입 하는 경우에는 복사할 요소가 없으니 O(1)에 실행 가능 한것이다 보통은 그러는데 가끔 O(n)이 될수도 있다 특히 vector처럼 dynamic array를 사용 한다고 하자, vector는 size포인터,첫 번째 요소 가리키는 포인터,capcity포인터 정보를 기본적으로 가지고 있다 하지만 size가 부족해지면 capacity는 보통 2배까지 추가 확보 한다 확보한 공간에 다시 copy할수있기 때문이다 즉 마지막 요소에 삽입할때 하필 size가 부족해서 capacity가 변경이 된다면 copy가 발생하여 O(n)이 될수있다는 의미이다. 그래서 **vector같은 dynamic array 사용할때는 reserve() 명령어로 미리 할당 받는게 중요하다!**
+
+
+
+
+
+하지만 요소를 앞 또는 중간에 삽입 , 검색, 삭제 하는 경우 최대 N의 시간이 걸릴수있습니다.
+
+
+배열 문제를 풀때는 index를 다루는 것에 익숙해질 필요가 있었습니다.
+
+
+#### 23/5/22 추가 내용
+
+또한 dynamic array로 vector 많이 사용하게 될것인데 (vector 따로 정리한 내용있다 참고 하면 될것 같다) O(n)이 발생하지 않게 reserve로 미리 할당하는게 중요하다
+
+11번 문제 이후로 array문제 추가 해서 업데이트 하겠습니다!
+
+
+
+
+
+### leetcode 704번 binary serach 연습 문제
+
+
+문제 들어가기전에 가장 기본적인 문제 하나 풀어 보면 좋을것 같아서 추가 한다 - 23/5/22
+
+
+
+
+[binary search](https://leetcode.com/problems/binary-search/)
+{: .notice--danger}
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 풀어볼 문제 링크 LeetCode
+
+[추가 fascinating](https://leetcode.com/problems/check-if-the-number-is-fascinating/submissions/)
+{: .notice--danger}
+
+
+[1번_moveZeros](https://leetcode.com/problems/move-zeroes/)
+{: .notice--danger}
+
+
+[2번_Find_pivot_index](https://leetcode.com/problems/find-pivot-index/)
+{: .notice--danger}
+
+
+[3번_Minimum_size_subarray_sum](https://leetcode.com/problems/minimum-size-subarray-sum/)
+{: .notice--danger}
+
+[추가 백준 14246 K보다 큰 구간](https://www.acmicpc.net/problem/14246)
+{: .notice--danger}
+
+[추가 leetcode smaller than cur num](https://leetcode.com/problems/how-many-numbers-are-smaller-than-the-current-number/description/)
+{: .notice--danger}
+
+
+[4번_Merge_sorted_Array](https://leetcode.com/problems/merge-sorted-array/)
+{: .notice--danger}
+
+
+[5번_Find_peak_array](https://leetcode.com/problems/find-peak-element/)
+{: .notice--danger}
+
+[추가 find peak array2]()
+{: .notice--danger}
+
+[6번_Merge_Intervals](https://leetcode.com/problems/merge-intervals/)
+{: .notice--danger}
+
+[7번_Shortest_Unsorted_continuout_subArray](https://leetcode.com/problems/shortest-unsorted-continuous-subarray/)
+{: .notice--danger}
+
+[8번_Find_duplicate_number](https://leetcode.com/problems/find-the-duplicate-number/)
+{: .notice--danger}
+
+[9번_Two_sum](https://leetcode.com/problems/two-sum/)
+{: .notice--danger}
+
+[10번_Rotate_Image_2D_array](https://leetcode.com/problems/rotate-image/)
+{: .notice--danger}
+
+[11번_search_2D_matrix](https://leetcode.com/problems/search-a-2d-matrix/)
+{: .notice--danger}
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 추가 fascinating
+
+정수 n, n*2, n*3을 이어 붙혔을때 1-9까지 digit 중복되면 안되고 0이 없는 거를 fascinating이라고 한다 fascinating이면 T 아니면 F 하는 문제 였다
+
+내가 푼 방식은 중복을 알아보기 위해 string 123456789를 통해 중복 확인 해주었다 그리고 0이 왔을때 인덱스 처리 하면 -1이 나오니까 이때 false를 return 하도록 하였다
+간단하게 풀기 좋은 문제 같다
+
+
+
+
+
+
+```c++
+class Solution
+{
+public:
+ bool isFascinating(int n)
+ {
+
+ string temp = "123456789";
+ string s = to_string(n)+to_string(n*2)+to_string(n*3);
+
+ for(auto&e:s)
+ {
+ if((e-48)-1==-1||temp[(e-48)-1]=='0')
+ {
+ return false;
+ }
+ temp[(e-48)-1]='0';
+
+ }
+ return true;
+ }
+};
+```
+
+
+
+
+
+
+### 1 번 moveZeros
+
+
+다른 배열을 copy해서 처리 하면 더 쉽게 풀리지만, 문제에서 Space Complex가 상수로 해결 하라는 조건이 있습니다.
+
+그래서 입력된 배열을 그대로 출력 공간을 사용해야합니다.
+
+0을 만날때 마다 배열에서 삭제 /삽입하는 것은 배열에서 효율적이지 않습니다.
+
+문제의 핵심은 0을 가리키는 index1, 0이 아닌 요소 가리키는 index2 두개의 index설정하는 것입니다.
+
+
+* c ++ 코드
+
+
+```c++
+
+class Solution {
+public:
+ void moveZeroes(vector& nums)
+ {
+ //0을 가리키는 index
+ int idx = 0;
+
+ for (int i = 0; i < nums.size(); i++)
+ {
+ if (nums[i] != 0)
+ {
+ swap(nums[idx], nums[i]);
+ idx++;
+ }
+ }
+ }
+};
+
+
+```
+위에 방법 처럼 풀면 1,1 처럼 연속적인 0 아닌 값 나왔을때도 자기 자신과 swap 하게 된다 이를 개선 한 방법은 다음의 코드이고 two pointe를 사용 했다.
+
+
+```c++
+class Solution {
+public:
+ void moveZeroes(vector& nums)
+ {
+ if(nums.size()==1)
+ {
+ return;
+ }
+ int idx1=0,idx2=1;
+
+ while(idx2 != nums.size())
+ {
+
+ //idx2와 idx1 사이에 0이 있으면 안된다 오직 0이 아닌 연속적인 값만 고려 하는 조건 식이다
+ if(idx2-idx1==1&&nums[idx1]!=0&&nums[idx2]!=0)
+ {
+ idx1++;
+ idx2++;
+ continue;
+ }
+
+
+ if(nums[idx1]!=0)
+ {
+ idx1++;
+ }
+ else if(nums[idx2]!=0)
+ {
+ nums[idx1]=nums[idx2];
+ nums[idx2]=0;
+
+ }
+
+ idx2++;
+ }
+ }
+};
+```
+
+**two pointer 방식으로 다시 풀어보면서 느낀점 두 포인터 간의 거리도 이용하면 연속적인 숫자, 거리를 조절 할수 있다는 것을 알게 되었다**
+
+
+
+개선 한 방법이 leetcode 해보았을때 더 빠르다
+
+
+
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 2번 Find pivot index
+
+pivot 기준으로 왼쪽 합과 오른쪽 합이 같이지는 index를 반환하는 문제입니다.
+
+우리가 문제에서 찾아내야하는 것은 pivot index입니다. 배열 처음 부터 pivot index인지 볼것이기 때문에
+pivot index기준 왼쪽 합과 오른쪽의 합을 알아야합니다.
+
+pivot index는 배열 처음 부터 시작하므로
+
+//초기화 조건
+left_sum =0;
+right_sum = 배열의 총합으로 초기화 할 수 있습니다.
+
+문제를 분석해보면 right sum 과 left sum이 같아질때 한박자 느리다는거 이게 핵심이다!!
+그리고 또 다른 분석은 pivot index 기준으로 값이 같다는 성질 즉 양쪽 값이 pivot index 기준으로 같다는 말
+
+* c++ 코드
+
+```c++
+class Solution {
+public:
+ int pivotIndex(vector& nums)
+ {
+ //배열의 총합을 구한다
+ int total = accumulate(nums.begin(), nums.end(), 0);
+
+ //초기화
+ int left_sum = 0;
+ int right_sum = total;
+ int prev = 0;
+
+ for (int i = 0; i < nums.size(); i++)
+ {
+ right_sum -= nums[i];
+ left_sum += prev;
+
+ if (left_sum == right_sum)
+ {
+ return i; //pivot index
+ }
+ prev = nums[i];
+ }
+
+ //pivot index없는 경우
+ return -1;
+ }
+};
+
+```
+
+* python 코드
+
+```python
+class Solution(object):
+ def pivotIndex(self, nums):
+
+ """
+ :type nums: List[int]
+ :rtype: int
+ """
+ total_sum = sum(nums)
+
+ right_sum = total_sum
+ left_sum = 0
+
+ for idx, num in enumerate(nums):
+ right_sum -= num
+ if left_sum == right_sum:
+ return idx
+ left_sum += num
+
+ return -1
+```
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 3번 Minimum Size Subarray Sum
+
+연속된 배열의 합 == target 중에서 길이가 가장 짧은 길이를 구하는 문제입니다.
+
+연속된 subArray의 합을 구하는 것이므로 진행 방향은 첫 요소 부터 진행하다가
+조건이 안맞으면 다음 요소 즉 두번째 요소부터 진행하는 방식으로 진행합니다. 두 번째 요소부터 시작할때 다시 더 헤줄 필요없이 첫번째 요소의 element만 빼주면 두 번째 element부터 더한것을 유지 할 수 있습니다.
+
+그리고 값이 target과 같아지거나 커지면 그때의 길이를 min함수로 업데이트합니다.
+
+
+* c++ 코드
+
+```c++
+int minSubArrayLen(int target, vector& nums)
+{
+ int left = 0;
+ int right = 0;
+ int sum = 0;
+ int len = INT_MAX;
+
+ while (right < nums.size())
+ {
+ sum += nums[right];
+
+ while (sum >= target) //right고정 될때 left 가 조절되어야하기 때문이다
+ {
+ len = min(len, right - left + 1);
+ sum -= nums[left];
+ left++;
+ }
+ right++;
+ }
+
+ //len이 초기값과 같다면 0 반환한다
+ return (len==INT_MAX) ? 0 : len;
+}
+```
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+
+### 추가 문제 백준 14246 K보다 큰 구간
+
+
+특정 구간의 합이 target k보다 큰 모든 쌍의 개수를 출력하는 문제 였다
+two pointer를 사용해서 문제를 해결 하였다 sum이 k보다 클때 뒤에 나오는 구간들도 모두 포함외 되므로 계산에 포함 시켰다 그리고 계속 해맸던것이 idx1이 sum>k의 조건이 아닐때까지 반복문을 돌렸어야 했는데 이걸 찾는데 오래 걸렸다. 아래는 내가 푼 문제의 코드이다 그리고 sum과 sub_count는 문제 조건에 맞추어서 long long int 해줌 이거 안하면 틀린걸로 판단 한다 사실 여기서 오래 걸렸다 (분명 맞는것 같은데 틀렸다고 나와서 계속 시도 하다가 long long int로 바꾸었더니 되었다 백준 싫어...)
+
+
+```c++
+#include
+#include
+
+
+using namespace std;
+
+int main()
+{
+ ios::sync_with_stdio(false);
+ cin.tie(NULL);
+
+ int n = 0, k = 0, idx1 = 0, idx2 = 0;
+ long long int sum = 0, sub_count = 0;
+ cin >> n;
+
+ vector nums(n);
+ for (int i = 0; i < n; i++)
+ {
+ cin >> nums[i];
+ }
+
+ cin >> k;
+
+
+ //idx1과 idx2가 같은곳 가리켜도 괜찮음
+
+ for(idx2;idx2=k일때까지 반복문 돌려 줘야 한다
+ //해맬때는 while대신에 if로 했었는데 사실 if-> while바뀐것 밖에 없는데 시간이 오래 걸렸다..
+ while (sum > k)
+ {
+ sub_count += nums.size() - idx2;
+
+ sum -= nums[idx1];
+ idx1++;
+
+ }
+
+
+
+ }
+
+ cout < smallerNumbersThanCurrent(vector& nums)
+ {
+ vector vec;
+
+ for(int i=0;inums[j])
+ {
+ count++;
+ }
+ }
+ vec.emplace_back(count);
+
+ }
+ return vec;
+
+
+ }
+};
+
+```
+
+하지만 time :O(n)으로 할수가 있었다 그런 sort,hashmap을 사용하는것이다.
+정렬 시킨 ans 배열을 hash map인 m에 emplace할껀데 이때 중복된 숫자는 하나로 처리 할수있도록 한다 그리고 핵심은 정렬시킨 ans요소를 큰 요소값 부터 넣어주는것이다
+이렇게 하면 큰 숫자 a보다 작은 요소개수를 알수가 있다 직접 해보면 무슨말인지 알수있다 어쨌든 인덱스를 뒤에서 부터 i= nums.size()-1부터 큰 요소값과 mapping해주면 현재 요소보다 작은 값의 개수를 알수가 있다
+
+
+```c++
+class Solution {
+public:
+ vector smallerNumbersThanCurrent(vector& nums) {
+ vector ans = nums;
+ unordered_map m;
+ sort(ans.begin(), ans.end());
+ for(int i=nums.size()-1; i>=0; i--)
+ m[ans[i]] = i;
+ for(int i=0; i arr1을 반환하기 때문입니다
+
+##### Hint
+**0이 아닌 요소 index부터 비교를 시작해서 값이 큰 값 먼저 arr1배열 끝에 삽입합니다.**
+
+
+만약 merge sort를 직접 구현 하고 배열을 합친다면
+Time : O(nlogn)의 복잡도로 구현 할 수 있습니다.
+
+
+* c++ 코드
+
+```c++
+class Solution
+{
+public:
+ void merge(vector& nums1, int m, vector& nums2, int n)
+ {
+
+
+ int arr1_size = m - 1; //숫자 끝 부분
+ int arr2_size = n - 1;
+ int idx = m + n - 1; //arr1의 끝 부분
+ while (arr2_size >= 0)
+ {
+ if (arr1_size >= 0 && nums1[arr1_size] >= nums2[arr2_size])
+ {
+ nums1[idx] = nums1[arr1_size];
+ idx--;
+ arr1_size--;
+
+ }
+ else
+ {
+ nums1[idx] = nums2[arr2_size];
+ arr2_size--;
+ idx--;
+ }
+ }
+ }
+};
+```
+
+* python 코드
+
+```python
+class Solution(object):
+ def merge(self, nums1, m, nums2, n):
+ """
+ :type nums1: List[int]
+ :type m: int
+ :type nums2: List[int]
+ :type n: int
+ :rtype: None Do not return anything, modify nums1 in-place instead.
+
+ """
+ idx = m + n - 1
+ l_1 = m - 1
+ l_2 = n - 1
+
+ while l_2 >= 0 and l_1 >= 0:
+ if nums2[l_2] > nums1[l_1]:
+ nums1[idx] = nums2[l_2]
+ l_2 -= 1
+
+ else:
+ nums1[idx] = nums1[l_1]
+ l_1 -= 1
+ idx -= 1
+```
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 5번 Find Peak Element
+
+
+O(N)으로 문제를 해결한다고 했을때는 sliding window를 3개 잡아서 주위값보다 큰지만 확인해 가면서 해결할수가 있다 하지만 문제에서 O(log N)으로 해결해야한다는 조건이 있습니다.
+
+O(log N)이면 binary search를 생각해 볼수있습니다.
+
+그래프를 그려보면 더 직관적으로 이해 할수가 있다 peak element처럼 꼭지점을 찾는거다 여기서 정렬되어있는 상황에서 binaray search를 생각 하지 말고 조금더 근본적으로 보면 이해하기 쉬울것이다 binary search는 우선 반으로 나누고 반으로 나눠서 요소를 찾는것이다 이 문제에도 크게 벗어나지 않는다 그래프 그려 보면 알겠지만 가장 큰 peak element 즉 극대점을 찾는게 아니다 local적으로 꼭지점있으면 그것도 정답에 포함이 된다 우선 mid값과 mid+1값을 비교해서 mid+1이 더 크면 꼭지점은 오른쪽에 있다고 보고 범위를 줄인다 만약 mid값이 더 크다면 반대로 범위를 왼쪽으로 줄여서 보면 된다 근본적으로 계속 반으로 범위를 설정해 가면서 원하는 요소 값을 찾는게 핵심인데 binary search 기본 내용에서 크게 벗어나지 않음을 알수가 있다
+
+
+그래서 binary serarch 구현과 비슷하게 코드를 구성 하면 아래와 같습니다.
+
+
+
+* c++ 코드
+
+```c++
+class Solution {
+public:
+ int findPeakElement(vector& nums)
+ {
+ //배열 크기가 1보다 작으면 0을 반환
+ if (nums.size() <= 1)
+ {
+ return 0;
+ }
+
+ //index초기화 합니다
+ int left = 0;
+ int right = nums.size() - 1;
+
+ //가운데 기준으로 peek element 찾는다 -> binary search
+ while (left < right)
+ {
+ int pivot = (left + right) / 2;
+ if (nums[pivot] < nums[pivot + 1])
+ {
+ left = pivot + 1;
+ }
+ else
+ {
+ right = pivot; //right도 포함해야한다
+ }
+ }
+ return left;
+ }
+};
+```
+
+
+
+# 13 Find peak element 2 leetcode
+
+위에서는 left-right만 파악하면 되었는데 grid라서 top-bottom도 신경 써야 하는 문제이다.
+
+
+
+
+위의 문제를 풀어보고나서 풀어보았다 내가 푼 방법은 binary search방식으로 풀지 않았다 그래서 사용해서 최적화 하는 코드도 같이 업데이트 하겠다
+<추후에 업데이트>
+
+내가 문제를 해결한 방법 binary search사용시 peak element를 전부 파악할수없으니까 sliding window 방식을 사용했다 그렇게 함으로써 left-right peak element해당하는 요소를 따로 배열로 정리를 하였고 이 요소를 가지고 top-bottom을 판단하였다 만약 top-bottom 조건에도 맞다면 return하도록 하였다
+2차원 배열 요소에 대한 index를 파악하기 위해 unordered_map을 사용했다 어쨌든 해결한 큰 틀은 위에와 같고 **binaray search 방식으로 최적화 하는 코드는 맨 밑에 추가 하겠다 현시점23/06/21에는 아직 안함 -- 업데이트시에는 지우기**
+
+
+
+
+**처음에 내가 풀었던 코드**
+
+```c++
+ class Solution
+ {
+ public:
+
+ bool judge(int left, int mid, int right)
+ {
+ if (leftright)
+ {
+ return true;
+ }
+ return false;
+ };
+
+ vector findPeakGrid(vector>& mat)
+ {
+ unordered_map> m;
+
+ vector temp = { -1 };
+
+ //O(N)
+ for (int i = 0; i < mat.size(); i++)
+ {
+ for (int j = 0; j < mat[0].size(); j++)
+ {
+ m.emplace(mat[i][j], make_pair(i, j));
+ temp.emplace_back(mat[i][j]);
+ }
+ }
+
+
+ temp.emplace_back(-1);
+ vector temp2;
+
+ //아직까지 O(N)
+ for (int i = 0; i + 2 < temp.size(); i++)
+ {
+ if (temp[i]temp[i + 2])
+ {
+ temp2.emplace_back(temp[i + 1]);
+ }
+ }
+
+ //해당 요소만 top bottom 비교
+
+ for (auto& e : temp2)
+ {
+ int top = m[e].first - 1;
+ int bottom = m[e].first + 1;
+ int left = 0, right = 0;
+ if (top == -1)
+ {
+ left = -1;
+ right = mat[bottom][m[e].second];
+ if (judge(left, e, right))
+ {
+ return vector {m[e].first, m[e].second};
+ }
+
+ }
+ else if (bottom == mat.size())
+ {
+ right = -1;
+ left = mat[top][m[e].second];
+ if (judge(left, e, right))
+ {
+ return vector {m[e].first, m[e].second};
+ }
+ }
+ else
+ {
+ left = mat[top][m[e].second];
+ right = mat[bottom][m[e].second];
+ if (judge(left, e, right))
+ {
+ return vector {m[e].first, m[e].second};
+ }
+
+ }
+
+
+ }
+
+
+
+
+ return vector {-1,-1};
+
+ }
+};
+
+```
+사실 시간 복잡도를 위에 코드에서 볼때 이해가 안되는게 처음 배열을 N만큼 순회 하는거 빼고 두번째 세번째 반복문은 N보다 작은 반복문이다 그래서 최종으로는 배열을 한번 순환한 N이 나올꺼라고 생각을 했다 그래서 문제에서 요구하는 n log(m)이나 m log(n)보다 더 괜찮을것이라고 생각을 했다 물론 비교적 메모리는 많이 사용한것 같지만 시간 복잡도만 보았을때는 O(n)이 나올것으로 예상하고 제출했는데 겨우 통과 될 정도의 속도였음을 알았다 -- **시간 체크 하는거 chrono보고 비교 해보기**
+
+
+
+
+**최적화 적용한 코드 binary search**
+
+```c++
+
+
+```
+
+**처음 코드와 두번째 코드 시간 비교 해보기**
+
+
+
+
+> 위에 문제 목록 추가 하기 +
+
+
+
+
+
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 6번 Merge Intervals
+
+문제 이름대로 구간을 범위에 맞추어서 합치는 문제입니다.
+
+
+intervals where intervals[i] = [starti, endi]
+
+구간은 위와 같이 start,end 순으로 입력이 됩니다
+
+구간을 합치려면 end_first ,start_second 두개를 비교해서 구간을 합쳐야 한다는것을 알수있습니다.
+
+이렇게 진행을 하면 모든 요소를 다 비교를 해주어야 하기 때문에 O(n^2)이 걸립니다.
+
+하지만 start중심으로 정렬을 한다면 O(NlogN+M)으로 해결 할수있을것입니다.
+왜냐하면 일일이 다 살펴 볼 필요없이 진행 할 수 있기 때문입니다.
+
+
+
+우선 이 문제를 보고 제가 푼 방식을 나열하고 코드를 보겠습니다
+참고로 제가 처음 생각한 코드는 실행은 되지만 시간 초과가 나왔기 때문에 결국 다른 방법으로 코드를 구현해야했습니다
+
+첫번째는 구간을 합치는 조건을 생각했습니다. end_first >= start_second이면 구간을 합칠수있다고 생각했습니다.
+두번째는 진행방식에 대해 생각했습니다. 구간 조건만 생각한다면 2중 반복문으로 모두 비교를 해주어야 하기 때문에 시간 초과가 날것입니다. 이를 위해 첫 요소를 정렬 시켜 주는 방식을 사용했습니다.
+세번째는 구현 방법을 생각 했습니다. 아래 코드를 보면서 부연 설명 하겠습니다.
+결론적으로 i번째 요소를 지우면서 진행하는 방향으로 생각했는데 vector.erase()함수를 사용해서 아마 시간 초과가 난것 같습니다.
+erase함수의 시간 복잡도는 O(n)이기 때문이고 for 문 안에서 사용하였기 때문에 O(n^2)이 넘어 간것 같습니다.
+
+
+
+그래서 새롭게 구현한것의 핵심은 지우는 방식을 바꾼것입니다. 배열에서 하나씩 땡겨오는 것처럼 구현을 했습니다. 이렇게 되면 마지막에는 구간이 합쳐진 개수만큼 뒤에 남을것이니까 합쳐진 만큼 pop_back하면 됩니다.
+
+
+* c++ 코드 (시간 초과 코드)
+
+```c++
+class Solution
+{
+public:
+ vector> merge(vector>& intervals)
+ {
+ sort(intervals.begin(), intervals.end()); //정렬
+
+ int size = intervals.size() - 1;
+ int idx = 0; //배열의 사이즈를 맞추기위한 변수
+ for (int i = 0; i < size; i++)
+ {
+ if (intervals[i - idx][1] >= intervals[i + 1 - idx][0])
+ {
+
+ intervals[i + 1 - idx][0] = intervals[i - idx][0];
+ intervals[i + 1 - idx][1] = max(intervals[i - idx][1], intervals[i+1- idx][1]); //범위가 큰쪽으로 맞추기 위함
+
+ intervals.erase(intervals.begin()+i - idx,intervals.begin()+i - idx +1); //O(n)
+ idx++;
+ }
+ }
+
+
+ return intervals;
+ }
+};
+```
+
+
+* c++ 코드
+
+```c++
+class Solution {
+public:
+ vector> merge(vector>& intervals)
+ {
+ //start 기준으로 정렬
+ sort(intervals.begin(), intervals.end());
+ int idx = 0;
+ for (int i = 1; i < intervals.size(); i++)
+ {
+
+
+ if (intervals[idx][1] >= intervals[i][0])
+ {
+ //조건이 맞으면 구간을 합친다
+ intervals[idx][1] = max(intervals[i][1], intervals[idx][1]);
+
+ }
+ else
+ {
+ idx++;
+ intervals[idx] = intervals[i];
+ }
+
+ }
+
+ //합쳐서 줄어든 만큼 pop하는 코드 intervals.size()가 항상 큰상황이다
+ while (intervals.size() != idx+1)
+ {
+ intervals.pop_back();
+ }
+
+
+ return intervals;
+ }
+};
+```
+
+
+처음 풀었던 방식과 두번째 방식에서 논리는 어느정도 일치 하지만 구간 삭제 하는 방식에서 차이가 있었다 erase로 O(n)복잡도로 삭제 하지 말고 O(1)으로 삭제 할수있게 두 포인터 조절 하는 감을 배울수있었다
+
+
+
+
+* python 코드
+
+```python
+class Solution(object):
+ def merge(self, intervals):
+ """
+ :type intervals: List[List[int]]
+ :rtype: List[List[int]]
+ """
+
+ #첫요소 기준으로 정렬하는 코드
+ intervals.sort(key=lambda x:x[0])
+
+ idx =0
+ for i in range(1,len(intervals)):
+ if intervals[idx][1]>=intervals[i][0]:
+ intervals[idx][1]=max(intervals[idx][1],intervals[i][1])
+
+ else:
+ idx+=1
+ intervals[idx]=intervals[i]
+
+ while(len(intervals)!=idx+1):
+ intervals.pop()
+
+ return intervals
+
+```
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 7번 Shortest Unsorted Continuous Subarray
+
+이번 문제 같은 경우는 정렬을 이용해서 문제를 해결하셔도 되지만
+TIME 은 O(NlogN)이 걸릴것입니다. 만약 TIME 을 O(N)으로 해결하고 싶다면 그래프를 그려보고 경향성을 따져 보아야합니다.
+
+LeetCode에 있는 Solution중 stack을 이용해서 푼 방법이 있는데 그 풀이 방식이 경향성을 따지고 푼 방식입니다.
+하지만 저의 코드는 stack을 이용하는 대신 반복문을 이용해서 문제를 해결했습니다.
+아래 코드는 O(n)의 시간 복잡도를 가집니다. 문제 풀이 방식은 최솟값과 최댓값을 찾아서 이어주는 방식이라기 보다는 그래프로 그려 보았을때
+처음 꺽이는 지점, 마지막의 꺽이는 지점을 찾아서 인덱스 계산 한것입니다.
+
+
+* c++ 코드
+
+```c++
+
+class Solution {
+public:
+ int findUnsortedSubarray(vector& nums)
+ {
+ if (nums.size() < 2)
+ {
+ return 0;
+ }
+
+ int end = 0;
+ int prev = nums[0];
+
+ //꺽이는 시작점 찾기 O(n)
+ for (int i = 0; i < nums.size(); i++)
+ {
+ if (nums[i] < prev)
+ {
+ end = i;
+ }
+ else
+ {
+ prev = nums[i];
+ }
+ }
+
+ int start = nums.size() - 1;
+ prev = nums[start];
+
+ //꺽이는 끝지점 찾기 O(n)
+ for (int i = nums.size() - 1; i >= 0; i--)
+ {
+ if (nums[i] > prev)
+ {
+ start = i;
+ }
+ else
+ {
+ prev = nums[i];
+ }
+ }
+
+ if (end != 0)
+ {
+ return end - start + 1;
+ }
+ return 0;
+
+ }
+};
+```
+* python code
+```python
+from typing import List
+
+class Solution:
+ def findUnsortedSubarray(self, nums: List[int]) -> int:
+
+ if len(nums) < 2:
+ return 0
+ end = 0
+ prev = nums[0]
+ for i in range(len(nums)):
+ if nums[i] < prev:
+ end = i
+ else:
+ prev = nums[i]
+
+ start = len(nums)-1
+ prev = nums[-1]
+
+ for i in range(len(nums))[::-1]:
+ if nums[i] > prev:
+ start = i
+ else:
+ prev = nums[i]
+
+
+ if end != 0:
+ return end-start+1
+
+ return 0
+
+```
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 8번 Find Dupicate
+
+
+중복된 숫자를 찾는 문제입니다. Hash Map을 이용해서 풀면 쉽게 문제를 해결 할 수 있습니다.
+
+하지만 SPACE를 O(N)으로 해결 해야한다면 Hash Map을 사용 할 수 없게 됩니다. 이런 경우에는 +/- 성질을 이용해서 문제를 풀면 좋습니다.
+
+입력으로 오는 배열의 값에 -1을 곱해줍니다. 만약 중복된 값이 있다면 음수는 양수가 될것입니다. 그러면 중복된 값을 찾게 된것이니 반환해주면 됩니다. Hash Map을 이용한 풀이와 사용하지 않은 풀이 코드는 아래와 같습니다.
+
+
+* c++ Hash Map 사용한 코드
+
+
+```c++
+class Solution {
+public:
+ int findDuplicate(vector& nums)
+ {
+ //
+ if (nums.size() == 0)
+ {
+ return 0;
+ }
+ unordered_map map;
+
+ for (int i = 0; i < nums.size(); i++)
+ {
+
+ if (map.find(nums[i]) != map.end())
+ {
+ return nums[i];
+ }
+ map[nums[i]]++;
+ }
+
+ }
+};
+```
+
+
+* c++ Hash Map 사용하지 않은 코드
+
+```c++
+class Solution {
+public:
+ int findDuplicate(vector& nums)
+ {
+ for(int i=0;i0)
+ {
+ return tmep_pos+1;
+ }
+ }
+ return -1;
+
+ }
+};
+
+```
+위와 같은 코드로 만들수있는 이유는 문제에서 [1,n]까지의 범위에서 반복된 숫자 하나만 찾으라는 문제였기 때문에 인덱스로 접근해서 문제를 풀수있는것이다.
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+### 9번 Two Sum
+
+이번 문제는 two pointer를 이용해서 푸는 문제입니다. 배열에 대한 감을 잡기 좋은 문제입니다. two sum 뿐만아니라 3,4,..N sum 문제 또한 LeetCode에 있으니까 필요하신 분은 찾아서 풀어보는것을 추천합니다.
+
+
+**풀이 방법**
+1. 정렬을 이용해서 푸는 방법
+
+ * 정렬을 하고 양쪽의 two pointer를 잡아서 target을 찾을수있습니다.
+
+2. hash map을 이용해서 푸는 방법
+
+ * Hash map key : target - arr[n]
+ Hash map value: index
+
+ * 해당 값을 찾으면 반환 한다
+
+
+
+정렬을 이용해서 문제를 푸신다면 , 한 가지 주의 할 점은 바뀐 index가 아니라 입력한 배열 index 그대로 유지를 해야한다는 점입니다.
+정렬 하기 전에 입력 배열의 index를 따로 저장을 하고 two sum 풀이를 이어나가야 합니다.
+
+
+Hash map을 이용한 풀이에서 핵심은 target - arr[n]을 key값으로 넣는 것 입니다. 만약 key값이 hash map에 있다면 그 값이 우리가 찾는 값입니다.
+
+* c++ 코드 정렬 사용
+
+```c++
+class Solution {
+public:
+ vector twoSum(vector& nums, int target)
+ {
+ //정렬 되었을때 index 유지 하기 위함이다
+ vector> temp; //first -> nums 요소 second -> index
+
+ for (int i = 0; i < nums.size(); i++)
+ {
+ temp.emplace_back(make_pair(nums[i],i));
+
+ }
+
+ //first인 nums[i]기준으로 정렬
+ sort(temp.begin(), temp.end());
+
+
+ int idx = 0;
+ int idx2 = nums.size() - 1;
+
+ int start = 0, end = 0;
+
+ while (idx < idx2)
+ {
+ //nums 배열의 요소로 비교
+ if (temp[idx].first + temp[idx2].first == target)
+ {
+ //정렬하기 전의 index를 유지한다
+ start = temp[idx].second;
+ end = temp[idx2].second;
+ break;
+ }
+
+ if (temp[idx].first + temp[idx2].first > target)
+ {
+ idx2--;
+ }
+ else
+ {
+ idx++;
+ }
+ }
+
+
+ return {start,end};
+
+ }
+};
+
+```
+
+
+위와 비슷한 방법이지만 temp 배열을 조금 수정 했습니다.
+
+탐색하는 방식과 정렬하는것은 동일하지만 target을 찾고 인덱스를 찾는것에 조금 차이를 주었습니다.
+
+처음에는 find를 정방향으로 두번 썼는데 같은 값이면 첫 번째만 find가 찾기 때문에 하나는 정방향 하나는 역방향에서 찾게 바꾸었습니다.
+그리고 역방향 find의 distance를 칮을때는 (temp.rend()-it2)-1 한번더 1을 빼주어야 함을 알수있었습니다.
+
+성능으로 따지면 위의 코드보다 좋지 않습니다. find의 시간 복잡도는 O(n)이니까요 -> 솔직히 temp 배열을 수정한것 밖에 차이가 없습니다
+
+```c++
+class Solution {
+public:
+ vector twoSum(vector& nums, int target)
+ {
+ vector temp = nums;
+
+ sort(nums.begin(), nums.end());
+
+ int idx1 = 0, idx2 = nums.size()-1;
+ int temp_val = 0;
+
+
+ while (idx1 < idx2)
+ {
+ temp_val = nums[idx1] + nums[idx2];
+ if (temp_val == target)
+ {
+ const auto it = find(temp.begin(), temp.end(), nums[idx1]);
+ //cout << "hello " << it - temp.begin() << endl;
+
+ const auto it2 = find(temp.rbegin(), temp.rend(), nums[idx2]);
+
+ return { int(it - temp.begin()),int((temp.rend()-it2)-1) };
+ }
+ if (temp_val > target)
+ {
+ idx2--;
+ }
+ else
+ {
+ idx1++;
+ }
+ }
+
+ }
+};
+```
+
+
+* c++ 코드 Hash map 사용
+
+```c++
+class Solution
+{
+public:
+ vector twoSum(vector& nums, int target)
+ {
+
+ // Hash map 사용
+ unordered_map hash; //key : target-num[i] value: index
+
+ vector result;
+ for(int i=0;i List[int]:
+
+ temp = sorted(nums)
+ arr_idx_size = len(nums)-1
+ idx,idx2=0,arr_idx_size
+
+ while idx target:
+ idx2-=1
+ else:
+ idx+=1
+
+
+ return []
+
+
+```
+
+
+다음은 hash를 사용한 파이썬 코드 입니다
+
+```python
+
+class Solution(object):
+ def twoSum(self, nums, target):
+ """
+ :type nums: List[int]
+ :type target: int
+ :rtype: List[int]
+
+ hash map -> dic사용하는 방법
+
+ O(n)으로 해결 가능
+ """
+
+ value={}
+
+ for idx,val in enumerate(nums):
+
+ if val in value:
+ return [idx,value[val]]
+
+ value[target-val]=idx
+
+
+```
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+
+### 10번 Rotate Image 2D array
+
+
+이번 문제는 2차원 배열에 대한 감을 찾기 좋은 문제입니다.
+
+n*n 2차원 행렬을 90도 회전한 모습을 출력하는 문제입니다.
+*단, 또다른 2차원 행렬의 공간을 만들어서는 안됩니다. 입력으로 들어온 matrix를 그대로 return 해야합니다.*
+
+4개의 지점이 같이 움직인다고 생각하면 이해하기 쉬울것입니다.
+
+n*n img matrix
+
+a b c a
+ ->
+c d d b
+
+int temp = img[b]
+img[b] = img[a]
+img[a] = img[d]
+img[d] = img[c]
+img[c] = temp
+
+
+* c++ 코드
+
+```c++
+
+void Rotate_img(vector>& arr)
+{
+ //n-1
+ int len = arr[0].size()-1;
+
+ //반절의 길이만큼 반복
+ for (int row = 0; row < arr.size() / 2; row++)
+ {
+ for (int col = 0; col < (arr.size() + 1) / 2; col++)
+ {
+
+
+ int temp = arr[len - col][row];
+
+ arr[len - col][row] = arr[len - row][len - col];
+ arr[len - row][len - col] = arr[col][len - row];
+ arr[col][len - row] = arr[row][col];
+ arr[row][col] = temp;
+
+
+ }
+ }
+}
+
+```
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 11번 Search a 2D Matrix I
+
+
+문제 설명을 간단히 해보면
+
+M*N 행렬이 다음과 같다고 하면
+
+| 1 | 3 | 5 | 7 |
+| ---- | ---- | ---- | ---- |
+| 10 | 11 | 16 | 20 |
+| 23 | 30 | 34 | 60 |
+
+
+1. 각 행은 정렬되어있다
+
+ * 1 3 5 7 , 10 11 16 20 등 각 행은 정렬되어있다
+
+2. 각 행의 첫 요소는 이전 행의 마지막 숫자보다 크다
+
+ * 10은 7보다 크고 23은 20보다 크다
+
+
+
+이런 행렬일때 target값이 행렬안에 있는지 없는지 T/F 로 출력하면 되는 문제입니다.
+
+
+저는 처음에 2번의 규칙을 활용해서 문제를 풀었습니다. 만약 target이 행의 마지막 요소보다 작다면 그 행에서 target을 찾으면 됩니다.
+
+아래는 직관적으로 문제를 푼 코드 입니다.
+
+* c++ 코드 직관적인 풀이 version
+
+```c++
+
+class Solution {
+public:
+ bool searchMatrix(vector>& matrix, int target)
+ {
+ //base case
+ if (matrix.size() == 0 || matrix[0].size() == 0)
+ {
+ return false;
+ }
+
+ int end = matrix[0].size()-1; //각 행의 크기
+
+ for (int i = 0; i < matrix.size(); i++)
+ {
+ //각 행의 마지막 요소가 target보다 같거나 크면 -> 2번 규칙을 활용한 것입니다.
+ if (matrix[i][end] >= target)
+ {
+ //해당 row에서 target요소를 찾는다 만약 찾았다면 true 반환
+ if (matrix[i].end() != find(matrix[i].begin(), matrix[i].end(), target))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+
+ }
+};
+
+```
+
+
+위의 풀이도 통과하는 방식이지만 조금 더 보안해서 문제를 풀수도 있습니다.
+
+* 1번 규칙과 2번 규칙을 다시 한번 봅시다.
+ * 1번 규칙을 통해 각 행은 정렬이 보장 되어있습니다.
+ * 2번 규칙을 통해 전의 행보다 지금의 행이 더 큰 값을 가지고 있음을 보장합니다
+
+1 번과 2번을 통합해서 생각해보면 전체적으로 보았을때 오름차순 정렬 경향성이 보장 되어있음을 알수있습니다.
+
+이런 상황에서 target값을 찾는 문제 .... 이제 감이 오시나요? .......
+
+
+
+Binary Search를 이용하기 적절한 상황임을 알수있습니다. 2차원 배열을 1차원 배열로 늘려서 생각 해봅니다.
+
+아래는 Binary Search로 문제를 푼 c++ 코드입니다.
+
+
+* c++ Binary Serach 이용한 풀이
+
+```c++
+
+class Solution
+{
+public:
+ bool searchMatrix(vector>& matrix, int target)
+ {
+ //base case
+
+ if (matrix.size() == 0 || matrix[0].size() == 0)
+ {
+ return false;
+ }
+
+ //Initialize m*n size matrix
+ int m = matrix.size();
+ int n = matrix[0].size();
+
+
+ //2차원 배열을 1차원 배열로 생각 했을때 길이입니다.
+ int left = 0;
+ int right = n * m - 1;
+
+
+ while (left <= right)
+ {
+ //mid = (left+right) / 2 와 동일합니다 OverFlow를 막기 위한 수학적 꼼수라고 생각하시면 좋습니다.
+ int mid = left + (right - left) / 2;
+
+ if (matrix[mid / n][mid % n] == target)
+ {
+ return true;
+ }
+ else if (matrix[mid / n][mid % n] > target)
+ {
+ right = mid - 1;
+ }
+ else
+ {
+ left = mid + 1;
+ }
+ }
+ return false;
+
+ }
+};
+
+```
+
+* 위의 코드에서 핵심
+ * 2차원 배열을 1차원 배열로 보기
+ * "mid / n", "mid % n" 이해하기
+ * mid는 2차원을 1차원으로 늘린것이므로 n size로 나누어서 몫과 나머지를 구하면 2차원 배열로 생각했을 때의 index를 구할수있습니다.
+
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 12번 Search a 2D Matrix II
+
+11번 문제와 거의 똑같은 문제인데 2번의 규칙만 달라진 문제입니다.
+
+
+**바뀐 2번 규칙**
+
+각 열은 정렬되어있다.
+
+
+바뀐 2번 규칙을 사용해서 위에서 풀었던 문제를 풀면 됩니다.
+
+바뀐 2번 규칙 때문에 처음에 직관적으로 풀이는 더 이상 사용 할 수 없습니다.
+또한 전체적으로 상승하는 경향성도 아니기 때문에 Binary Search도 사용 할 수 없습니다.
+
+예제 행렬)
+
+| 1 | 4 | 7 | 11 | 15 |
+| ---- | ---- | ---- | ---- | ---- |
+| 2 | 5 | 8 | 12 | 19 |
+| 3 | 6 | 9 | 16 | 22 |
+| 10 | 13 | 14 | 17 | 24 |
+| 18 | 21 | 23 | 26 | 30 |
+
+
+이번 문제 또한 2번 규칙의 성질을 잘 활용해서 문제를 풀어야 합니다.
+
+앞에 문제를 풀었던 것 처럼 1번 규칙과 2번 규칙을 통해 해결 방안을 생각해 보겠습니다.
+
+**각 행과 열은 각각 정렬 되어있다**
+
+만약에 찾는 target이 16이라고 생각 해봅시다
+
+18 요소에서 탐색을 시작해봅시다.
+
+그러면 각 행과 열은 각각 정렬 되어 있다는 사실 덕분에
+
+* *18이 포함된 행*
+ 즉 18 21 23 26 30 에는 찾는 target이 없다는것을 보장 할수있습니다.
+
+그러면 행을 올릴수 있습니다. 다시 10요소에서 target을 찾기를 반복합니다.
+
+10은 16 보다 작습니다. 그러면 찾는 target은 10이 포함된 열에 포함이 되지 않았음을 보장 할 수 있습니다.
+
+그러면 13으로 넘어 갈 수 있습니다. 즉 다음 열로 이동을 할수있습니다.
+
+이 원리를 이용해서 코드를 작성 하면 아래와 같습니다.
+
+* c++ 코드
+
+```c++
+class Solution
+{
+public:
+ bool searchMatrix(vector>& matrix, int target)
+ {
+ //matrix[m][0]에서 탐색을 시작 하기 위한 초기화
+ int m = matrix.size() -1;
+ int idx = 0;
+
+ while (m >= 0 && idx target) //target보다 크다면 행이동을 합니다.
+ {
+ m--;
+ }
+ else //아닌 경우는 열 이동을 합니다.
+ {
+ idx++;
+ }
+ }
+
+
+
+ return false;
+ }
+};
+```
+
+
+------------------------------------------------------------
+
+### 추가 문제 leetcode best time buy and sell stock
+
+
+처음 시도해본 코드 -> 시간 초과 아마도 O(N^2)라서?
+
+
+
+
+```c++
+class Solution {
+public:
+ int maxProfit(vector& prices)
+ {
+ int max_val = -1;
+ int buy_idx=0;
+ int sell_idx = 1;
+ //vector temp;
+ //temp.reserve(100000);
+
+ //sell val - buy val
+ while(buy_idx!=prices.size()-1)
+ {
+ for(int i=sell_idx;imax_val)
+ {
+ max_val = t;
+
+ }
+
+ }
+ //max_val = max(max_val,*max_element(temp.begin(),temp.end()));
+
+ //temp.clear();
+ buy_idx++;
+ sell_idx++;
+ }
+
+
+
+ return max_val<=0 ? 0:max_val;
+
+
+ }
+};
+```
+
+시도 해볼수있는거 incre/decre로 정렬 하고 포인터 비교 하는 방식? -> 시도 하다 아닌것 같아서 포기
+
+결국 solution을 보았다 2번째로 생각하던 방식이 조금 있다 결국에 최대 이익을 얻기 위해서는 최대 값 - 최소값이 유지가 되어야 한다 solution에서 확인할수있었던건 최소값유지 하는 거였다 sell - buy니까 sell이 최대값이 되고 buy가 최소값을 가지면 최대 이익이 된다 buy는 처음 부터 진행해 나가는데 (이건 1,2번째에서도 인지 했던 부분) 모든 buy값을 보는게 아니라 최소를 유지 하는 buy value만 가져가겠다는 거다. 처음 코드에서 시간 초과 나오는 이유가 buy idx를 업데이트 해나가면서 모든 sell 값을 보려고 했기 때문이다 그걸 buy idx가 업데이트 할때마다 하고 있다 그렇게 하지 말고 즉 매 buy val 마다 sell valu비교 하려 하지 말고 최소 buy val을 정하면 한번에 순회로 sell val과 비교하면서 해결 할수가 있다
+
+
+```c++
+class Solution {
+public:
+ int maxProfit(vector& prices)
+ {
+ int max_val = -1;
+ int min_val = prices[0];
+
+ for(int i=1;istring문자를 추가 하는게 가능 함 요소 변경하는건 안된다
+
+3. string은 heap에 할당 된다 -> string view사용하는 이유
+
+4. visual studio community 2019 기준 15 character 이하면 heap에 할당 안하고 그 이상일때 할당을 한다 즉 작은 문자열에 대해 마음 편히 string 사용해도 된다
+
+
+
+### string_views
+
+문자열에 대한 pointer와 길이만 가진다 -> 임시 객체를 생성하지 않고 문자열 사용할수가 있다
+문자열에 대한 사이즈 정보를 가지고 있기 때문에 null문자 없어도 종료를 알수가 있다
+
+
+* 다양한 문자열 타입을 전달 받을수 있는 안전하면서 효과적인 방법을 제공한다 (char 배열,c style 배열,string)
+
+
+* 원본 데이터에 대한 변경 방지 한다
+
+string view사용할때 string 타입만 사용가능한게 아니라 c style, const char등을 받을수 있으니까 1번의 할당도 하지 않기 위해 const char *를 사용할수도 있다
+
+
+
+
+
+
+### Intro
+
+안녕하세요 이번에는 문자열 파트인데요. 풀어볼 문제는 총 8문제 입니다.
+posting이 길어질수 있으므로 필요한 문제만 보시는 것을 추천합니다.
+
+
+
+### 풀어볼 문제 링크 LeetCode
+
+[1번_implement strstr()](https://leetcode.com/problems/implement-strstr/)
+{: .notice--danger}
+
+
+[2번_Add strings ](https://leetcode.com/problems/add-strings/)
+{: .notice--danger}
+
+
+[3번_Group Anagrams](https://leetcode.com/problems/group-anagrams/)
+{: .notice--danger}
+
+
+[4번_Length of the longest substring without repeating characters](https://leetcode.com/problems/longest-substring-without-repeating-characters/)
+{: .notice--danger}
+
+[5번_word pattern ](https://leetcode.com/problems/word-pattern/)
+{: .notice--danger}
+
+[6번_valid paindrome I ](https://leetcode.com/problems/valid-palindrome/)
+{: .notice--danger}
+
+
+[7번_valid paindrome II](https://leetcode.com/problems/valid-palindrome-ii/)
+{: .notice--danger}
+
+
+[7번_String Matching in an Array](https://leetcode.com/problems/string-matching-in-an-array/)
+{: .notice--danger}
+
+
+
+
+### 추가 문제 백준 듣보잡 1764
+
+```c++
+
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+int main()
+{
+ ios::sync_with_stdio(false);
+ cin.tie(0);
+ int n=0,m=0;
+ cin>>n;
+ cin>>m;
+
+ set s;
+ vector result;
+
+ for(int i=0;i>temp;
+ s.emplace(temp);
+ }
+
+ for(int i=0;i>temp;
+
+ // if(i==0)
+ // {
+ // continue;
+ // }
+ if(s.count(temp)==1)
+ {
+ result.emplace_back(temp);
+ }
+
+ }
+ sort(result.begin(),result.end());
+ cout< haystack.size())
+ {
+ return -1;
+ }
+
+ //needle과 현재문자열의 hash값 계산을 위한 초기화
+ int needle_hash = 0;
+ int cur_hash = 0;
+
+
+ //초기값을 설정하는 작업이다
+ for (int i = 0; i < needle.size(); i++)
+ {
+ //hash는 아스키 코드로 계산합니다
+ needle_hash += needle[i] - 'a'; // needle의 hash값 계산
+ cur_hash += haystack[i] - 'a'; //needle개수 만큼 haystack hash값 계산
+ }
+
+ //needle은 ll의 hash값 계산 ,haystack은 needle의 개수 2 만큼 hash 계산 즉 he까지 hash계산
+
+ for (int i = 0; i < haystack.size() - needle.size() + 1; i++) //needle size만큼 비교할꺼니까
+ {
+ if (i > 0) //초기값 설정해놓았기 때문이다
+ {
+ cur_hash += haystack[i + needle.size()-1] - 'a';
+ cur_hash -= haystack[i - 1] - 'a';
+
+ // i ==1이었다면 cur hash 는 hel까지 hash 저장 후 -> h hash값을 지운다 즉 cur_hash = > el의 hash값이다
+ }
+
+ //hash값이 커지는것을 방지하기 위해서 값을 더 줄이기 위함이다 [소수로 나누어야함]
+ cur_hash %= mod;
+ needle_hash %= mod;
+
+ //needle hash와 같지 않으면 다시
+ if (cur_hash != needle_hash)
+ {
+ continue;
+ }
+ bool equal = true;
+
+ //hash 충돌로 같은 값을 가질수있으므로 정말 맞는지 확인한다
+ for (int j = 0; j < needle.size(); j++) //hash 충돌을 확인하는 작업이다
+ {
+ //값이 다르면 equal =false
+ if (haystack[i + j] != needle[j])
+ {
+ equal = false;
+ break;
+ }
+ }
+ //hash값이 같다면 return
+ if (equal)
+ {
+ return i;
+ }
+ }
+
+
+
+ return -1;
+
+ }
+};
+```
+
+
+hash값 계산은 아스키 코드로 진행 하였고 값이 커지는 것을 방지 하기 위해 소수값인 mod로 나머지를 구한 값으로 hash값을 계산 했습니다.
+
+
+하지만 앞서 언급 했듯이 hash를 이용하지 않고도 문제를 간단하게 풀수있습니다. 언어에서 지원하는 find 함수를 이용하면 더 쉽게 문제를 해결 할 수 있습니다. 아래는 python 코드입니다
+
+
+**range search로 haystack needle 문제 해결 한게 있다 참고 하기**
+
+```c++
+class Solution {
+public:
+ int strStr(string haystack, string needle)
+ {
+ auto found = std::ranges::search(haystack,needle);
+
+ if(found.empty())
+ {
+ return -1;
+ }
+ else
+ {
+ return std::distance(haystack.begin(),found.begin());
+ }
+ }
+};
+```
+
+
+
+leetcode가 c++20을 지원 하지 않아서 ranges를 사용할수가 없다 어쨌든 작동은 한다
+
+
+
+* python 코드
+
+```python
+class Solution(object):
+ def strStr(self, haystack, needle):
+ """
+ :type haystack: str
+ :type needle: str
+ :rtype: int
+ Input: haystack = "hello", needle = "ll"
+ Output: 2
+ """
+ return haystack.find(needle)
+```
+
+
+------------------------------------------------------------------------------------------------------------------------------
+
+
+### 2 번 Add String
+
+문자열로 주어진 숫자를 더해서 다시 문자열로 반환하는 문제 입니다. 이 문제는 carry 즉 올림수 처리를 잘 해야 문제를 해결 할수있습니다.
+
+더하기를 할때 1의 자리 부터 더하므로 문자열 마지막 요소까지 index 설정하고 진행 합니다.
+
+
+* c++ 코드
+
+```c++
+class Solution
+{
+public:
+ string addStrings(string num1, string num2)
+ {
+
+ int carry = 0;//올림수
+ int sum = 0,a=0,b=0;
+
+ int size1 = num1.size() - 1; //문자열 마지막 요소로 맞추기
+ int size2 = num2.size() - 1;
+
+ string result = "";
+
+ //입력으로 들어온 문자열이 남아있다면 진행 합니다
+ while (size1 >= 0 || size2 >= 0)
+ {
+
+ a = 0; //첫 번째 문자열을 정수형으로 바꾼 값
+ b = 0; //두 번째 문자열을 정수형으로 바꾼 값
+ //첫 번째 문자열 길이가 남아있다면
+ if (size1 >= 0)
+ {
+
+ a = num1[size1] - '0';
+ size1--;
+ }
+
+ //두 번째 문자열 길이가 남아있다면
+ if (size2 >= 0)
+ {
+ b = num2[size2] - '0';
+ size2--;
+ }
+
+
+ //올림수 carry 까지 포함해서 더한다
+ sum = (a + b)+carry;
+
+ //sum의 올림수 계산
+ carry = sum / 10;
+
+ //result 문자열에 계산 값을 추가 합니다
+ result += to_string(sum % 10);
+
+
+
+
+ }
+
+ //만약 carry가 남아 있다면
+ if (carry > 0)
+ {
+ result += to_string(carry);
+ }
+
+ //result를 반전 합니다
+ reverse(result.begin(), result.end());
+
+ return result;
+
+
+
+
+ }
+};
+```
+
+올림수 carry를 다루는 것에 익숙해 진다면 어렵지 않게 해결 할 수 있는 문제 입니다.
+
+
+------------------------------------------------------------------------------------------------------------------------------
+
+### 3번 Group Anagrams
+
+
+이번 문제는 Anagram의 그룹을 찾는 문제 입니다.
+
+Anagram에 대해서 모르신다면 다음 링크로 가서 참고 해보세요!
+
+[Anagram 개념](https://ko.wikipedia.org/wiki/%EC%96%B4%EA%B5%AC%EC%A0%84%EC%B2%A0)
+{: .notice--danger}
+
+
+이제 anagram을 어떻게 찾을지를 생각 해야하는데요. 같은 문자로 다른 단어를 만드는게 anagram이니까
+입력으로 들어오는 단어를 정렬해서 저장 한다면 쉽게 anagram을 찾을 수 있습니다.
+
+* c++ 코드
+
+```c++
+class Solution
+{
+public:
+ string count_alpha(string str)
+ {
+ //알파벳 순서대로 숫자를 세주고 count하는 방식의 함수이다
+ string result = "";
+
+ char count[26] = { 0, };
+
+ // count배열에 문자 개수 세기
+ for (auto& e : str)
+ {
+ count[e - 'a']++;
+
+ }
+ for (int i = 0; i < 26; i++)
+ {
+
+ result += string(count[i], i + 'a'); //문자열 개수 만큼 result에 더한다
+
+ }
+ return result;
+ }
+
+ vector> groupAnagrams(vector& strs)
+ {
+
+ unordered_map> map;
+
+
+ //정렬한 결과를 value에 넣는 과정
+ for (auto& e : strs)
+ {
+ //같은 anagram끼리 vector에 넣는다
+ map[count_alpha(e)].emplace_back(e);
+ }
+
+ vector> result;
+
+
+ for (auto& ee : map)
+ {
+ //두번째 요소를 result벡터에 삽입한다
+ result.emplace_back(ee.second);
+ }
+
+ return result;
+
+
+ }
+};
+```
+
+정렬을 통해 Anagram의 특성을 이해 할 수 있는 문제 였습니다.
+
+------------------------------------------------------------------------------------------------------------------------------
+
+
+### 4번 Length of the longest substring without repeating characters
+
+
+반복하지 않는 가장 긴 substring의 길이를 찾는 문제 입니다. 이 문제는 HashMap을 이용해서 해결 할 수 있는데요.
+중복된 문자가 나오면 index를 업데이틀 할 수 있기 때문 입니다.
+
+
+* c++ 코드
+
+
+```c++
+class Solution
+{
+public:
+ int lengthOfLongestSubstring(string s)
+ {
+
+ int start =0;
+ unordered_map seen;
+ int result=0;
+
+ for(int end =0;end compare1;
+ unordered_map compare2;
+
+ for (auto& ele : inp1)
+ {
+ os >> token; //공백을 제거한 문자열이 옵니다
+
+ //compare1 hash map에서 ele를 못찾았다면
+ if (compare1.find(ele) == compare1.end())
+ {
+ //compare1에서 없는 요소가 compare2에서 찾으면 false입니다
+ //왜냐하면 a 와 dog는 pattern으로 묶어져 있기 때문에 a에서 dog가 없는데 dog에 a가 있다면 fasle입니다.
+ if (compare2.find(token) != compare2.end())
+ {
+ return false;
+ }
+ else //compare1,compare2에 token과 ele를 추가 합니다
+ {
+ compare1.emplace(ele, token);
+ compare2.emplace(token, ele);
+
+ }
+ }
+ //또한 compare1과 대응하는 값이 token이 아니면 false입니다.
+ else if (compare1[ele]!=token)
+ {
+ return false;
+ }
+
+
+ }
+ return true;
+}
+```
+
+Hash Map 2개를 만들어서 해결 해야 한다는 점과 a와 dog는 서로 대응한다는 점을 주의 해야 했던 문제 였습니다.
+
+
+
+------------------------------------------------------------------------------------------------------------------------------
+
+
+### 6번 Valid Palindrome I
+
+
+문자열 문제중 가장 흔하고 기초적인 문제로 볼 수 있습니다.
+
+회문은 raar 같이 시작과 끝 지점이 같은 것을 의미 합니다.
+
+회문이 무엇인지 모르겠다면 아래 링크를 참고 해주세요
+
+[회문 위키백과](https://ko.wikipedia.org/wiki/%ED%9A%8C%EB%AC%B8)
+{: .notice--danger}
+
+
+
+이 문제에서는 공백과 특수 문자등이 포함된 문자열에서 palindrome을 찾는 문제 입니다.
+
+
+* c++ 코드
+
+
+```c++
+
+class Solution
+{
+
+public:
+ bool isPalindrome(string s)
+ {
+
+ int start = 0;
+ int end = s.size() - 1;
+
+ while (start < end)
+ {
+ //공백이나 특수 문자가 아닐때까지 start와 end index를 조절 합니다
+ while (start!=s.size()-1&&!isalnum(s[start]))
+ {
+ start++;
+ }
+ while (end!=0&&!isalnum(s[end]))
+ {
+ end--;
+ }
+
+ //대문자라면 소문자로 바꾸는 코드 입니다
+ if (isupper(s[start]))
+ {
+ s[start] += 32;
+ }
+ if (isupper(s[end]))
+ {
+ s[end] += 32;
+ }
+
+ //start와 end index값이 모두 문자이고 서로 같지 않다면
+
+ //입력 문자열이 ",."만 올수도 있기 때문에 isalnum으로 확인하는 조건이 필요하다
+
+ if (isalnum(s[start])&& isalnum(s[end])&&s[start] != s[end])
+ {
+ return false;
+ }
+
+ start++;
+ end--;
+
+
+ }
+ return true;
+ }
+};
+```
+
+특수 문자나 공백을 제거 하고 start와 end index요소가 같은지 아닌지 판단 해주면 됩니다.
+또한 입력 문자열이 ",." 만 올수도 있기 때문에 isalnum함수로 확인하는 조건이 필요했습니다.
+
+
+
+------------------------------------------------------------------------------------------------------------------------------
+
+
+### 7번 Valid Palindrome II
+
+이 문제는 앞에 6번 문제의 연장선의 문제 입니다. 하나만 삭제 했을때도 palindrome을 유지하는 확인하는 문제 였습니다.
+
+start와 end index에서 살펴 보다가 서로 다른 문자가 왔을때 (즉 palindrome 이 아닌 조건이 왔다면)
+하나를 삭제 했을때도 palindrome인지 아닌지를 따져야 합니다. 크게 두가지로 생각 할 수 있습니다.
+
+**palindrome 따지는 두 가지**
+1. start +1 부터 end까지 palindrome이 되는지 확인하기
+2. start부터 end-1까지 palindrome이 되는지 확인하기
+
+앞에 2가지중 하나라도 만족 한다면 한 문자를 삭제해도 palindrome을 만족하는 문자열임을 알 수 있습니다.
+
+
+* c++ 코드
+```c++
+class Solution
+{
+public:
+ bool validPalindrome(string s)
+ {
+ //한개의 문자는 무조건 palindrome이다
+ if (s.size() == 1)
+ {
+ return true;
+ }
+
+ //index초기화
+ int start = 0;
+ int end = s.size()-1;
+
+ //2가지 중 하나가 맞는지 아닌지 확인하는 bool 변수
+ bool result = true,result2=true;
+
+
+ while (start < end)
+ {
+ //palindrome 이 아닌 조건이 나왔다면
+ if (s[start] != s[end])
+ {
+
+ //1번 따지기
+ if (s[start + 1] == s[end])
+ {
+ int l = start + 1;
+ int e = end;
+ while (l < e)
+ {
+ if (s[l] != s[e])
+ {
+ result = false;
+ }
+ l++;
+ e--;
+ }
+ //palindrome이라면 true 반환하기
+ if (result)
+ {
+ return true;
+ }
+ }
+
+ //2번 따지기
+ if (s[start] == s[end - 1])
+ {
+ int l = start;
+ int e = end-1;
+ while (l < e)
+ {
+ if (s[l] != s[e])
+ {
+ result2 = false;
+ }
+ l++;
+ e--;
+ }
+ //palindrome이라면 true 반환
+ if (result2)
+ {
+ return true;
+ }
+
+ }
+ //1번 2번 모두 아니라면 palindrome이 아니다
+ return false;
+
+ }
+ start++;
+ end--;
+ }
+ return true;
+
+
+ }
+};
+```
+
+------------------------------------------------------------------------------------------------------------------------------
+
+
+### 8번 String Matching in an Array
+
+이번 문제는 string배열에서 substring을 출력 하는 문제 였습니다.
+
+저는 이 문제를 풀때 대상을 제외한 모든 문자들을 비교하면서 substring인지 확인했습니다.
+
+* c++ 코드
+
+```c++
+class Solution
+{
+public:
+ vector stringMatching(vector& words)
+ {
+ vector result;
+
+ for (auto& e : words)
+ {
+ //자신을 제외한 모든 문자들을 비교하기 위해서 입니다.
+ for (auto& ee : words)
+ {
+ //만약 자기 자신이라면 넘어 갑니다.
+ if (ee == e)
+ {
+ continue;
+ }
+
+ //핵심 조건
+ //substring임을 찾고 result벡터요소와 중복되지 않다면
+ if (e.find(ee) != string::npos && find(result.begin(), result.end(), ee) == result.end())
+ {
+ //result벡터에 추가 합니다
+ result.emplace_back(ee);
+
+ }
+ }
+ }
+ return result;
+ }
+};
+```
+
+
+c++ string은 find함수를 제공 합니다 -> substring 확인
+그리고 algorithm 헤더 안에 find함수를 통해 vector안에 중복되는 값이 있는지 확인 할수 있었습니다.
+
+
+------------------------------------------------------------------------------------------------------------------------------
+
+### 마무리
+
+string 문제는 Hash , HashMap을 자주 이용하는 것 같습니다.
+혹시 아직 Hash, HashMap에 대해서 잘 모른다면 공부 하고 오신 후에 string을 보는 것을 추천 합니다.
+
diff --git a/_posts/2022-01-31-sort.md b/_posts/2022-01-31-sort.md
new file mode 100644
index 000000000000..a7be6ef98dd4
--- /dev/null
+++ b/_posts/2022-01-31-sort.md
@@ -0,0 +1,903 @@
+---
+layout: single
+title: "정렬 종류 개념"
+categories: Sort
+tag : [c++,python,Algorithm,LeetCode,Sort,Buble sort,Merge sort,Radix sort,Count sort,Shaker sort, Quick sort]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### Intro
+
+이번 포스팅에서는 정렬 관련 문제를 풀기 보다 정렬 관련 종류와 개념에 대해서 포스팅 하겠습니다.
+
+목록을 보시면 포스팅 하려는 정렬 종류가 나와 있으니 참고 하시면 좋을 것 같습니다.
+
+----------------------------------------------------------------------------------------------------------------------
+
+### Buble sort
+
+1. 큰값 또는 작은 값을 설정해서 하나하나씩 정해나가는 정렬입니다.
+
+2. stable한 sortring
+
+3. Worst Time : O(n^2)
+
+
+* c++코드
+
+```c++
+void buble_sort(int *arr,int size)
+{
+ for (int i = 0; i < size-1; i++)
+ {
+ for (int j = 0; j < size-1; j++)
+ {
+ if (arr[j] > arr[j+1])
+ {
+ swap(arr[j], arr[j+1]);
+ }
+ }
+ }
+
+
+ //정렬한 결과를 출력하는 반복문
+ for (int i = 0;i < size; i++)
+ {
+ cout << arr[i] << " ";
+ }
+
+}
+```
+
+* python 코드
+
+```python
+def Buble_sort(n):
+ # 뒤에서부터 정렬해 나가는 방식
+
+ for i in range(len(n)-1):
+ for j in range(len(n)-1):
+ if n[j] > n[j+1]:
+ n[j],n[j+1]=n[j+1],n[j]
+
+ return n
+```
+
+------------------------------------------------------------------------------------------------------------------------
+
+### Shaker sort
+
+Buble sort 방식을 최적화 한 정렬 입니다. 양쪽으로 buble sort하는 정렬 방식 입니다.
+
+양쪽으로 정렬을 진행 합니다.
+
+[shaker sort 위키 백과 링크](https://ko.wikipedia.org/wiki/%EC%B9%B5%ED%85%8C%EC%9D%BC_%EC%A0%95%EB%A0%AC)
+{: .notice--danger}
+
+
+
+* c++ 코드
+
+```c++
+void shaker_sort(int *arr,int size)
+{
+ int left = 0,last=0;
+ int right = size-1;
+
+ while (left arr[i + 1])
+ {
+ swap(arr[i], arr[i + 1]);
+ last = i;
+ }
+ }
+
+ //마지막 요소를 정했으니 그 전의 index last를 right에 삽입
+ //위의 shaker sort 위키 백과 링크 보기
+ right = last;
+
+ //역방향에서 다시 buble sort진행
+ for (int j = right; j > left; j--)
+ {
+ if (arr[j] < arr[j - 1])
+ {
+ swap(arr[j], arr[j - 1]);
+ last = j;
+
+ }
+
+ }
+
+ left = last;
+ }
+
+ for (int i = 0; i < size; i++)
+ {
+ cout << arr[i] << " ";
+ }
+}
+```
+
+
+* python 코드
+
+```python
+def shaker_sort(n):
+ left =0
+ last =0
+ right = len(n)-1
+ while leftn[i+1]:
+ n[i],n[i+1]=n[i+1],n[i]
+ last = i
+
+ #right가 range안에서 바뀌면 안되니까 last 변수 쓴것이다
+ right = last
+
+ for j in range(right,left,-1):
+ if n[j] 나뉠 대상이 좁혀 지는 효과가 있다.
+
+
+
+* pivot 선택 기준을 재귀로 구현하기 c++
+
+```c++
+//앞,가운데,끝 요소를 정렬하는 함수
+int sorted(vector& arr,int start,int mid,int end)
+{
+ //세개의 index에 있는 원소를 정렬하는 함수이다
+
+ //처음 첫 요소 start
+ //가운데 인덱스 mid
+ //끝 인덱스 end
+
+ //start요소가 mid 원소 보다 크면 swap한다
+ if (arr[mid] < arr[start])
+ {
+ swap(arr[mid], arr[start]);
+ }
+
+ //mid 원소가 end원소보다 크면 swap한다
+ if (arr[mid] > arr[end])
+ {
+ swap(arr[mid], arr[end]);
+
+ }
+
+ //마지막으로 start원소가 mid보다 크면 swap한다
+ if (arr[start] > arr[mid])
+ {
+ swap(arr[start], arr[mid]);
+ }
+
+ //가운데 index를 반환한다
+ return mid;
+}
+void quick_sort_recur(vector &arr,int left,int right)
+{
+ //left -> 배열 처음 index
+ //right -> 배열 마지막 index
+ //원소가 2개라면 비교하고 return 한다
+ if ((right - left) == 1)
+ {
+
+ if (arr[right] < arr[left])
+ {
+
+ swap(arr[right], arr[left]);
+ }
+ return;
+ }
+
+ //left와 right를 pl pr에 삽입한다
+ int pl = left;
+ int pr = right;
+
+ //sorted함수를 통해 앞,가운데,끝 인덱스를 정렬한다
+ int pivot_idx = sorted(arr, left, (left + right) / 2, right);
+
+ //pivot에 정렬된 가운데 index원소를 삽입한다
+ int pivot = arr[pivot_idx];
+
+
+ //가운데 원소와 끝에서 2번째 원소를 swap한다
+ swap(arr[pivot_idx], arr[right - 1]);
+
+ //pivot값은 끝에서 2번째 index에 위치하고 있다
+
+ //앞,가운데,끝은 정렬 되어있으므로 index위치 조정한다
+ pl++;
+ pr -= 2;
+
+ //pivot 기준으로 정렬한다
+ while (pl <= pr)
+ {
+ //pivot보다 값이 작으면 pl인덱스 조정한다 -> 넘어간다는 의미
+ while (pivot > arr[pl])
+ {
+ pl++;
+ }
+ //pivot보다 값이 크면 pr인덱스 조정한다
+ while (pivot < arr[pr])
+ {
+ pr--;
+ }
+ if (pl <= pr)
+ {
+ //pivot에 맞게 swap한다
+ swap(arr[pl], arr[pr]);
+ pl++;
+ pr--;
+ }
+ }
+
+ //다시 left ~pr 까지 재귀함수로 보낸다
+ if (left < pr)
+ {
+ quick_sort_recur(arr, left, pr);
+ }
+
+ //pl ~ right까지 재귀함수로 보낸다
+ if (right > pl)
+ {
+ quick_sort_recur(arr, pl, right);
+ }
+
+}
+```
+
+
+
+재귀 함수 부분에서는 pivot을 선택하고 pivot 기준으로 정렬을 계속 해주는 방식으로 진행 합니다.
+
+
+
+
+
+* stack을 이용해서 반복문으로 구현하기 c++
+
+```c++
+void quick_sort_iter(vector& arr,int left,int right)
+{
+ //stack 자료구조
+ stack> stack;
+
+ //(left,right)범위를 stack에 넣는다
+ stack.emplace(make_pair(left, right));
+
+ //stack이 빌때 까지 반복한다
+ while (!stack.empty())
+ {
+ //stack top에 있는 인덱스를 pl,pr인덱스에 삽입한다
+ int pl = left = stack.top().first;
+ int pr = right = stack.top().second;
+ stack.pop();
+
+ //pivot선택 기준에 따라 정렬한다
+ int pivot_idx = sorted(arr,pl,(pl+pr)/2,pr);
+ //가운데 index를 pivot 설정
+ int pivot = arr[pivot_idx];
+
+ //끝 2번째와 pivot swap한다
+ swap(arr[pivot_idx], arr[pr - 1]);
+
+ //위치 조정한다
+ pl++;
+ pr -= 2;
+
+
+ while (pl <= pr)
+ {
+ while (arr[pl] < pivot)
+ {
+ pl++;
+ }
+ while (arr[pr] > pivot)
+ {
+ pr--;
+ }
+ if (pl <= pr)
+ {
+ swap(arr[pr], arr[pl]);
+ pl++;
+ pr--;
+ }
+
+ }
+
+ //나눌 다음 대상을 stack에 push한다
+ if (left < pr)
+ {
+ stack.emplace(make_pair(left,pr));
+ }
+ if (right > pl)
+ {
+ stack.emplace(make_pair(pl, right));
+ }
+ }
+
+
+}
+```
+
+
+stack구조를 사용해서 quick sort를 구현 했습니다. 재귀 함수 처럼 다음 분할 대상을 재귀함수로 보내는 것이 아니라 stack에 push하는 방식으로 진행 하였습니다.
+
+정리 하자면 재귀로 인덱스를 다시 보내는 대신 stack에 push함으로써 다시 분할 할수 있도록 구현 한것입니다.
+
+stack을 사용한 이유는 FILO(First in Last out)의 성질 때문입니다. 분할 해야하는 다음 인덱스를 먼저 처리 해야하기 때문에 stack을 사용했습니다.
+
+
+
+
+* Quick sort 재귀, 반복 python 코드
+```python
+
+from typing import MutableSequence
+
+"""
+Quick sort 구현 할것이다
+
+pivot 선택에 따라 성능이 달라진다
+
+최적의 pivot선택 방법 노트에 정리 해놨다 그 방법으로 재귀 반복 quick sort구현 할것이다
+
+반드시 원소가 2개인 경우 고려 해주어야한다
+
+
+재귀
+
+반복
+-> 스택 사용하기
+"""
+
+def quick_sort_recur(a:MutableSequence,left:int,right:int)->None:
+
+ if (right-left)==1:
+ a[left],a[right] = sorted((a[left],a[right]))
+ return
+ pl = left
+ pr = right
+ a[pl],a[(pl+pr)//2],a[pr]=sorted((a[pl],a[(pl+pr)//2],a[pr]))
+
+ pivot =a[(pl+pr)//2]
+ a[(pl + pr) // 2],a[pr-1]=a[pr-1],a[(pl+pr)//2]
+
+
+ pl+=1
+ pr-=2
+
+ while pl<=pr:
+ while pivot>a[pl]:
+ pl+=1
+ while pivotpl:
+ quick_sort_recur(a,pl,right)
+
+
+
+def quick_sort_iterator(a:MutableSequence,left:int,right:int)->None:
+
+ stack=[]
+ stack.append((left,right))
+
+ while stack:
+ pl,pr = left,right=stack.pop()
+
+ a[pl],a[(pl+pr)//2],a[pr] = sorted((a[pl],a[(pr+pl)//2],a[pr]))
+ pivot = a[(pl+pr)//2]
+ a[(pl + pr) // 2],a[pr-1]=a[pr-1],a[(pl+pr)//2]
+ pl+=1
+ pr-=2
+
+ while pl<=pr:
+ while pivot>a[pl]:
+ pl+=1
+ while pivotpl:
+ stack.append((pl,right))
+
+
+
+
+a = [7,8,9,6,5,4,1,2,3,3]
+quick_sort_recur(a,0,len(a)-1)
+print(a)
+
+
+```
+
+
+Quick sort에서 pivot에 대한 이해를 하시면 merge sort를 더 잘 이해 할 수 있습니다.
+
+
+
+------------------------------------------------------------------------------------------------------------------------
+
+### Merge Sort
+
+Quick sort에서 pivot에 대한 이해도가 있다면 이번에 merge sort는 쉽게 이해 할수 있을 것 입니다.
+
+Merge sort는 분할 해서 정렬후 다시 합치는 정렬 방식이기 때문입니다.
+
+그리고 Merge sort 구현 방식을 보면 Add string문제의 코드 구조와 비슷하다는것을 알수있습니다.
+
+
+Time: O(n log n)
+
+
+* c++ 코드
+
+```c++
+vector mergeSort(vector& arr)
+{
+ //base case
+ //size 가 1이면 arr return 한다
+
+ if (arr.size() == 1)
+ {
+ return arr;
+
+ }
+
+ //mid설정
+ int mid = arr.size() / 2;
+
+ //left ~ mid 까지
+ vector left_nums(arr.begin(), arr.begin() + mid);
+
+ //mid ~ right 까지
+ vector right_nums(arr.begin() + mid, arr.end());
+
+ //분할 해서 재귀함수 돌린다
+ vector sorted_left = mergeSort(left_nums);
+ vector sorted_right = mergeSort(right_nums);
+
+ //정렬한 결과를 저장하는 배열
+ vector sorted_nums;
+
+ int idx_l = 0, idx_r = 0;
+
+ //left 와 right를 merge하는 코드
+ while (idx_l < sorted_left.size() || idx_r < sorted_right.size())
+ {
+ //left배열이 먼저 끝난 경우 남은 right배열을 sorted_nums배열에 넣는다
+ if (idx_l == sorted_left.size())
+ {
+ sorted_nums.emplace_back(sorted_right[idx_r]);
+ idx_r++;
+ continue;
+ }
+ if (idx_r == sorted_right.size())
+ {
+ sorted_nums.emplace_back(sorted_left[idx_l]);
+ idx_l++;
+ continue;
+ }
+
+
+ //left배열 요소가 값이 더 크면 작은 값이 right배열 요소를 sorted_num배열에 넣는다
+ if (sorted_right[idx_r] <= sorted_left[idx_l])
+ {
+ sorted_nums.emplace_back(sorted_right[idx_r]);
+ idx_r++;
+ }
+ else
+ {
+ sorted_nums.emplace_back(sorted_left[idx_l]);
+ idx_l++;
+
+ }
+ }
+ return sorted_nums;
+
+
+}
+```
+
+* python 코드
+```python
+"""
+Merge sort
+
+분할 정복 느낌이 있다
+
+왼 오 나누어서 분할해서 합치는 방식 -> 많이 봤던 패턴 방식이다
+
+재귀적으로 구현하겠다
+"""
+from typing import List
+def mergeSort(nums:List[int])->List[int]:
+
+ length = len(nums)
+ if length==1:
+ return nums
+
+ mid =length/2
+
+ left_nums = nums[:mid]
+ right_nums = nums[mid:]
+
+ sorted_left = mergeSort(nums=left_nums)
+ sorted_right = mergeSort(nums = right_nums)
+
+
+
+ sorted_nums=[]
+ idx_l =0
+ idx_r =0
+
+ while idx_l 최대값 - 최소값 만큼 배열 만드는 시간 O(k)가 소요 되기 때문이다
+
+
+Stable 한 sort입니다.
+
+
+
+**Count sort 진행 방식**
+
+1. 입력 리스트 원소의 개수를 저장하는 배열 만든다
+2. 만든 배열의 누적 합을 구한다
+3. 인덱스로 쓰기 위해 -1 한다
+4. 새로운 배열 B에 만든 배열의 인덱스 위치에 입력 배열의 원소를 삽입하면 정렬 된다
+
+
+
+Time : O(n+alpha)
+
+
+
+
+누적 합이 요소의 누적합이 아니라 요소가 몇개 있는지의 합이다
+
+
+
+
+
+
+
+
+* c++ 코드
+
+
+```c++
+void count_sort(vector&arr)
+{
+ //arr 원소의 개수를 저장하기 위한 배열이다
+ vector temp(*max_element(arr.begin(),arr.end())+1,0);
+
+ //결과
+ vector result(arr.size(),0);
+
+ //입력 배열 arr의 개수를 저장하는 배열 만든다
+ for (auto& e : arr)
+ {
+ temp[e]++;
+ }
+
+ //누적 합을 구하기 위한 변수
+ int acc = 0;
+
+ //개수를 저장한 배열temp를 누적합 배열로 바꾸는 코드
+ for (int i = 0; i < temp.size(); i++)
+ {
+ acc += temp[i];
+
+ temp[i] = acc;
+ }
+
+ //인덱스로 사용하기 위해 -1을 모든 원소에 한다
+ for (int i = 0; i < temp.size(); i++)
+ {
+ temp[i] -= 1;
+ }
+
+ //끝 요소부터 반복문 돌린다
+ for (int i = arr.size()-1; i > -1; i--)
+ {
+ //누적합 배열 temp와 arr이용해서 result배열 넣는다
+ result[temp[arr[i]]] = arr[i];
+
+ //같은 값의 원소를 중복으로 처리하지 않기 위함입니다.
+ temp[arr[i]] -= 1;
+
+ }
+
+ //result
+ cout << "Result is " << endl;
+ for (auto& e : result)
+ {
+ cout << e << " ";
+ }
+
+
+
+}
+```
+
+* python 코드
+
+
+```python
+def counting_sort(a:MutableSequence)->MutableSequence:
+
+ b=[0]*len(a) #result배열
+ f=[0]*(max(a)+1) #누적 합 구하는 배열
+
+ for i in a: #a 인덱스 개수 센다
+ f[i]+=1
+
+ acc=0
+ for i in range(len(f)):#누적합 구한다
+ acc+=f[i]
+ f[i]=acc
+
+
+ f = [i-1 for i in f] #누적합 구한 배열에 -1한다
+
+ for i in range(len(a)-1,-1,-1): #a 배열원소를 f배열 인덱스를 참고해서 b에 삽입한다
+ b[f[a[i]]]=a[i]
+
+ f[a[i]]-=1
+
+ return b
+
+
+```
+
+c++ 코드 기준으로 temp는 누적 도수 분포표를 만든것이라고 생각하면 됩니다.
+
+예) arr[8] = 3
+ temp[3] = 5
+
+이라고 해봅시다. 그러면 0~3사이는 5개가 있다는 의미입니다.
+
+
+
+
+------------------------------------------------------------------------------------------------------------------------
+
+
+### Radix sort
+
+
+count sort를 보완한 sort입니다. count sort는 최솟값과 최댓값 gap이 크면 비효율적인 알고리즘이 됩니다.
+그래서 Radix sort가 보완 합니다.
+
+Radix sort는 자릿수로 정렬하는 정렬 방식 입니다. 단, 이때 정렬은 stable해야합니다.
+
+
+예) [391,582,50,924,134,8,192] 배열이 있다고 할때 count sort를 이용하면 각 수를 세기 위해 900개 이상의 공간을 만들어야합니다
+
+그래서 최솟값과 최댓값 gap이 크면 비효율적인 알고리즘이 됩니다.
+
+
+Radix sort는 자릿수 별로 정렬하는 방식이라고 보면 됩니다.
+일의 자리끼리 정렬하고 십의자리끼리 정렬하면서 진행 합니다.
+
+
+Time : O(n+k)*w(자릿수 개수)
+
+
+
+
+참고로 Radix sort는 count sort를 사용하기 때문에 앞에 count sort를 건너 뛰셨다면 보는것을 추천합니다.
+
+
+
+* c++ 코드
+
+
+```c++
+//Radix sort를 위한 count sort함수입니다.
+vector count_sort_for_radix(vector&arr,int digit)
+{
+ //0-9까지의 원소만 올것이기때문에 10으로 설정했습니다. (자릿수끼리 비교하기 때문입니다.)
+ vector count(10, 0);
+
+
+ vector result(arr.size(), 0);
+
+ for (auto& ele : arr)
+ {
+ //각 자릿수 digit에 맞게 나눠준다 그후 0-9값을 유지하기 위해 %10 한다
+ int count_idx = (int)(ele / pow(10, digit))% 10;
+
+ count[count_idx] ++;
+
+ }
+ //count sort 와 동일 하다
+ int acc = 0;
+ for (int i = 0; i < count.size(); i++)
+ {
+ acc += count[i];
+ count[i] = acc;
+ }
+ for (int i = 0; i < count.size(); i++)
+ {
+ count[i] --;
+ }
+ for (int i = arr.size()-1; i > -1; i--) //뒤에서 부터 넣어주면 stable한 특성 살릴수가 있다
+ {
+ result[count[arr[i]]] = arr[i];
+ count[arr[i]] --;
+ }
+ return result;
+
+}
+
+
+void Radix_sort(vector&arr)
+{
+ //arr의 최댓값을 찾습니다.
+ int max_val = *max_element(arr.begin(), arr.end());
+
+ //최댓값의 자릿수를 알아내는 변수입니다.
+ int digits = (int)(log10(max_val)) + 1;
+
+ vector result(arr);
+
+ for (int i = 0; i < digits;i++)
+ {
+ result = count_sort_for_radix(result, i);
+ }
+
+
+ cout << "\nResult is " << endl;
+
+ for (auto& ele : result)
+ {
+ cout << ele << " ";
+ }
+
+}
+
+```
+
+* python 코드
+
+
+```python
+def Counting_sort_Digit(nums:List[int],digit:int)->List[int]:
+ counts=[0]*10 #10개로 고정되어있다 -> counting sort 쓰기 좋은 환경
+
+ for num in nums:
+ count_idx = (num//pow(10,digit))%10
+ counts[count_idx]+=1
+
+ acc=0
+ for count in range(len(counts)):
+ acc+=counts[count]
+ counts[count] = acc
+
+ counts=[i-1 for i in counts]
+
+ result = [0]*len(nums)
+
+ for idx in range(len(nums)-1,-1,-1):
+ result[counts[nums[idx]]]=nums[idx]
+ counts[nums[idx]]-=1
+
+ return result
+
+def Radix_sort(nums:List[int])->List[int]:
+
+ largest_nums = max(nums)
+ digits = int(math.log10(largest_nums))+1 #자릿수 개수를 계산한다
+
+ result = nums
+ for digit in range(digits):
+ result = Counting_sort_Digit(result,digit)
+
+ return result
+
+```
+
+각 자릿수끼리 비교를 하고 정렬하기 때문에 최솟값과 최댓값의 gap이 크더라도 효율적인 정렬을 할 수 있습니다.
+
+
+
+------------------------------------------------------------------------------------------------------------------------
+
+### 마무리
+
+이번 포스팅에서는 정렬 관련 문제를 푸는 대신 정렬의 종류와 개념을 코드로 구현 하는 시간을 가졌습니다.
+
+정렬 관련 문제는 이후 백준 문제 모음에서 업로드 할 예정이니 필요하신분은 백준 문제 모음 부분으로 가셔서 참고 하셔도 좋을것 같습니다.
+
+정렬 관련 개념이 아직 확실하지 않다면 유튜브 ,구글을 통해 학습하시는 것이 좋을 것 같습니다.
+
+긴 글 읽어 주셔서 감사합니다.
diff --git a/_posts/2022-02-04-heap.md b/_posts/2022-02-04-heap.md
new file mode 100644
index 000000000000..88479c369249
--- /dev/null
+++ b/_posts/2022-02-04-heap.md
@@ -0,0 +1,1209 @@
+---
+layout: single
+title: "Heap 개념 및 관련 문제"
+categories: [Heap,priority Queue]
+tag : [c++,python,Algorithm,LeetCode,Heap,Kth Largest Element in an Array,Top K Frequent Elements,Merge k Sorted Lists ,Find the Kth Largest Integer in the Array,디스크 컨트롤러]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### Intro
+
+안녕 하세요 이번 포스팅에서는 heap에 대해서 알아 볼 것 입니다.
+heap에 대한 기본적인 개념과 코드 구현을 보고 Priority Queue에 대해서 알아볼것입니다.
+그리고 관련 문제를 포스팅하는 것으로 마무리 하겠습니다.
+
+
+---------------------------------------------------------------------------------------------------------------------------------
+
+### Heap
+
+Heap은 완전 이진 트리 구조를 가지고 있는 자료 구조 입니다.
+**부모 값이 자식 값 보다 크다**는 조건도 heap(max heap) 이고 **부모 값이 자식 값 보다 작다**는 조건도 heap(min heap)입니다.
+
+즉 두값의 대소 관계가 일정하면 heap이라고 볼 수 있습니다.
+
+완전 이진 트리 구조이기 때문에 max heap이라면 root노드가 가장 큰 값을 가지고 있을 것 입니다.(min heap은 반대)
+
+* 삽입
+
+완전 이진 트리 구조이기 때문에 가장 왼쪽에 값을 삽입 후 부모 노드와 비교하면서 swap한다
+
+Time : O(log N)
+
+
+
+
+* 삭제
+
+root 노드를 pop 후 가장 왼쪽에 있는 노드를 swap 한다 그리고 아래에서 비교를 하면서 값을 갱신한다.
+
+Time : O(log N)
+
+
+min heap의 leaf node가 (완전 이진 트리니까 가장 왼쪽 leaf node) 반드시 max val이 아니다 그래서 min heap,max heap은 가장 작은수 큰수를 구하고 싶을때 사용해야 한다
+-> 그래서 min heap을 만들었다고 해서 그 요소가 다 내림차순으로 정렬되어있는게 아니다!
+>문제를 풀다가 lowerbound와 같이 사용한적 있는데 lower,upper bound는 요소에서 동일 또는 큰값을 찾을 뿐이다 어쨌든 min heap 대신 sort를 해서 푼적이 있다
+
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+
+### Hepify
+
+Heap구조를 만드는 것을 Heapify라고 생각 하면 될 것 같다.
+
+완전 이진 트리 구조 므로 Linked list를 이용해서 hepify할 수 도 있다. Tree구조에서는 부모 노드와 자식 노드가 있으므로 위에서 언급한 삽입 ,삭제 방법을 그대로 실행하면 작동 할것이다.
+
+그러나 배열로 구현 할 수도 있다. 이번 포스팅에서는 배열로 heapify를 구현 할 것 입니다.
+
+* 배열에서 관계 공식
+
+1. 부모
+ * (index - 1)/2
+
+2. 왼쪽 자식
+ * 2*index+1
+
+3. 오른쪽 자식
+ * 2*index+2
+
+
+배열 관계 공식을 통해 index통해 부모 노드 와 왼쪽 자식 노드, 오른쪽 자식 노드를 구분 할 수 있습니다.
+
+heap에서 언급한 삽입, 삭제 방식을 배열에서 똑같이 구현 하면 됩니다.
+
+c++에서는 heap을 제공해주는데 heap구현을 살펴 본 다음 c++에서 제공하는 heap 사용법을 간단하게 알아 보겠습니다.
+
+
+* heap구현 c++ 코드
+
+```c++
+#include
+
+using namespace std;
+
+class Heap
+{
+private:
+
+ int* arr;
+ int current_size;
+ int size_;
+
+ //가운데 지점에서 계속 heapify 진행하기 위함이다
+ void convertArrayIntoHeap()
+ {
+ //current_size/2-1 -> 부모 노드 부터 시작
+ for (int i = current_size / 2 -1; i > -1; i--)
+ {
+ heapify(current_size, i);
+ }
+ }
+
+
+ void heapify(int size, int rootidx)
+ {
+ //부모 노드
+ int max_val = rootidx;
+
+ int left = 2 * rootidx + 1; //왼쪽 자식 노드
+
+ int right = 2 * rootidx + 2; //오른쪽 자식 노드
+
+ //왼쪽 자식 노드가 부모 노드보다 큰 경우 부모 노드 갱신
+ if (leftarr[max_val])
+ {
+ max_val = left;
+ }
+
+ //오른쪽 자식 노드가 부모 노드보다 큰 경우 부모 노드 갱신
+ if (rightarr[max_val])
+ {
+ max_val = right;
+ }
+
+ //처음 부모 노드 max_val이 바뀌었다면 swap한다
+ if (max_val != rootidx)
+ {
+ swap(arr[max_val], arr[rootidx]);
+ heapify(size, max_val);
+ }
+ }
+
+
+public:
+
+ //constructor
+ Heap(int size)
+ :current_size(0),size_(size),arr(new int [size])
+ {
+
+ }
+
+ //insertion heap
+
+ void insert(const int value)
+ {
+ if (current_size < size_)
+ {
+ arr[current_size] = value;
+ current_size++;
+ if (current_size == size_)
+ {
+ convertArrayIntoHeap();
+ }
+ }
+ else
+ {
+ cout << "\nThe heap is full.\n";
+ }
+ }
+
+ int top()
+ {
+ return arr[0];
+ }
+
+ int pop()
+ {
+ //root 노드와 가장 왼쪽 노드를 swap한다
+ swap(arr[0], arr[current_size - 1]);
+
+ //그후 값을 비교 갱신한다
+ heapify(current_size - 1, 0);
+
+ //값 1개가 삭제 되므로 size가 줄어든다
+ current_size--;
+
+ return arr[current_size];
+ }
+ void print_heap()
+ {
+ for (int i = 0; i < size_; i++)
+ {
+ cout << arr[i] << ' ';
+ }
+ }
+
+};
+
+
+int main()
+{
+ int size = 9;
+ Heap heap(size);
+
+ for (int i = 0; i < size; i++)
+ {
+ int value = 0;
+ cin >> value;
+ heap.insert(value);
+ }
+ heap.print_heap();
+
+ return 0;
+}
+```
+
+
+위의 코드는 class로 heap구조를 구현한 코드입니다.
+
+아래의 코드도 maxheap이며 구조는 거의 동일하나 max_heap 구현에 더 초점이 맞추어져 있습니다.
+
+
+
+* max_heap c++ 코드
+
+
+
+```c++
+
+void max_hepify(vector &arr,int rootidx)
+{
+
+ int left = 2 * rootidx + 1; //왼쪽 자식 노드
+ int right = 2 * rootidx + 2; //오른쪽 자식 노드
+
+ int Max = rootidx; //부모 노드
+
+ //오른쪽 자식 노드, 왼쪽 자식 노드 값이 부모 노드 보다 크면 부모노드를 갱신한다
+ if (leftarr[Max])
+ {
+ Max = left;
+ }
+ if (rightarr[Max])
+ {
+ Max = right;
+ }
+
+ //부모 노드가 처음과 다르면
+ if (Max != rootidx)
+ {
+ //swap한다
+ swap(arr[Max], arr[rootidx]);
+
+ //swap한 값을 갱신한다
+ max_hepify(arr, Max); //재귀 함수 호출
+ }
+
+
+
+}
+int main()
+{
+ vector arr = { 1,3,5,2,4,8,6,7,9 };
+
+
+ for (int i = arr.size() / 2; i > -1; i--)
+ {
+ //부모 노드가 i로 들어간다
+ max_hepify(arr, i);
+ }
+
+
+
+ for (auto& e : arr)
+ {
+ cout << e << " ";
+ }
+ cout << endl;
+ return 0;
+}
+```
+
+
+
+* c++에서 heap 사용하는 예 cppreference make_heap에서 참고한 코드 입니다.
+
+```c++
+/*
+ make_heap in cpp
+
+ c++에서 heap 기초 사용 방법
+
+ #include 해야한다
+
+
+ make_heap(first,last,comp)
+
+ first last 는 주소 요소의 범위이다
+
+ comp는 comparison function object이다 sort처럼 비교함수가 올수있다
+
+
+
+
+ -max heap은
+ make_heap그대로 사용하면 됨
+
+ -min heap
+ make_heap(first,last,greater<>) comp함수 써야한다
+
+
+ a new element can be added using std::push_heap(). 새로운 요소를 추가할때 사용가능
+
+ the first element can be removed using std::pop_heap().
+
+*/
+void print(std::string_view text, std::vector const& v = {}) {
+ std::cout << text << ": ";
+ for (const auto& e : v) std::cout << e << ' ';
+ std::cout << '\n';
+}
+
+int main()
+{
+ print("Max heap");
+
+ std::vector v{ 3, 2, 4, 1, 5, 9 };
+ print("initially, v", v);
+
+ std::make_heap(v.begin(), v.end());
+ print("after make_heap, v", v);
+
+ std::pop_heap(v.begin(), v.end());
+ print("after pop_heap, v", v);
+
+ auto top = v.back();
+ v.pop_back();
+ print("former top element", { top });
+ print("after removing the former top element, v", v);
+
+ print("\nMin heap");
+
+ std::vector v1{ 3, 2, 4, 1, 5, 9 };
+ print("initially, v1", v1);
+
+ std::make_heap(v1.begin(), v1.end(), std::greater<>{});
+ print("after make_heap, v1", v1);
+
+ std::pop_heap(v1.begin(), v1.end(), std::greater<>{});
+ print("after pop_heap, v1", v1);
+
+ auto top1 = v1.back();
+
+ v1.pop_back();
+
+ print("former top element", { top1 });
+ print("after removing the former top element, v1", v1);
+}
+
+
+```
+
+
+
+
+
+### 위에서 구현한 heapy기준으로 heap sort 만들기
+
+```c++
+vector heapsort(vector&vec)
+{
+ vector result;
+
+ make_heap(vec.begin(),vec.end());
+ while(!vec.empty())
+ {
+ pop_heap(vec.begin(),vec.end());
+ result.emplace_back(vec.back());
+ vec.pop_back();
+ }
+ return result;
+
+
+
+}
+
+```
+
+
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+### Priority Queue
+
+우선 순위 큐는 일반적인 큐와 다른 구조의 큐 구조 입니다. 큐와 스택은 원소가 들어가는 순서 나가는 순서가 정해져 있는 자료 구조이지만
+우선 순위 큐는 우선 순위에 따라 data가 나가는 자료 구조 입니다.(**들어간 순서에 상관없이 우선순위가 높은 데이터가 먼저 나오는구조**) 우선 순위 큐는 기본 적으로 heap의 구조 이기 때문에 heap 포스팅에서 다뤄 보겠습니다.
+
+우선 순위 큐는 배열, linked list로 구현 할 수 도 있지만 최악의 경우 Time : O(n)이 걸립니다.
+그래서 우선 순위 큐를 구현 할때 heap의 구조를 사용해서 구현 합니다.
+
+heap과 동일하지만 heap에서는 값이 크다 작다 즉 max, min으로 이루어져 있다면 우선 순위 큐에서는 꼭 값이 크다 작다만이 기준이 아닌것 같습니다. pair로 예를 들어보면 first가 3보다 작은 것 중에서 second가 작은것 부터 우선 순위를 따진다면 이때 우선 순위 큐를 사용하는것 같습니다. (개인적인 생각이라서 틀렸다면 댓글로 지적 해주세요)
+
+
+c++에서 지원하는 priority Queue 사용법을 간단하게 알아보겠습니다.
+
+
+* c++ 코드 cppreference에서 참고한 코드 입니다.
+
+```c++
+#include
+#include
+#include
+
+/*
+ STL priority queue 사용법을 간단하게 정리해봄
+
+ #inculde 를 해야한다
+
+ heap과 같다고 보면 된다
+
+
+ template<
+ class T,
+ class Container = std::vector,
+ class Compare = std::less
+> class priority_queue;
+
+
+큐와 마찬가지로 front pop등 기능을 지원한다
+
+*/
+
+using namespace std;
+
+int main()
+{
+ priority_queue q; //기본으로 하면 max heap그리고 min heap다를수있다 자료형 크기대로 우선순위정해짐
+
+ vector data = { 1,8,5,6,3,4,0,9,7,2 };
+
+ for (auto& n : data)
+ {
+ q.push(n);
+ }
+
+ cout << "This is q " << endl;
+ while (!q.empty())
+ {
+ cout << q.top() << " ";
+ q.pop();
+ }
+ cout << endl;
+
+ priority_queue, greater> q2(data.begin(), data.end());
+
+ cout << "This is q2" << endl;
+ while (!q2.empty())
+ {
+ cout << q2.top() << " ";
+ q2.pop();
+ }
+ cout << endl;
+
+ // Using lambda to compare elements.
+ //auto cmp = [](int left, int right) { return (left ^ 1) < (right ^ 1); };
+ //std::priority_queue, decltype(cmp)> q3(cmp);
+
+ //decltype은 auto와 비슷하지만 auto와 다르게 타입을 그대로 보존한다
+
+
+
+ return 0;
+}
+```
+
+
+
+
+
+그리고 unordered map에서 second 값 기준으로 heap을 구성하고 싶다면 다음과 같이 사용할수가 있다
+
+```c++
+#include
+#include
+#include
+
+using namespace std;
+
+
+int main() {
+ unordered_map map;
+ map[3] = 1;
+ map[33] = 2;
+ map[333] = 3;
+
+
+ auto cmp = [](pair const& p1, pair const& p2)
+ {
+ return p1.second < p2.second;
+ };
+
+ priority_queue, vector>,decltype(cmp)> pq;
+
+ for (auto&it:map) {
+ pq.push(make_pair(it.first, it.second));
+ }
+
+ while (!pq.empty()) {
+ auto top = pq.top();
+ pq.pop();
+ cout << top.first << " " << top.second << endl;
+ }
+
+ return 0;
+}
+
+
+```
+
+이때 비교 함수(compare function)은 람다 표현식 사용해도 되지만 decltype()안에다가 선언해야 작동을 한다!->c++20기준
+
+참고로 c++17로 돌린다고 하면
+
+```c++
+ struct Compare {
+ bool operator()(pair const& p1, pair const& p2) {
+ return p1.second < p2.second;
+ }
+ };
+
+```
+
+다음과 같은 구조체를 만들어야 한다 람다 표현식 그대로 인자로 넣으면 작동 하지 않는다
+
+
+
+
+
+compare함수에 기준 여러개 적용하기
+
+문제를 따로 언급 하지 않겠지만 문제를 풀다가 여러 조건을 compare함수에 넣어야 할때가 있었는데 그 내용을 정리 해보려 한다
+
+1. abs(x)+abs(y)의 값이 작은것을 기준
+2. x가 작은값을 기준
+3. y가 작은값을 기준
+
+다음과 같은 3개의 기준을 compare함수에 적용한 코드이다
+
+```c++
+struct Compare {
+ bool operator()(pair& a,pair& b) {
+ long long int sum1 = abs(a.first) + abs(a.second);
+ long long int sum2 = abs(b.first) + abs(b.second);
+ if (sum1 != sum2) {
+ return sum1 > sum2;
+ }
+ else if (a.first != b.first) {
+ return a.first > b.first;
+ }
+ else {
+ return a.second > b.second;
+ }
+ }
+};
+```
+
+-----------------------------------------------------------------------------
+
+
+
+
+
+
+
+기본적인 개념과 구현은 살펴 본것 같으니 관련 문제를 풀어보도록 하겠습니다.
+
+
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+
+### 문제 링크
+
+[1번 Kth Largest Element in an Array](https://leetcode.com/problems/kth-largest-element-in-an-array/)
+{: .notice--danger}
+
+[2번 Top K Frequent Elements](https://leetcode.com/problems/top-k-frequent-elements/)
+{: .notice--danger}
+
+[3번 Merge k Sorted Lists](https://leetcode.com/problems/merge-k-sorted-lists/)
+{: .notice--danger}
+
+[4번 Find the Kth Largest Integer in the Array](https://leetcode.com/problems/find-the-kth-largest-integer-in-the-array/)
+{: .notice--danger}
+
+[5번 디스크 컨트롤러](https://programmers.co.kr/learn/courses/30/lessons/42627)
+{: .notice--danger}
+
+[앞에서 삭제하기 II 코드트리](https://www.codetree.ai/missions/8/problems/delete-it-from-the-beginning-2?utm_source=clipboard&utm_medium=text)
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+
+### 1번 Kth Largest Element in an Array
+
+
+k 번재로 큰 숫자를 배열에서 찾는 문제 입니다. 이 문제를 보고 그냥 정렬후 k번째 원소를 반환하면 될 것이라고 생각합니다.
+그런데 min heap으로 문제를 풀면 더 효율적으로 문제를 풀 수 있습니다.
+
+
+* min heap 방법
+
+ * k 크기만큼 min heap을 만들고 크기가 넘어가면 pop을 한다 그러면 K번째로 큰 요소와 k까지의 요소까지 구할수있다
+
+ * k크기만큼 빼고 pop한다는건 최소값들을 계속해서 pop 하기때문에 결국 남는건 점점 큰숫자들만 남게 된다
+
+
+삽입 삭제가 O(log n)인데 k개의 size만큼 삽입 삭제를 반복하니까
+
+Time : O(n log k)
+
+space : O(k)
+
+-> space complex를 줄일 수 있다
+
+* c++ 코드
+
+```c++
+class Solution {
+public:
+ int findKthLargest(vector& nums, int k)
+ {
+ // temp 벡터
+ vector temp;
+ for(auto&e:nums)
+ {
+ temp.emplace_back(e);
+
+ //min heap구성 한다
+ push_heap(temp.begin(),temp.end(),greater<>{});
+
+ //size가 k개 넘어가면
+ if(k{});
+ temp.pop_back();
+ }
+ }
+
+ // k 번째로 큰 수 return 한다
+ return temp[0];
+ }
+};
+```
+
+
+min heap을 이용해서 k 번째로 큰 수를 찾는 방법에 대해 알아 보았습니다.
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+### 2번 Top K Frequent Elements
+
+자주 나오는 k개의 element를 구하는 문제 입니다.
+
+이 문제는
+
+1. hash map 과 sort를 이용해서 풀 수도 있다
+
+Time: O(N+ N log N)
+
+
+2. hash_map + min heap
+
+앞에 문제 처럼 min heap과 k를 이용해서 빈번의 최대를 따로 저장할수있다 ->정렬을 할필요없다
+k는 상수로 볼수있다
+
+Time complextiy -> O(n+m)으로 볼수있다
+
+
+앞의 1번 문제와 비슷한 방식으로 풀 수 있다
+
+hashmap으로 element를 count해주고 count한 value기준으로 min heap을 해주면 k개의 빈번한 element를 구할 수 있다.
+
+
+
+* c++ 코드
+
+
+```c++
+class Solution {
+public:
+ vector topKFrequent(vector& nums, int k)
+ {
+ //hash map을 vector로 쓰기 위함
+ vector> result;
+
+ //hash map
+ unordered_map heap_hash;
+
+ for (auto& cur : nums)
+ {
+ //중복 체크를 하는 과정없이 구현할수있다
+ heap_hash[cur]++;
+ }
+
+ for (auto& e : heap_hash)
+ {
+ //첫 번째 원소를 기준으로 min heap을 만드니까 e.second부터 삽입한다 count 기준으로 min heap진행 해야한다
+ result.emplace_back(e.second,e.first);
+ push_heap(result.begin(), result.end(), greater<>{});
+
+ if (k < result.size())
+ {
+ pop_heap(result.begin(), result.end(), greater<>{});
+ result.pop_back();
+ }
+ }
+
+ //결과 : 반환 벡터
+ vector Result;
+
+ for (int i = 0; i < result.size(); i++)
+ {
+ Result.emplace_back(result[i].second);
+ }
+
+ return Result;
+
+
+ }
+};
+```
+
+
+맨위에서 priority queue와 unordered_map을 가지고 compare함수 기준으로 처리한 코드는 다음과 같다
+대부분의 코테 사이트에서 c++20을 지원하지 않기 때문에 compare함수는 람다 표현식으로 사용하지 말고 구조체나 함수 식으로 사용해야 한다
+
+
+
+
+
+```c++
+class Solution {
+public:
+
+ struct Compare {
+ bool operator()(pair const& p1, pair const& p2) {
+ return p1.second < p2.second;
+ }
+ };
+
+ vector topKFrequent(vector& nums, int k)
+ {
+ unordered_map map;
+
+ for(auto&e:nums)
+ {
+ map[e]++;
+ }
+
+
+ priority_queue, vector>,Compare> pq;
+ for(auto&e:map)
+ {
+ pq.push(make_pair(e.first,e.second));
+ }
+
+
+ vector result;
+
+ for(int i=0;i& lists)
+ {
+ //리스트 사이즈가 0이면
+ if (lists.size() == 0)
+ {
+ return NULL;
+ }
+
+ //ListNode * ret, tail NULL 초기화
+ ListNode* ret = NULL;
+ ListNode* tail = NULL;
+
+
+
+ //priority 에서 lamda 표현식 사용하는 방법 (min hepa 만들기 위함 )
+ auto comp = [](ListNode* a, ListNode* b) {return a->val > b->val; };
+
+
+ //우선 순위 큐
+ priority_queue, decltype(comp)> pq(comp);
+
+
+ //list에 원소 있다면 모두 우선순위 큐에 넣는다
+ for (int i=0;inext;
+
+ }
+
+ }
+
+ //우선 순위 큐에는 각 리스트 노드의 벡터 값이 우선 순위에 따라 정렬 되어있음
+
+ while (!pq.empty())
+ {
+
+
+ ListNode* temp = pq.top();
+ pq.pop();
+
+ if (temp->next != NULL)
+ {
+ pq.push(temp->next);
+ }
+
+ //List add 과정
+
+ if (ret == NULL)
+ {
+ ret = temp;
+ }
+ else
+ {
+ tail->next = temp;
+ }
+ tail = temp;
+ }
+
+ return ret;
+ }
+};
+```
+
+
+예) [[1,5,4],[1,4,3],[6,2]]
+
+우선 순위 큐에 넣으면
+
+[[1,4,5],[1,3,4],[2,6]]의 순서대로 바뀝니다
+
+그리고 while(!pq.empty())까지 첫 요소부터 비교를 하면서 linked list를 만듭니다.
+
+
+정렬 포스팅에서는 다루지 않았지만 정렬중에 heap을 이용한 정렬 heap 정렬이 있습니다.
+heap정렬에 대해 공부 하시면 위의 코드를 더 쉽게 이해 할 수 있을 것 입니다.
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+
+### 4번 Kth Largest Element in an Array
+
+
+이번 문제는 k번째 요소를 구하는게 아니라 정렬을 했을때 k번째로 큰 수를 구하는 문제 입니다.
+
+주의 하실 점은
+**Note: Duplicate numbers should be counted distinctly. For example, if nums is ["1","2","2"], "2" is the first largest integer, "2" is the second-largest integer, and "1" is the third-largest integer.**
+
+
+중복된 숫자도 별개로 숫자를 세주어야한다는 것입니다.
+
+
+
+1번 문제와 비슷한 유형의 문제 입니다. 단 배열 내용이 string인 점 그리고 중복된 원소는 따로 count해야한다는 점을 인지 하고 문제를 풀 면 되겠습니다.
+
+
+
+* c++ 코드
+
+
+```c++
+class Solution
+{
+public:
+
+//자릿수로 크기 정하는 compator구조체
+ struct compator {
+ bool operator()(string a, string b)
+ {
+ if (a.size() == b.size())
+ {
+ for (int i = 0; i < a.size(); i++)
+ {
+ if (a[i] - '0' > b[i] - '0')
+ {
+ return true;
+ }
+ else if (a[i] - '0' < b[i] - '0')
+ {
+ return false;
+ }
+ }
+ }
+ return a.size() > b.size();
+ }
+ };
+
+ string kthLargestNumber(vector& nums, int k)
+ {
+ priority_queue,compator> q;
+
+ //1번 문제의 min heap과 비슷한 구조
+ for (auto& e : nums)
+ {
+ q.push(e);
+ if (k < q.size())
+ {
+ q.pop();
+ }
+ }
+ return q.top();
+ }
+};
+```
+
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+
+### 5번 디스크 컨트롤러
+
+이번 문제는 Leetcode가 아니라 프로그래머스에 있는 문제 입니다.
+
+개인적으로 이번 문제에서 아쉬웠던 점은 같은 시간대에서는 우선 순위 큐 순서에 따라(1번째 원소를 기준으로) 처리를 하였는데 다른 작업 시간대에 대해서 처리를 잘 하지 못해서 해맸던 문제 였습니다.
+
+
+* c++ 코드
+
+
+```c++
+
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+//1번째 원소를 비교하여 우선순위 정한다
+struct compater
+{
+ bool operator()(vector a,vector b)
+ {
+
+ return a[1] > b[1];
+ }
+};
+int solution(vector> jobs)
+{
+ int answer = 0;
+ sort(jobs.begin(), jobs.end());
+
+ //우선 순위 큐
+ priority_queue, vector>, compater> q;
+
+ int temp = 0, j = 0;
+ while (j < jobs.size() || !q.empty())
+ {
+
+ //같은 시간대에 다른 작업들 있으면 우선 순위 큐에 넣어준다
+ if (jobs.size() > j && temp >= jobs[j][0])
+ {
+ q.push(jobs[j]);
+ j++;
+ continue;
+ }
+
+ if (!q.empty())
+ {
+ //0번째 와 1번째의 차이를 구하는 코드
+ temp += q.top()[1];
+ answer += temp - q.top()[0];
+
+ q.pop();
+ }
+ else //다음 작업으로 진행
+ {
+ //다른 작업 시간이라면 temp를 새로 지정해야한다
+ //같은 시간대의 시간대만 따로 처리 하기 위함이다
+
+ temp = jobs[j][0];
+ }
+ }
+ return answer / jobs.size();
+}
+
+```
+
+다른 작업 시간대의 처리만 잘 했다면 우선 순위 큐를 이용해서 풀기 좋은 문제 였습니다.
+
+--------------------------------------------------------------------------------------------------------------------------------
+
+### 앞에서 부터 삭제 하기 - 코드 트리 문제
+
+
+얼핏 보면 쉬운 문제 처럼 보이지만 처음 풀어본 입장에서 쉬운 문제는 아니었다
+
+앞에서 부터 k개를 삭제 하고 난 후 남아있는 숫자에서 가장 작은 숫자 하나를 구해야 하니까 min heap을 사용해야 한다는것을 알수가 있었다 그리고 나서 평균 구하는건 할수가 있으니 넘어가는데.. 문제는 k개를 지웠을때 평균값이 최대가 되어야 한다는것을 어떤 방식으로 전개하면 알수있을지 처음에 고민이 되었다 k는 1부터 n-2까지만 고려 한다고 했으므로 고려 끝에 1~n-2까지 k개를 지우면서 고려 해야 하겠다고 생각 했다 그래서 1~n-2까지 삭제 하고 min heap만들고 처리 했는데 시간 초과가 나와서 질문을 해본 결과 min heap은 o(n)이 걸리는데 이걸 for 문 안에서 돌리고 있어서 시간초과가 나오는것을 알게 되었다 이때 k를 n-2부터 1까지 고려를 해보면 min heap의 사용 빈도를 줄일수있을것이라는 힌트를 얻게 되었는데 이 힌트를 적용하면 처음에만 min heap을 사용하고 이후에는 push heap , pop heap만으로도 처리가 가능하다는것을 알게 되었다 (log(n)) 하지만 여전히 시간 초과가 나와서 정말 당황을 했는데 accumulate에서 발생하는 시간 초과임을 알수있었다 이걸 해결하기 위해 다른 사람들이 푼 방식을 보았는데 누적 합으로 해결하고 있었다 사실 다른 내용 보다 이 내용 때문에 지금까지 길게 정리하는것도 있다 이후 내용에도 누적합(prefix sum)에 대해 내용 정리 할것인데 [개념은 거기서 보기] 우선 여기 문제만 생각 해본다 할때 상황이 딱 맞는 상황임을 뒤늦게 알수있었다
+
+
+
+
+내가 작성한 코드
+
+
+```c++
+#include
+#include
+#include
+#include
+#include
+//using namespace std;
+int main()
+{
+ std::ios::sync_with_stdio(false);
+ std::cin.tie(NULL);
+
+ std::vectorv;
+ std::vectorprefix_sum;
+ v.reserve(100000);
+ prefix_sum.reserve(100000);
+
+ int n=0;
+ double max_val = -1.0;
+ prefix_sum.emplace_back(0);
+ //std::cout<<"DDD ";
+ std::cin>>n;
+
+
+ for(int i=1;i<=n;i++)
+ {
+
+ int t=0;
+ std::cin>>t;
+
+ v.emplace_back(t);
+ prefix_sum[i] = prefix_sum[i-1]+t;
+
+
+ }
+
+ std::vector temp(v.begin()+(n-3), v.end());
+ std::make_heap(temp.begin(), temp.end(), std::greater<>{});
+
+
+ for(int i=n-3;i>=0;i--)
+ {
+ //std::vector temp = v;
+ //std::make_heap(temp.begin()+i, temp.end(), std::greater<>{});
+ if(i!=n-3)
+ {
+
+ temp.emplace_back(v[i]);
+
+ push_heap(temp.begin(),temp.end(),std::greater<>{});
+ }
+
+ std::pop_heap(temp.begin(), temp.end(), std::greater<>{});
+
+ int ele = temp.back();
+ //std::cout<<"CCC "<{});
+
+
+
+
+
+ }
+
+ std::cout.precision(2);
+ std::cout << std::fixed;
+ std::cout< arr = { "","", "abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
+
+ //입력 받은 숫자
+ string num = "";
+
+ //결과 반환하는 벡터 배열
+ vector result;
+public:
+
+ // 1.recursion할때 마다 무엇을 선택할 것인가
+ //str,idx를 재귀함수 할때마다 고려할 것이다
+ void BT(string str, int idx)
+ {
+ //num의 사이즈와 같을때까지 반복한다
+ //Base case
+ if (str.size() == num.size())
+ {
+ result.emplace_back(str);
+ return;
+ }
+
+
+ for (auto& e : arr[num[idx] - '0'])
+ {
+ //다음 재귀함수 프로세스와 현재 프로세스 종료 설정
+ BT(str+e, idx + 1);
+ }
+ }
+
+ vector letterCombinations(string digits)
+ {
+ //빈 문자이면 빈 배열 반환 -> 예외 상황 처리
+ if (digits == "")
+ {
+ return {};
+ }
+
+ //입력 받은 숫자를 num에 넣는다
+ num = digits;
+ BT("", 0);
+
+ return result;
+
+ }
+};
+```
+
+
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 2번 Backtracking subsets
+
+
+이번 문제는 중복이 없는 subset을 구하는 문제 입니다. 각 문자를 뽑는 경우 아닌경우를 나누어서 생각하면 됩니다.
+
+
+* c++ 코드
+
+```c++
+class Solution {
+ vector> result;
+ vector num;
+public:
+
+ //idx, letter를 매개 변수로 넣으면서 진행
+ void BT(int idx, vector& letter)
+ {
+ //base case 종료 조건
+ if (idx == num.size())
+ {
+ result.emplace_back(letter);
+ return;
+ }
+
+
+ //해당 문자 안 뽑는 경우
+ //다음 재귀함수 프로세스 설정
+ BT(idx + 1, letter);
+
+ letter.emplace_back(num[idx]); //해당 문자를 추가한다
+
+ //해당 문자 뽑는 경우
+ //현재 프로세스 종료 설정
+ BT(idx + 1, letter);
+ letter.pop_back(); //원상 복귀
+
+ }
+
+ vector> subsets(vector& nums)
+ {
+ num = nums;
+ vector letter;
+
+
+ BT(0, letter);
+
+ return result;
+
+ }
+};
+```
+
+
+이번 문제는 문자를 뽑고 안뽑고 진행하는 모델을 먼저 생각하고 backtracking으로 진행하는게 중요한 문제 였습니다.
+
+Time : O(n 2^n)
+
+ * 진행 될때마다 2배씩 늘어나기 때문에 2^n이고 이 과정이 n번 수행 되기 때문입니다.
+
+
+Space : O(n)
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 3번 permutations
+
+
+이번 문제는 순열 문제 입니다. 결과 값의 개수는 n!만큼 나올 것입니다.
+
+
+왜 n!의 개수가 나오는지 생각해보면 이해하기 쉬워질 것입니다.
+
+1 2 3 4가 있다면 처음 경우만 생각 해보겠습니다.
+
+1 2 3 4
+2 1 3 4 (1과 2를 swap한 결과)
+3 1 2 4 (2와 3을 swap한 결과)
+4 1 2 3 (3와 4을 swap한 결과)이 가능 할것입니다. (아래 for반복문이 swap하는 이유 )
+
+각 반복문의 BT함수는 1 2 3 4일때 2 1 3 4일때를 차례대로 들어가면서 가능한 순열의 경우를 탐색해 나갑니다.
+
+(1 2 3 4는 또 다시 여러개의 순열로 이루어질수있습니다. 2를 대상으로 다시 swap합니다.)
+
+
+
+
+* c++ 코드
+
+```c++
+class Solution {
+ vector> ans;
+public:
+ void BT(int idx, vector nums)
+ {
+ //base case
+ if (idx == nums.size())
+ {
+ ans.emplace_back(nums);
+ return;
+ }
+
+ //idx부터 swap하는 반복문
+ //현재 프로세스 종료 설정
+ for (int i = idx; i < nums.size(); i++)
+ {
+ //다음 재귀함수 프로세스 설정
+ swap(nums[idx], nums[i]);
+ BT(idx + 1, nums);
+
+ }
+ }
+ vector> permute(vector& nums)
+ {
+ BT(0, nums);
+
+ return ans;
+ }
+};
+
+```
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 4번 Combination Sum
+
+
+
+이번 문제에서 고려할 점은 후보 배열의 원소가 반복해서 사용될수있다는 것입니다.
+
+
+* c++ 코드
+
+```c++
+class Solution {
+ vector> result;
+ vector num;
+public:
+
+ void BT(int idx, int target, vector arr)
+ {
+ //base case 종료 조건
+ if (target == 0)
+ {
+ result.emplace_back(arr);
+ }
+ else if (target < 0) //target==0되고 한번 더 들어오면 종료한다
+ //back하는 조건
+ {
+ return;
+ }
+ /*
+ 입력 배열 원소가 반복될수있기 때문에 반복문 설정을 잘 해주어야하는데
+ 현재 원소 인덱스 부터 시작할수있게 idx설정한다
+
+ */
+ for (int i = idx; i < num.size(); i++)
+ {
+ arr.emplace_back(num[i]);
+
+ BT(i, target - num[i], arr); //다음 재귀함수 프로세스 설정 i번째부터 시작하기 위해 idx = i ,
+ //target-num[i]해서 target탐색
+ //현재 프로세스 종료 설정
+ arr.pop_back();
+ }
+ return;
+
+ }
+ vector> combinationSum(vector& candidates, int target)
+ {
+ num = candidates;
+ vector arr;
+ BT(0, target, arr);
+
+ return result;
+ }
+};
+```
+
+
+
+사실 앞에 3문제는 backtracking문제라기 보다 Recursive, DFS문제에 가깝다고 생각합니다.
+거의 모든 경우를 탐색하기 때문입니다. 하지만 이번 문제는 그나마 조건을 보고 아니면 back하는 프로세스를 조금
+느끼실 수 있던 문제였다고 생각 합니다.
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 5번 restore_ip_adr
+
+
+문제 이해가 안될수도 있기 때문에 추가 설명을 먼저 하겠습니다.
+
+
+ip version 4의 ip Format은 다음과 같습니다. (8bit를 4개 쓸수있다는 의미와 동일 합니다. 8bit의 범위는 0~255)
+
+
+IP Format : (0-255).(0-255).(0-255).(0-255)
+
+문제에서 invalid ip가 왜 안되는지 이해 했을 것 이라고 생각 됩니다.
+
+
+invalid한 ip 조건
+
+1. leading 0오면 안된다
+2. ip format을 넘어가는 숫자 오면 안된다 즉 255이상 0이하의 숫자가 오면 안됩니다.
+
+
+
+가능성을 파악하는 문제 => Backtracking 문제 입니다.
+
+
+ **BASE CASE**
+
+ 1. Catch answer
+
+ -> vector에 추가를 해야한다 그러려면 일단 string s끝까지 탐색이 되어야한다
+ 그리고 . 기준 정수 개수가 정확히 4개 여야한다 그래야 ip version 4이다
+
+ 2. Dead Path
+
+ 2-1 ) . 기준으로 정수가 4개 이상인 경우는 더 안봐도 된다
+ 2-2) 비교 숫자가 0-255범위를 벗어난다면 더 안봐도 된다
+
+
+**Process**
+
+1. Choose
+
+ 0-255 범위를 확인을 해야한다 그러면 1자리부터 100자리까지 모든 가능성을 확인해야한다
+
+2. Explore
+
+ 0-255 범위가 맞다면 추가 하면서 recursive 로 탐색해나간다
+
+3. Unchoose
+
+ 3-1) 0-255 범위를 벗어난다면 선택하지 않고 다음으로 넘어간다
+ 3-2) leading 0가 있다면 더이상 가지 않고 다음으로 넘어간다
+
+
+
+* c++ 코드
+
+```c++
+class Solution
+{
+ vector res;
+
+public:
+
+ void BT(string t, int counter, string& s, int pos)
+ {
+ // counter 는 . 기준으로 정수가 4개를 넘어가는지 아닌지 확인하는 변수
+ //pos는 대상 s끝까지 갔는지 확인하는 변수
+
+ //BASE CASE in BT
+
+ if (pos == s.size() && counter == 4)
+ {
+ t.pop_back(); //t 마지막에 . 을 제거하기 위함이다
+ res.emplace_back(t);
+ return;
+ }
+
+ // .기준으로 정수가 4개 넘어갔을때 DEAD PATH
+ if (counter > 4)
+ {
+ return;
+ }
+
+ for (int start = 1; start <= 3 && pos + start <= s.size(); start++)
+ {
+ string temp = s.substr(pos, start);
+ stringstream os;
+ os.clear();
+
+ //Unchoose in BT leading 0를 선택하지 않는다
+ if (temp.size() > 1 && temp[0] == '0')
+ {
+ continue;
+ }
+
+ //문자열-> 정수 변환
+ os.str(temp);
+ int val = 0;
+ os >> val;
+
+ //Choose in BT
+ if (val <= 255 && val >= 0)
+ {
+ string kl = t + temp+'.'; //1자리부터 . 붙히면서 모든 가능성을 본다
+ //왜냐하면 정확히 4개의 정수로 나누어 떨어져야하기때문이다 그리고 0-255범위이기때문에 start는 1부터 3인것이다
+
+
+ //pos+start 는 다음으로 넘어간다는 의미이다
+ BT(kl, counter + 1, s, pos + start);
+
+ }
+
+
+
+ }
+
+
+ }
+
+ vector restoreIpAddresses(string s)
+ {
+ BT("", 0, s, 0);
+ return res;
+ }
+};
+
+```
+
+
+이번 문제를 통해 backtracking을 좀더 이해 할수있었을것이라고 생각 됩니다.
+모든 가능성 중에서 원하는 조건일때만 탐색을 진행하고 아니라면 빠져나가는 가지치기를 경험 할 수 있었습니다.
+
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 6번 Word Search
+
+
+이번 문제는 word search 문제 입니다. grid에서 해당 word가 있으면 T아니라면 F를 반환하는 문제 입니다.
+한 문자 기준으로 위 아래 왼쪽 오른쪽 4방향으로 이동할수있습니다.
+
+
+해당 단어가 있는지 모든 경우를 우선 탐색해야합니다. 탐색 과정 속에서 조건이 맞지 않으면 back을 해야 하는 문제이므로 backtracking문제입니다.
+
+
+문제 전략은 스타트 지점에서 4방향을 모두 탐색을 이어갈것입니다. 4방향중에서 하나라도 true가 나온다면 해당 word가 존재한다는 의미이므로 true를 반환 할 것입니다.
+
+
+스타터 지점을 찾고 탐색을 이어가는게 핵심입니다.
+
+
+
+* c++ 코드
+
+```c++
+class Solution
+{
+ string temp;
+
+public:
+
+ bool BT(vector>& board,int idx,int row,int col)
+ {
+ //base case
+
+ //size에 도달하면 True
+ if (idx==temp.size())
+ {
+
+ return true;
+ }
+
+ //back 조건
+ //board를 벗어나는 경우 그리고 다음 row col이 temp[idx]가 아니라면 false를 반환한다
+ if (row < 0 || col < 0 || row >= board.size() || col >= board[0].size() || board[row][col] != temp[idx])
+ {
+
+ return false;
+ }
+
+
+
+ board[row][col] = ' ';
+
+ //다음으로 탐색 하는 프로세스 설정
+ //4방향에 대해서 모든 경우에 T/F를 or개념으로 묶는다 하나라도 true가있으면 true를 출력한다
+ bool res = BT(board, idx + 1, row - 1, col) ||
+ BT(board, idx + 1, row, col - 1) ||
+ BT(board, idx + 1, row, col + 1) ||
+ BT(board, idx + 1, row + 1, col);
+
+
+ //' '공백으로 바꾼 곳을 원상복구한다 => 그래야 여러 스타트 지점이 있어도 탐색을 이어나갈수있다
+ board[row][col] = temp[idx];
+
+ return res;
+
+
+
+ }
+ bool exist(vector>& board, string word)
+ {
+ temp = word;
+
+
+ for (int i = 0; i < board.size(); i++)
+ {
+ for (int j = 0; j < board[0].size(); j++)
+ {
+ //word[0]스타트 지점을 찾는다 그리고 BT가 T일때 찾는 문자가 있는것이다
+ if (board[i][j]==word[0]&& BT(board, 0, i, j)) //스타트 지점에 4방향을 돌아봤을때 word가 있다는 의미이다
+ {
+
+ return true;
+
+ }
+ }
+
+
+
+
+ }
+
+
+ return false;
+ }
+};
+```
+
+
+
+원상복구를 하는 부분 **board[row] [col] = temp[idx]** 이 부분이 있어야 스타트 지점이 여러개 있어도 탐색을 이어갈 수 있었습니다.
+
+
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+
+### 7번 valid sudoku
+
+스도쿠가 유효한지 판단하는 문제입니다. 사실 이 문제는 Backtracking을 쓰지 않고도 풀수있는 문제입니다. 그래서 이번 문제는 backtracking을 사용하지않고 문제를 풀어 보겠습니다.
+
+
+
+**주의**
+사실 이어지는 문제 8번을 풀다가 추천 문제에 있어서 풀어본 문제라서 backtracking관련 문제는 아니지만 이어지는 문제도 스도쿠 문제이기 때문에 이번 문제를 이해하시면 다음 문제를 이해하는데 도움이 될 것 같아서 이번 포스팅에 넣어 보았습니다. bactracking문제만 풀고 싶으시면 이 문제는 넘어가셔도 됩니다.
+
+
+
+
+스도쿠의 규칙은 9 * 9 행렬에서 각 가로줄에는 중복되지 않는 숫자 1-9 ,각 세로줄 , 3 * 3 행렬도 마찬가지로 중복 되지 않는 숫자 1-9가 있어야 합니다
+
+유효한지 판단하려면 위의 규칙을 지켰는지 확인을 하면 됩니다.
+
+
+
+
+* c++ 코드
+
+```c++
+class Solution {
+public:
+ bool isValidSudoku(vector>& board)
+ {
+ //hash set 설정
+ //각 row, col , 3*3행렬에 중복되지 않는 1-9를 넣는 해쉬이다
+ unordered_set seen;
+
+ //9*9 행렬 탐색
+ for (int row = 0; row < 9; row++)
+ {
+ for (int col = 0; col < 9; col++)
+ {
+ //값이 있다면
+ if (board[row][col] != '.')
+ {
+
+ //각 row,col ,3*3행렬에 값이 있다는것을 표시 하기 위한 변수들
+ string row_str = "R" + to_string(row) + board[row][col];
+ string col_str = "C" + to_string(col) + board[row][col];
+ string sub_arr = "B" + to_string(row / 3) + to_string(col / 3) + board[row][col]; //3*3 행렬 고려해야하기때문에 /3한다
+
+ //hash에 있다면 false
+ if (seen.find(row_str) != seen.end() ||
+ seen.find(col_str) != seen.end() ||
+ seen.find(sub_arr) != seen.end())
+ {
+ return false;
+ }
+ //hash에 값 넣는다 (중복되지 않는 1-9)
+ seen.emplace(row_str);
+ seen.emplace(col_str);
+ seen.emplace(sub_arr);
+
+ }
+ }
+ }
+ return true;
+ }
+};
+```
+
+해쉬 셋에 각 row, 각 col, 각 3*3행렬의 유효한 값을 저장합니다. 만약 해쉬셋에서 중복된 값을 발견하면 false를 반환하는 구조 입니다.
+
+
+스도쿠가 유효한지 아닌지만 판단하면 되는 문제 였기 때문에 큰 어려움은 없었을 것 입니다.
+
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 8번 Sudoku Solver
+
+
+앞에 7 번 문제를 보시고 왔다면 이 문제를 이해하는데 도움이 될것입니다. 앞의 문제와는 다르게 난이도가 있는 문제 입니다.
+이번 문제는 스도쿠를 직접 푸는 문제입니다.
+
+빈 곳에 1-9중복되지 않는 숫자를 스도쿠 규칙에 맞추어서 풀어야합니다.
+
+그래서 입력으로 들어온 grid를 전체 탐색하면서 빈곳에 값을 넣어줄것인데 스도쿠 규칙에 따라 각 row,각 col , 각 3*3행렬에 넣으려는 값이 중복하는지 안하는지 확인을 하면서 값을 삽입해야합니다.
+
+
+
+* c++ 코드
+
+```c++
+class Solution {
+public:
+ pair isEmpty(vector>& board)
+ {
+ for (int i = 0; i < 9; i++)
+ {
+ for (int j = 0; j < 9; j++)
+ {
+ if (board[i][j] == '.')
+ {
+ return make_pair(i,j);
+ }
+ }
+ }
+
+ return make_pair(10, 10); //9*9 matrix를 다 마친 경우
+
+ }
+
+ bool check_row(int x, char val, vector>& board)
+ {
+ for (int i = 0; i < 9; i++)
+ {
+ if (board[x][i] == val) //각 row에 같은 val있으면 조건에 맞지않는다
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ bool check_col(int y, char val, vector>& board)
+ {
+ for (int j = 0;j < 9; j++)
+ {
+ if (board[j][y] == val)
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool check_box(int x, int y, char val, vector>& board) //sub box 모두를 탐색할것이다
+ {
+ int X = x / 3; // 빈곳 row
+ int Y = y / 3; //빈곳 col 의 sub box위치
+
+ //각 sub box의 범위를 가리키기 위함이다
+ X = 3 * X;
+ Y = 3 * Y;
+
+ for (int i = 0; i < 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+
+ //sub box에 같은 val 있으면 false
+ if (board[X + i][Y + j] == val)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+
+
+ }
+ bool solve(vector>& board)
+ {
+ pair empty_slot = isEmpty(board);
+
+ if (empty_slot.first == 10 && empty_slot.second == 10)
+ {
+ //9*9 모든 경우를 다 탐색 한 경우이다
+
+ return true; //catch ans => 9*9 다 돈 경우 정답을 출력할수있다
+ }
+ int row = empty_slot.first;
+ int col = empty_slot.second;
+ for (char val = '1'; val <= '9'; val++)
+ {
+ if (check_row(row, val, board) && check_col(col, val, board) && check_box(row, col, val, board))
+ {
+ board[row][col] = val; //choose 조건에 맞는 다면 val로 교체한다
+
+ if (solve(board)) //Explore 계속 탐색해 나간다
+ {
+ return true;
+ }
+ board[row][col] = '.'; //unChoose 조건에 맞지 않는 val이면 다시 원상 복구 한다
+ }
+ }
+ return false; //Dead path 조건 맞지 않으면 backtracking 한다
+ }
+ void solveSudoku(vector>& board)
+ {
+
+ solve(board);
+
+ }
+};
+
+```
+
+
+간단히 다시 리뷰를 해보면 빈곳에 1-9값을 넣어줄것인데 유효한지 각 row,col 3*3행렬 조건을 따져 줍니다. 계속 진행을 하다가 끝나는 조건 (9 * 9행렬 모두 돈 경우)일때 종료를 합니다.
+그 전까지는 solve가 계속 탐색을 진행 합니다. 그래서 if문은 solve가 끝나는 조건을 만나야 비로소 연쇄적으로 true를 반환하면서 함수가 끝나게 됩니다.
+
+유효한 값의 가능성을 계속 탐색하면서 값이 유효하지 않다면 바로 이전으로 돌아가는 성질의 문제이므로 backtracking문제로 볼수있었습니다.
+->스도쿠 조건에 따라 검사를 진행하는 과정은 7번 문제를 풀어보시면 더 쉽게 이해하실수있을 것 입니다.
+
+
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+### 9번 N-Queen
+
+
+마지막 문제는 N-Queen 문제입니다. 이 문제는 backtracking의 성질을 잘 보여주는 대표적인 backtracking 문제입니다.
+
+
+n이 주어질때 n * n의 보드에서 n개의 퀸이 서로 공격하지 않도록 보드에 배치하는 문제입니다. 체스에서 퀸은 대각선 ,수직 , 수평으로 이동 할수있습니다.
+서로 공격하지 않도록 배치해야 하므로 대각선 , 수평, 수직에 다른 퀸이 배치되어있으면 안됩니다. 이때 정답은 하나가 아닐수있습니다.
+
+
+
+8번 문제와 비슷한 유형의 문제라고 보시면 될것 같습니다. 스도쿠 문제를 풀때 또한 조건에 따라 처리를 해주었는데 이번에는 퀸의 성질에 따라 조건을 처리 하면 됩니다.
+
+
+
+우선 n = 4라고 가정하고 설명을 이어가겠습니다. 그러면 4 * 4 행렬에서 답을 찾아가야합니다.
+0부터 16번째까지 모두 Q의 자리를 찾아서 탐색해 나간다면 O(4*16^(16+1))이 걸릴것입니다. 4는 왜 곱해지냐면 col과 대각선을 확인할때 걸리는 시간이 있기 때문입니다.
+
+저희는 이 Time을 더 최적화 해야합니다. 여기서 더 생각 해볼수있는것은 같은 row에 2개의 퀸이 올수없다는 것입니다. 그렇다면 각 row에 대해서 위치를 정해주고 이어 갈 수 있다면
+
+TIME : O(4*4^(4+1))로 줄일수 있을 것입니다. (row을 따로 검사 하지 않아도 되는 이유 )
+
+
+아래 c++코드가 위와 같은 프로세스로 진행 되었습니다.
+
+
+
+
+
+
+* c++ 코드
+
+
+```c++
+class Solution {
+public:
+
+ void set_board(vector& board, int& n) { // 보드 만들기
+
+
+ board.reserve(n); //n개 만큼 크기 설정
+
+ //char vector로 입력이 오기 때문에 string으로 묶는 과정
+ string s = "";
+ for (int i = 0; i < n; i++) {
+ s = s + '.';
+ }
+
+ //묶은 string을 보드로 만드는 과정
+ for (int i = 0; i < n; i++) {
+ board.emplace_back(s);
+ }
+ return;
+ }
+
+ //퀸의 성질 확인하는 함수
+ bool check_safe(vector& board, int& row, int& col, int& n) {
+
+
+
+ for (int i = 0; i <= row; i++) { // col확인 같은 col에 Q있으면 false
+ if (board[i][col] == 'Q') {
+ return false;
+ }
+ }
+
+ //대각선 확인할때 현재 row보다 아래의 대각선 위치는 고려 하지 않는다
+ int i = row;
+ int j = col;
+ while (i >= 0 && j >= 0) { // 현재 row 기준 왼쪽 대각선 확인
+ if (board[i][j] == 'Q') {
+ return false;
+ }
+ i--;
+ j--;
+ }
+
+ i = row;
+ j = col;
+ while (i >= 0 && j < n) { //현재 row 기준 오른쪽 대각선 확인
+ if (board[i][j] == 'Q') {
+ return false;
+ }
+ i--;
+ j++;
+ }
+
+
+ return true;
+
+ }
+
+ void nqueen(vector>& sol, vector& board, int row, int& n) {
+
+ //n*n행렬이기 때문에 row가 n과 같아지면 모두 탐색 했다는 의미 이므로 종료
+ //base case
+ if (row == n) {
+
+ sol.emplace_back(board);
+ return;
+ }
+
+ for (int i = 0; i < n; i++) { // n*n행렬이기 때문에 row, col모두 0~n-1까지의 범위 가진다
+
+ //각 row마다 퀸 자리 정해준다
+ if (check_safe(board, row, i, n)) {
+ board[row][i] = 'Q';
+
+ //현재row에 Q넣고 다음 row부터 다시 탐색 한다
+ nqueen(sol, board, row + 1, n);
+ board[row][i] = '.'; //중복하는 답을 찾기 위해 원상 복귀 한다
+ }
+ }
+
+ return;
+ }
+ vector> solveNQueens(int n) {
+
+ vector> sol; //결과 배열
+
+ vectorboard; //n 배열 보드
+
+ set_board(board, n); //n 보드 만들기
+
+ nqueen(sol, board, 0, n); //탐색 시작
+
+ return sol;
+ }
+};
+
+```
+
+
+col과 대각선을 해결할때 O(N)의 time쓰는것 보다 O(1)으로 최적화 할수도 있는데 hashset을 이용해주면 가능합니다.
+
+
+row에 Q정해졌다면 그때 col위치를 hash에 넣어줍니다 그리고 마지막에 row에서 Q넣을 때 기존 처럼 모두 검사하는것이 아니라 hashset에서 없는 위치를 찾아서 넣어주면 O(1)으로 해결 할 수있습니다.
+
+
+대각선의 경우는 왼쪽 대각선과 오른쪽 대각선을 따로 생각을 해주어야 하는데 좌표를 (x,y)로 가정 해보겠습니다.
+
+왼쪽 대각선의 경우 x==y이기 때문에 x-y=0입니다.
+
+오른쪽 대각선의 경우 x+y의 값이 일정하다는 성질이 있습니다. 이 특성을 이용해서 hashset을 만들어준다면 대각선 처리 또한 O(1)으로 해결 가능합니다.
+
+
+아래의 python 코드는 위의 프로세스의 결과 입니다.
+
+
+* python 코드
+
+```python
+from typing import List
+
+
+class NQueens:
+ def solve(self, n: int) -> List[List[str]]:
+ self.__results = []
+ self.__col_set = set() #column duplicates
+ self.__diag_set1 = set() #row-col duplicates
+ self.__diag_set2 = set() #row+col duplicates
+ self.__n = n #length
+
+ for x in range(n):
+ self.__bt(0,x,[])
+
+ return self.__results
+
+ #python str is immutable 보드 만들기
+ def __create_str_row(self, col:int) -> str:
+ str_list = ['.']* self.__n
+ str_list[col] = 'Q'
+ return ''.join(str_list)
+
+ def __bt(self, row:int, col:int, board:List[str]):
+ #exit conditions base case
+ if row==self.__n or col==self.__n:
+ return
+ if col in self.__col_set:
+ return
+
+ # 왼쪽 대각선 성질
+ diag1_info = row-col
+
+ #오른쪽 대각선 성질
+ diag2_info = row+col
+
+ # 설정한 hash에 값이 있다면 return
+ if diag1_info in self.__diag_set1:
+ return
+ if diag2_info in self.__diag_set2:
+ return
+
+ #process
+ str_line = self.__create_str_row(col)
+ board.append(str_line)
+
+ if len(board) == self.__n:
+ self.__results.append(board.copy())
+ board.pop()
+ return
+
+ #duplicates sets hash set 설정
+ self.__col_set.add(col)
+ self.__diag_set1.add(diag1_info)
+ self.__diag_set2.add(diag2_info)
+
+ #recursive calls
+ for x in range(self.__n):
+ self.__bt(row+1,x,board)
+
+ #duplicates sets pop
+ self.__diag_set2.remove(diag2_info)
+ self.__diag_set1.remove(diag1_info)
+ self.__col_set.remove(col)
+ board.pop()
+
+nQsolver = NQueens()
+
+```
+
+
+
+
+-----------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 마무리
+
+이번 문제를 통해 bactracking에 대한 감을 잡는 시간이 되었으면 좋겠습니다. 특히 마지막 문제는 유명하고 대표적인 문제인 만큼 여러번 보고 이해하는 것을 추천 드립니다.
+
+긴 글 읽어 주셔서 감사합니다.
+
+
+
diff --git a/_posts/2022-03-05-DP.md b/_posts/2022-03-05-DP.md
new file mode 100644
index 000000000000..343a2e0bbff2
--- /dev/null
+++ b/_posts/2022-03-05-DP.md
@@ -0,0 +1,205 @@
+---
+layout: single
+title: "Dynamic Programming 개념 및 관련 문제"
+categories: [Dynamic Programming,DP,Recursive,Climbing stairs,Min cost Climbing stairs,Minimum Path Sum,Conis Change,Decode way,Maximum Subarray,Maximum Product Subarray,Longest Palindromic Substring,Word Break ]
+tag : [c++,python,Algorithm,C++,]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### intro
+
+안녕하세요 이번 포스팅에서는 DP 즉 Dynamic Programming에 대해서 포스팅 할 것 입니다.
+
+DP는 큰 문제를 작은 문제로 나누어서 푸는 방식이라고 보면 될 것 같습니다. 그래서 problem과 sub problem을 정의하는게 매우 중요하다고 할수있습니다.
+
+분할 정복과 비슷해 보이지만 DP는 중복 될 수 있지만 분할 정복은 중복 될수 없다는 데에 차이가 있습니다.
+
+그래서 DP에서는 중복 하는 문제를 한번만 계산하기 위해 memoization을 사용하기도 합니다.
+
+
+일반적으로 DP 문제는 특정 양을 최대화 또는 최소화하는 문제 , 특정 조건 또는 특정 확률 문제에서 배열을 계산해야하는 문제가 있습니다.
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 피보 나치 문제
+
+문제를 풀기 전에 피보나치 문제를 먼저 보면서 DP에 대한 감을 체험해 보도록 하겠습니다.
+
+피보 나치를 혹시 모르신다면 아래 링크에서 확인하세요
+[피보나치 위키백과](https://ko.wikipedia.org/wiki/%ED%94%BC%EB%B3%B4%EB%82%98%EC%B9%98_%EC%88%98)
+{: .notice--danger}
+
+
+DP문제에서 가장 힘든 부분은 개인적으로 상태들의 관계를 통한 점화식 부분일 것이라고 생각합니다.
+그러나 피보나치 함수는 점화식을 알고 시작 하기 때문에 비교적 쉽습니다.
+
+일반적으로 처음 피보나치를 구현 하면 아래처럼 할 것 입니다.
+
+
+* c++ 코드
+
+```c++
+
+int fibo_gener(int n)
+{
+ if (n == 0 )
+ {
+ return 0;
+ }
+ if (n == 1)
+ {
+ return 1;
+ }
+
+ return fibo_gener(n - 1) + fibo_gener(n - 2);
+}
+
+
+```
+
+이런 식으로 구현 하게 되면
+
+TIME :O(2^N)의 시간 복잡도를 가지게 됩니다.
+
+
+지금까지의 단계는 DP문제로 치면 점화식을 그대로 코드로 구현한 것 입니다.
+그러나 DP문제는 크게 Top down과 Bottom up으로 최적화를 할 수 있습니다.
+
+
+일반적인 피보나치 함수를 Top Down방식과 Bottom up방식으로 최적화를 해보겠습니다.
+
+Top-down : 큰 문제를 작은 문제로 나누면서 푼다 -> 재귀로 구현
+
+Bottom-up : 작은 문제 부터 차례대로 푼다 -> 반복문으로 구현
+
+
+첫 번째는 top down 방식인 memoization을 사용한 최적화 방법입니다.
+
+DP느 분할 정복과는 다르게 sub problem이 중복 될 수 있습니다. 그래서 중복되는 문제를 한번만 계산하기 위해서 memoization을 사용합니다.
+
+계산한 결과를 배열에 저장하면서 만약 memo배열에 값이 있다면 그 값을 그대로 사용하면서 중복 계산을 하지 않는 방식이다
+
+* memoization c++ 코드
+
+
+```c++
+
+
+int memo[100]={0,};
+int fibonacci(int n) {
+ if (n <= 1) {
+ return n;
+ } else {
+ if (memo[n] > 0) { // memo의 값이 0이 아니면
+ return memo[n]; // 그 값을 그대로 사용
+ }
+ memo[n] = fibonacci(n-1) + fibonacci(n-2);
+ return memo[n];
+ }
+}
+```
+
+
+
+memoization을 이용해서 구현 하면 기존의 O(2^N)의 시간 복잡도가 O(N)으로 줄어들게 된다
+
+
+
+
+그러나 memoization은 오버플로우 문제가 있기 때문에 bottom up으로 문제를 풀면 좋다
+
+
+사실 피보나치 함수를 계산할때는 이전값과 이전이전값 즉 두개의 값만 있으면 계산할수있다.
+
+
+
+
+* bottom up c++코드
+
+재귀 사용하지 않고 반복문 사용한다.
+
+
+```c++
+
+long long int fibo_iter(int n)
+{
+ int prev = 0, cur = 1;
+
+ if (n == 0)
+ {
+ return 0;
+ }
+ if (n == 1)
+ {
+ return 1;
+ }
+
+ for (int i = 2; i <= n; i++)
+ {
+ int temp = cur;
+ cur += prev;
+ prev = temp;
+
+ }
+ return cur;
+
+
+}
+
+
+```
+
+
+
+
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+### 문제 링크
+
+
+
+[1번 Climbing stairs](https://leetcode.com/problems/min-cost-climbing-stairs/)
+{: .notice--danger}
+
+[2번 Min cost Climbing stairs](https://leetcode.com/problems/min-cost-climbing-stairs/)
+{: .notice--danger}
+
+[3번 Minimum sum Path ](https://leetcode.com/problems/minimum-path-sum/)
+{: .notice--danger}
+
+[4번 Conis Change](https://leetcode.com/problems/coin-change/)
+{: .notice--danger}
+
+[5번 Decode Way](https://leetcode.com/problems/decode-ways/)
+{: .notice--danger}
+
+[6번 Maximum Subarray](https://leetcode.com/problems/maximum-subarray/)
+{: .notice--danger}
+
+[7번 Maximum Product Subarray](https://leetcode.com/problems/maximum-product-subarray/)
+{: .notice--danger}
+
+[8번 Longest Palindromic Substring](https://leetcode.com/problems/longest-palindromic-substring/)
+{: .notice--danger}
+
+[9번 Word Break](https://leetcode.com/problems/word-break/)
+{: .notice--danger}
+
+[10번 Partition Equal Subset Sum](https://leetcode.com/problems/partition-equal-subset-sum/)
+{: .notice--danger}
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
diff --git a/_posts/2022-04-17-compile_programming.md b/_posts/2022-04-17-compile_programming.md
new file mode 100644
index 000000000000..9f7935df865d
--- /dev/null
+++ b/_posts/2022-04-17-compile_programming.md
@@ -0,0 +1,34 @@
+---
+layout: single
+title: "컴파일러 프로그램"
+categories: [introduction,Compiler]
+tag : [c,java,compiler]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 소개글
+
+안녕하세요 **프로그램 언어와 컴파일러** 과목을 수강하면서 정리한 자료를 posting 할 생각 입니다.
+평소에는 one note에 정리를 하는 편인데 github page와 연동 하는게 어렵 더라구요 그래서 pdf로 일단 내보내고 이 블로그에 게시 할 예정입니다.
+
+일단 chapter 별로 올릴 예정입니다.
+저도 pdf로 다운 받고 추가로 공부를 진행하면서 메모가 추가 될 예정입니다.
+
+메모 되기 전에 pdf를 원하시는 분들을 위해 통합으로 만든 pdf 파일을 아래에 준비 해놓았습니다.
+
+
+
+중간고사이전내용pdf
+
+
+
+그리고 pdf안에 유용한 사이트의 링크도 포함 되어있으니 참고하실 분들은 참고하시면 될 것 같습니다.
+
+
+마지막으로 내용중에 수정이 필요하거나 틀린 내용이 있다면 댓글로 반드시 알려 주세요!
+
+감사합니다.
diff --git a/_posts/2022-04-20-AST.md b/_posts/2022-04-20-AST.md
new file mode 100644
index 000000000000..c6082c84f09a
--- /dev/null
+++ b/_posts/2022-04-20-AST.md
@@ -0,0 +1,79 @@
+---
+layout: single
+title: "Abstract Syntax Tree"
+categories: [Lexical Analysis,Scanner,Regular Expression,AST,JAVA,Compiler]
+tag : [Lexical Analysis,lexer,lexical,scanner,parser,AST impliment of java,JAVA,java]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작 하며
+
+Recursive Descent parsing algorithm을 이용해서 stream of tokens를 parse tree of AST로 변환하는 내용을 학습 할 수 있습니다.
+
+
+
+
+
+AST pdf
+
+
+
+### 과제 내용에 대한 본인의 답안
+
+
+저작권 문제가 있을 것 같아서 코드는 따로 공유 하지 않겠습니다.
+필요하다면 그때는 댓글로 알려주세요!!!
+
+
+### 내용 요약 및 정리 및 마무리
+
+* Recursive Descent parsing algorithm을 이용해서 stream of tokens를 parse tree of AST로 변환하는 내용을 배운다
+
+ bnf는 left recursion 때문에 revursive descent parsing 사용 불가 -> EBNF로 바꾸어야 사용가능 EBNF는 recursive를 iterator로 바꾸었기 때문이다.
+
+
+
+ * Token은 terminal이다 terminal이면 match() , Non terminal이면 함수를 call해야한다
+ -> recursive
+ left recursive rule이 있다면 사용 불가능 (예 BNF)
+
+ EBNF의 {} 같은 경우 0번이사반복을 인식하기 위해 Lookahead 방법을 사용한다. 즉 미리 보기이다.
+
+* AST 생성하기
+
+ 1. parsing 과정에서 AST생성
+ 2. syntax tree를 AST로 변환
+
+ * parse tree에 internal non terminal 제거
+ * separator와 puctuation(괄호) Terminal symbols 제거
+ * 모든 사소한 non terminal 제거
+ * 남아있는 non terminal을 leaf terminal로 대체
+
+
+
+ 흔히 방법 1로 AST를 생성한다
+
+
+* Abstract syntax of Clite를 통해 AST를 생성할 것 이다.
+
+ EBNF of clite와 비교해서 어떠한 것이 바뀌었는지 보세요
+ 일단 선언부와 실행부로 나눈것까지는 비슷하다
+ int abc = 45; 이런식으로 구성이 안된다는 의미이다. int abc; abc = 45; 이런식으로 구성이 된다는 의미 입니다.
+
+
+
+**과제7보고서를 보면 lexer , AST, Parser 코드에 대해 이해 할수있을것으로 생각된다**
+
+
+
+
+
+
+
+
+
+
diff --git a/_posts/2022-04-20-Clite.md b/_posts/2022-04-20-Clite.md
new file mode 100644
index 000000000000..e4b466aaa9d3
--- /dev/null
+++ b/_posts/2022-04-20-Clite.md
@@ -0,0 +1,61 @@
+---
+layout: single
+title: "Clite"
+categories: [clite,Compiler]
+tag : [compiler,clite,c,clite of c]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+### 시작 하며
+
+Syntax part 2에서 살펴본 EBNF of Clite와 BNF of Clite의 연장선이라고 생각하면 될 것 같습니다.
+
+
+
+
+Clite pdf
+
+
+
+
+### 과제에 대한 본인의 답안
+
+
+Clite C 비교 과제 pdf
+
+
+**cliet의 구문중에 c에 없거나 다른 요소**
+
+statement를 0번 이상 지원하는거 즉 null statement를 지원한다
+
+
+**clite program parse tree**
+
+pdf에 정의한 EBNF 가지고 parse tree 작성하면 되는데 내용이 길어서 생략된것이 있지만 흐름은 파악 할 수 있다.
+
+
+**clite에 없는 C 특징**
+
+
+주석,함수,다차원 배열, for 문 , case문, goto 문 , 초기화, 구조체,typedef, 삼항 연산자, pointer,++ -- 연산자, sizeof, shift operation
+
+
+
+
+
+### 내용 요약 및 정리 및 마무리
+
+
+* Clite 표현식을 통해 다시 한번 우선 순위가 낮은 방향에서 위의 방향으로가 먼저 표현되고 top down으로 진행 되는것을 확인 할수있습니다.
+
+|| -> && -> ==/!= -> <>,<=,>= -> +- -> */% -> unary -! 순으로 진행 합니다. 무슨말?
+
+Expression -> Conjunction - > Equop -> Relop -> Addition -> Term-> Factor-> primary 순으로 진행을 한다는 의미입니다.
+
+
+
diff --git a/_posts/2022-04-20-Lexer.md b/_posts/2022-04-20-Lexer.md
new file mode 100644
index 000000000000..64dccfc5d4e1
--- /dev/null
+++ b/_posts/2022-04-20-Lexer.md
@@ -0,0 +1,557 @@
+---
+layout: single
+title: "Lexical Analysis and Finite State Machine"
+categories: [Lexical Analysis,Scanner,Regular Expression,Finite State Machine,Compiler]
+tag : [Lexical Analysis,lexer,lexical,scanner,token,parser,Regular Expression,Regular Grammar,Finite automata,Finite State Machine,Lexer impliment of C,C,c]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+### 시작하며
+
+Lexical Analysis(Scanner)에 대해 학습 할 수 있습니다.
+그리고 Regular Expression과 Finite State Machine에 대해서도 학습 할 수 있습니다.
+
+
+Lexer pdf
+
+
+
+### 과제에 대한 본인의 답안
+
+
+
+토론 생각 답
+
+1. pdf에 token의 RE표현식 있다
+
+2. 여러 token 즉 keyword,id,type,operation등을 인식하는 sub automata를 통합하면 된다
+
+3. source program에 오류가 있다는게 애매하긴했다. syntax문제가 있다면 parser의 synatax analyzer가 처리를 할 것이고 lexer에 정의 되지 않는 token이 있다면 lexer가 Error를 처리 할 것 이다.
+
+4. lexer level과 syntax level의 차이점
+
+ lexer는 token이 정의된 token인지 확인 밖에 못한다. 괄호가 matching이 되는지 적절한 변수명을 썻는지 등에 대한 문법 오류는 syntax level에서 처리 할 수 있다.
+
+
+5. syntax error,sementic error,lexical error
+
+6. lexer가 token을 구분하면 parser에게 넘기고 parser가 만든 parse tree를 통해 syntax analayzer가 syntax level의 Error을 처리하면 될 것 같다
+
+ lexer는 문자가 잘못되었거나 이런건 detect할 수 있지만 문법적으로 틀린것인지는 탐지 할 수 없는데 syntax level의 오류를 어떻게 처리 하라고 한건지 잘 모르겠다
+
+**Lexical Error는 character의 순서가 token pattern과 맞지 않을 때 발생한다.**
+
+
+```c++
+
+#define _CRT_SECURE_NO_WARNINGS
+#define MAX_STR_SIZE 100
+
+/*
+*
+*
+*
+ 파일 읽고 파일 쓰기로 결과물 출력하는 프로그램
+
+
+
+*/
+
+
+
+#include
+#include
+#include
+#include
+#include
+void get_token(char* str, FILE* ff);
+int Check_keyword(char buffer[]);
+int is_operator(char* str, int* idx); //operator확인하는 함수
+int is_parenthesis(char* str, int* idx); //괄호 확인하는 함수
+
+//token 자료 구조
+char keywords[13][10] = { "int","float","double","char","if","else","while","for","break","continue","const","return"};
+char Operator[10] = {"><=+/*-%!"};
+char parenthesis[7] = {"[{()}]"};
+char OP[3] = {"=+-"};
+
+int main()
+{
+
+ FILE* fp,*fw; //파일 포인터
+ char ch;
+ char str_buffer[MAX_STR_SIZE];
+ char int_text[20]; //int count를 문자열로 변환할때 사용
+ int count = 1; //line 행 count를 의미한다
+ fp = fopen("input_lexical.txt","r"); //입력 파일 읽기 모드
+ fw = fopen("output_lexical.txt", "w+");
+
+ //파일 읽기 이상 없는지 확인
+ if (fp == NULL)
+ {
+ printf("Read the file ERORR\n");
+ exit(1);
+
+ }
+
+ //파일 쓰기 이상 없는지 확인
+ if (fw == NULL)
+ {
+ printf("Wirte the file ERORR\n");
+ exit(1);
+ }
+
+ //파일 읽기
+ while (fgets(str_buffer,MAX_STR_SIZE,fp))
+ {
+ //LINE n 처리한다
+ //한줄씩 파일에서 가지고 온다
+ fputs("\nLINE ", fw);
+ sprintf(int_text, "%d ", count++);
+ fputs(int_text, fw);
+ fputs(str_buffer, fw);
+
+ // //주석 처리
+ //주석이면 LINE만 출력하고 다음으로 넘어간다
+ if (str_buffer[0] == '/' && str_buffer[1] == '/')
+ {
+ continue;
+ }
+
+
+
+ get_token(str_buffer, fw);
+
+
+
+
+ }
+
+
+ fclose(fp);
+ fclose(fw);
+
+
+ return 0;
+}
+
+//인자로는 파일에서 가지고온 한줄, 파일쓰기 포인터
+void get_token(char *str,FILE *ff)
+{
+ int left = 0;
+ int len = strlen(str); //str 길이
+
+ int operator_mode= 0;
+ int buffer_idx = 0;
+ char buffer[20];
+
+ char ch[4]; //operator 출력하기 위한 버퍼
+
+ int flag4 = 0; //goto ONE,TWO 처리 위한 flag
+ int flag5 = 0; ////goto THREE,FOUR 처리 위한 flag
+
+
+
+ while (left token은 Regual Language인데 context free language보다 간단한 방법으로 정의 할 수 있다
+ front-end 모듈화 분리하여 더 쉽게 구현 할 수 있다
+ 이는 프로그램이 커지고 복잡해지는 것을 방지 할 수 있다.
+
+
+
+* Token is Terminal Symbols
+
+ 문장에서 사용되는 최소 단위의 문법 요소
+
+ Regular Expression으로 표현한다
+ (위에서 Token은 regual language라고 했는데 RL는 RE로 표현 할수있으므로 의미적으로 통한다)
+
+* Regular Language
+
+ RG,RE,finite state machine으로 정의 가능
+
+ RG에서 집중해서 봐야할것은 정의한 구조이다
+ 예제를 통해 RG가 정의한 구조를 적용해 보아라 (terminal Nonterminal or non terminal 구조이다)
+
+ **a ㅌ Terminal** 인 a를 Regular Expression으로 표현 할 수 있다
+
+
+ Finite automata
+ RE으로 이루어진 token을 판별할수있게 해주는 model
+ lexer가 token 구분할때 이 model을 사용해서 token을 구분 할 수 있다.
+
+
+ token구분 하기 위해 마지막에는 반드시 token에 포함되지 않는 symbol 읽어야한다
+
+ 마지막에 읽은건 pushback 처리를 해준다
+
+* lexer 구현
+
+ token을 한번에 구분하지 않고 keyword,id,type등의 sub finite automata를 구성해서 통합하는 방식으로 구현 한다
+
+ 이때 마지막 글자는 push back과정을 하고 Start state로 돌아간다
+
+ push back은 마지막 요소를 읽었으면 읽지 않은 상태로 만들고 start로 돌아오는 역할을 한다
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_posts/2022-04-20-Syntax1.md b/_posts/2022-04-20-Syntax1.md
new file mode 100644
index 000000000000..fe22cb324b13
--- /dev/null
+++ b/_posts/2022-04-20-Syntax1.md
@@ -0,0 +1,92 @@
+---
+layout: single
+title: "Syntax part 1"
+categories: [Syntax,Classifications of Languages,Compiler]
+tag : [syntax part 1,compiler,grammar,Grammar,Derivation,BNF,Type of Grammar]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작하며
+
+Syntax에 관한 내용을 배울 것 입니다. 1과 2편을 나누었습니다.
+
+
+
+
+Syntax1 내용정리 pdf
+
+
+
+
+### 내용 요약 및 정리 및 마무리
+
+
+* Grammar는 {V_n,V_t,P,S} 총 4가지 요소로 이루어져 있다.
+
+* grammar와 language 사이의 관계
+
+rule과 derivation rule의 차이를 Derivation을 통해 알수있었다
+
+직접 유도를 한 것을 바탕으로 간접유도를 통해 특정 Grammar가 생성 할수 있는 요소인지를 판단 할 수 있다
+
+leftmost는 왼쪽 부터 terminal을 확정 짓는 것이고 rightmost는 오른쪽 부터 terminal요소를 확정 짓는 것이라고 생각한다
+
+Grammar Type에 따라 생성되는 Language가 다르다
+
+동치는 생성결과가 같은것을 의미한다
+
+예)
+G1 = ({S}, {a}, P, S), where P: S -> a | aS
+G2 = ({A}, {a}, P, A), where P: A -> a | aA
+
+G1 <=> G2 서로 동치 관계 이다.
+
+-> 모호한 표현식 공부 할 때 쓰일 예정
+
+
+* Write a grammar for each of the following languages. For Q5 ,use V_t = {(,)}
+
+ 1. L1 = {a^n | n ≥ 0}
+
+ a^0,a^1...
+
+ 2. L2 = {a^nb^n | n ≥ 0}
+
+ a^2,a^4b^3...
+
+ 3. L3 = {ωω^R | ω ∈ V_T * }, where V_T = {a,b}.
+
+ R은 reverse를 의미한다
+ abba baab
+
+ 4. L4 = {ω | ω = ω^R , ω ∈ V_T * }, where V_T = {a,b}.
+
+ pailndrom 예시
+
+ 5. L5= {ω|ω:balanced parentheses}, where V_T = {(, )}.
+
+ (),(()),()()(())......
+
+
+
+simple matching lanuguage a^nb^n 은 CFL type2
+
+double matching language a^n b^n c^n은 CSL type1
+
+mirror image language L3같은 예제 CFL type2
+
+palindrome language L4같은 예제 CFL type2
+
+parenthesis language L5같은 예제 CFL type2
+
+
+
+
+
+
diff --git a/_posts/2022-04-20-Syntax2.md b/_posts/2022-04-20-Syntax2.md
new file mode 100644
index 000000000000..f1919bc2ef7c
--- /dev/null
+++ b/_posts/2022-04-20-Syntax2.md
@@ -0,0 +1,88 @@
+---
+layout: single
+title: "Syntax part 2"
+categories: [Syntax,Parse Tree,Compiler]
+tag : [syntax part 2,compiler,EBNF,BNF of Clite,EBNF of Clite,Ambituity,parse tree,associativity and precedence]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+### 시작하며
+
+Syntax part 2를 이어가 보도록 하겠습니다.
+
+
+parse tree에 대한 개념을 배울수있고 결합성과 우선순위, 모호한 표현 처리 방법에 대해 학습 할수있습니다.
+
+그리고 Clite 문법에 관한 EBNF, BNF 표현식을 공부 할 수 있습니다.
+
+
+
+
+Syntax2 내용정리 pdf
+
+
+
+
+
+### 과제 내용에 대한 본인의 답안
+
+
+사실 내가 작성한 보고서 내용과 비슷하긴 하지만 엄밀히 말하면 pdf안에 ebnf of clite 또는 bnf of clite의 내용이 정답에 가깝다 그걸 참고 하세요
+
+
+### 내용 요약 및 정리 및 마무리
+
+* parse tree개념을 알 수 있었습니다.
+
+ parse tree에서 우선순위 관계 start symbol,nonterminal symbol,terminal symbol과 대응
+ 되는 node를 알 수 있었습니다.
+
+ 아래쪽에 있을수록 우선순위가 높다
+
+* 결합성과 우선순위에 관해 알 수 있었습니다.
+
+ +,-,%,*는 좌결합 **은 우결합 관계
+
+* 계산 식을 bnf든 ebnf로 나타낸때 고찰
+
+ 우선 순위에 따라 top down으로 표현하는 것 같습니다.
+ +/-에관한 Expr을 표현하고 */%를 표현할수있는 Term을 표현하고
+ **을 표현할수있는 Factor 표현하고
+ 마지막으로 숫자를 표현 할수있는 primary순으로 표현식을 이어가는 것 같습니다.
+
+ **Expr은 Term을 포함하고 있고 Term은 Factor를 포함하고 있고 Factor는 primary를 포함하고 있습니다.**
+
+
+* 모호한 표현 조건
+
+ 문장 A가 두개의 다른 parse tree를 가질때
+ <=> 두개의 다른 leftmost derivations를 가질때
+ <=> 두개의 다른 rightmost derivations를 가질때
+
+ **leftmost derivations와 rightmost derivations를 같이 쓰면 안된다**
+
+
+* 모호성 해결 방법
+
+ 1. 문법을 처음 부터 모호성이 없도록 설계
+
+ 문법이 길고 복잡해진다
+
+ 2. Grammar이외의 추가 규칙 사용
+
+
+* EBNF
+
+ {} iteration
+ () choice
+ [] option
+
+
+
+
+
diff --git a/_posts/2022-04-26-Operating_system_intro.md b/_posts/2022-04-26-Operating_system_intro.md
new file mode 100644
index 000000000000..091b0e326448
--- /dev/null
+++ b/_posts/2022-04-26-Operating_system_intro.md
@@ -0,0 +1,30 @@
+---
+layout: single
+title: "Operating system 학부 과정 정리 "
+categories: [Operating System,OS,introduction]
+tag : [Operating System,OS]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작하며
+
+학부 과정에서 배우는 operating system 공부한 자료 정리하려고 합니다
+
+제가 개인적으로 공부한 자료에 추가적인 필기와 추가적인 설명이 각 챕터마다 더해 질 것 입니다.
+
+제가 필기한 것을 원하지 않을 경우 아래의 pdf를 확인하시면 될것 같습니다.(단, 이후에 나오는 자료와 차이가 있을 수 있습니다.)
+
+
+중간고사이전내용OSpdf
+
+
+
+compile_programming과 마찬가지로 진행 될 것 같습니다. 참고하시면 될 것 같아요
+
+마지막으로 추가 사항이나 요구사항이 있다면 댓글로 남겨 주세요
+
+감사합니다.!
\ No newline at end of file
diff --git a/_posts/2022-04-26-process_syncri.md b/_posts/2022-04-26-process_syncri.md
new file mode 100644
index 000000000000..1abb7c30dd39
--- /dev/null
+++ b/_posts/2022-04-26-process_syncri.md
@@ -0,0 +1,276 @@
+---
+layout: single
+title: "Process thread Synchronize"
+categories: [Operating System,OS,process,synchronize,Mointor,semaphore,mutex,critical section,lock]
+tag : [Operating System,OS,process,synchronize,Mutex,Critical Section,Critical Section Problem,Semaphore,monitor,lock]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작하며
+
+이번 포스팅에서는 semaphore,mutex,monitor에 대한 개념을 조금 더 추가 해서 정리 하겠습니다
+
+
+아래 pdf 링크에서 정리 했던 내용을 확인 할수있습니다.
+
+process_thread_syn_pdf
+
+
+
+---------
+
+
+
+
+
+## critical section problem
+
+
+
+한 프로세스 내에서 타 프로세스들과 공유하는 영역에 접근하는 코드상의 영역이다.
+
+**다수의 프로세스들끼리 데이터가 공유되는 경우 프로세스들 간 critical section의 이용순서는 동기화가 되어야한다 동기화를 어떻게 할것인가에 대한 문제 이다**
+
+
+
+![ㅁㄴㅇㄹ없는 그림](C:\github_blog\meang123.github.io\images\2022-04-26-process_syncri\ㅁㄴㅇㄹ없는 그림.png)
+
+
+
+
+
+
+
+이를 해결하기 위한 기본 뼈대는 위의 그림과 같다 critical section들어가기 전에 즉 entry section에서 대기하는 영역 필요하고 critical section 이용 후에는 exit section에서 critical section 사용을 완료 했다고 알리는 영역이 필요하다
+
+
+
+critical section problem이 해결 되기 위해서는 3가지가 충족 되어야 한다
+
+
+
+1. **mutex Exculsion**
+
+ - 하나의 프로세스가 임계구역 사용중이라면 다른 프로세스들은 임계구역 접근할수없다 즉 동시에 접근할수없다는 이야기이다
+
+ - 이 특성은 write only 파일 같은 경우 필요한 특성이다.
+
+ - 하지만 Read only 처럼 수정이 불가능 하다면 상호 배타성 특성이 없어도 무방하다
+
+
+
+2. **progress**
+
+ - 임계구역에서 진행하는 프로세스가 없다면 대기중인 프로세스가 임계구역을 사용해야함을 의미한다 즉 진행성이라고 보면 된다
+
+
+
+3. **Bounded wating**
+
+ - 모든 프로세스들은 임계구역에 한정된 시간 내에 진입 해야한다 즉 하나의 프로세스가 무한한 시간동안 임걔구역을 사용할수없다
+ - 기근 현상을 방지 하기 위함이다
+
+
+
+
+
+이 문제를 해결 하기 위해
+
+HW solution -> mutex
+
+SW solution -> semaphore
+
+
+
+
+
+----------------
+
+
+
+## Mutex (HW solution)
+
+
+
+가상의 잠금 장치인 lock을 이용해서 임계구역 동기화하는 방식이다.
+
+lock은 sharable resource이다.
+
+
+
+lock을 획득하는 함수는 atomic operation이다
+
+
+
+atomic operation
+
+* 실행중에 간섭받거나 중단되지 않는다
+* 같은 메모리 영역에 대해 동시에 실행되지 않는다
+* context switching 일어나지 않음이 보장 된다
+
+
+
+
+
+![화면 캡처 2022-07-19 162618](C:\github_blog\meang123.github.io\images\2022-04-26-process_syncri\화면 캡처 2022-07-19 162618.png)
+
+
+
+> lock이 없어야 while문에서 빠져 나오고 cs 영역으로 들어갈수있다
+>
+> cs영역 사용 이후 lock을 해제 해준다
+>
+> 위의 구조는 mutex exculsion 만족하지만 bounded waiting은 만족하지 못한다
+
+
+
+**pros**
+
+멀티 코어 환경이고 cs이용 시간이 평균적으로 적다면 오히려 lock획득 위해 계속 while문 돌게 하는게 전체적인 overhead줄이는 방법일수있다
+
+
+
+**cons**
+
+* busy waiting : lock 얻기 위해 기다리는 프로세스/스레드들은 cs 진입위해 대기중인 상태임에도 계속 실행 상태인 현상
+
+ 즉 대기하는데 실제로는 while문 때문에 cpu 사용하고 있다 -> cpu 사이클 낭비
+
+* 우선순위 역전 현상 발생할수도 있다. 실제로 우선순위가 높은 프로세스가 lock을 취할수없어서 대기 해야하는 상황
+
+
+
+
+
+--------------------------------
+
+
+
+## Semaphore (SW solution)
+
+
+
+하나이상의 프로세스 / 스레드가 critical section에 접근 가능하도록 하는 것이다.
+
+뮤텍스에는 임계영역에 접근 가능한 쓰레드 개수를 조절하는 기능이 없다. 그러나 세마포어는 가지고 있다.
+
+
+
+* binary semaphore
+* counting semaphore
+
+
+
+wait,signal로 조작 된다 wait 하거나 signal중에는 semaphore 변수를 변경하는 과정이기 때문에 독립적으로 발생해야한다
+
+
+
+**busy waitng**을 해결하기 위해 아래와 같이 작동 시킨다 -> block 시켜서 block list로 넣는것으로 해결
+
+
+
+
+
+![제목 dfdfd그림](C:\github_blog\meang123.github.io\images\2022-04-26-process_syncri\제목 dfdfd그림.png)
+
+
+
+
+
+counting semaphore에서 세마포어 값 S는 공유되는 자원들의 개수(협동 프로세스/스레드 간 접근 하도록 허용된)로 초기화 된다
+
+
+
+예를 들어 최초에 프로세스 1, 프로세스 2, 프로세스 3이 협동 관계에 있고 공유되는 메모리 영역에 총 10개의 변수가 있다 가정하면 초기 계수 세마포어는 10의 값을 가진다
+
+
+
+그러나 세마포어는 deadlock, starving의 문제가 남아있다. 또한 wait, signal의 순서가 변경 되거나 하면 오류가 발생하는 구조이다
+
+
+
+----------
+
+
+
+## Monitor
+
+
+
+lock에 wating queue 뿐 아니라 conditional variable에도 wating queue가 있는 모델이다
+
+즉 각 conditional variable마다 하나의 대기 큐를 가지고 있는것이다.
+
+
+
+* 한번에 하나의 스레드만 실행돼어야 할때
+* 여러 스레드와 협업이 필요할때
+
+
+
+wait 상태 들어가기 전에 lock을 release하고 들어간다
+
+
+
+**condition variable**
+
+조건을 기다리는 스레드들이 대기하는 공간인 waiting queue를 가집니다. condition variable은 세 가지 동작이 있는데 아래와 같습니다.
+
+
+
+**- wait()** : 한 스레드가 condition variable에 데고 이 동작을 수행하면, 자기 자신을 이 condition variable의 waiting queue에 넣고 대기 상태로 전환하게 됩니다.
+
+
+
+**- signal()** : 한 스레드가 condition variable에 데고 이 동작을 수행하면, condition variable의 waiting queue에서 대기 중인 스레드 중 하나를 깨우게 됩니다.
+
+
+
+**- broadcast()** : 한 스레드가 condition variable에 데고 이 동작을 수행하면, condition variable의 waiting queue에서 대기 중인 스레드 전부를 깨우게 됩니다.
+
+**[출처]** [동기화에서 모니터는 이렇게 사용됩니다](https://blog.naver.com/myca11/222650655740)|**작성자**
+
+
+
+
+
+### product/consumer problem with monitor
+
+
+
+![화면 캡처 2022-07-21 155003](C:\github_blog\meang123.github.io\images\2022-04-26-process_syncri\화면 캡처 2022-07-21 155003.png)
+
+ **[출처]** [쉬운코드 유튜브 모니터 영상](https://www.youtube.com/watch?v=Dms1oBmRAlo)|**작성자**
+
+
+
+
+
+
+
+product /consumer 문제에서 공유되는 자원은 buffer q이다. fullCV,emptyCV는 conditional variable이다. 각 wating queue를 가지고 있다.
+
+producer는 buffer q가 가득 찼을때 fullCV wating queue에 삽입 한다 consumer는 buffer q가 비어 있으면 emptyCV wating queue에 삽입 하는 구조이다.
+
+
+
+멀티 스레드 환경이므로 여러가지 상황이 발생할수있다. 그리고 wating queue에서 스케쥴링 방식은 구현에 따라 다를수있다.
+
+또한 운영체계 시스템 설계가 또 다를수 있기 때문에 wait는 반드시 while문 안에서 작동해야한다
+
+
+
+signal은 하나만 깨우는것이고 broadcast는 모두를 깨우는 작업이다. signal에서는 대기 큐에 있는 task를 ready Queue로 보내서 실행 시킬수있게 한다.
+
+
+
+
+
+
+
diff --git a/_posts/2022-06-04-TypeChecker.md b/_posts/2022-06-04-TypeChecker.md
new file mode 100644
index 000000000000..077a21b0bced
--- /dev/null
+++ b/_posts/2022-06-04-TypeChecker.md
@@ -0,0 +1,56 @@
+---
+layout: single
+title: "Static Type checker "
+categories: [CliteP,JAVA,TypeChecker,Compiler]
+tag : [clite,cliteP,TypeChecker,Static type checker,JAVA,java,Function,Call Statement, Call Expression]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작 하며
+
+AST에서 나온 결과로 type checking을 하게 됩니다.
+
+<변수,타입>의 typeMap 자료구조를 만들어서 타입을 확인합니다.
+
+clite에서 type check를 어떻게 진행하는지는 정리한 pdf에서 알 수 있습니다.
+
+
+원노트에서 정리한 기반의 내용의 pdf는 아래 링크에서 확인 할 수 있습니다.
+
+
+Static Type Checker one note pdf
+
+
+
+
+
+### 내용 요약 및 정리 및 마무리
+
+함수의 내용도 타입 체크 어떻게 하는지 포함하겠다
+
+Type checker는 변수와 타입을 typeMap 자료구조에 삽입한다.
+
+V()함수로 타입 체크를 하는데 인자에 무엇이 오는가에 따라 역할이 다르다
+
+1. Declarations 같은 경우는 중복 선언이 되었는지 확인
+
+2. Declarations, Functions를 인자로 받는 경우 선언부의 이름과 함수의 이름이 같지 않는지 확인을 한다.
+
+3. Functions을 인자로 받는 경우 Declarations와 마찬가지로 함수끼리 이름이 중복되지 않는지 확인을 한다.
+
+4. Functions, TypeMap이 인자로 온 경우 함수의 parameter, locals의 내용을 선언부 배열에 넣어서 V(Declarations)를 통해 유효한 parameter, locals인지 확인을 한다.
+
+함수가 main이 아니라면 void형이 아닌데 return이 없는 경우에 대한 유효 체크를 한다. 또 Void형인데 return 형이 있는 경우에 대한 처리도 하고 main 함수에 return이 있는지에 대한 유효 확인도 한다.
+
+5. Statement, Typemap을 인자로 받은 경우 Assignment의 경우는 Variable은 typeMap에 정의 되어있는지 확인하고 Expression은 유효한지 확인을 한다. 또 변수와 할당하는 값의 타입이 같은지 확인을 해야한다. 만약 같지 않다면 float일때는 int형 , int 형일때는 char형까지만 지원하고 나머지는 지원하지 않느다.
+Loop, condional의 경우 조건식이 bool 타입인지 확인을 해야한다. 그리고 conditional은 than statement, else statement가 유효한지 판단하기 위해 V()를 재 호출한다. LOOP의 경우도 body가 유효한지 확인을 하기 위해 재 호출을 한다.
+
+callStatement는 함수에 대한 타입 유효 검사를 진행하는데 전달하는 인자와 parameter개수가 같은지 부터 힘수에 대한 유효 검사를 진행한다. 또 함수의 이름을 선언 하지 않는경우데 대한 에러도 같이 확인한다
+
+6. Expression, typemap이 인자로 오는 경우 변수가 선언이 되었는지 아닌지 유효검사를 하고 Binary같은 경우에는 계산하는 변수끼리 타입이 같은 지 확인을 한다. Unaray에서는 !가 오면 bool type으로 유효 검사를 하여야하고 NegateOp가 오면 int형으로 처리를 해야한다. unary에서는 타입 변환도 같이 처리를 한다. Callexpression의 경우는 함수이름이 없는 경우, 함수가 void인데 1+f(1)하면 안되는 경우, 전달하는 인자 개수와 받는 parameter 개수가 일치하는지에 대한 유효검사를 진행한다. callsatement에서 처리하는 유효검사와 비슷하다.
+
+
diff --git a/_posts/2022-06-05-Deadlock.md b/_posts/2022-06-05-Deadlock.md
new file mode 100644
index 000000000000..bbe462024f16
--- /dev/null
+++ b/_posts/2022-06-05-Deadlock.md
@@ -0,0 +1,11 @@
+---
+layout: single
+title: "Deadlock "
+categories: [Operating System,OS,Deadlock,]
+tag : [Operating System,OS,Deadlock]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
\ No newline at end of file
diff --git a/_posts/2022-06-05-Functions.md b/_posts/2022-06-05-Functions.md
new file mode 100644
index 000000000000..1c3ba010ba66
--- /dev/null
+++ b/_posts/2022-06-05-Functions.md
@@ -0,0 +1,68 @@
+---
+layout: single
+title: "Functions Semantics "
+categories: [CliteP,JAVA,Functions,Function,Activation Record,Compiler]
+tag : [CliteP,JAVA,Functions,Function,Activation Record,static link, dynamic link,NonLocal,chain offset, local offset,Runtime stack, heap]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+### 시작하며
+
+메모리 구조와 함수의 구조를 알수 있습니다.
+
+중첩 함수가 지원 되는 pascal에서 함수는 어떻게 call이 되는지 전반적인 느낌을 알수있습니다.
+Activation Record의 개념과 static link, dynamic link의 구조에 대해서 알수있습니다.
+
+
+Function_Semantic one note pdf
+
+
+
+### 내용 정리 및 마무리
+
+* pass by value,reference,value result
+
+* Argument와 Parameter 차이
+
+* stack(static,runtime) <-> Heap의 메모리 구조
+
+* Runtime memory organization
+
+* Activation Record
+ - local
+ - parameter
+ - return address
+ - result
+ - static link , dynamic link
+
+* chain offset, local offset
+
+* Example 문제 분석
+
+**static link, dynamic link 개념 안다는 가정**
+
+컴파일 시간에 (chain offset, local offset) binding 하면
+런 타임 시간에 binding한 정보 가지고 변수를 찾는다
+
+
+마지막 그림에서 봐야할 것은 sub 1의 static link가 어디로 연결 되어있는지(BigSUB)
+
+sub2의 static link는 어디로 연결 되어있는지 (BIGsub)
+
+그러면 sub1에서 B는 어디서 찾고 있나 BIGSub에서 찾고 있다
+sub3의 A는 어디서 찾고 있나? statick link 2번 타고 들어가서 BIGSUB에서 찾고 있다
+
+
+실제 프로그램 구현 할때는 변수가 해당 stackFrame에 없으면 연결된 static link를 타고 찾을수있도록 구현 했다
+
+그리고 실제 구현한 프로그램에서는 중첩 함수 지원 하지 않는다
+
+global stackFrame 안에 main 등 여러 함수가 들어가는 방식
+이렇게 되면 global stackFrame안에 있는 함수들의 static link는 모두 global stackFrame을 가리키게 되고 dynamic link 구조만 다르게 진행 될 것이다.
+
+
diff --git a/_posts/2022-06-05-Semaintics.md b/_posts/2022-06-05-Semaintics.md
new file mode 100644
index 000000000000..f4bb6af08a70
--- /dev/null
+++ b/_posts/2022-06-05-Semaintics.md
@@ -0,0 +1,67 @@
+---
+layout: single
+title: "Semantics "
+categories: [CliteP,JAVA,Functions,Function,Semantics,Compiler,Meaning Function]
+tag : [CliteP,JAVA,Functions,Function,Semantics,Compiler,Meaning Function,State,Stack,Stack Frame,Frame Stack]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작 하며
+
+간단한 내용 정리와 구현 한 프로그램에서 semantics를 어떻게 구현 하였는지 배운점을 기록 하겠습니다.
+
+아래에 원노트로 정리한 파일이 있습니다.
+
+
+Semantic one note pdf
+
+
+
+### 내용 정리 및 마무리
+
+* short circuit으로 프로그램을 더 간결하게 만들 수 있다
+
+* 수학과 컴퓨터 계산은 같지 않음 예) overflow
+
+* 선언만 되어있으면 undef로 되어있고 할당되거나 값이 바뀌면 다시 설정 된다
+
+* copy, reference 차이
+ * copy한 값은 서로 영향을 주지 않음 -- have the same value
+ * reference는 서로 영향을 받는다 -- point the same object
+
+
+* Environment , State
+
+ - Environment
+ * name-> memory location 대응 시킴 ""
+
+ - State
+ * memory location -> value 대응 시킴 "<154,5>"
+ * identifier, value 집합으로 정의
+
+
+* **실제 프로그램 구현 내용**
+
+Semantic를 구현하기 위해 3가지 class를 추가로 구현했다. FramState, StackFrame, State이다.
+
+FrameState는 interpreter 실행중에 발생하는 변수와 대응하는 값에 집합이다. HashMap 자료구조를 통해 key에 변수, value에 변수값을 넣는다. onion 함수는 변수와 값을 주면 변수의 값을 파라메터로 넘긴 값으로 바꿔주는 함수이다.
+
+StateFrame은 Activation Record에 해당하는 클라스이다. StateFrame은 함수이름, static link, dynamic link, FrameState로 구성되어있다. 마지막으로 State에서는 만든 stackFrame을 stack에 push, pop 하는 역할을 하고 stack에 있는 stackFrame을 처리하는 클라스이다. static link , dynamic link 설정이 이루어지고 variable, value를 재설정 하는 역할도 이 클래스가 한다.
+Semantics 클래스를 보면서 각 클래스에 세부적인 내용을 살펴보겠다.
+
+**1 semantics**
+**1.1 M(program p )정의**
+**1.2 initialState(program p) 정의**
+
+meaning Function에 program이 인자로 들어가면 initial()함수가 실행이 되는데 전역변수에 대한 stackFrame을 만든다. 그리고 전역변수 globals에 대한 stackFrame과 program안에 정의된 함수들을 state 생성자에서 초기화 한다. 이때 stack이 생성이 되고 현재 함수를 나타내는 current_func이 초기화 된다.
+다시 M(Program p)로 돌아오면 main함수에 대한 StackFrame을 생성한다. 이때 static link, dynamic link와 새로운 FrameState가 생성이 되고 state stack에 push된다. M(program p)은 현재 함수의 M(current_func.body,stat)를 반환하면서 계속 실행이 이어진다.
+
+**1.3 M(Statement)**
+Statement의 종류에 따라 meaning function을 처리하였다. Assignment는 <변수, 변수 값>을 state stack top의 StackFrame에 값을 대응시킨다. 만약에 assignment의 <변수, 변수 값>이 Stack top StatckFrame에 없다면 static link를 타고 들어가서 값을 찾아서 대응시킨다. Block의 경우는 모든 statement에 대해 meaning function을 호출한다. Block에서 return이 있다면 즉시 반환을 한다. Loop의 경우도 조건식을 확인해주고 Loop안에 return 문 있는 경우 바로 반환을 해주어야 하기 때문에 확인하는 작업을 해준다. CallStatement의 경우는 함수가 넘겨주는 인자를 배열에 저장을 하고 state stack에 push를 해주면서 current_func을 push하는 StackFrame으로 바꿔준다. 그리고 byValue() 함수를 통해 저장한 argument를 함수의 parameter에 넘기는 작업을 한다. Parameter로 argument를 넘기면 그때 정의한 함수의 실행부가 실행이 된다. 실행이 완료되면 stack에서 pop을 한다. 이때 dynamic link가 가리키는 StackFrame이 current_func이 되고 pop을 한다. Return meaning function을 보면 <$ret, 반환 값>을 Stack에 top에 있는 StackFrame에서 찾아서 업데이트 한다. 만약 없다면 static link를 타고 들어가서 대응하는 변수 찾아서 수정한다. M(Statement)의 반환 타입은 State이기 때문에 state stack에 저장 되어있는 StatackFrame의 내용이 수정이 되거나 Stack이 조정이 되거나 등의 작업을 한다.
+
+**1.4 M(Expression)**
+Expression도 종류에 따라 meaning function을 처리한다. M(Expression)은 Value를 반환 타입으로 가지기 때문에 Value를 반환한다. 일반 변수 값 Value라면 Value를 그대로 반환한다. VariableRef라면 변수에 대응하는 값을 stack에 top에서 value를 찾는다. 만약 없다면 static link를 타고 찾아서 반환한다. Binary인 경우 meaning function을 통해 expression term1, term2를 value로 바꿔주고 operation 정보와 함께 applyBinary 함수를 실행한다. 이 함수는 Binary에서 실행하는 연산 결과에 대한 Value를 반환해주는 함수이다. Unary인 경우도 Binary와 마찬가지로 meaning function을 통해 expression term1을 value로 전환하고 applyUnary 함수를 적용해서 Unary대한 결과를 Value로 반환한다. 마지막으로 CallExpression을 살펴보면 callstatement와 비슷한 구조로 진행이 된다. parameter로 넘기는 인자를 args 배열에 저장을 하고 state stack에 새로운 함수에 대한 StackFrame을 push한다. current_funct을 현재 statckFrame으로 바꿔준다. 함수의 실행부를 실행하고 stack에서 pop하는 구조까지 비슷하게 흘러가지만 다른 점은 return에 대한 처리이다. Return meaning function은 state에 variable과 expression처리한 value를 새로 업데이트 해주고 saw_ret 불리언 변수를 true로 바꿔준다. CallExpression에서는 return 문에 함수가 올 수도 있기 때문에 이에 대한 처리가 추가적으로 이루어진다. block안에서 return f()함수가 있었다고 하면 return이 있기 때문에 saw_ret = true가 된다. 그리고 f()에 대한 처리가 callExpression에서 이루어질 때 temp_saw_ret = saw_ret로 상태 값을 임시 저장한다. 이렇게 하는 이유는 f()함수의 실행부가 처리될때 saw_ret가 true로 되어있으면 제대로 작동을 하지 않기 때문에 일단 saw_ret = false로 처리하고 body를 정상적으로 처리하기 위함이다. F()의 처리가 끝나면 그때 temp_saw_ret에 저장 되어있던 상태 값을 saw_ret에 저장시키고 return처리를 한다.
diff --git a/_posts/2022-06-07-Bottom_up_parser.md b/_posts/2022-06-07-Bottom_up_parser.md
new file mode 100644
index 000000000000..18878c422103
--- /dev/null
+++ b/_posts/2022-06-07-Bottom_up_parser.md
@@ -0,0 +1,66 @@
+---
+layout: single
+title: "Bottom up Parser "
+categories: [CliteP,JAVA,Bottom up Parser, LR parser,Compiler]
+tag : [CliteP,JAVA,Top down parser, LR parser,Conflict,Parsing Table, rightmost derivation]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작하며
+
+Bottom up parser에 대한 내용과 LR Parser에 대한 내용 및 parser table 적용하는 내용은 아래 PDF 링크에 내용이 있습니다.
+
+
+Bottom up Parser One Note PDF
+
+
+
+### 내용 정리 및 마무리
+
+
+* **LR parser**
+
+ - bottom up parser
+ - rightmost derivation in reverse
+ - LL parser보다 poweful -> 대부분의 programming language에서 구문 분석 가능하다
+
+
+* **용어 정리**
+
+ - **reduce**
+
+ - A-> B인 경우 B => A로 역변환하는것을 의미한다
+ - pdf 예를 들어보면 A->b 의 production이 있을때 abbcde에서 aAbcde로 바뀐것을 예로 들 수 있다. [b가 A로 reduce 되었다]
+
+ - **handle**
+
+ - abbcde => aAbcde 역변환 할때 handle b를 non terminal A로 치환함
+
+ - **handle pruning**
+ - handle b를 A로 reduce하는 것을 handle prunning이라고 한다
+
+
+
+* LR parsing은 handle pruning을 반복하여 start symbol로 reduce한다
+
+* pdf에 parser example있는데 step을 따라가면서 직접 해보기를 바란다
+
+* LALR은 모호한 문법 파싱 못한다
+
+ - conflict 발생하기 때문이다
+
+* conflict 발생해도 precdence와 associativity를 이용해서 해결 가능
+
+* Conflict 종류
+
+ - **Shift reduce conflict**
+
+ ○ Shift와 reduce 모두 가능한 상황
+
+ - **Reduce- reduce conflict**
+ ○ 두가지 이상의 rule로 reduce 가능
+
diff --git a/_posts/2022-06-07-Top_Down_parsing.md b/_posts/2022-06-07-Top_Down_parsing.md
new file mode 100644
index 000000000000..343ae84ea7ad
--- /dev/null
+++ b/_posts/2022-06-07-Top_Down_parsing.md
@@ -0,0 +1,90 @@
+---
+layout: single
+title: "Top Down Parser "
+categories: [CliteP,JAVA,Top down parser, LL parser,Predictive parser,Compiler]
+tag : [CliteP,JAVA,Top down parser, LL parser,First,Follow,Parsing Table, leftmost derivation,Predictive parser]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작하며
+
+Top down parser중에 Backtraking이 없는 predictive parser에 대해서 정리한 pdf가 아래에 링크에 있습니다.
+
+Top Down Parser One Note PDF
+
+
+
+
+
+### 정리 및 마무리
+
+
+* **LL parsing** : 왼쪽에서 스캔해서 파싱하는 방식 , left most dervation
+
+* **Nondeterministic top down parsing** : 규칙 선택이 잘못 된 경우 backtracking 필요하다
+
+* **Deterministic top down parsing** -> predictive parser : Backtracking을 배제 한 것이다.
+
+ - lookahead 방식 : LL(1) -> one toekn lokkahead top down predictive parser
+
+ - lookahead는 frist , follow함수를 이용해서 구현한다. 이러한 정보 가지고 parsing table을 만든다
+
+ - parsing table에 action이 2개 이상이 오면 모호해진다 -> 충돌 발생
+
+
+* **left recursion은 infinite loop 발생한다**
+
+
+* parsing table이 주어졌을때 스택에 거꾸로 push한다는것만 인지하고 진행 하면 문법 G에서 해당 input string이 유효한지 아닌지 확인 할 수 있다.
+
+ - LL(1) parsing은 잘못 되면 backtracking 하는데 backtracking 하지 않으려면 LL condition을 만족해야한다 -> Frist, Follow 함수 알고리즘 필요
+
+ - 모든 문법이 LL parsing 할 수 없다
+
+
+* **First (X) 함수**
+
+ - X가 생성하는 스트링의 시작 위치에 올 수 있는 terminal의 집합 x=>* 입실론 이면 입실론도 포함이다.
+
+ - pdf에 나와 있는 예제로 설명을 보충하자면 E <- T <- F 관계가 되잖아 이런 이유는 Frist E에서 F 까지 non terminal로 계속 들어가서이다 F에서 결과물이 나오니까 관계 가지는 함수들도 같은 결과를 가지게 된다
+
+
+* **Follow (X) 함수**
+
+ - X라는 symbol뒤에 나올수 있는 symbol들을 포함한다
+
+ - 입실론은 없어야한다
+
+ - 즉 유도 과정에서 x뒤에 올수 있는 terminal의 집합이다
+
+ - x가 start symbol이면 $가 온다
+
+ - 보충 설명
+
+ - Follow(X) :
+
+ - a. Y -> αXβ => First (β) - ε
+ - b. Y -> αXβ && ε ㅌ First(β) [First β가 ε 생성한다면 ] => Follow(Y)이다
+ - Y-> αX => Follow(Y)
+
+
+ - pdf에 내용을 보충해보면 Follow E' = Follow E' U Follow E인데 Follow E'이 recursive이니까 결국에 Follow E와 동일한 결과를 얻게 된다
+
+
+* **LL condition**
+
+ - A-> a | b
+
+ 1. First (a) n First(b) = 공집합
+
+ 2. if a가 입실론을 생성한다면 Follow(A) n Follow(b) = 공집합
+
+
+ 2 가지 조건을 만족해야 ll codition 만족 하는 것이다.
+
+
+
diff --git a/_posts/2022-06-07-lex_yacc.md b/_posts/2022-06-07-lex_yacc.md
new file mode 100644
index 000000000000..ac3a3c5d318a
--- /dev/null
+++ b/_posts/2022-06-07-lex_yacc.md
@@ -0,0 +1,26 @@
+---
+layout: single
+title: "Lex and Yacc "
+categories: [Lex,Yacc, Compiler]
+tag : [lex,Yacc,compiler]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작 하며
+
+lex 와 yacc에 대해 간단하게만 언급 되어있습니다. 자세한건 온라인에서 메뉴얼을 찾아 봐야합니다.
+
+
+
+lex yacc One Note PDF
+
+
+
+
+### 정리 및 마무리
+
+
diff --git a/_posts/2022-07-09-Basic_of_OS.md b/_posts/2022-07-09-Basic_of_OS.md
new file mode 100644
index 000000000000..d49c4b5305b6
--- /dev/null
+++ b/_posts/2022-07-09-Basic_of_OS.md
@@ -0,0 +1,135 @@
+---
+layout: single
+title: "Basic of OS "
+categories: [Operating System,OS,Basic]
+tag : [Operating System,OS]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작하며
+
+os 내용 들어가기 전에 전체적인 그림을 보는 파트 입니다.
+전체적으로 컴퓨터 구조가 어떻게 이루어져 있는지 알 수 있습니다.
+
+Basic_of_OSpdf
+
+
+
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+
+### 내용 정리
+
+컴퓨터는 여러개의 cpu와 장치들로 이루어져 있다. 실행시키려면 메모리에 load되어있어야 한다
+
+
+
+![화면 캡처 2022-07-09 194116](C:\github_blog\meang123.github.io\images\2022-07-09-Basic_of_OS\화면 캡처 2022-07-09 194116.png)
+
+
+
+> **OS 정의와 관련 키워드**
+>* 하드웨어와 유저 사이의 interface이다
+>* Bootstrap program
+ - 컴퓨터가 시작할때 작동하는 프로그램
+ - ROM에 저장되어있다
+ - OS 를 load할 위치와 system을 실행할 방법을 알고 있다
+ - OS kernel에서 위치되어있고 load된다
+
+
+
+
+* **interrupt**
+ - event에 의해 발생한다
+
+
+* **system call**
+
+* OS는 각 device controller에 대해 device driver를 가지고 있다
+
+
+
+> **IO Operation**
+>
+> * **device controller**
+>
+> * Hardware program
+>
+> * 장치와 OS에서 명령을 수신하는데 사용할수있는 모든 종류의 소프트웨어간의 고속도로 역할을 한다
+>
+> * local buffer를 가지고 있다
+>
+> * 1. Input register, output register(Data register) - for data
+>
+> 2. Control register - CPU가 보낸 I/O 명령을 임시저장하는 역할
+>
+> 3. Status register - Data Register의 상태를 표시 받을 준비가 됐는지 안됐는지
+>
+>
+>
+> * **device driver**
+> * device와 OS 사이의 interface 역할을 한다
+> * 다른 종류의 OS의 상호작용을 위한 software program
+> *
+
+![blog_2](C:\github_blog\meang123.github.io\images\2022-07-09-Basic_of_OS\blog_2.png)
+
+
+
+
+
+> device driver는 device controller안에 레지스터에 적절한 레지스터 내용을 load한다 (예 키보드에서 친 글자에 대한 레지스터 내용 cpu는 받은 내용이 키보드에 어떤 글자인지 모르니까 키보드 device controller에게 관련 레지스터 내용을 넘긴다 )
+>
+> dvice controller안에 loca buffer가 가득 차면 device controller는 device driver에 interrupt 걸어서 알린다
+
+
+
+> 많은 디바이스가 있으면 interrupt 많이 걸리는 구조(per bit 마다 interrupt를 걸기 때문이다) 이기 때문에 DMA라는 구조를 사용해서 해결한다 원래는 cpu를 통해서만 메모리 접근이 가능한 구조인데 DMA controller도 메모리에 접근할수있게 함으로써 많은 IO deviec 처리 성능을 올린다
+>
+> local buffer 작업이 다 끝나면 메모리로 복사하는 작업을 해주고 interrupt를 발생시켜서 한번에 처리하는 방식이다
+>
+> -> per block 마다 interrupt한다
+
+
+
+----------------------
+
+
+
+## *프로세스 A가 디스크로부터 파일을 읽어오는 명령을 실행한다고 했을 때 내부적으로 일어나는 과정은 다음과 같다.*
+
+
+
+1. 프로세스 A가 시스템 콜을 요청하면서 CPU 내에 인터럽트 라인을 세팅한다.
+
+2. CPU는 실행 중이던 명령어를 마치고 인터럽트 라인을 통해 인터럽트가 걸렸음을 인지한다.
+
+3. mode bit를 0으로 바꾸고 OS에게 제어권을 넘긴다.
+
+4. 현재 실행 중이던 프로세서의 상태 및 정보를 PCB(process control block)에 저장한다. 그리고 PC(program counter)에는 다음에 실행할 명령어의 주소를 저장한다.
+
+5. 시스템 콜 루틴에 해당하는 곳으로 점프하고, 시스템 콜 테이블을 참조하여 파일 읽기에 해당하는 시스템 콜을 실행한다.
+
+6. 해당 루틴을 끝내면, mode bit를 1로 바꾸고 PCB에 저장했던 상태들과 PC를 복원시킨다.
+
+7. PC에 저장된 주소(=마지막으로 실행했던 명령어의 다음)로 점프하여 계속 실행한다.
+
+
+
+-----------------------
+
+
+
+> **mutiprograming and multitasking**
+>
+> 한 작업이 다른 일을 하고 있다면(IO작업) cpu의 사용률을 높이기 위해 다른 작업에 cpu를 사용할 수 있다
+>
+>
+>
+> time sharing system : cpu가 특정 시간에만 사용 할 수 있다. 많은 task들이 공유 할수 있는 구조 ==> multiprogramming과의 차이점이다
\ No newline at end of file
diff --git a/_posts/2022-07-10-Process.md b/_posts/2022-07-10-Process.md
new file mode 100644
index 000000000000..7de9096ee51e
--- /dev/null
+++ b/_posts/2022-07-10-Process.md
@@ -0,0 +1,343 @@
+---
+layout: single
+title: "Process"
+categories: [Operating System,OS,Process,Context switching,Process control block, PCB,Cooperated process,System call]
+tag : [Operating System,OS,Process,system call]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작하며
+
+프로세스 관련 내용 정리한 pdf는 아래 링크를 통해 확인 할 수 있습니다.
+
+Process_PDF
+
+
+
+-----------------------------------------------
+
+
+
+### 내용 정리
+
+
+
+> **process**
+>
+> 정의 : 실행중인 혹은 실행을 위해 주기억장치 상에 적재된 프로그램 메모리에 load된 순간부터 프로세스가 된다
+>
+> 프로세스는 하나의 프로그램을 여러번 돌리기 위해서 필요하다
+>
+>
+>
+> * data,bss,stack,heap,code 영역으로 나뉜다
+>
+> * IO 시간이 cpu 시간보다 느리기 때문에 scheduling이 필요하다
+>
+> * active는 passive가 있어야 돌아갈수있다 -> 프로세스가 아니라 프로그램이 돈다는 표현 하는 이유
+>
+> * 프로그램은 여러개의 프로세스로 이루어져 있다고 생각해도 큰 문제는 없다
+>
+> * 프로그램은 passive
+>
+> * 프로세스는 active이다
+>
+>
+>
+> * ![process_state](C:\github_blog\meang123.github.io\images\2022-07-10-Process\process_state.png)
+>
+> New,ready,running, wating,terminated 단계로 프로세스 상태를 나타낼수 있다
+>
+>
+>
+> * **New**
+>
+> * 프로세스가 처음 만들어질때의 상태
+> * 해당 프로세스의 PCB가 커널 내부에 생성
+> *
+>
+> * **ready**
+>
+> *
+>
+> * **running**
+>
+> * running -> waiting
+>
+> * I/O 때문이다
+> * User의 key 입력을 받아야하는 상황일때
+> * Output screen에 출력해야하는 경우
+> * OS는 ready상태와 waitting상태를 구분해야한다
+> * I/O 이외에도 Hardware Event , OS operation(우선순위문제등)에 의해 watting으로 가기도 한다
+>
+> - **Wait for user to type the next key (다음 키 칠때까지 기달)**
+> - **Wait for outptut to appear on the screen (display 시킬 때까지 기달)**
+> - **Program tried to read a file (OS가 어떤 블록을 읽고 실제로 메모리에서 요청된 정보를 읽을 때까지)**
+> - **Netscape tries to follw a link (URL) - 웹사이트에서 주는 정보를 다 받을 때까지**
+> -
+>
+> * running -> ready
+>
+> * process가 cpu 시간을 다 썼을 경우 -> time sharing system
+>
+> * priority scheduling 따라 interrupt에 의해 ready상태로 갈수도 있다 -> **context switching** 일어난거라고 생각해도 됨
+>
+>
+>
+> * **waiting(block)**
+>
+> * critical section을 기다릴때도 waiting 상태를 사용한다
+>
+> * **terminated**
+>
+> * 정상 종료,에러 났을때, 부적절한 명령어 실행 되었을때, 메모리 부족 할때, IO failuer일때 발생한다
+> * PCB도 제거 된다
+
+
+
+
+
+## **Process control block(PCB)**
+
+
+
+실행 프로세스 정보와 상태를 저장해 놓은 자료 구조
+
+bss 영역에 저장 된다
+
+
+
+>* **PID (process id number)**
+>
+>
+>
+>* **Userid of owner**
+>
+>* - 계정 정보 (자원 사용시간등을 관리)
+>
+>
+>
+>- **Memory space**
+>
+>- - 메모리 관리 정보(page table,segment table)
+>
+>
+>
+>- **Pc,sp, register** **정보들**
+>
+>- - CPU 레지스터에 있던 그 당시 상태 값
+>
+>
+>
+>- **Process State**
+>
+>- - new,ready,watting….
+>
+>
+>
+>- **CPU scheduling information**
+>
+>- - 우선순위등과 같은 스케줄링 관련 정보들 -> 우선순위 때문에 스케줄러가 관여한다
+>
+>
+>
+>- **I/O state**
+>
+>- - 입출력 상태 정보 (할당 받은 입출력 장치, 파일등에 대한 정보등 )
+>
+>
+>
+>- **context saving** **영역 저장**
+
+
+
+
+
+## **System call**
+
+
+
+> 응용 프로그램의 요청에 따라 커널에 접근하기 위한 interface이다
+>
+> 운영체제 서비스 접근하기 위한 수단이다. system call을 통해 커널 자원 사용 요청한다.
+>
+>
+>
+> user mode에서 운영체제 서비스인 메모리, 하드웨어 자원을 사용할때 OS 서비스를 사용해야한다
+>
+>
+>
+> * 종류
+>
+> * **Process control**
+>
+> * load,execute,wait for time, abort ....
+>
+>
+>
+> * **File manipulation**
+>
+> * create,delete,open,write,read,close등의 연산 할때
+>
+>
+>
+> * **Device manipulation**
+>
+> * request device, release device
+>
+> * logically atteach or detach device
+>
+>
+>
+> * **information mainternace**
+>
+> * 시간, 날짜 정보 유지 하는것도 system call이다
+>
+>
+>
+> * **Communications**
+>
+> * 프로세스간에 통신
+
+
+
+
+
+## **context switch**
+
+
+
+
+
+> - 현재 프로세스의 상태를 저장하고 다른 프로세스의 상태를 읽어 오는 과정이다
+> - switching동안에는 아무것도 못한다 --> pure overhead
+>
+> + contex는 현재 process의 PCB 내용이다
+>
+> - 커널에 의해 발생하기 때문에 overhead가 있다
+>
+> - interrupt가 걸리면 다른 프로세스 먼저 실행한다
+>
+> - system call과 context switching은 다른 개념이다
+
+
+
+**사용하는 이유**
+
+* overhead이지만 전체적으로 보면 이득이다
+
+* io시간 같이 오래 걸리는 작업을 기다리기보다 다른 process일을 하는게 전제척으로 보면 오히려 overhead가 작다
+
+
+
+**많이 자주 사용하지 않는 이유**
+
+- 순수한 overhead가 발생하기 때문이다
+- 자주 문맥 전환하면 오히려 실행 시간 보다 스위칭에 더 많은 시간을 쓰게 된다
+
+
+
+**프로세스간 context switching은 메모리가 다르기 때문에 메모리 관련 작업을 추가로 해야한다 ==> thread간 문맥전화이 더 가벼운 이유이다 tread간에는 메모리 관련 작업 하지 않는다 **
+
+
+
+
+
+--------
+
+
+
+### **Inter Process Communication (IPC)**
+
+
+
+프로세스 사이의 통신이다. messaging passing model과 shared memory model이 있다
+
+
+
+> 프로세스가 독립적이라면 서로 통신 할 수 없다. OS가 자신 이외에 할당된 메몰이 공간 영역에 접근하는것을 허용하지 않기 때문이다.
+>
+> 그러나 협력 프로세스는 다른 프로세스의 실행에 영향줄수있다. 하나의 일을 끝내기 위해 여러개의 프로세스가 협력한다
+>
+>
+>
+> **협력 프로세스 장점**
+>
+> * imformation sharing
+> * computation speed up
+> * modularity
+> * convenience
+
+
+
+
+
+## shared memory model
+
+
+
+- 데이터를 공유 하는 주기억 장치 상의 공유 영역을 만들어서 협력 프로세스들 간에 사용하도록 하는 모델
+
+- 처음 공유 메모리를 설정하는 시스템 호출을 제외하면 이후 공유 메모리 사용 접근에는 커널의 개입 없이 자유롭게 사용가능하다
+
+- 생산자-소비자 문제에 대한 해법의 일종이다
+ - 생산된 데이터만 보관하는 버퍼를 만들고 그 버퍼에 내용을 소비자가 사용하는 방식으로 해결 하는 방법이 있다
+ - 이때 버퍼 구현은 Bounded buffer, Unbounded buffer 방식이 있다 ---- 자세한 내용은 위의 pdf에서 확인
+
+
+
+
+
+shared memory model은 프로세스 안에 스레드가 사용한다. 같은 주소에서 공유 메모리 사용할때 우위가 있다
+
+
+
+----------------
+
+
+
+## message Passing model
+
+
+
+* 프로세스간 메시지의 형태로 데이터를 주고 받는 형태이다 -> 같은 주소 공유하지 않고 동기화하는 방법이다
+
+* distributed system (client-server model)에서 유용하다
+ * 통신하고자 하는 프로세스가 네트워크로 연결된 다른 컴퓨터에 있을때 유용한 방식이다
+* 직접/간접 통신 방법이 있다 - > pdf 참고
+* 두 프로세스 간에 통신을 하기 위해서는 반드시 두 프로세스 간에 공유되는 메일박스가 있어야한다
+ * mail box는 kernel안에 위치한 버퍼이다. 즉 커널을 통해 프로세스 통신을 하는 모델이다
+ * 각각의 mail box는 고유 식별자를 가진다
+
+
+
+![IPC@](C:\github_blog\meang123.github.io\images\2022-07-10-Process\IPC@.png)
+
+
+
+* send, recive operation이 있다
+
+* 동기화 , 비동기화 방식으로 send, receive operation 방법이 있다 --> PDF 내용 확인
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_posts/2022-07-13-Treads.md b/_posts/2022-07-13-Treads.md
new file mode 100644
index 000000000000..68b4efb3defd
--- /dev/null
+++ b/_posts/2022-07-13-Treads.md
@@ -0,0 +1,186 @@
+---
+layout: single
+title: "Threads"
+categories: [Operating System,OS,Thread,C++,multi threads, fork,exec,system call]
+tag : [Operating System,OS,Thread,multi thread,user level,kernel level]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작 하며
+
+스레드에 관한 내용을 포스팅 할 것 입니다. 밑에 pdf 링크에서 스레드에 관하여 정리한 내용을 확인 할 수 있습니다.
+
+
+
+Thread_PDF
+
+
+
+이번 포스팅에서는 pdf에 내용을 보충하여 정리 하겠습니다.
+
+
+
+-------------------
+
+
+
+### 내용 정리
+
+
+
+## **Thread**
+
+
+
+* 한 프로세스 내에서 실행 흐름의 단위 혹은 cpu가 처리할수있는 작업의 최소 단위
+
+* unit of scheduling
+
+
+
+> 등장 배경
+>
+> 프로세스 기반일때라는 가정을 하면 두가지 이상의 일을 처리하기 위해 context switching으로 처리하면 overhead가 상당히 크다
+>
+> 프로세스가 독립적으로 분리 되어있기 때문이다. 그래서 나온 개념이 thread이다. 모든것을 독립해서 처리 할 필요가 없다는 것이다.
+>
+> 스레드는 프로세스 안에서 공유 하는 상태 정보들(code, data, file..)이 있기 때문에 프로세스가 context switching하는것 보다 효율이 좋다 왜냐하면 **메모리 접근을 할 필요가 없기 때문이다**
+
+
+
+
+
+![제목 없는 그림](C:\github_blog\meang123.github.io\images\2022-07-13-Treads\제목 없는 그림.png)
+
+
+
+- Stack, TID, PC, Register set을 thread마다 할당한다.
+- 코드 영역, heap영역, data영역을 공유한다
+
+
+
+
+
+![다운로드](C:\github_blog\meang123.github.io\images\2022-07-13-Treads\다운로드.png)
+
+
+
+
+
+multi thread가 프로세스보다 가지는 장점도 있지만 -- pdf 참고
+
+하나의 스레드에 문제가 발생하면 프로그램 전체에 영향을 줄수있다는 단점도 있다. ------> 동기화 문제에 신경을 써야한다.
+
+
+
+> **프로세스와 스레드의 차이 **
+>
+> 지금까지 프로세스 상태 및 문맥 전환 내용은 스레드에 관한 내용이다.
+>
+> 같은 프로세스 안에 속해 있는 스레드 끼리 context switching 일어나면 메모리 접근이 없으니까 속도가 빠르다
+>
+> 하지만 다른 프로세스 안에 있는 스레드와 context switching 일어나면 기존의 프로세스끼리의 문맥 전환과 같다 즉 메모리 접근을 한다
+>
+> 즉 근본적인 차이점은 메모리를 공유하냐 안하냐의 차이라고 이해하면 될것 같다
+
+
+
+
+
+-----------------
+
+
+
+## **Multi Thread Model**
+
+
+
+- **Kernel level thread**
+
+ - > 커널이 스레드를 생성해주는 모델이다 -> system call을 통해 스레드 생성
+ >
+ > 즉 스케줄러와 스케줄링에 필요한 스레드 정보가 커널 영역에 존재하는 모델이다
+ >
+ >
+
+- **User level thread**
+
+ - > 커널에 의존적이지 않은 형태로 스레드 기능을 제공하는 라이브러리를 활용한 모델이다
+ >
+ > 유저 영역에서 실행 되기 때문에 커널은 스레드 존재를 확인하지 못한다
+
+
+
+user mode와 kernel mode는 서로 독립적인 영역이다. user mode에서 동작시 kernel mode 영역으로 접근할수 없다. kernel mode일때는 모든 영역 접근 허용된다.
+
+관련 내용은 3가지 모델과 함께 pdf에 더 자세하게 나와있다
+
+
+
+스레드는 메모리를 공유하기 때문에 동기화하는 작업이 중요하다
+
+
+
+-----------------
+
+
+
+## fork() exec() system call
+
+
+
+fork를 통해 부모와 똑같은 자식 프로세스 만든다 pid만 다르다 exec의 argument를 통해 완전히 다른 프로세스로 대체 된다
+
+자세한 내용은 프로세스 포스팅에 pdf 자료를 보면 될것 같다
+
+
+
+하나의 프로세스 대해서 fork할때는 자식 프로세스 만든다는 개념인데 만약에 2개의 프로세스가 존재 하는데 fork를 하면 2개에 대한 자식 프로세스가 만들어진다 즉 fork를 한번에 연속적으로 사용하면 개수가 늘어난다
+
+
+
+UNIX system에서는 fork의 종류를 두가지로 분류 할수있다
+
+
+
+* 모든 스레드에 대해서 fork
+* thread that invoked 에 대해서만 fork 즉 특정 프로세스에 대해서만 fork처리 한다는 의미 이다
+
+
+
+application에 따라 두가지 방법중에 언제 쓰는지 결정 할수있다
+
+
+
+**시나리오 1**
+
+> fork후 바로 exec하는 경우 2번째 방법으로 fork 하는 방식이다
+>
+> 왜냐하면 모든 스레드에 대해서 fork했다고 하고 여러개의 자식 프로세스 만들어도 exec하면 하나의 새로운 프로세스로 대체 되기 때문이다 즉 모든 스레드에 대해 자식 프로세스 만들 필요가 없는 상황인것이다
+
+
+
+**시나리오 2**
+
+>forking이후 exec()하지 않는 경우 첫번째 방법으로 fork하는 방식
+>
+>
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/_posts/2022-07-14-Scheduling.md b/_posts/2022-07-14-Scheduling.md
new file mode 100644
index 000000000000..578e0e3e6279
--- /dev/null
+++ b/_posts/2022-07-14-Scheduling.md
@@ -0,0 +1,110 @@
+---
+layout: single
+title: "Scheduling"
+categories: [Operating System,OS,Scheduling,priority inversion,priority scheduling,Round Robine scheduling]
+tag : [Operating System,OS,CPU scheduling]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작하며
+
+이번 포스팅에서는 스케쥴링 알고리즘에 관하여 포스팅 합니다 관련 내용은 아래 pdf에서 확인 할수있습니다.
+
+
+
+(전반적인 내용이 pdf와 겹치는 내용의 반복일것 같아서 따로 내용 정리는 생략 했습니다)
+
+
+
+추가로 포스팅하는 내용은 priority inversion 우선순위 역전에 관하여 추가 하고 포스팅 마무리 하겠습니다.
+
+
+
+Scheduling_PDF
+
+
+
+--------
+
+
+
+
+### 추가 보완 내용
+
+
+
+## **priority inversion**
+
+
+
+> **우선 순위 역전 문제**
+>
+> - 우선 순위가 높은 태스크가 READY상태 (실행 가능)로 바뀌었지만 더 낮은 우선순위의 태스크가 CPU를 점유하고 있어서 실행되지 못하는 상태
+>
+>
+>
+> > **발생 원인 :** 스케쥴링과 동기화 사이의 상호 작용 결과로 발생한다
+> >
+> > 스케쥴링 규칙에서 실행되어야 하는 스레드와 동기화에서 실행되어야하는 스레드가 서로 다른 경우
+> >
+> > 결과적으로 두 스레드의 우선순위가 역전되어 나타난다
+>
+>
+>
+> 1. 비선점 스케쥴링이 낮은 우선순위의 task가 자원을 점유 [no preemption scheduling]
+> 2. RTOS서의 multex를 위한 세마포어를 이용
+> 3. 공유자원의 장기 소유
+> 4. 자원점유후 release시 낮은 우선순위의 태스크가 자원을 점유하는 경우
+>
+>
+>
+>
+>
+> RTOS 개발시 태스크간에 우선순위를 예상하여 inversion 일어나지 않도록 해야한다
+>
+>
+>
+>
+>
+>
+>
+> **해결 기법**
+>
+>
+>
+> 1. **Priority inheritance protocol (계승 프로토콜)**
+>
+>
+>
+> * 우선순위가 낮은 프로세스가 세마포어를 소유하고 실행중일때 우선순위가 높은
+>
+> 프로세스가 실행되었을때 세마포어가 없다면 실행이 안되는데 우선순위가 낮은 프로세스를
+>
+> 우선순위가 높은 프로세스만큼 우선순위를 일시적으로 높여주는 것이다
+>
+>
+>
+> * 높은 우선순위의 프로세스를 블록시키고 있는 프로세스(하)는 높은 우선순위 프로세스의 우선순위를 계승하는것이다. 이 프로세스(하)가 세마포어를 반환하면 원래의 우선순위로 되돌아간다.
+>
+>
+>
+>
+>
+> ![ffff](C:\github_blog\meang123.github.io\images\2022-07-14-Scheduling\ffff.png)
+>
+>
+>
+> ![dfg](C:\github_blog\meang123.github.io\images\2022-07-14-Scheduling\dfg.png)
+>
+>
+>
+>
+>
+> 2. **Priority ceiling protocol (상한 프로토콜)**
+> * 주로 1번 방법으로 해결하는것 같아서 따로 정리는 안했습니다. 필요해지면 다시 업데이트 하는 방식으로 하겠습니다. 키워드는 있으니까 궁금하신 분은 검색 하시면 될것 같아요
diff --git a/_posts/2022-07-15-Threads_c++.md b/_posts/2022-07-15-Threads_c++.md
new file mode 100644
index 000000000000..e169a1cf600d
--- /dev/null
+++ b/_posts/2022-07-15-Threads_c++.md
@@ -0,0 +1,311 @@
+---
+layout: single
+title: "1편 Threads c++"
+categories: [Operating System,OS,Multi Thread,C++,cppreference,join,jthread]
+tag : [Operating System,OS,Thread,join,jthread]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작하며
+
+멀티 스레드 c++ 1편은 스레드에 관한 내용을 포스팅 하겠습니다.
+intro에서도 언급 했듯이 **"코드없는 프로그래밍"** 유튜브 내용을 참고 하면서 작성 했습니다. 추가로 cpprefernce 내용도 함께 참고해서 포스팅 하였습니다.
+
+멀티 스레드의 문제는 동기화 입니다. 동기화에 대해 이해도가 있다면 이해하기 쉬워 질것입니다.
+
+
+
+---------------------------
+
+
+
+c++에서 thread는 object로 만들어지고 object가 stack이나 heap영역에 스레드 생성하는 방식이다.
+
+
+
+## constructor
+
+
+
+아래 코드는 cpprefernce thread constructor부분 코드 입니다.
+
+```c++
+#include
+#include
+#include
+#include
+
+void f1(int n) //call by value
+{
+ for (int i = 0; i < 5; ++i) {
+ std::cout << "Thread 1 executing\n";
+ ++n;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10)); //10milsecond 만큼 기다립니다
+ }
+}
+
+void f2(int& n) //call by reference
+{
+ for (int i = 0; i < 5; ++i) {
+ std::cout << "Thread 2 executing\n";
+ ++n;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+}
+
+class foo
+{
+public:
+ void bar()
+ {
+ for (int i = 0; i < 5; ++i) {
+ std::cout << "Thread 3 executing\n";
+ ++n;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ int n = 0;
+};
+
+class baz
+{
+public:
+ void operator()()
+ {
+ for (int i = 0; i < 5; ++i) {
+ std::cout << "Thread 4 executing\n";
+ ++n;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+ int n = 0;
+};
+
+int main()
+{
+ int n = 0;
+ foo f;
+ baz b;
+ std::thread t1; // t1 is not a thread
+ std::thread t2(f1, n + 1); // pass by value
+ // 함수와 인자 전달 하는 방법
+
+ std::thread t3(f2, std::ref(n)); // pass by reference refernce는 ref()를 통해 wrapping해야한다
+
+ std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
+ // copy constroctor안됨 R value 또는 move constroctor 여야한다
+
+ std::thread t5(&foo::bar, &f); // t5 runs foo::bar() on object f
+ std::thread t6(b); // t6 runs baz::operator() on a copy of object b
+ t2.join();
+ t4.join();
+ t5.join();
+ t6.join();
+ std::cout << "Final value of n is " << n << '\n';
+ std::cout << "Final value of f.n (foo::n) is " << f.n << '\n';
+ std::cout << "Final value of b.n (baz::n) is " << b.n << '\n';
+}
+```
+
+
+
+std::thread (fn)하면 main에서 만들어진 thread object는 stack 영역에 fn 함수를 가리키고 join()을 통해 fn 스레드가 실행 한다
+
+
+
+* copy constroctor는 안되고 move constroctor로 스레드 객체를 넘길수있다 즉 R value
+* 함수와 함수 인자를 thread 통해 전달하는 방식은 위의 코드 참고
+* reference로 전달할때는 std::ref()으로 wrapping 해주어야 한다
+
+
+
+
+
+## destroctor
+
+thread 종료 시키는 terminator가 작동하면서 종료 된다
+
+cf : jthread 같은 경우 destroctor에 join과 stop token이 있어서 자동으로 가능
+
+
+
+
+
+## join
+
+현재 thread를 block 하고 실행이 끝날때까지 기다린다 -> 우선 순위 스케쥴링 방식이 아니다 ,no context switching
+
+
+
+join의 문제는 생성한 스레드가 join을 하지 않거나 여러번 중첩 사용했을때 발생한다. main에서 만들어진 thread object는 연결 되어있는데 join 하지 않으면 main에 있는 thread object가 종료가 되기 때문에 문제가 발생한다.
+
+이런 문제를 c++20 이전에는 detach를 통해 분리 할수있었다. 근데 분리하는 구조는 좋은 구조는 아니다. 그래서 c++ 20에서는 jthread를 지원한다. jthread는 아래에서 더 자세히 알아본다.
+
+
+
+thread object는 stack영역, heap 영역에 생성 할 수 있다. 아래 코드는 heap영역에 thread생성 한 것이다.
+
+
+
+```c++
+#include
+#include
+#include
+#include
+
+void fn()
+{
+ cout << this_thread::get_id() << endl; //thread id
+}
+
+int main()
+{
+ cout << "my computer is supported " << thread::hardware_concurrency() << endl;
+
+ //thread vector 만들어서 heap영역에 스레드 생성 할수도 있다
+
+ //thread는 object이다
+ vector threads;
+ for (int i = 0; i < 10; i++)
+ {
+ threads.emplace_back(thread(fn));
+
+ }
+
+ for (auto& thread : threads)
+ {
+ thread.join();
+ }
+
+
+
+ return 0;
+}
+
+```
+
+
+
+-----------------
+
+
+
+멀티 스레드는 공유 자원을 쓰기 때문에 동기화 하는 문제가 중요하다. 아래의 코드를 보면 스레드를 생성하면 join을 해주어서 동기화 해주는것을 알수있다. 만약 이런 동기화 작업이 없다면 올바른 결과가 나오지 않을것이다. -- 사실 여기까지만 살펴보면 순차적 프로그램이랑 별 차이가 없다 후에 동기화 부분에 대해서 보고 나면 이해하기 쉬어질것으로 생각 된다.--
+
+
+
+그리고 Operating system 포스팅에서도 스레드 동기화 내용이 있으니 이 부분을 먼저 보고 오면 더 도움이 될것 같다
+
+
+
+```c++
+#include
+#include
+#include
+#include
+
+void fn(int &a)
+{
+ this_thread::sleep_for(chrono::seconds(1s));
+ cout << a << endl;
+}
+void threadCaller(thread& t)
+{
+ int num = 42;
+ t = thread(fn, std::ref(num));
+ t.join(); //동기화 중요하다
+}
+int main()
+{
+ thread t1;
+ threadCaller(t1);
+ t1.join();
+
+
+ return 0;
+}
+
+```
+
+
+
+
+
+----------------------
+
+
+
+> **thread_local keyword**
+>
+> 함수의 지역 변수와 같은 맥락이다
+>
+> 만들어진 스레드에 대해서 독립적으로 가지는 keyword이다.
+>
+> 즉 생성된 각 스레드마다 독립적인 공간을 가진다고 이해 하면 될것 같다 ---> 관련내용이 더 필요하다면 cppreference thread_local 부분을 인터넷에서 참고 하면 될것 같다
+
+
+
+
+
+## Jthread
+
+이전에 join에서 발견된 문제를 보완해주는 내용이다. c++20 버전부터 지원을 한다
+
+
+
+* rejoin in 한다고 보면 된다. 즉 join, detach하지 않아도 에러 없이 종료 할수 있다.
+
+* stop token 있다
+ * 무한히 기다려 주지 않는다는 의미이다.
+ * 일정 시간이 지나면 자동으로 terminate한다
+ * **stop token에 관한 내용은 cppreference jthread stop_token에 관련 내용이 있다. 필요하면 참고 하자**
+
+
+
+```c++
+#include
+#include
+#include
+#include
+
+using namespace std;
+
+void fn()
+{
+ cout << "this is fn function " << endl;
+}
+int main()
+{
+ jthread t1(fn);
+
+
+ return 0;
+}
+```
+
+
+
+join함수가 없어도 정상 작동을 한다. 그리고 fn에서 무한 루프가 있다고 해도 일정 시간이 지나면 terminate 된다
+
+
+
+--------------
+
+
+
+## Data Race
+
+두개 이상의 스레드가 공유 자원을 사용하고 있으면서 발생하는 문제
+
+결국 동기화 관련 문제이다 이 문제를 해결하기 위해서는 동기화에 대한 내용을 알아야 한다 다음 포스팅에서 이어서 하겠다.
+
+
+
+
+
diff --git a/_posts/2022-07-15-multi_thread_intro.md b/_posts/2022-07-15-multi_thread_intro.md
new file mode 100644
index 000000000000..cff0857a2b4d
--- /dev/null
+++ b/_posts/2022-07-15-multi_thread_intro.md
@@ -0,0 +1,24 @@
+---
+layout: single
+title: "multi threads c++"
+categories: [Operating System,OS,Multi Thread,C++,introduction,intro]
+tag : [Operating System,OS,Thread,introduction]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+### 시작 하며
+
+멀티 스레드 관련 개념을 코딩을 통해 더 자세히 다루기 위해 이번 포스팅 부터 시작하려 합니다.
+thread,semaphore,lock, mutex등 OS에서 배운 내용을 직접 코딩 해보면서 한층 더 이해하는 시간이 되었으면 좋겠습니다.
+
+이번 포스팅 부터 진행하는 내용은 코드없는 프로그래밍 유트브를 따라해보면서 정리한 내용입니다. 추가로 제가 공부한 내용까지 포스팅을 할것이지만 저작권은 **"코드없는 프로그래밍 유튜브에 있습니다."**
+
+아래 링크를 통해 관련 영상 볼 수 있습니다.
+
+[코드없는 프로그래밍](https://www.youtube.com/channel/UCHcG02L6TSS-StkSbqVy6Fg)
+{: .notice--danger}
+
diff --git a/_posts/2022-07-21-multi_thread_syn.md b/_posts/2022-07-21-multi_thread_syn.md
new file mode 100644
index 000000000000..45f3fba8f2b9
--- /dev/null
+++ b/_posts/2022-07-21-multi_thread_syn.md
@@ -0,0 +1,765 @@
+---
+layout: single
+title: "multi thread Synchronize with c++"
+categories: [Operating System,multi thread,process,synchronize,semaphore,mutex,critical section,c++,C++,Lock]
+tag : [Operating System,OS,process,synchronize,Mutex,Critical Section,Critical Section Problem,Semaphore,c++,lock]
+toc: true
+author_profile: false
+sidebar:
+ nav : "docs"
+search: true
+---
+
+
+
+### 시작하며
+
+멀티 스레드 챕터 시리즈 이어나가고 있습니다. 이번 포스팅에서는 지난 포스팅에서 문제가 되었던 data race관련 문제에 관한 이야기 입니다.
+동기화에 대한 내용을 코드와 함께 정리 하는 포스팅입니다.
+
+또한 OS 부분에서 프로세스/ 스레드 동기화 대한 내용 포스팅 한적 있는데 먼저 보고 오시면 이해하는데 더 도움이 될것 같습니다.
+
+그래서 개념에 대한 이야기 보다는 어떻게 코드로 구현이 되는지에 초점을 두고 진행하겠습니다.
+
+
+
+-------------
+
+
+
+## Mutex
+
+
+
+lock , unlock 개념 #include mutex 해야 사용 할수 있다
+
+
+
+mutex로 보호하는 critical section은 최소화가 되어야 의미가 있다 만약 공유 되는 자원이 많아지면 즉 critical section 커지면 하나의 스레드만 계속 사용되기 때문에 비효율적이 된다 즉 핵심은 최소화 해야한다.
+
+
+
+**그리고 흔히 mutex에서 착각하는게 있는데 lock을 얻지 못해 block상태에 갔다고 해서 먼저 온 스레드가 lock을 먼저 획득한다는 보장은 없다**
+
+스케쥴링 방식 ,OS 구현 방식에 따라 달라진다
+
+
+
+```c++
+/*
+mutex 관련 코드
+
+임계구역은 최대한 적게 해야한다
+lock을 했을때 성능이 어느 정도 나오는지 검사하는 코드
+
+*/
+
+#include
+#include
+#include