Journey of LeetCode|DAY 32
Preface
This is a new day to continue my Greedy Algorithm journey.
Learn something new and keep reviewing what I learnt before.
1. Monotone Increasing Digits
LeetCode Link: 738. Monotone Increasing Digits
An integer has monotone increasing digits if and only if each pair of adjacent digits x and y satisfy x <= y.
Given an integer n, return the largest number that is less than or equal to n with monotone increasing digits.
Example 1:
Input: n = 10
Output: 9
Example 2:
Input: n = 1234
Output: 1234
Example 3:
Input: n = 332
Output: 299
Constraints:
0 <= n <= 109
Analysis and Solution
Greedy Algorithm
LeetCode C++ as followings Greedy Algorithm
class Solution {
public:
int monotoneIncreasingDigits(int N) {
string strNum = to_string(N);//int converts to string
// flag is used to mark where the assignment 9 starts
int flag = strNum.size();// Set to this default value, in order to prevent the second for loop from being executed when the flag is not assigned
for (int i = strNum.size() - 1; i > 0; i--) {//traverse from back to front
if (strNum[i - 1] > strNum[i] ) {//eg:98,9>8
flag = i;//flag=2-1=1
strNum[i - 1]--;//9-- =>8
}
}
for (int i = flag; i < strNum.size(); i++) {
strNum[i] = '9';//98=>88=>89
}
return stoi(strNum);// stoi function is to Convert n-ary string to decimal
}
};
2. Best Time to Buy and Sell Stock with Transaction Fee
LeetCode Link: 714. Best Time to Buy and Sell Stock with Transaction Fee
You are given an array prices where prices[i] is the price of a given stock on the ith day, and an integer fee representing a transaction fee.
Find the maximum profit you can achieve. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction.
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,3,2,8,4,9], fee = 2
Output: 8
Explanation: The maximum profit can be achieved by:
- Buying at prices[0] = 1
- Selling at prices[3] = 8
- Buying at prices[4] = 4
- Selling at prices[5] = 9
The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
Example 2:
Input: prices = [1,3,7,5,10,3], fee = 3
Output: 6
Constraints:
1 <= prices.length <= 5 * 104
1 <= prices[i] < 5 * 104
0 <= fee < 5 * 104
Analysis and Solution
Greedy Algorithm
LeetCode C++ as followings Greedy Algorithm
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int result = 0;
int minPrice = prices[0]; // record the lowest price
for (int i = 1; i < prices.size(); i++) {
// case 2: Equivalent to buying
if (prices[i] < minPrice) minPrice = prices[i];
// case 3: Keep the original state (because it is not cheap to buy at this time, and you will lose money if you sell)
if (prices[i] >= minPrice && prices[i] <= minPrice + fee) {
continue;
}
// Calculate the profit, there may be multiple calculations of the profit, the last calculation of the profit is the real selling
if (prices[i] > minPrice + fee) {
result += prices[i] - minPrice - fee;
minPrice = prices[i] - fee; // Case 1, this step is critical to avoid repeated deduction of handling fees
}
}
return result;
}
};
3.Binary Tree Cameras
LeetCode Link: 968. Binary Tree Cameras
You are given the root of a binary tree. We install cameras on the tree nodes where each camera at a node can monitor its parent, itself, and its immediate children.
Return the minimum number of cameras needed to monitor all nodes of the tree.
Example 1:
Input: root = [0,0,null,0,0]
Output: 1
Explanation: One camera is enough to monitor all nodes if placed as shown.
Example 2:
Input: root = [0,0,null,0,null,0,null,null,0]
Output: 2
Explanation: At least two cameras are needed to monitor all nodes of the tree. The above image shows one of the valid configurations of camera placement.
Constraints:
The number of nodes in the tree is in the range [1, 1000].
Node.val == 0
Analysis and Solution
Greedy Algorithm
LeetCode C++ as followings Greedy Algorithm
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
private:
int result;
int traversal(TreeNode* cur) {
// null node, the node is coveraged
if (cur == NULL) return 2;
int left = traversal(cur->left); // left traverse
int right = traversal(cur->right); // right traverse
// case 1
// Both left and right nodes are covered
if (left == 2 && right == 2) return 0;
// case 2
// left == 0 && right == 0 The left and right nodes are not covered
// left == 1 && right == 0 The left node has a camera, the right node is not covered
// left == 0 && right == 1 The left node is not covered, the right node has a camera
// left == 0 && right == 2 The left node is not covered, the right node is covered
// left == 2 && right == 0 The left node is covered, the right node is not covered
if (left == 0 || right == 0) {
result++;
return 1;
}
// case 3
// left == 1 && right == 2 The left node has a camera, the right node is covered
// left == 2 && right == 1 left node is coverd,right node has a camera
// left == 1 && right == 1 left node and right node have cameras
// In other cases, the previous code has been covered
if (left == 1 || right == 1) return 2;
// without else in the above code, The main purpose is to show the various branch conditions, which will help readers understand the code
// Will not run to this return -1 logic.
return -1;
}
public:
int minCameraCover(TreeNode* root) {
result = 0;
// case 4
if (traversal(root) == 0) { // root is not coverd
result++;
}
return result;
}
};