栈的压入、弹出序列
题目描述:输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)
算法思想: 将第一个序列数据先压栈,如果最上面的数据与第二个需要弹出的数据相同,进行判断下一个栈顶数据是否为需要弹出的数据,如果是继续进行这样的判断,如果不是就跳出循环将第一个序列的数据压栈。最终如果弹出数列全都遍历完了,说明是压栈序列的弹出序列。
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
int pushVsize = pushV.size();
stack<int> stacktemp;
int j = 0;
for(int i = 0; i < pushVsize; i++) {
stacktemp.push(pushV[i]);
while(stacktemp.top() == popV[j]) {
stacktemp.pop();
j++;
if(stacktemp.empty()) break;
}
}
return j==pushVsize;
}
};
包含min函数的栈
定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。在该栈中调用push、pop、top、min的时间复杂度都是o(1)。
定义一个辅助栈,用于存放数据栈每次入栈时的最小元素,辅助栈的栈顶元素是数据栈内最小值。
class Solution {
public:
void push(int value)
{
data.push(value);
if(data.empty() || value<smin.top())
smin.push(value);
else
smin.push(smin.top());
}
void pop()
{
if(!data.empty() && !smin.empty())
{
data.pop();
smin.pop();
}
}
int top()
{
return data.top();
}
int min()
{
return smin.top();
}
private:
stack<int> data;
stack<int> smin;
};
两个栈实现队列
class Solution
{
public:
void push(int node) {
stack1.push(node); //实现入队
}
//出队思想:
int pop() { //队列出队的底层实现:先将元素依次从1栈弹出,再依次压入至2栈,
int a; //再 每次调用pop()出队列,返回一个元素。
if(stack2.empty()){
while(!stack1.empty()){
a = stack1.top();
stack2.push(a);
stack1.pop();
}
}
a = stack2.top();
stack2.pop();
return a;
}
private:
stack<int> stack1;
stack<int> stack2;
};
两个队列实现栈
两个队列q1, q2。不管是插入还是弹出,保证总有一个队列为空。那么:
-
队列入栈:将元素插入空队列,同时将非空队列的元素依次插入到空队列。此时之前的非空队列变为空队列,空队列变为非空队列。
-
队列出栈:将非空队列的队首弹出即可。
class QueueStack {
public:
// 保证每个时刻都有一个队列为空队列
// Push element x onto stack.
void push(int x) {
if(q1.empty())
{
q1.push(x);
while(!q2.empty())
{
q1.push(q2.front());
q2.pop();
}
}
else
{
q2.push(x);
while(!q1.empty())
{
q2.push(q1.front());
q1.pop();
}
}
}
// Removes the element on top of the stack.
void pop() {
if(q1.empty())
{
q2.pop();
}
else
{
q1.pop();
}
}
// Get the top element.
int top() {
if(q1.empty())
{
return q2.front();
}
else
{
return q1.front();
}
}
// Return whether the stack is empty.
bool empty() {
return (q1.empty() && q2.empty());
}
queue<int> q1;
queue<int> q2;
};
小顶堆的实现
void AdjustDown(int arr[], int i, int n)
{
int j = i * 2 + 1;//子节点
while (j<n)
{
if (j+1<n && arr[j] > arr[j + 1])//子节点中找较小的
{
j++;
}
if (arr[i] < arr[j])
{
break;
}
swap(arr[i],arr[j]);
i = j;
j = i * 2 + 1;
}
}
void MakeHeap(int arr[], int n)//建堆
{
int i = 0;
for (i = n / 2 - 1; i >= 0; i--)//((n-1)*2)+1 =n/2-1
{
AdjustDown(arr, i, n);
}
}
void HeapSort(int arr[],int len)
{
int i = 0;
for (i = n / 2 - 1; i >= 0; i--)//((n-1)*2)+1 =n/2-1
{
AdjustDown(arr, i, n);
}
for (i = len - 1; i >= 0; i--)
{
swap(arr[i], arr[0]);
AdjustDown(arr, 0, i);
}
}
大顶堆实现
// 递归方式构建大根堆(len是arr的长度,index是第一个非叶子节点的下标)
void adjust(vector<int> &arr, int index,int len)
{
int left = 2*index + 1; // index的左子节点
int right = 2*index + 2;// index的右子节点
int maxIdx = index;
if(left<len && arr[left] > arr[maxIdx]) maxIdx = left;
if(right<len && arr[right] > arr[maxIdx]) maxIdx = right;
if(maxIdx != index)
{
swap(arr[maxIdx], arr[index]);
adjust(arr, maxIdx, len);
}
}
// 堆排序
void heapSort(vector<int> &arr, int size)
{
// 构建大根堆(从最后一个非叶子节点向上)
for(int i=size/2 - 1; i >= 0; i--)
{
adjust(arr, i ,size);
}
// 调整大根堆
for(int i = size - 1; i >= 1; i--)
{
swap(arr[0], arr[i]); // 将当前最大的放置到数组末尾
adjust(arr,0, i-1); // 将未完成排序的部分继续进行堆排序
}
}
定义 : priority_queue<Type, Container, Functional>
其中Type 为数据类型,Container为保存数据的容器,Functional 为元素比较方式。
默认 : 大顶堆,比较方式默认用operator< ,所以如果把后面2个参数缺省的话,优先队列就是大顶堆(降序),队头元素最大
push:插入元素到队尾
pop: 弹出队头元素
top:访问队头元素
一般使用 :
// 大顶堆
priority_queue<int, vector<int>, less<int> > q;
// 小顶堆
priority_queue<int, vector<int>, greater<int> > q;
有序矩阵中第K小的元素
给定一个 n x n 矩阵,其中每行和每列元素均按升序排序,找到矩阵中第k小的元素。 请注意,它是排序后的第k小元素,而不是第k个元素。
示例:
matrix = [
[ 1, 5, 9],
[10, 11, 13],
[12, 13, 15]
],
k = 8, 返回 13。
说明: 你可以假设k 的值永远是有效的, 1 ≤ k ≤ n2 。
1、遍历矩阵: 用一个优先级队列保存数组,然后遍历矩阵,维护优先级队列大小为k,这样遍历完,直接取出优先级队列top即可
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int n=matrix.size();
priority_queue<int> q;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
q.push(matrix[i][j]);
//默认大顶堆,弹出的是最大的,遍历完剩余的是最小的K个。
if(q.size()>k) q.pop();
}
}
return q.top();
}
};
2、二分法:二分法一般常用的有两种做法,一个是常规的有序数组,然后索引二分查找目标元素,如lower_bound、upper_bound等,另外一种是无序数组,但是知道了上下限之后,通过二分上下限查找目标元素,这一题采用的就是这种方法。
-
lower_bound(起始地址,结束地址,要查找的数值) ,函数用于在指定区域内查找不小于(大于等于)目标值的第一个元素。
-
upper_bound(起始地址,结束地址,要查找的数值) 返回的是 第一个大于待查找数值 出现的位置。
class Solution {
public:
int kthSmallest(vector<vector<int>>& matrix, int k) {
int n=matrix.size(),l=matrix[0][0],r=matrix[n-1][n-1]+1;
int mid=l;
while(l<r){
mid=l+(r-l)/2;
int cnt=0,cnt2=0;
for(int i=0;i<n;i++){
auto &v=matrix[i];
cnt+=lower_bound(v.begin(),v.end(),mid)-v.begin();
cnt2+=upper_bound(v.begin(),v.end(),mid)-v.begin();
}
if(cnt<k&&cnt2>=k) return mid;
if(cnt<k) l=mid+1;
else r=mid;
}
return mid;
}
};
字符串的top k统计
题目描述:给定一个字符串数组,再给定整数k,请返回出现次数前k名的字符串和对应的次数。返回的答案应该按字符串出现频率由高到低排序。如果不同的字符串有相同出现频率,按字典序排序。
-
对于两个字符串,大小关系取决于两个字符串从左到右第一个不同字符的 ASCII 值的大小关系。比如"ah1x"小于"ahb",“231”<”32“
-
字符仅包含数字和字母
算法分析:
-
对于这道题,首先可以用哈希表在遍历的过程中得到每个字符串的个数,然后是根据哈希表的值进行排序的问题。
-
采用C++中优先队列priority_queue构建自定义比较方式的小顶堆,我们写结构体cmp重载()运算符,比较方式为哈希表的值,当值相同时,比较哈希表的键。
-
遍历完哈希表中的所有键值对后,优先队列中存放的就是前k大的字符串及次数值。题目要求存放在vector中,我们遍历优先队列,逐个取出放入vector中,由于是小顶堆,先出来的是前k大中最小的,所以根据题目要求,需要将vector的元素逆序转换一下。
struct cmp{
bool operator()(pair<string,int>&p1,pair<string,int>&p2){
return p1.second>p2.second||(p1.second==p2.second&&p1.first<p2.first);
}
};
class Solution {
public:
/**
* return topK string
* @param strings string字符串vector strings
* @param k int整型 the k
* @return string字符 串vector<vector<>>
*/
vector<vector<string> > topKstrings(vector<string>& strings, int k) {
// write code here
vector<vector<string>>res;
if(k>strings.size()||strings.size()==0||k<=0) return res;
unordered_map<string,int>temp;
priority_queue<pair<string,int>,vector<pair<string, int>>,cmp>pq;
for(int i=0;i<strings.size();i++)
temp[strings[i]]++;
for(auto iter=temp.begin();iter!=temp.end();iter++)
{
if(pq.size()<k)
pq.push(make_pair(iter->first,iter->second));
else if(iter->second>pq.top().second||(iter->second==pq.top().second&&iter->first<pq.top().first))
{
//小顶堆,弹出的是最小的,遍历完剩余的是最大的K个。
pq.pop(); //把最小的pop掉
pq.push(make_pair(iter->first,iter->second));
}
}
while(!pq.empty())
{
res.push_back(vector<string>{pq.top().first,to_string(pq.top().second)});
pq.pop();
}
reverse(res.begin(),res.end());
return res;
}
};