1.设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。
- push(x) -- 将元素 x 推入栈中。
- pop() -- 删除栈顶的元素。
- top() -- 获取栈顶元素。
- getMin() -- 检索栈中的最小元素
解:前四个操作均可以使用stack来完成,检索最小元素,需要重新用一个新的stack来存储每次压入元素的最小值。
代码:
using namespace std;
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
s.push(x);
if (s_min.empty() || x <= s_min.top())
{
s_min.push(x);//同时将元素压入另外一个栈中
}
}
void pop() {
if (s.top() == s_min.top())
{
s_min.pop();
}
s.pop();
}
int top() {
return s.top();
}
int getMin() {
return s_min.top();
}
private:
stack<int> s;
stack<int> s_min;
};
int main()
{
MinStack *obj = new MinStack();
obj->push(-2);
obj->push(0);
obj->push(-1);
cout << obj->getMin() << endl;
return 1;
}
2.在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
解:找出第k个最大的数据,即先用降序进行排序再输出。
代码:
using namespace std;
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
sort(nums.begin(), nums.end(), greater<int>());
return nums[k - 1];
}
};
int main()
{
vector<int> a = { 3,2,3,1,2,4,5,5,6 };
Solution s1;
cout << s1.findKthLargest(a,4) << endl;
return 1;
}
3.中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
代码:
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder()
{
}
void addNum(int num)
{
if (min_heap.size() == 0 || num <= min_heap.top())
min_heap.push(num);
else if (max_heap.size() == 0 || num >= max_heap.top())
max_heap.push(num);
else {
if (max_heap.size() < min_heap.size())
max_heap.push(num);
else
min_heap.push(num);
}
int diff = min_heap.size() - max_heap.size();
if (abs(diff) > 1) {
if (max_heap.size() > min_heap.size()) {
min_heap.push(max_heap.top());
max_heap.pop();
}
else {
max_heap.push(min_heap.top());
min_heap.pop();
}
}
}
double findMedian()
{
if (max_heap.size() == min_heap.size())
return (max_heap.top() + min_heap.top()) / 2.0;
else if (max_heap.size() > min_heap.size())
return max_heap.top();
else
return min_heap.top();
}
private:
priority_queue<int, vector<int>, greater<int>> max_heap;//优先队列,最大值在队首
priority_queue<int, vector<int>, less<int>> min_heap;//创建优先队列,最小值在队首
};
int main()
{
vector<int> a = { 2,3,4 };
MedianFinder s1;
s1.addNum(1);
s1.addNum(2);
//s1.addNum(3);
cout << s1.findMedian()<< endl;
return 1;
}
4.给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。
请注意,它是排序后的第k小元素,而不是第k个元素。
示例:matrix = [ [ 1, 5, 9], [10, 11, 13], [12, 13, 15] ], k = 8, 返回 13。
解:因为要输出第k个大的元素,可以考虑用优先对列来完成,即每插入一个元素就进行依次排序。
代码:
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int len = matrix.size();
priority_queue<int> q;
for (int i = 0; i < len; i++)
{
for (int j = 0; j < len; j++)
{
q.push(matrix[i][j]);
if (q.size()>k)
{
q.pop();
}
}
}
return q.top();
}
};
int main()
{
Solution s1;
vector<vector<int>> p = { {1,2,3},{2,3,4},{4,5,6} };
std::cout << s1.kthSmallest(p,4);
}
5.给定一个非空的整数数组,返回其中出现频率前 k 高的元素。
示例 1:输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]
解:利用map存储每个次出现的次数。在将其放入vector中进行排序,在取出前面k个
代码:
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
map<int, int> record;
vector<pair<int, int>> record2;
vector<int>result;
for (int i = 0; i < nums.size(); i++)
record[nums[i]]++;
for (auto i = record.begin(); i !=record.end(); i++)
{
record2.push_back(pair<int, int>(i->second, i->first));
}
sort(record2.begin(), record2.end());
for (int i = record2.size()-1; i >=0&&k>0; i--,k--)
{
result.push_back(record2[i].second);
}
return result;
}
};
int main()
{
Solution s1;
vector<int> p = { 1,1,1,2,2,3 };
std::cout << s1.topKFrequent(p,4)[0];
}
6.给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口 k 内的数字。滑动窗口每次只向右移动一位。返回滑动窗口最大值。
示例:输入: nums = [1,3,-1,-3,5,3,6,7]
, 和 k = 3 输出: [3,3,5,5,6,7]
解:通过利用双端序列来进行索引的增加与删除
代码:
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> q;
vector<int>res;
for (int i = 0; i < nums.size(); i++)
{
if (!q.empty() && q.front() == i - k)
q.pop_front();
while (!q.empty() && nums[q.back()] < nums[i])
q.pop_back();//弹出当前的索引
q.push_back(i);
if (i >= k - 1)//长度超过k
res.push_back(nums[q.front()]);
}
return res;
}
};
int main()
{
Solution s1;
vector<int> p = { 1,3,-1,-3,5,3,6,7 };
std::cout << s1.maxSlidingWindow(p,3)[0];
}
7.实现一个基本的计算器来计算一个简单的字符串表达式的值。字符串表达式仅包含非负整数,+
, -
,*
,/
四种运算符和空格 。 整数除法仅保留整数部分。
解:从字符串中取出数字与运算符号,一旦遇到运算符则将数字要入栈中。
代码:
class Solution {
public:
int calculate(string s) {
stack<int> tmp;
char sign = '+';
int value = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] <= '9' && s[i] >= '0') {
value *= 10;
value += s[i] - '0';
}
if ((s[i] != ' ' && (s[i] <'0' || s[i]>'9')) || i == (s.length() - 1)) {
if (sign == '+') {
tmp.push(value);
}
else if (sign == '-') {
tmp.push(-value);
}
else if (sign == '*') {
int num = tmp.top() * value;
tmp.pop();
tmp.push(num);
}
else if (sign == '/') {
int num = tmp.top() / value;
tmp.pop();
tmp.push(num);
}
sign = s[i];
value = 0;
}
}
int res = 0;
while (!tmp.empty()) {
res += tmp.top();
tmp.pop();
}
return res;
}
};
int main()
{
Solution s1;
vector<int> p = { 1,3,-1,-3,5,3,6,7 };
std::cout << s1.calculate("2+3*3");
}
8.根据逆波兰表示法,求表达式的值。有效的运算符包括 +
, -
, *
, /
。每个运算对象可以是整数,也可以是另一个逆波兰表达式。
解:如果当前字符为变量或者为数字,则压栈,如果是运算符,则将栈顶两个元素弹出作相应运算,结果再入栈,最后当表达式扫描完后,栈里的就是结果。
代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
if (tokens.empty())return 0;
stack<int>s;
int a, b;
for (int i = 0; i < tokens.size(); ++i) {
if (tokens[i] != "+" && tokens[i] != "-" && tokens[i] != "*" && tokens[i] != "/")
s.push(stoi(tokens[i]));//将字符串转为数字并压栈
else {
//遇到运算符则弹出两个栈顶数据进行计算,将计算结果重新压栈
a = s.top();
s.pop();
b = s.top();
s.pop();//弹出两个数据
if (tokens[i] == "+")
s.push(a + b);
else if (tokens[i] == "*")
s.push(a*b);
else if (tokens[i] == "-")
s.push(b - a);
else if (tokens[i] == "/")
s.push(b / a);
}
}
return s.top();//返回栈顶元素
}
};
int main()
{
Solution s1;
vector<string> p = { "10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+" };
std::cout << s1.evalRPN(p);
}