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

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值