352. Data Stream as Disjoint Intervals
题目
Given a data stream input of non-negative integers a1, a2, …, an, …, summarize the numbers seen so far as a list of disjoint intervals.
For example, suppose the integers from the data stream are 1, 3, 7, 2, 6, …, then the summary will be:
[1, 1] [1, 1], [3, 3] [1, 1], [3, 3], [7, 7] [1, 3], [7, 7] [1, 3], [6, 7]
Follow up:
What if there are lots of merges and the number of disjoint intervals are small compared to the data stream’s size?
解决思路
这道题解到一般的时候, 在 arr.push_back(Interval) 的时候, 突然想起了浅拷贝,深拷贝的问题.这里再来复习一遍.
简单的来说,【浅拷贝】是增加了一个指针,指向原来已经存在的内存。而【深拷贝】是增加了一个指针,并新开辟了一块空间让指针指向这块新开辟的空间。
【浅拷贝】在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误.
当一个类里面只有基本类型的时候(不带指针的时候),就无所谓浅拷贝深拷贝了,因为都是值的复制,但是如果一个类里面有类似于 char *s
的变量的时候, 浅拷贝和深拷贝的区别就区分出来了.
而 vector.push_back(const _Ty& _Val)
是调用了对象的拷贝复制函数,所以push_back的拷贝方式是由你自己对象的拷贝方式决定的.
参考链接: stl中push_back的拷贝方式
c++浅拷贝和深拷贝
回到题目本身,思路很简单,就是维护一个排序好的interval,然后再二分查找
代码
int binarySearch(vector<Interval>& arr, int begin, int end, int val){
// 找出第一个arr[index].begin >= val的index, 没有返回-1
if (arr[end].start < val) return -1;
while(begin < end){
int mid = (begin+end) >> 1;
if(val >= arr[mid].start)
begin = mid +1;
else if(val < arr[mid].start)
end = mid;
}
if(arr[begin].start > val)
return begin;
else return -1;
}
class SummaryRanges {
public:
/** Initialize your data structure here. */
vector<Interval> arr;
SummaryRanges() {
}
void addNum(int val) {
if( arr.empty() ){
arr.push_back(Interval(val, val));
return ;
}
int index = binarySearch(arr, 0, arr.size()-1, val);
if(index == -1){
if( arr[arr.size() - 1].end >= val) return;
else if(arr[arr.size() - 1].end + 1 == val ){
arr[arr.size() - 1].end = val;
}
else
arr.push_back(Interval(val, val));
}
else if (index == 0){
if( arr[0].start == val + 1) arr[0].start = val;
else arr.insert(arr.begin(), Interval(val, val));
}
else{
if( val + 1 == arr[index].start && val == arr[index - 1].end + 1){
arr[index].start = arr[index-1].start;
arr.erase(arr.begin() + index - 1);
}
else if( val + 1 == arr[index].start ){
arr[index].start = val;
}
else if( val == arr[index - 1].end + 1) {
arr[index - 1].end = val;
}
else if( val <= arr[index - 1].end ){
return;
}
else {
arr.insert(arr.begin() + index, Interval(val, val));
}
}
}
vector<Interval> getIntervals() {
return arr;
}
};
449. Serialize and Deserialize BST
问题
Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.
Design an algorithm to serialize and deserialize a binary search tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary search tree can be serialized to a string and this string can be deserialized to the original tree structure.
The encoded string should be as compact as possible.
Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms should be stateless.
分析
一开始以为是普通的树进行序列化,那这样的话考虑的是通过记录 length, pre_order, in_order
来达到目的,然后反序列化的时候根据这三个字段来生成一个树。
但是因为这棵树是BST, 本身就有一定的规则限制,所以直接通过pre_order
就可以实现了。在反序列化的时候,较为巧妙地用到了栈这个数据结构。考虑到了FIFO这个特性。
代码
class Codec {
public:
// Encodes a tree to a single string.
string serialize(TreeNode* root) {
if( root == nullptr ) return "";
string tmp = to_string(root->val);
if(root->left)
tmp += "/" + serialize(root->left);
if(root->right)
tmp += "/" + serialize(root->right);
return tmp;
}
// Decodes your encoded data to tree.
TreeNode* deserialize(string data) {
stack<TreeNode*> nodeStack;
if(data == "") return nullptr;
// 获得第一个数字。 作为root节点。
// 放入stack中,获得下一个数字,如果小,插入左节点, 如果大,则弹出stack
int index = 0;
TreeNode* root = nullptr, *newNode, *topNode;
while(index < data.size()){
int num = 0;
// acquire first digit
while(index < data.size() && data[index] != '/'){
num *= 10;
num += data[index] - '0';
++index;
}
// skip "/"
++index;
if(nodeStack.empty()){
root = new TreeNode(num);
nodeStack.push(root);
}
else if(!nodeStack.empty()){
newNode = new TreeNode(num);
topNode = nodeStack.top();
if( num < topNode->val ){
topNode->left = newNode;
nodeStack.push(newNode);
}
else{
while( !nodeStack.empty() && num >= nodeStack.top()->val ){
topNode = nodeStack.top();
nodeStack.pop();
}
topNode->right = newNode;
nodeStack.push(newNode);
}
}
}
return root;
}
};
714. Best Time to Buy and Sell Stock with Transaction Fee
题目
Your are given an array of integers prices
, for which the i
-th element is the price of a given stock on day i
; and a non-negative integer fee
representing a transaction fee.
You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)
Return the maximum profit you can make.
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.
Note:
0 < prices.length <= 50000
.0 < prices[i] < 50000
.0 <= fee < 50000
.
分析
无意中刷到了 Morgan Stanly 终面 on-site 的一道面试题。当时面试的时候没考虑到手续费的问题(也算是没弄清楚问题)
这题最重要的就是弄清楚每个点只有两种状态:买入和售出
。
刚开始想这道题的时候,一直想着要通过一个变量来保存之前买的股票的价格 p1 ,然后卖出的时候再通过做差 p2 - p1
来计算利润。
但是换种思路会简单很多,炒股的时候可能也应该有这种心态,叫沉没成本:就是你当初购买股票的钱已经花出去了,是已经固定的成本,接下来的决策就应该针对当前市面价格,做出决策,在价格最高的时刻卖出去,即便可能这个价格比当初买的价格还低。
如果这么来想的话,就应该通过 balance 来记录自己现有的钱。 买入就是 balance - p1, 卖出就是 balance + p2 。然后又因为购买的规则,一天只能进行一个操作。那么可以想到用 DP
来解决这个问题:
用sold[i]
, hold[i]
分别代表第i天进行卖出,买入操作的最大获益,那么状态转移方程是:
sold[i] = max(sold[i-1], hold[i-1] + p[i] - fee)
hold[i] = max(hold[i-1], sold[i-1] - p[i])
代码
typedef long long LL;
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
// init sold[0], hold[0]
// sold[i] = max(sold[i-1], hold[i-1] + p[i] - fee)
// hold[i] = max(hold[i-1], sold[i-1] - p[i])
LL sold[prices.size()], hold[prices.size()];
sold[0] = 0;
hold[0] = 0 - prices[0];
LL ans = 0;
for (int i = 1 ; i < prices.size() ; ++i){
sold[i] = max(sold[i-1], hold[i-1] + prices[i] - fee);
hold[i] = max(hold[i-1], sold[i-1] - prices[i]);
if ( sold[i] > ans ) ans = sold[i];
}
return ans;
}
};