๊ฐ์ฅ ์์ ๋ฌธ์ ๋ค ๋ถํฐ ๋ต์ ๊ตฌํด๊ฐ๋ฉฐ ์ ์ฒด ๋ต์ ์ฐพ๋ ๋ฐฉ์
ํผ๋ณด๋์น ํจ์ ๊ตฌํ์ ์๋ก ๋ค์๋ฉด,,
int fibonacci(int n)
{
dp[0] = 0, dp[1] = 1;
// ์์ ๋ฌธ์ ๋ถํฐ,,
for (int i = 2; i <= n; i++)
dp[i] = dp[i - 1] + dp[i - 2];
}
recursion์ด ์๋๋ผ, ์๊ฐ๊ณผ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ค์ผ ์ ์๋ค
ํฐ ๋ฌธ์ ๋ฅผ ๋ฐฉ๋ฌธ ํ ์์ ๋ฌธ์ ๋ฅผ ํธ์ถํ์ฌ ๋ต์ ์ฐพ๋ ๋ฐฉ์
int fibonacci(int n)
{
if (n == 0) return 0;
if (n == 1) return 1;
if (dp[n] != -1) return dp[n];
// ํฐ๋ฌธ์ ๋ฐฉ๋ฌธํด์ ๊ฑฐ๊ธฐ์ recursion์ผ๋ก ์์ ๋ฌธ์ ๋ฅผ ํธ์ถ!
dp[n] = fibonacci(n - 1) + fibonacci(n - 2);
return dp[n];
}
์ ํ์์ ์ดํดํ๊ธฐ ์ฝ๋ค
You are climbing a staircase. It takes n
steps to reach the top.
Each time you can either climb 1
or 2
steps. In how many distinct ways can you climb to the top?
Example 1:
Input: n = 2
Output: 2
Explanation: There are two ways to climb to the top.
1. 1 step + 1 step
2. 2 steps
Example 2:
Input: n = 3
Output: 3
Explanation: There are three ways to climb to the top.
1. 1 step + 1 step + 1 step
2. 1 step + 2 steps
3. 2 steps + 1 step
๊ทผ๋ฐ ์ ์ด์ ๋๊ฐ๋ฅผ ๋ํ๋๊ฑฐ์ผ,, ์ดํด๊ฐ ์๋ผ ๋ ๋ฐ๋ณธ๊ฐ
์ ! !!
๊ทธ๋๊น ๋ด๊ฐ ์ง๊ธ stair 2์ ์๋ค๊ณ ์น์
๊ทธ๋ผ ๋ด๊ฐ ๊ฐ ์ ์๋ ๊ณณ์ stair 3๊ณผ 4์ด๋ค (ํ๋ฒ์ 1 step or 2 step๋ง ๊ฐ ์ ์์ผ๋)
๊ทธ๋ฌ๋ฏ๋ก stair 3์ด๋ 4์์ 5๋ก ๊ฐ ์ ์๋ ๊ฒฝ์ฐ์ ์๋ฅผ ๋ํด์ฃผ๋ฉด
๋ด๊ฐ stair 2์์ 5๋ก ๊ฐ ์ ์๋ ๊ฒฝ์ฐ์ ์๊ฐ ๊ณ์ฐ ๋๋ ๊ฒ์ด๋ค!
(notice: ๋ง์ง๋ง ๋๊ฐ๋ ํญ์ 1๋ก ์ฑ์์ง๊ณ ์์ํ๋ค)
์๊ฐํด๋ณด์
stair 4 (๋ง์ง๋ง ๋๋ฒ์งธ)์์ stair 5๋ก (๋ง์ง๋ง) ๊ฐ๋ ๋ฐฉ๋ฒ์ ํ๋๋๊น ๋น์ฐํ 1
stair 5๋ ๋ค๋ฅธ ๋ ๋ฐ์ ๋จ๊ณ ๊ณ๋จ์์ 1๊ณ๋จ ์ฌ๋ผ๊ฐ๋ ๊ฒ์ ๋ฏธ๋ฆฌ ๊ณ ๋ คํด์ ์ ์ด์ค๊ฒ!
class Solution {
public:
int climbStairs(int n) {
int one_step = 1;
int two_step = 1;
for (int i = 0; i <= n - 2; i++) { // ๋ง์ง๋ง ๋ ๊ณ๋จ์ 1๋ก ์ด๋ฏธ ๊ณ์ฐ ๋์ด์์ผ๋,
// ๊ทธ ๋ง์ง๋ง ๋ ๊ณ๋จ ์ ๊น์ง๋ง loop์ ๋๋ฉด ๋๋ค
int temp = one_step;
one_step = one_step + two_step;
two_step = temp;
}
return one_step;
}
};
... ๋ชจ๋ฅด๊ฒ์ผ
You are given an integer array cost
where cost[i]
is the cost of ith
step on a staircase. Once you pay the cost, you can either climb one or two steps.
You can either start from the step with index 0
, or the step with index 1
.
Return the minimum cost to reach the top of the floor.
Example 1:
Input: cost = [10,15,20]
Output: 15
Explanation: You will start at index 1.
- Pay 15 and climb two steps to reach the top.
The total cost is 15.
Example 2:
Input: cost = [1,100,1,1,1,100,1,1,100,1]
Output: 6
Explanation: You will start at index 0.
- Pay 1 and climb two steps to reach index 2.
- Pay 1 and climb two steps to reach index 4.
- Pay 1 and climb two steps to reach index 6.
- Pay 1 and climb one step to reach index 7.
- Pay 1 and climb two steps to reach index 9.
- Pay 1 and climb one step to reach the top.
The total cost is 6.
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int two = cost[0]; // min cost when taking the 2 stairs before
int one = cost[1]; // min cost when taking the 1 stair before
int curr = INT_MAX; // cost of the current stair, indeed the result
for (int i = 2; i <= cost.size(); i++) {
int c = 0;
if (i != cost.size()) c = cost[i];
curr = min(two + c, one + c);
// update two, one for the next stari
two = one;
one = curr;
}
return curr;
}
};
Given a string s
, return the longest palindromic substring in s
.
Example 1:
Input: s = "babad"
Output: "bab"
Explanation: "aba" is also a valid answer.
Example 2:
Input: s = "cbbd"
Output: "bb"
์ผ๋จ ์๊น ์งํ์ฒ ์์ ๋ดค๋ ์์์ด๋ผ ๋ณต๊ธฐ๋ฅผ ํด๋ณด๋ฉด์ ํผ์ ํ์ด๋ณด์
์์ด๋์ด๋:
each letter๊ฐ palindrome์ ๊ฐ์ด๋ฐ๋ผ๊ณ ์๊ฐํ ์ํ๋ก ๊ณ์ ์์ชฝ์ผ๋ก ํผ์ ธ๋๊ฐ๋ ๊ฒ์ด๋ค
ํ์ง๋ง, palindrome์ด ์ง์์ผ์๋ ์์ํ
๋, ๊ทธ๋ด ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด i, i+1 ๋ฅผ ๋ฌถ์ด์ ๊ฐ์ด๋ฐ๋ผ๊ณ ์๊ฐํ์ฌ ํผ์ ธ๋๊ฐ๋ ๋ฐฉ๋ฒ๋ consider ํด์ฃผ์ด์ผํ๋ค
class Solution {
public:
string longestPalindrome(string s) {
int result_start = 0;
int result_length = 0;
for (int i = 0; i < s.size(); i++) {
palindrome(s, i, i, result_start, result_length);
palindrome(s, i, i+1, result_start, result_length);
}
return s.substr(result_start, result_length);
}
private:
void palindrome(string s, int i, int j, int &result_start, int &result_length) {
while (i >= 0 && j < s.size()) {
if (s[i] != s[j]) break;
if (result_length < j - i + 1) {
result_start = i;
result_length = j - i + 1;
}
i--;
j++;
}
}
};
Given a string s
, return the number of palindromic substrings in it.
A string is a palindrome when it reads the same backward as forward.
A substring is a contiguous sequence of characters within the string.
Example 1:
Input: s = "abc"
Output: 3
Explanation: Three palindromic strings: "a", "b", "c".
Example 2:
Input: s = "aaa"
Output: 6
Explanation: Six palindromic strings: "a", "a", "a", "aa", "aa", "aaa".
์์ ๋ฌธ์ ๋ ๊ฑฐ์ ๋น์ทํ๋ค! ์ด์ ๋ชจ๋ ๊ฒฝ์ฐ์ ์๋ฅผ ์ธ์ด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๋ค
class Solution {
public:
int countSubstrings(string s) {
int result = 0;
for (int i = 0; i < s.size(); i++) {
palindrome(s, i, i, result);
palindrome(s, i, i+1, result);
}
return result;
}
private:
void palindrome(string s, int i, int j, int &result) {
while (i >= 0 && j < s.size()) {
if (s[i] != s[j]) break;
result++;
i--;
j++;
}
}
};
Given an integer array nums
, return the length
of the longest strictly increasing subsequence
Example 1:
Input: nums = [10,9,2,5,3,7,101,18]
Output: 4
Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4.
Example 2:
Input: nums = [0,1,0,3,2,3]
Output: 4
Example 3:
Input: nums = [7,7,7,7,7,7,7]
Output: 1
Subsequence๋ฅผ ๊ตฌํ๋ ๋ฌธ์ ๋ผ์, ์ด๋ค element๋ฅผ ์ฌ์ฉํ ์ง ์ฒ์๋ถํฐ ๊ณ์ ์ฒดํฌํ์ฌ ์ ๋ฐ์ดํธ ํด์ฃผ์ด์ผ ํ๋ค
์ด๋ฐ์์ผ๋ก...
for (int i = 0; i < n; i++) {
for (int j = 0; j < i; j++) {
//...
}
}
(Note: Subarray๋ฅผ ๊ตฌํ๋ ๋ฌธ์ ์์๋ ์กฐ๊ฑด์ ์ด๊ธ๋๋ฉด ํ์ฌ element๋ถํฐ ๋ค์ ์์ํ์๋ค!)
class Solution {
public:
int lengthOfLIS(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n, 1);
int result = 1;
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
if (nums[j] < nums[i]) {
// nums[j]๋ฅผ ํฌํจํ๋ subsequence๊ฐ ๋ ๊ธธ๋ค๋ฉด update ํด์ค๋ค
// nums[i] ์ด์ ์ dp๊ฐ๋ค์ ๋ชจ๋ ์ต์ (= the final longest subsequence) ๊ฐ์ ๊ฐ์ง๊ณ ์๋ค
dp[i] = max(dp[i], dp[j] + 1);
}
}
result = max(result, dp[i]);
}
return result;
}
};
Given an integer array nums
, find the subarray which has the largest sum and return its sum.
Example 1:
Input: nums = [-2,1,-3,4,-1,2,1,-5,4]
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Example 2:
Input: nums = [1]
Output: 1
Example 3:
Input: nums = [5,4,-1,7,8]
Output: 23
nums[0:i+1]
์ maximum subarray๋ ์ด ๋ ์ค ํ๋์ด๋ค
ํ์ฌ ์์(i)์ ๊ฐ
์ด๊ฑฐ๋ ์ด์ ์ ๊ตฌํ๋ ๋ถ๋ถ์งํฉ์ ์ต๋ ๊ฐ + ํ์ฌ ์์
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int result = INT_MIN;
int cur_sum = 0;
for (int i = 0; i < nums.size(); i++) {
// cur_sum์ ์ง๊ธ๊น์ง max sum์ ๊ฐ์ง๊ณ ์๋ subarray์ sum์ ๋ณด๊ด
// ๊ทธ๋์ ์ง๊ธ ์ฌ๊ธฐ์ ๋ญ ํ๋๊ฑฐ๋๋ฉด
// subarray๋ฅผ ์ด๊ธฐํ ํ๊ณ ์ฌ๊ธฐ๋ถํฐ ๋ค์ ์์ํ ๋๊ฐ ํฌ๋ (nums[i])
// ์๋๋ฉด subarray๋ก ๊ณ์ ์ด์ด์ ํ์ฌ ๊ฐ์ ํฌํจํ์๋๊ฐ ๋ ํฌ๋ (nums[i] + cur_sum)
cur_sum = max(nums[i], nums[i] + cur_sum);
result = max(cur_sum, result);
}
return result;
}
};
cur_sum
์ ๊ณ์ max๋ก keep up ํ๋๋ฐ ์ final answer์ด ์๋๋,,,๋ฉด
cur_sum
์ subarray์ ์์์์น๊ฐ ์ฌ๋ฌ๊ฐ์ง๋ก ๊ณ ๋ ค๋๋ฉด์ ๊ฐ์ฅ ์ต๊ทผ(not max) ์์์์น์์๋ถํฐ์ max๋ฅผ following ํ๊ธฐ ๋๋ฌธ์ result์ ๊ณ์ ๋น๊ตํด์ฃผ๋ฉด์ updateํด์ฃผ์ด์ผ ํ๋ค
product๊ฐ ๊ฐ์ฅ ํฐ subarray๋ฅผ ์ฐพ๋ ๋ฌธ์ ์ด๋ค
subarray๋ continuousํ element๋ก๋ง ์ด๋ฃฐ ์ ์๋ค
.
.
์ด์ ๋ฌธ์ ์ ๋๊ฒ ์ ์ฌํด ๋ณด์ด์ง๋ง ์๊ฐํด์ผํ ๊ฒ ํ๋ ๋ ์๋ค (์ค์_
์์๊ฐ ํ๋๋ง ์์ผ๋ฉด ์ข์ง๋ง, ๋๊ฐ (ํน์ ์ง์๊ฐ)๊ฐ ์๋ค๋ฉด maximum product์ ์ํฅ์ ์ค๋ค.
์ฐ๋ฆฌ๋ ์ด๋ป๊ฒ ์์๋ฅผ ํฌ๊ธฐํ ์ง ์๋๋ฉด ๊ฐ์ ธ๊ฐ์ง ๊ฒฐ์ ํด์ผํ ๊น?
โ track currMax
& currMin
๋ง์ฝ ํ์ฌ ์ซ์๊ฐ ์์๋ผ๋ฉด, currMin
์ ๊ณฑํด์ฃผ๋ฉด maximum product๋ฅผ ๊ฐ์ ธ๋ค์ค์๋ ์๋๊ฒ!
ํ์ฌ ์ซ์๊ฐ ์์๋ผ๋ฉด, currMax
์ ๊ณฑํด์ฃผ๋ฉด max product๋ฅผ ์ฃผ๊ฒ์ง.
๊ตณ์ด if๋ก ์์ ์์๋ฅผ ์ฒดํฌํ์ง ์์๋ ์ด๋ ๊ฒ ์ฌ์ฉํ ์ ์๋ค
max(currMax * nums[i], currMin * nums[i])
์ด์ ์ด๋ ๊ฒ ๊ณฑํด์ค ๊ฐ๊ณผ์ ํ์ฌ ์ซ์๋ฅผ ๋น๊ต ํ์ ๋ ๋ ํฐ์๋ฅผ currMax
์ ์ ์ฅํ์ฌ subarray๋ฅผ ์ฌ์์ํ ๊ฑด์ง, ์ด์ด๊ฐ๊ฑด์ง ์ ํ๋๊ฑฐ๋ค
๋์์ currMin
๋ updateํด์ฃผ์ด์ผ ํ๋ค
์์ ๋ก์ง๊ณผ ๋น์ทํ๊ฒ,
min(currMin * nums[i], currMax * nums[i])
๋ก ํํํ๋ค
๋จ, currMax
๋ฅผ ์์ ์์ updateํด์ฃผ์๊ธฐ ๋๋ฌธ์, temp
์ ๋ณด๊ดํ์ด์ผ ํ๋ค
๋ง์ฐฌ๊ฐ์ง๋ก ์ด ๊ฐ๊ณผ ํ์ฌ๊ฐ์ ๋น๊ตํ์ ๋ ๋ ์์ ์๋ฅผ currMin
์ ์ ์ฅํ๋ค
class Solution {
public:
int maxProduct(vector<int>& nums) {
int currMax = nums[0];
int currMin = nums[0];
int result = nums[0];
for (int i = 1; i < nums.size(); i++) {
int temp = currMax;
currMax = max(max(currMax * nums[i], currMin * nums[i]), nums[i]);
currMin = min(min(temp * nums[i], currMin * nums[i]), nums[i]);
result = max(result, currMax);
}
return result;
}
};
There is a robot on an m x n
grid. The robot is initially located at the top-left corner (i.e., grid[0][0]
). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]
). The robot can only move either down or right at any point in time.
Given the two integers m
and n
, return the number of possible unique paths that the robot can take to reach the bottom-right corner.
The test cases are generated so that the answer will be less than or equal to 2 * 10^9
.
Example 1:
Input: m = 3, n = 7
Output: 28
Example 2:
Input: m = 3, n = 2
Output: 3
Explanation: From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Down -> Down
2. Down -> Down -> Right
3. Down -> Right -> Down
๊ฐ๊ฐ์ cell์์ ๊ทธ๊ณณ๊น์ง์ unique path๋ฅผ ๊ณ์ฐ ํด์ ๋ณด๊ดํ๋ฉด ๋๊ฒ๋น
์ง๊ธ cell์์ unique path๋ฅผ ๊ณ์ฐ ํ๋ ๋ฐฉ๋ฒ์
๋ก๋ด์ด down or right๋ง ์์ง์ผ ์ ์๋ค๊ณ ํ์ผ๋๊ฐ ..
์์์ ์๊ฑฐ๋ ์ผ์ชฝ์์ ์์๊ฑฐ๋๊น,,
๊ทธ๋ฆฌ๊ตฌ ,, cell์ ๋ชจ๋ 0์ผ๋ก initialize ํด์ผํ๊ณ
(except for the base cases)
class Solution {
public:
int uniquePaths(int m, int n) {
vector<vector<int>> grid(m, vector<int>(n)); // initialized with 0
// basecase
// the row and column that contains the start cell
for (int i = 0; i < m; i++) {
grid[i][0] = 1;
}
for (int j = 0; j < n; j++) {
grid[0][j] = 1;
}
// now dp!
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
grid[i][j] = grid[i-1][j] + grid[i][j-1];
}
}
return grid[m-1][n-1];
}
};
You are given an m x n
integer array grid
. There is a robot initially located at the top-left corner (i.e., grid[0][0]
). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]
). The robot can only move either down or right at any point in time.
An obstacle and space are marked as 1
or 0
respectively in grid
. A path that the robot takes cannot include any square that is an obstacle.
Return the number of possible unique paths that the robot can take to reach the bottom-right corner.
Example 1:
Input: obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
Output: 2
Explanation: There is one obstacle in the middle of the 3x3 grid above.
There are two ways to reach the bottom-right corner:
1. Right -> Right -> Down -> Down
2. Down -> Down -> Right -> Right
Example 2:
Input: obstacleGrid = [[0,1],[0,0]]
Output: 1
์์ solution์์ obstacle์ ๊ดํ condition๋ค๋ง ์กฐ๊ธ ๋ ์ถ๊ฐํด์ฃผ์๋ค.
์ฃผ์ด์ง obstacleGrid๋ฅผ dp๋ก ๋ฎ์ด์์ ๊ณ์ฐํ๋๊ฒ ํน์ง์ด๋ค
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
if (obstacleGrid[0][0] == 1)
return 0;
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
// reuse the obstacleGrid as the dp calculation matrix
obstacleGrid[0][0] = 1; //the start point initialized as 1
// the first row
for (int i = 1; i < m; i++) {
// if the current cell has the obstacle (has 1 in the cell)
// or the previous cell had 0 path to the cell
// (means there was a obstacle during this straight path journey)
if (obstacleGrid[i][0] == 1 || obstacleGrid[i-1][0] == 0)
obstacleGrid[i][0] = 0;
else
obstacleGrid[i][0] = 1;
}
// the first column
for (int j = 1; j < n; j++) {
// ์ฌ๊ธฐ๋ ์์๋ ๋๊ฐ์ด
// ํ์ฌ cell์ ์ฅ์ ๋ฌผ์ด ์๊ฑฐ๋ ํน์
// ์ด์ cell์ด 0์ผ๋ก mark๋์ด์๋ค๋ฉด ์ฅ์ ๋ฌผ์ด ์ ์ ์ด๋๊ฐ์ ์๋๋จ ๋ป
if (obstacleGrid[0][j] == 1 || obstacleGrid[0][j-1] == 0)
obstacleGrid[0][j] = 0;
else
obstacleGrid[0][j] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1) {
obstacleGrid[i][j] = 0;
} else {
obstacleGrid[i][j] = obstacleGrid[i-1][j] + obstacleGrid[i][j-1];
}
}
}
return obstacleGrid[m-1][n-1];
}
};
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security systems connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given an integer array nums
representing the amount of money of each house, return the maximum amount of money you can rob tonight without alerting the police.
Example 1:
Input: nums = [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
Example 2:
Input: nums = [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
Total amount you can rob = 2 + 9 + 1 = 12.
class Solution {
public:
int rob(vector<int>& nums) {
int prev = 0;
int curr = 0;
int next = 0;
for (int i = 0; i < nums.size(); i++) {
next = max(prev + nums[i], curr);
prev = curr;
curr = next;
}
return curr;
}
};
same as the previous question, except for that the house is are placed in a circle
์ง์ด ๋๊ทธ๋๊ฒ ์ด์ด์ ธ ์์ผ๋ฏ๋ก ๋ง์ง๋ง์ง์ robํ๋ค๋ฉด ์ฒซ๋ฒ์งธ ์ง์ robํด์๋ ์๋๋ค
class Solution {
public:
int rob(vector<int>& nums) {
int n = nums.size();
if (n == 1) return nums[0];
// ๋ง์ฝ ์ฒซ๋ฒ์ฌ ์ง์ robํ๋ค๋ฉด ๋งจ ๋ง์ง๋ง ์ง์ ํ๋ณด์์ ์ ์ธ
int from_0 = robber(nums, 0, n - 1);
// ์ฒซ๋ฒ์งธ ์ง์ robํ์ง ์๋๋ค๋ฉด ๋ง์ง๋ง์ง๋ robํ ๊ฐ๋ฅ์ฑ ์ด์ด๋
int from_1 = robber(nums, 1, n);
return max(from_0, from_1);
}
private:
int robber(vector<int>& nums, int start, int end) {
int prev = 0; // 2before
int curr = 0; // 1before
int next = 0; // current
for (int i = start; i < end; i++) {
next = max(prev + nums[i], curr);
prev = curr;
curr = next;
}
return curr;
}
};
You are given an integer array prices
where prices[i]
is the price of a given stock on the ith
day.
On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. However, you can buy it then immediately sell it on the same day.
Find and return the maximum profit you can achieve.
Example 1:
Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Total profit is 4 + 3 = 7.
Example 2:
Input: prices = [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Total profit is 4.
Example 3:
Input: prices = [7,6,4,3,1]
Output: 0
Explanation: There is no way to make a positive profit, so we never buy the stock to achieve the maximum profit of 0.
์๊ฐํด๋ณด๋ฉด ๊ณ์ ๊ฐ์ด ์ค๋ฅธ๋ค๊ณ ๋ณผ ๋
์ด ๋๊ฐ์ด ๊ฒฐ๊ตญ ๊ฐ์ profit์ด๋ค
ํ๊ณณ์์ ๋ฐ๋ก ๋ค์ ์ด ์ ์๋ค๋ ์กฐ๊ฑด์ด ์๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฅ ํ ์ผ์ด๋ค
๋ ๊ฐ์ด ๋ด๋ ค๊ฐ๋ค๋ฉด ํ์ง ์์ ๊ฒ์ด๋๊น ์ฌ๋ผ๊ฐ๋ ๊น์ง ๋๊ธฐํ๋ค
๊ณ์ ๋ด๋ ค๊ฐ๋ค๊ฐ ๊ฐ์ด ์ฌ๋ผ๊ฐ๋ค๋ฉด ๊ณ์ ๋ด๋ ค๊ฐ ๋ง์ง๋ง ๊ฐ์ด ์ ์ผ ์์ ๊ฐ์ด๋ฏ๋ก ๊ฑฐ๊ธฐ์ ์ฌ์ ๋ค์๋ ํ๋ฉด ๊ทธ๊ฒ max profit์ด๋ค
๊ทธ๋ฌ๋ฏ๋ก ํ๋ฃจ ์ฐจ์ด๋ก ์ฃผ์์ ์ฌ๊ณ ํ๊ณ ๋ฅผ ๋ฐ๋ณตํด์ positive number๋ฉด profit์ ๊ณ์ ๋ํด์ฃผ๋ฉด ๋๋ค
class Solution {
public:
int maxProfit(vector<int>& prices) {
int profit = 0;
int n = prices.size();
for (int i = 1; i < n; i++) {
profit += max(0, prices[i] - prices[i-1]);
}
return profit;
}
};
You are given an array prices
where prices[i]
is the price of a given stock on the ith
day.
Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions:
Note: You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).
Example 1:
Input: prices = [1,2,3,0,2]
Output: 3
Explanation: transactions = [buy, sell, cooldown, buy, sell]
Example 2:
Input: prices = [1]
Output: 0
Consider the different profits if we buy, sell, or cooldown on Day i
.
Use 3 variables to track max profits if our last action is to buy, sell, or cooldown TILL Day i
.
Be careful about what action we took TILL Day i-1
,
if we choose to do certain actions ON Day i
.
Buy today
โ the last action till yesterday MUST BE cooldown
compare: cooldown yesterday and buy today
vs. max profit yesterday when the last action is to buy (keeping 'buy' status)
Sell today
โ the last action till yesterday MUST BE buy
compare: sell the stock based on the last buy
vs. max profit yesterday when the last action is to sell (keeping 'sell' status)
Cooldown today
โ the last action till yesterday MUST BE sell OR cooldown
compare: max profit yesterday when the last actioin is sell
vs. max profit yesterday when the last action is cooldown
We always need to check if we decide to buy/sell/cooldown today, can we earn more profit than yesterday, if not, we will give up and remain the max profit we met so far.
class Solution {
public:
int maxProfit(vector<int>& prices) {
if (prices.size() <= 1) return 0;
// max profit value for each of the actions from yesterday
int cooled = 0;
int sold = 0;
int bought = 0;
//on the first day, the only choice is to buy
bought -= prices[0];
for (int i = 1; i < prices.size(); i++) {
int cooled_temp = cooled;
int sold_temp = sold;
int bought_temp = bought;
bought = max(cooled_temp - prices[i], bought_temp);
sold = max(bought_temp + prices[i], sold_temp);
cooled = max(sold_temp, cooled_temp);
}
return max(sold, cooled); //only can do sell or cooldown on the lastday
}
};
Given a string s
and a dictionary of strings wordDict
, return true
if s
can be segmented into a space-separated sequence of one or more dictionary words.
Note that the same word in the dictionary may be reused multiple times in the segmentation.
Example 1:
Input: s = "leetcode", wordDict = ["leet","code"]
Output: true
Explanation: Return true because "leetcode" can be segmented as "leet code".
Example 2:
Input: s = "applepenapple", wordDict = ["apple","pen"]
Output: true
Explanation: Return true because "applepenapple" can be segmented as "apple pen apple".
Note that you are allowed to reuse a dictionary word.
Example 3:
Input: s = "catsandog", wordDict = ["cats","dog","sand","and","cat"]
Output: false
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
// store the words from dictionary to hash for constant lookup
unordered_set<string> word_dict;
for (int i = 0; i < wordDict.size(); i++) {
word_dict.insert(wordDict[i]);
}
int n = s.size();
vector<bool> dp(n + 1);
// dp์์ true๋ฅผ ๊ธฐ์ค์ผ๋ก new substring์ ์์ํ๊ธฐ ๋๋ฌธ์
// ์ฒซ๋ฒ์งธ letter์์ true๋ก ์ง์ ํด์ฃผ์ด์ผ ํ๋ค
dp[0] = true;
// let's process the string bottom up
for (int i = 1; i <= n; i++) {
for (int j = i-1; j >= 0; j--) {
if (dp[j]) {
// dp[j] == true ์ด๋ฉด s[0:j]๊ฐ segmented ๋ ์ ์๋ค๋ ๊ฒ์ด๊ณ ,
// s[0:j]์์ ๋๊ณ ,
// s[j:]๋ถํฐ matching์ ์์ํด์ผ ๋๋ค!
string substring = s.substr(j, i - j); //substr(starting index, length)
if (word_dict.find(substring) != word_dict.end()) {
// if this substring exists in the dictionary
dp[i] = true; // meaning that s[j:i+1] exists in the dict
break;
}
}
}
}
return dp[n];
}
};
You are given an integer array coins
representing coins of different denominations and an integer amount
representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Example 3:
Input: coins = [1], amount = 0
Output: 0
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
// each index in dp represents the remainder
// dp[i] will represent minimum # of coins to fulfill the corresponding remainder amount
vector<int> dp(amount + 1, amount + 1); // initialize #coins to max number
// cannot initialize with INT_MAX,
// because we perfrom + 1 operation when taking min
// to fulfill 0 cost, we need 0 coins
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int c = 0; c < coins.size(); c++) {
if (i >= coins[c]) { //if this coin fits into remainder amount
// update current dp such that is the minimum between
// the current dp
// or
// when using this coin
dp[i] = min(dp[i], dp[i - coins[c]] + 1);
}
}
}
if (dp[amount] == amount + 1) return -1;
return dp[amount];
}
};
You are given an integer array coins
representing coins of different denominations and an integer amount
representing a total amount of money.
Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0
.
Example 1:
Input: amount = 5, coins = [1,2,5]
Output: 4
Explanation: there are four ways to make up the amount:
5=5
5=2+2+1
5=2+1+1+1
5=1+1+1+1+1
Example 2:
Input: amount = 3, coins = [2]
Output: 0
Explanation: the amount of 3 cannot be made up just with coins of 2.
class Solution {
public:
int change(int amount, vector<int>& coins) {
int n = coins.size();
// sort coins vector
sort(coins.begin(), coins.end());
vector<vector<int>> dp(amount + 1, vector<int>(n));
// initialize the basecase
for (int j = 0; j < n; j++) {
dp[0][j] = 1;
}
for (int i = 1; i <= amount; i++) {
for (int j = n - 1; j >= 0; j--) {
if (coins[j] > i) {
dp[i][j] = 0;
} else {
dp[i][j] += dp[i - coins[j]][j]; // comb. using this coin
if (j != n - 1)
dp[i][j] += dp[i][j+1]; // ALL the other comb. w/o using this coin
}
}
}
return dp[amount][0];
}
};
Given a string w/ only digits, return # ways to decode it (letter โ digit)
s = "12" -> 2 (AB 1 2 or L 12)
s = "226" -> 3 (2 26 or 22 6 or 2 2 6)
class Solution {
public:
int numDecodings(string s) {
if (s[0] == '0') {
return 0;
}
int n = s.size();
vector<int> dp(n + 1);
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
int ones = stoi(s.substr(i - 1, 1));
if (ones > 0) {
dp[i] += dp[i - 1];
}
int tens = stoi(s.substr(i - 2, 2));
if (tens >= 10 && tens <= 26) {
dp[i] += dp[i - 2];
}
}
return dp[n];
}
};
Given a non-empty array nums
containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
Example 1:
Input: nums = [1,5,11,5]
Output: true
Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:
Input: nums = [1,2,3,5]
Output: false
Explanation: The array cannot be partitioned into equal sum subsets.
์ผ๋จ nums
๊ฐ 2๊ฐ์ ๊ฐ์ ํฉ์ ๊ฐ์ง subset์ผ๋ก ๋๋ ์ง ์ ์๋์ง ํ์ธ์ด ํ์ํ๋ค
โ ๋ชจ๋ ์ซ์๋ฅผ ๋ค ๋ํ์ ๋(=sum) ์ผ๋จ ์ง์๋ผ๋ฉด ๊ฐ๋ฅ์ฑ์ ์๋๊ฒ
(ํ์๋ผ๋ฉด ๋ฐ๋ก return false, ๋๊ฐ๋ก ๋๋ ์ง ์ ์๋ค)
์ด์ ๊ตฌํ sum์ ์ด๋ฑ๋ถํ ๊ฐ์ target
์ผ๋ก ์ ํด๋๊ณ ,
nums
์ ์ซ์๋ค๋ก ๋ง๋ค ์ ์๋ ๋ชจ๋ ๊ฐ๋ฅํ subset์ ๊ฐ๊ฐ์ sum์ ๊ตฌํ๋ค
์ด์ค์ target
์ด ์๋ค๋ฉด true, ์๋๋ผ๋ฉด false๋ฅผ returnํ๋ค
class Solution {
public:
bool canPartition(vector<int>& nums) {
int target = 0;
for (int i = 0; i < nums.size(); i++) {
target += nums[i];
}
if (target % 2 == 1)
return false;
target /= 2;
// now find each and every subset's sum
// and store into hashset
unordered_set<int> subset_sums;
subset_sums.insert(0);
for (int i = 0; i < nums.size(); i++) {
unordered_set<int> _subset_sums;
for (auto it = subset_sums.begin(); it != subset_sums.end(); it++) {
if (*it + nums[i] == target) {
// the target reached
return true;
}
// for each of the subset sums generated so far,
// we will add nums[i] to those subset sums
// to store the subset sums using nums[i]
_subset_sums.insert(*it + nums[i]);
_subset_sums.insert(*it); // since we are generating new _subset_sum
// need to do this because of the for loop on subset_sum
}
subset_sums = _subset_sums;
}
// when here, target sum wasn't created in the subset sum
return false;
}
};
Given two strings text1
and text2
, return the length of their longest common subsequence. If there is no common subsequence, return 0
.
Example 1:
Input: text1 = "abcde", text2 = "ace"
Output: 3
Explanation: The longest common subsequence is "ace" and its length is 3.
Example 2:
Input: text1 = "abc", text2 = "abc"
Output: 3
Explanation: The longest common subsequence is "abc" and its length is 3.
Example 3:
Input: text1 = "abc", text2 = "def"
Output: 0
Explanation: There is no such common subsequence, so the result is 0.
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n = text1.size();
int m = text2.size();
vector<vector<int>> dp(n+1, vector<int>(m+1)); //+1 for the basecase
for (int i = n - 1; i >= 0; i--) {
for (int j = m - 1; j >= 0; j--) {
if (text1[i] == text2[j])
dp[i][j] = dp[i+1][j+1] + 1;
else
dp[i][j] = max(dp[i+1][j], dp[i][j+1]);
}
}
return dp[0][0];
}
};
You are given an integer array nums
and an integer target
.
You want to build an expression out of nums
by adding one of the symbols '+' and '-' before each integer in nums
and then concatenate all the integers.
For example, if nums = [2, 1], you can add a '+' before 2 and a '-' before 1 and concatenate them to build the expression "+2-1".
Return the number of different expressions that you can build, which evaluates to target.
Example 1:
Input: nums = [1,1,1,1,1], target = 3
Output: 5
Explanation: There are 5 ways to assign symbols to make the sum of nums be target 3.
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
Example 2:
Input: nums = [1], target = 1
Output: 1
ํ์ฌ ์ซ์๋ฅผ ๋ํ๊ฑฐ๋ ๋นผ๊ฑฐ๋ ๋๊ฐ์ง ๊ฒฝ์ฐ๊ฐ ์๋ค๊ณ ์๊ฐํ๊ณ ์ฝ๋ฉํ๋ฉด ๊ฐ๋จํ๋ค
๊ทธ๋ ๊ฒ ์ซ์๋ฅผ ๋ํ๊ฑฐ๋ ๋บ์ ๋ ๋์ค๋ total
์ ๊ฐ์ด ๋ณด๊ดํ์
{index
, total
} โ # of ways
nums[index]
๋ฅผ ํฌํจ ํ์ ๋์ ์ํฌํจ ํ์ ๋ ์ด๋ ๊ฒ ๋๊ฐ์ง๋ก map์๋ ๊ฐ์ index๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ ๋ค์ด ๋๊ฐ๊ฐ ์๊ฒ ๋๋ค.
base case:
class Solution {
public:
int findTargetSumWays(vector<int>& nums, int target) {
return backtrack(nums, target, 0, 0);
}
private:
// {(index, total) -> # of ways}
map<pair<int, int>, int> dp;
int backtrack(vector<int>& nums, int target, int i, int total) {
if (dp.find({i, total}) != dp.end()) {
// if the value was already calculted
return dp[{i, total}];
}
// basecase when we used all the numbers
if (i == nums.size()) {
// Valid: current total is equal to target -> this is one valid expression! -> return 1
// Invlid: current total is NOT equal to target
return total == target ? 1 : 0;
}
// calculate the number of expressions if we add this number
int positive = backtrack(nums, target, i + 1, total + nums[i]);
// calculate the number of expressions if we subtract this number
int negative = backtrack(nums, target, i + 1, total - nums[i]);
// store the result to the map
dp[{i, total}] = positive + negative;
return dp[{i, total}];
}
};
๋ชจ๋ cell๋ค ๋๋ฉด์ ์, ์๋, ์ค๋ฅธ์ชฝ, ์ผ์ชฝ์์๋ถํฐ ์์ ๋ ์ค์ longest increasing path๋ฅผ ๋ถ๋ฌ์์
๋ฆฌํดํ๋ค.
dfs๋ฅผ ๊ณ์ ๋์ง ์๋๋ก cache (Dynamic Programming) ํ๋ค!
class Solution {
public:
int longestIncreasingPath(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
int result = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
result = max(result, dfs(matrix, -1, i, j, m, n));
}
}
return result;
}
private:
// {(i, j) -> longest increasing path at (i, j)}
map<pair<int, int>, int> dp;
int dfs(vector<vector<int>>& matrix, int prev, int i, int j, int m, int n) {
// prev -> stores the value from where it came from
if (i < 0 || i >= m || j < 0 || j >= n || matrix[i][j] <= prev) {
// out of bound or
// current value is less than where it came from (we are looking for increasing path)
return 0;
}
if (dp.find({i, j}) != dp.end()) {
// if already performed use it
return dp[{i, j}];
}
// current cell count as 1
int result = 1;
// for every direction find the maximum path
result = max(result, 1 + dfs(matrix, matrix[i][j], i - 1, j, m, n));
result = max(result, 1 + dfs(matrix, matrix[i][j], i + 1, j, m, n));
result = max(result, 1 + dfs(matrix, matrix[i][j], i, j - 1, m, n));
result = max(result, 1 + dfs(matrix, matrix[i][j], i, j + 1, m, n));
dp[{i, j}] = result;
return dp[{i, j}];
}
};