刷题日记:面试经典 150 题 DAY4
42.接雨水
原题链接 42.接雨水
在学校的算法小学期做过,做法是基于一个重要的观察:
- 一列列的看,当前列雨水的高度由,左边最高墙和右边最高墙中的较小值决定
可以预先处理出前缀最大和后缀最大,这样整个做法时间和额外空间复杂度都是 O ( N ) O(N) O(N)
cpp
class Solution {
public:
int trap(vector<int>& height) {
int len = height.size();
int leftmax[len],rightmax[len];
int temp = 0;
for(int i = 0;i<len;i++) {
temp = max(temp,height[i]);
leftmax[i] = temp;
}
temp = 0;
for(int i = len-1;i>=0;i--) {
temp = max(temp,height[i]);
rightmax[i] = temp;
}
temp = 0;
for(int i = 1;i < len-1;i++) {
int wall = min(leftmax[i-1],rightmax[i+1]);
temp += max(0,wall-height[i]);
}
return temp;
}
};
学习官方题解中给出的单调栈做法:
- 维护一个单调递减的栈
- 当新入量比栈顶高时,执行出栈操作
- 将栈顶出栈,这相当于这段雨水的"底"
- 此时的栈顶的就是雨水的左边界,即将入栈的新元素为雨水的右边界
- 判断雨水的宽度: i − l e f t − 1 i-left-1 i−left−1
- 判断雨水的高度: m i n { h i , h l e f t } − h t o p min\{h_i,h_{left}\}-h_{top} min{hi,hleft}−htop
cpp
class Solution {
public:
int trap(vector<int>& height) {
stack<int> st;
int len = height.size();
int result = 0;
for(int i = 0;i < len;i++) {
while(st.size() && height[i]>height[st.top()]) {
int t = st.top();
st.pop();
if(st.empty()) {
break;
}
int left_wall = st.top();
int w = i - left_wall - 1;
int h = min(height[left_wall],height[i])-height[t];
result += h*w;
}
st.push(i);
}
return result;
}
};
13.罗马数字转整数
原题链接 13.罗马数字转整数
打表
cpp
class Solution {
public:
int romanToInt(string s) {
int map[26];
map['V'-'A'] = 5;
map['L'-'A'] = 50;
map['D'-'A'] = 500;
map['M'-'A'] = 1000;
int N = s.size();
int ans = 0;
int i = 0;
while(i < N) {
switch(s[i]) {
case 'I':
if(s[i+1] == 'V') {
ans += 4;
i += 2;
} else if(s[i+1] == 'X') {
ans += 9;
i += 2;
}
else {
ans += 1;
i += 1;
}
break;
case 'X':
if(s[i+1] == 'L') {
ans += 40;
i += 2;
} else if(s[i+1] == 'C') {
ans += 90;
i += 2;
}
else {
ans += 10;
i += 1;
}
break;
case 'C':
if(s[i+1] == 'D') {
ans += 400;
i += 2;
} else if(s[i+1] == 'M') {
ans += 900;
i += 2;
}
else {
ans += 100;
i += 1;
}
break;
default:
ans += map[s[i++]-'A'];
break;
}
}
return ans;
}
};
12.整数转罗马数字
原题链接 12.整数转罗马数字
打表
cpp
class Solution {
public:
string getOne(int n) {
switch(n) {
case 0: return "";
case 1: return "I";
case 2: return "II";
case 3: return "III";
case 4: return "IV";
case 5: return "V";
case 6: return "VI";
case 7: return "VII";
case 8: return "VIII";
case 9: return "IX";
}
return "";
}
string getTen(int n) {
switch(n) {
case 0: return "";
case 1: return "X";
case 2: return "XX";
case 3: return "XXX";
case 4: return "XL";
case 5: return "L";
case 6: return "LX";
case 7: return "LXX";
case 8: return "LXXX";
case 9: return "XC";
}
return "";
}
string getHundred(int n) {
switch(n) {
case 0: return "";
case 1: return "C";
case 2: return "CC";
case 3: return "CCC";
case 4: return "CD";
case 5: return "D";
case 6: return "DC";
case 7: return "DCC";
case 8: return "DCCC";
case 9: return "CM";
}
return "";
}
string getThousand(int n) {
switch(n) {
case 0: return "";
case 1: return "M";
case 2: return "MM";
case 3: return "MMM";
}
return "";
}
string intToRoman(int num) {
int one = num%10;
int ten = (num/10)%10;
int hundred = (num/100)%10;
int thousand = num/1000;
return getThousand(thousand)+getHundred(hundred)+getTen(ten)+getOne(one);
}
};
58.最后一个单词长度
原题链接 58.最后一个单词长度
直接从后向前遍历
cpp
class Solution {
public:
int lengthOfLastWord(string s) {
int len = s.size();
int result = 0;
int i;
for(i = len-1;s[i]==' ';i--);
for(;i>=0 && s[i] != ' ';i--,result++) ;
return result;
}
};
14.最长公共前缀
原题链接 14.最长公共前缀
横向扫描或者正向扫描,暴力
cpp
class Solution {
public:
string longestCommonPrefix(vector<string>& strs) {
string ans = {};
int len = strs[0].size();
int N = strs.size();
for(int i = 0; i < len;i++) {
for(int j = 1;j < N;j++) {
if(strs[j][i] != strs[0][i]) {
return ans;
}
}
ans.push_back(strs[0][i]);
}
return ans;
}
};
```