From 2695f42511023376a6f20f5f28ccd9add7fed939 Mon Sep 17 00:00:00 2001 From: obzva Date: Mon, 26 Aug 2024 18:34:02 +0900 Subject: [PATCH 1/6] Solution: Two Sum --- two-sum/flynn.md | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 two-sum/flynn.md diff --git a/two-sum/flynn.md b/two-sum/flynn.md new file mode 100644 index 000000000..a84c800c8 --- /dev/null +++ b/two-sum/flynn.md @@ -0,0 +1,49 @@ +## Description + +`key: num, value: index`를 저장할 hashmap을 선언합니다. + +배열 `nums`의 첫번째 원소를 hashmap에 저장합니다. (`nums[0]: 0`) + +배열 `nums`를 두번째 원소부터 조회하여 `target - nums[i]`가 hashmap에 존재하는지 판단합니다. + +만약 `target - nums[i]`가 hashmap에 존재한다면 정답 배열을 반환하고, 그렇지 않다면 hashmap에 새로운 쌍을 추가합니다. + +## Big-O + +주어진 배열 `nums`의 크기 N에 대해, + +Time complexity: `O(N)` + +- 배열 `nums`를 순회하기 때문에 `O(N)`의 시간 복잡도를 가집니다. + +Space complexity: `O(N)` + +- hashmap의 크기가 배열 `nums`의 크기에 가깝게 커질 수 있으므로 `O(N)`의 공간복잡도를 가집니다. + +--- + +```cpp +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map past; // key: num value: index + vector res; + + past.insert({nums[0], 0}); + + for (int i = 1; i < nums.size(); i++) { + int remainder = target - nums[i]; + + if (past.find(remainder) != past.end()) { + res.push_back(i); + res.push_back(past[remainder]); + break; + } else { + past.insert({nums[i], i}); + } + } + + return res; + } +}; +``` From fdd4d40e7edf34e172da63ad1561e0f9d17ed94a Mon Sep 17 00:00:00 2001 From: obzva Date: Mon, 26 Aug 2024 23:16:17 +0900 Subject: [PATCH 2/6] Solution: Climbing Stairs --- climbing-stairs/flynn.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 climbing-stairs/flynn.md diff --git a/climbing-stairs/flynn.md b/climbing-stairs/flynn.md new file mode 100644 index 000000000..573be8c18 --- /dev/null +++ b/climbing-stairs/flynn.md @@ -0,0 +1,40 @@ +## Description + +다이나믹 프로그래밍을 이용하여 풀 수 있습니다. + +아래와 같이 `memo` 배열을 정의했을 때, + +``` +memo[0] = 1 +memo[1] = 1 +memo[i] = distinct ways to climb to the i-th stair +``` + +다음과 같은 점화식이 성립합니다. + +``` +memo[i] = memo[i - 2] + memo[i - 1] (i > 1) +``` + +## Big-O + +Time complexity: O(N) + +Space complexity: O(N) + +--- + +```cpp +class Solution { +public: + int climbStairs(int n) { + vector memo(2, 1); + + for (int i = 2; i <= n; i++) { + memo.push_back(memo[i - 1] + memo[i - 2]); + } + + return memo[n]; + } +}; +``` From c8db8688b174eb7e5ed1a80cf0b5810b72bf6ad1 Mon Sep 17 00:00:00 2001 From: obzva Date: Mon, 26 Aug 2024 23:33:59 +0900 Subject: [PATCH 3/6] Solution: Product of Array Except Self --- product-of-array-except-self/flynn.md | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 product-of-array-except-self/flynn.md diff --git a/product-of-array-except-self/flynn.md b/product-of-array-except-self/flynn.md new file mode 100644 index 000000000..8e34dc546 --- /dev/null +++ b/product-of-array-except-self/flynn.md @@ -0,0 +1,39 @@ +## Description + +한 칸씩 밀린 상태로 누적곱을 배열에 기록해주는 것을 두 번 진행해주면 원하는 바를 얻을 수 있습니다. + +| index | 0 | 1 | 2 | 3 | +| ----- | --------- | --------- | --------- | --------- | +| value | 1 | 2 | 3 | 4 | +| acc-> | | 1 | 1 x 2 | 1 x 2 x 3 | +| <-acc | 2 x 3 x 4 | 3 x 4 | 4 | | +| res | 2 x 3 x 4 | 1 x 3 x 4 | 1 x 2 x 4 | 1 x 2 x 3 | + +## Big-O + +Time complexity: O(N) + +Space complexity: O(N) + +--- + +```cpp +class Solution { +public: + vector productExceptSelf(vector& nums) { + vector res(nums.size(), 1); + + for (int i = 1; i < nums.size(); i++) { + res[i] *= nums[i - 1] * res[i - 1]; + } + + int acc = 1; + for (int i = nums.size() - 2; i >= 0; i--) { + acc *= nums[i + 1]; + res[i] *= acc; + } + + return res; + } +}; +``` From 7491493007873cb3b50cb0abac429c1351f9e169 Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 27 Aug 2024 00:12:47 +0900 Subject: [PATCH 4/6] Solution: Combination Sum --- combination-sum/flynn.md | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 combination-sum/flynn.md diff --git a/combination-sum/flynn.md b/combination-sum/flynn.md new file mode 100644 index 000000000..852059248 --- /dev/null +++ b/combination-sum/flynn.md @@ -0,0 +1,73 @@ +## Description + +`queue`를 이용한 BFS로 주어진 `candidates`의 조합을 만듭니다. + +조합의 합 S의 크기에 따라 아래와 같이 연산을 진행합니다. + +``` +S < target: 조합에 새로운 수를 추가하여 queue에 다시 push +S == target: 정답 배열 res에 해당 조합을 push +S > target: 더 이상 queue에 조합을 등록하지 않음 +``` + +## Big-O + +`candidates` 배열의 크기를 `N`, `target`의 크기를 `T`, `candidates` 배열의 원소 중 가장 작은 원소의 크기를 `K`라고 했을 때, + +Time complexity: `O(N ^ (T / K))` + +- `queue`에 담긴 각 조합들은 최대 `N`개의 새로운 조합들을 만들어 낼 수 있습니다 +- 이걸 `Tree`에 빗대어 생각해보면 각 `node` 당 `N`개의 자식들을 갖는다고 볼 수 있습니다 +- `Tree`의 깊이는 `T / K`에 비례합니다 + +Space complexity: `O((T / K) * (N ^ (T / K)))` + +- `queue`의 크기는 앞서 말한 `Tree`의 `node` 개수만큼 늘어날 수 있습니다 +- `node`가 지닌 조합 배열의 크기는 `T / K` 까지 커질 수 있습니다 + +--- + +```cpp +class Solution { +public: + vector> combinationSum(vector& candidates, int target) { + vector> res; + queue>>> q; // {acc, {idx, combination}} + + for (int i = 0; i < candidates.size(); i++) { + int num = candidates[i]; + + if (num <= target) { + vector comb; + comb.push_back(num); + q.push({num, {i, comb}}); + } + + } + + while (!q.empty()) { + auto p = q.front(); + q.pop(); + + int acc = p.first, idx = p.second.first; + auto comb = p.second.second; + + if (acc == target) { + res.push_back(comb); + } else if (acc < target) { + for (int i = idx; i < candidates.size(); i++) { + int num = candidates[i]; + + if (acc + num <= target) { + vector new_comb(comb); + new_comb.push_back(num); + q.push({acc + num, {i, new_comb}}); + } + } + } + } + + return res; + } +}; +``` From f6d75c62fbbd3a3c1c7485c764b6f797ef30130e Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 27 Aug 2024 00:29:36 +0900 Subject: [PATCH 5/6] Solution: Coin Change --- coin-change/flynn.md | 47 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 coin-change/flynn.md diff --git a/coin-change/flynn.md b/coin-change/flynn.md new file mode 100644 index 000000000..4875018ca --- /dev/null +++ b/coin-change/flynn.md @@ -0,0 +1,47 @@ +## Description + +DP를 이용하여 풀이할 수 있습니다. + +배열 `memo`를 아래와 같이 정의합니다. + +``` +memo[i] = i원을 만들기 위해 필요한 동전의 최소 개수 +각 원소의 값은 초기값은 10^4 + 1로 설정함 (max(amount) / min(coin) + 1) +``` + +앞서 정의한 배열 `memo`를 이용하면 아래 점화식이 성립합니다. + +``` +memo[i] = min(memo[i], memo[i - coin] + 1) if i - coin >= 0 +``` + +## Big-O + +배열 `coins`의 크기를 `N`, 정수 `amount`의 크기를 `K`라고 했을 때, + +Time complexity: `O(N * M)` + +Space complexity: `O(M)` + +--- + +```cpp +class Solution { +public: + int coinChange(vector& coins, int amount) { + int MAX = 10000 + 1; + vector memo(amount + 1, MAX); + memo[0] = 0; + + for (int i = 1; i <= amount; i++) { + for (auto coin : coins) { + if (i - coin >= 0) { + memo[i] = min(memo[i], memo[i - coin] + 1); + } + } + } + + return memo[amount] == MAX ? -1 : memo[amount]; + } +}; +``` From c6de304a76a4f8a5634e2106623c7b90fc5bebeb Mon Sep 17 00:00:00 2001 From: obzva Date: Tue, 27 Aug 2024 20:27:43 +0900 Subject: [PATCH 6/6] Fix: md -> cpp --- climbing-stairs/flynn.cpp | 13 +++++ climbing-stairs/flynn.md | 40 -------------- coin-change/flynn.cpp | 19 +++++++ coin-change/flynn.md | 47 ----------------- combination-sum/flynn.cpp | 43 +++++++++++++++ combination-sum/flynn.md | 73 -------------------------- product-of-array-except-self/flynn.cpp | 19 +++++++ product-of-array-except-self/flynn.md | 39 -------------- two-sum/flynn.cpp | 23 ++++++++ two-sum/flynn.md | 49 ----------------- 10 files changed, 117 insertions(+), 248 deletions(-) create mode 100644 climbing-stairs/flynn.cpp delete mode 100644 climbing-stairs/flynn.md create mode 100644 coin-change/flynn.cpp delete mode 100644 coin-change/flynn.md create mode 100644 combination-sum/flynn.cpp delete mode 100644 combination-sum/flynn.md create mode 100644 product-of-array-except-self/flynn.cpp delete mode 100644 product-of-array-except-self/flynn.md create mode 100644 two-sum/flynn.cpp delete mode 100644 two-sum/flynn.md diff --git a/climbing-stairs/flynn.cpp b/climbing-stairs/flynn.cpp new file mode 100644 index 000000000..65c867da0 --- /dev/null +++ b/climbing-stairs/flynn.cpp @@ -0,0 +1,13 @@ +class Solution { +public: +int climbStairs(int n) { +vector memo(2, 1); + + for (int i = 2; i <= n; i++) { + memo.push_back(memo[i - 1] + memo[i - 2]); + } + + return memo[n]; + } + +}; diff --git a/climbing-stairs/flynn.md b/climbing-stairs/flynn.md deleted file mode 100644 index 573be8c18..000000000 --- a/climbing-stairs/flynn.md +++ /dev/null @@ -1,40 +0,0 @@ -## Description - -다이나믹 프로그래밍을 이용하여 풀 수 있습니다. - -아래와 같이 `memo` 배열을 정의했을 때, - -``` -memo[0] = 1 -memo[1] = 1 -memo[i] = distinct ways to climb to the i-th stair -``` - -다음과 같은 점화식이 성립합니다. - -``` -memo[i] = memo[i - 2] + memo[i - 1] (i > 1) -``` - -## Big-O - -Time complexity: O(N) - -Space complexity: O(N) - ---- - -```cpp -class Solution { -public: - int climbStairs(int n) { - vector memo(2, 1); - - for (int i = 2; i <= n; i++) { - memo.push_back(memo[i - 1] + memo[i - 2]); - } - - return memo[n]; - } -}; -``` diff --git a/coin-change/flynn.cpp b/coin-change/flynn.cpp new file mode 100644 index 000000000..10ec8dcce --- /dev/null +++ b/coin-change/flynn.cpp @@ -0,0 +1,19 @@ +class Solution { +public: +int coinChange(vector& coins, int amount) { +int MAX = 10000 + 1; +vector memo(amount + 1, MAX); +memo[0] = 0; + + for (int i = 1; i <= amount; i++) { + for (auto coin : coins) { + if (i - coin >= 0) { + memo[i] = min(memo[i], memo[i - coin] + 1); + } + } + } + + return memo[amount] == MAX ? -1 : memo[amount]; + } + +}; diff --git a/coin-change/flynn.md b/coin-change/flynn.md deleted file mode 100644 index 4875018ca..000000000 --- a/coin-change/flynn.md +++ /dev/null @@ -1,47 +0,0 @@ -## Description - -DP를 이용하여 풀이할 수 있습니다. - -배열 `memo`를 아래와 같이 정의합니다. - -``` -memo[i] = i원을 만들기 위해 필요한 동전의 최소 개수 -각 원소의 값은 초기값은 10^4 + 1로 설정함 (max(amount) / min(coin) + 1) -``` - -앞서 정의한 배열 `memo`를 이용하면 아래 점화식이 성립합니다. - -``` -memo[i] = min(memo[i], memo[i - coin] + 1) if i - coin >= 0 -``` - -## Big-O - -배열 `coins`의 크기를 `N`, 정수 `amount`의 크기를 `K`라고 했을 때, - -Time complexity: `O(N * M)` - -Space complexity: `O(M)` - ---- - -```cpp -class Solution { -public: - int coinChange(vector& coins, int amount) { - int MAX = 10000 + 1; - vector memo(amount + 1, MAX); - memo[0] = 0; - - for (int i = 1; i <= amount; i++) { - for (auto coin : coins) { - if (i - coin >= 0) { - memo[i] = min(memo[i], memo[i - coin] + 1); - } - } - } - - return memo[amount] == MAX ? -1 : memo[amount]; - } -}; -``` diff --git a/combination-sum/flynn.cpp b/combination-sum/flynn.cpp new file mode 100644 index 000000000..d81a64aa3 --- /dev/null +++ b/combination-sum/flynn.cpp @@ -0,0 +1,43 @@ +class Solution { +public: +vector> combinationSum(vector& candidates, int target) { +vector> res; +queue>>> q; // {acc, {idx, combination}} + + for (int i = 0; i < candidates.size(); i++) { + int num = candidates[i]; + + if (num <= target) { + vector comb; + comb.push_back(num); + q.push({num, {i, comb}}); + } + + } + + while (!q.empty()) { + auto p = q.front(); + q.pop(); + + int acc = p.first, idx = p.second.first; + auto comb = p.second.second; + + if (acc == target) { + res.push_back(comb); + } else if (acc < target) { + for (int i = idx; i < candidates.size(); i++) { + int num = candidates[i]; + + if (acc + num <= target) { + vector new_comb(comb); + new_comb.push_back(num); + q.push({acc + num, {i, new_comb}}); + } + } + } + } + + return res; + } + +}; diff --git a/combination-sum/flynn.md b/combination-sum/flynn.md deleted file mode 100644 index 852059248..000000000 --- a/combination-sum/flynn.md +++ /dev/null @@ -1,73 +0,0 @@ -## Description - -`queue`를 이용한 BFS로 주어진 `candidates`의 조합을 만듭니다. - -조합의 합 S의 크기에 따라 아래와 같이 연산을 진행합니다. - -``` -S < target: 조합에 새로운 수를 추가하여 queue에 다시 push -S == target: 정답 배열 res에 해당 조합을 push -S > target: 더 이상 queue에 조합을 등록하지 않음 -``` - -## Big-O - -`candidates` 배열의 크기를 `N`, `target`의 크기를 `T`, `candidates` 배열의 원소 중 가장 작은 원소의 크기를 `K`라고 했을 때, - -Time complexity: `O(N ^ (T / K))` - -- `queue`에 담긴 각 조합들은 최대 `N`개의 새로운 조합들을 만들어 낼 수 있습니다 -- 이걸 `Tree`에 빗대어 생각해보면 각 `node` 당 `N`개의 자식들을 갖는다고 볼 수 있습니다 -- `Tree`의 깊이는 `T / K`에 비례합니다 - -Space complexity: `O((T / K) * (N ^ (T / K)))` - -- `queue`의 크기는 앞서 말한 `Tree`의 `node` 개수만큼 늘어날 수 있습니다 -- `node`가 지닌 조합 배열의 크기는 `T / K` 까지 커질 수 있습니다 - ---- - -```cpp -class Solution { -public: - vector> combinationSum(vector& candidates, int target) { - vector> res; - queue>>> q; // {acc, {idx, combination}} - - for (int i = 0; i < candidates.size(); i++) { - int num = candidates[i]; - - if (num <= target) { - vector comb; - comb.push_back(num); - q.push({num, {i, comb}}); - } - - } - - while (!q.empty()) { - auto p = q.front(); - q.pop(); - - int acc = p.first, idx = p.second.first; - auto comb = p.second.second; - - if (acc == target) { - res.push_back(comb); - } else if (acc < target) { - for (int i = idx; i < candidates.size(); i++) { - int num = candidates[i]; - - if (acc + num <= target) { - vector new_comb(comb); - new_comb.push_back(num); - q.push({acc + num, {i, new_comb}}); - } - } - } - } - - return res; - } -}; -``` diff --git a/product-of-array-except-self/flynn.cpp b/product-of-array-except-self/flynn.cpp new file mode 100644 index 000000000..6ee176660 --- /dev/null +++ b/product-of-array-except-self/flynn.cpp @@ -0,0 +1,19 @@ +class Solution { +public: +vector productExceptSelf(vector& nums) { +vector res(nums.size(), 1); + + for (int i = 1; i < nums.size(); i++) { + res[i] *= nums[i - 1] * res[i - 1]; + } + + int acc = 1; + for (int i = nums.size() - 2; i >= 0; i--) { + acc *= nums[i + 1]; + res[i] *= acc; + } + + return res; + } + +}; diff --git a/product-of-array-except-self/flynn.md b/product-of-array-except-self/flynn.md deleted file mode 100644 index 8e34dc546..000000000 --- a/product-of-array-except-self/flynn.md +++ /dev/null @@ -1,39 +0,0 @@ -## Description - -한 칸씩 밀린 상태로 누적곱을 배열에 기록해주는 것을 두 번 진행해주면 원하는 바를 얻을 수 있습니다. - -| index | 0 | 1 | 2 | 3 | -| ----- | --------- | --------- | --------- | --------- | -| value | 1 | 2 | 3 | 4 | -| acc-> | | 1 | 1 x 2 | 1 x 2 x 3 | -| <-acc | 2 x 3 x 4 | 3 x 4 | 4 | | -| res | 2 x 3 x 4 | 1 x 3 x 4 | 1 x 2 x 4 | 1 x 2 x 3 | - -## Big-O - -Time complexity: O(N) - -Space complexity: O(N) - ---- - -```cpp -class Solution { -public: - vector productExceptSelf(vector& nums) { - vector res(nums.size(), 1); - - for (int i = 1; i < nums.size(); i++) { - res[i] *= nums[i - 1] * res[i - 1]; - } - - int acc = 1; - for (int i = nums.size() - 2; i >= 0; i--) { - acc *= nums[i + 1]; - res[i] *= acc; - } - - return res; - } -}; -``` diff --git a/two-sum/flynn.cpp b/two-sum/flynn.cpp new file mode 100644 index 000000000..b05a54af7 --- /dev/null +++ b/two-sum/flynn.cpp @@ -0,0 +1,23 @@ +class Solution { +public: + vector twoSum(vector& nums, int target) { + unordered_map past; // key: num value: index + vector res; + + past.insert({nums[0], 0}); + + for (int i = 1; i < nums.size(); i++) { + int remainder = target - nums[i]; + + if (past.find(remainder) != past.end()) { + res.push_back(i); + res.push_back(past[remainder]); + break; + } else { + past.insert({nums[i], i}); + } + } + + return res; + } +}; diff --git a/two-sum/flynn.md b/two-sum/flynn.md deleted file mode 100644 index a84c800c8..000000000 --- a/two-sum/flynn.md +++ /dev/null @@ -1,49 +0,0 @@ -## Description - -`key: num, value: index`를 저장할 hashmap을 선언합니다. - -배열 `nums`의 첫번째 원소를 hashmap에 저장합니다. (`nums[0]: 0`) - -배열 `nums`를 두번째 원소부터 조회하여 `target - nums[i]`가 hashmap에 존재하는지 판단합니다. - -만약 `target - nums[i]`가 hashmap에 존재한다면 정답 배열을 반환하고, 그렇지 않다면 hashmap에 새로운 쌍을 추가합니다. - -## Big-O - -주어진 배열 `nums`의 크기 N에 대해, - -Time complexity: `O(N)` - -- 배열 `nums`를 순회하기 때문에 `O(N)`의 시간 복잡도를 가집니다. - -Space complexity: `O(N)` - -- hashmap의 크기가 배열 `nums`의 크기에 가깝게 커질 수 있으므로 `O(N)`의 공간복잡도를 가집니다. - ---- - -```cpp -class Solution { -public: - vector twoSum(vector& nums, int target) { - unordered_map past; // key: num value: index - vector res; - - past.insert({nums[0], 0}); - - for (int i = 1; i < nums.size(); i++) { - int remainder = target - nums[i]; - - if (past.find(remainder) != past.end()) { - res.push_back(i); - res.push_back(past[remainder]); - break; - } else { - past.insert({nums[i], i}); - } - } - - return res; - } -}; -```