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);
}