- to do
- before 13.4] Maximal Square
mark: improve using rotating array
int maximalSquare(vector<vector<char>>& matrix) {
if (matrix.empty() || matrix[0].empty()) return 0;
int m = matrix.size(), n = matrix[0].size();
// dp : maxSide[i][j] stores maximalSquare's side length who uses matrix[i][j] as rightMost corner
vector<vector<int>> maxSide(m, vector<int>(n, 0));
int ret = 0;
for (int i=0; i<m; ++i) {
maxSide[i][0] = matrix[i][0]-'0';
ret = max(ret, maxSide[i][0]);
}
for (int j=0; j<n; ++j) {
maxSide[0][j] = matrix[0][j]-'0';
ret = max(ret, maxSide[0][j]);
}
for (int i=1; i<m; ++i) {
for (int j=1; j<n; ++j) {
if (matrix[i][j]!='0') {
int m1 = maxSide[i][j-1], m2 = maxSide[i-1][j], minm = min(m1, m2);
maxSide[i][j] = minm + (matrix[i-minm][j-minm]-'0');
ret = max(ret, maxSide[i][j]);
}
}
}
return ret*ret;
}
- again Largest Rectangle in Histogram
- 1) 改進(jìn)的暴力 O(n)?
- 最原始的暴力是從左往右遍歷,當(dāng)前ith whole bar為左界限,向右延伸找第一個(gè)矮于自己的; 算出面積。O(n^2)
- 或者另一種想法,最大矩形必然包含了某一個(gè)立柱的全部。所以遍歷是向左右延伸,算用了當(dāng)前立柱的最大面積。(所以當(dāng)前立柱是rect內(nèi)最低高度)
- 所以每一步想要知道lefti of 向左延伸遇到的第一個(gè)比自己矮的立柱,以及righti同理。所以
area = heights[i] * (righti-lefti-1)
。 這里又有兩種辦法- dp 兩遍遍歷構(gòu)建leftIndex[], rightIndex[]
-
用非遞減stack來(lái)找lefti/righti
先說(shuō)stack的辦法:
- 所以每一步想要知道lefti of 向左延伸遇到的第一個(gè)比自己矮的立柱,以及righti同理。所以
- 考慮非遞減的array【1,4,5,5,7,9】,如果算用了當(dāng)前立柱的最大面積,很簡(jiǎn)單只需要從右往左遍歷,記住incremental的寬度n-i,乘以height[i]得到面積。(雖然在重復(fù)值情況中,【n-2】的5不會(huì)得到最大值,但是最左邊的重復(fù)值會(huì)保證捕捉最大值)
-
如果在1的基礎(chǔ)上加上一個(gè)違反規(guī)律更小的6 => array【1,4,5,5,7,9,6】
===========我是啟動(dòng)畫(huà)面(xia)感(che)的分割線==============
順序的大人的看到了小矮紅i的加入,之前的簡(jiǎn)單算法hold不住了,暫停下遍歷來(lái)觀察下:
發(fā)現(xiàn)在小矮紅線以上的那些高柱其實(shí)找到了righti就是i,換而言之小矮成了高柱們一輩子的短板限制,sad;而小矮呢,它的lefti并不關(guān)心高柱們有多高多厲害,而是向左第一個(gè)比小矮還矮的柱子2hhh。
既然互不關(guān)心一拍即合,那么高柱們就退場(chǎng)了,但別漏了當(dāng)maxArea的可能性啊,所以退場(chǎng)前算一下Area:height[self] * (i-lefti-1)
where lefti = s.empty()? i : s.top()
.
退場(chǎng)結(jié)束。
終于又回到非遞增的規(guī)則世界~可是退場(chǎng)的高柱會(huì)影響未來(lái)的面積記錄突破嗎?小矮說(shuō) 不會(huì)的,即使高柱在,未來(lái)我右邊的每個(gè)柱子往左延伸都要經(jīng)過(guò)我這一關(guān),別忘了我是他們的短板。
那好,別忘了所有柱子都要算面積,元素都是算了面積再被pop,意思是stack最后要清空。當(dāng)然可以加一個(gè)while not empty{loop},或者巧妙的
resume遍歷
- 所以這道題和Maximal Rect相通之處就是可以把平面看做大矩陣,條形看做1,非條形看做0,尋找最大全1矩陣。
- reference
public:
// 暴力
int largestRectangleArea(vector<int>& heights) {
if (heights.empty()) return 0;
int n = heights.size();
vector<int> h(n+2, -1);
// left[i] gives the index of farthest reachable bar on the LHS
vector<int> left(n+1, -1);
vector<int> right(n+2, -1);
//往左找第一個(gè)比自己矮的
for (int i=1; i<=n; ++i) {
int k = i;
//比自己高就繼續(xù)找
while (h[i] <= h[k-1]) k = left[k-1];
left[i] = k;
}
for (int i=n; i>0; --i) {
int k = i;
//比自己高就繼續(xù)找
while (h[i] <= h[k+1]) k = right[k+1];
right[i] = k;
}
int ret = 0;
for (int i=1; i<=n; ++i) {
ret = max(ret, h[i]*(right[i]-left[i]+1));
}
return ret;
}
- 2) using stack
int largestRectangleArea(vector<int>& heights) {
int ret = 0, n = heights.size();
stack<int> s;
// want to calculate maxarea using the whole heights[i]
// meaning: extend farthest to left, find first bar < heights[i]; same to right
int i=0;
while (i<n) {
if (s.empty() || heights[i]>=heights[s.top()]) {
s.push(i++);
} else {
// calculate area of bar w/ heights[tp] as height
int tp = s.top();
s.pop();
int width = s.empty()? i : i-s.top()-1;
ret = max(ret, width*heights[tp]);
}
}
while (!s.empty()) {
// calculate area of bar w/ heights[tp] as height
int tp = s.top();
s.pop();
int width = s.empty()? i : i-s.top()-1;
ret = max(ret, width*heights[tp]);
}
return ret;
}
13.5] Best Time to Buy and Sell Stock III
lalala
開(kāi)始忘記stockI解dp存的是當(dāng)天賣會(huì)得到的收入,而非當(dāng)前最佳收入。
int maxProfit(vector<int>& prices) {
int n = prices.size();
if (n<2) return 0;
// build dp1: dp1[i] gives maxProfit so far of period [0-i]
int minSoFar = prices[0], maxP = 0;
vector<int> dp1(n, -1);
for (int i=0; i<n; ++i) {
minSoFar = min(minSoFar, prices[i]);
maxP = max(maxP, prices[i] - minSoFar);
dp1[i] = maxP;
}
// build dp2: dp2[i] gives maxProfit so far of period [i-(n-1)]
int maxSoFar = prices[n-1];
maxP = 0;
vector<int> dp2(n, -1);
for (int i=n-1; i>=0; --i) {
maxSoFar = max(maxSoFar, prices[i]);
maxP = max(maxP, maxSoFar - prices[i]);
dp2[i] =maxP;
}
// dp2[n] = 0
dp2.push_back(0);
// build dp3:
int maxRet = INT_MIN;
for (int k=0; k<n; ++k) {
maxRet = max(maxRet, dp1[k] + dp2[k+1]);
}
return maxRet;
}
- naive recursive method
bool isInterleave(string s1, string s2, string s3) {
if (s3.size() != s1.size() + s2.size()) return false;
if (s2.empty()) return s1.compare(s3)==0;
if (s1.empty()) return s2.compare(s3)==0;
if (s1[0]!=s3[0] && s2[0]!=s3[0]) return false;
bool ret = false;
if (s1[0]==s3[0]) ret = ret || isInterleave( s1.substr(1, s1.size()-1), s2, s3.substr(1, s3.size()-1) );
if (s2[0]==s3[0]) ret = ret || isInterleave( s1, s2.substr(1, s2.size()-1), s3.substr(1, s3.size()-1) );
return ret;
}
- better dp
Make sure understand what the memo structure holds and where the bound is. Follow the equation at all time. Bug when I wasn't clear what the boundry means and another bug see comment below.
bool isInterleave(string s1, string s2, string s3) {
if (s1.size()+s2.size() != s3.size()) return false;
if (s3.empty()) return true;
int m = s1.size(), n = s2.size(), l = s3.size();
vector<vector<bool>> dp(m+1, vector<bool>(n+1, false));
dp[m][n] = true;
for (int i=m-1; i>=0; --i) dp[i][n] = dp[i+1][n] && s1[i]==s3[i+n];
for (int j=n-1; j>=0; --j) dp[m][j] = dp[m][j+1] && s2[j]==s3[m+j];
for (int i=m-1; i>=0; --i) {
for (int j=n-1; j>=0; --j) {
int k = i+j;
if (s3[k]==s1[i] || s3[k]==s2[j]) {
dp[i][j] = (s3[k]==s1[i] && dp[i+1][j]) ||
(s3[k]==s2[j] && dp[i][j+1]);
}
}
}
return dp[0][0];
}