4.力扣2018年常見編程題總結(堆、棧和隊列)

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.給定一個非空的整數數組,返回其中出現頻率前 高的元素。

示例 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 內的數字。滑動窗口每次只向右移動一位。返回滑動窗口最大值。

示例:輸入: 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);
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章