1. 用栈实现队列(NO.232)
题目描述:使用栈实现队列的下列操作:
push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。
解题思路:是用两个栈,一个用于入队操作,一个用于出队操作。一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转,经过第二个栈时再次被反转,此时就是先进先出顺序。
class MyQueue {
public:
/** Initialize your data structure here. */
MyQueue() {
stack<int> st1;
stack<int> st2;
}
/** Push element x to the back of queue. */
void push(int x) {
st1.push(x);
}
/** Removes the element from in front of queue and returns that element. */
int pop() {
if (st2.empty()){
while (!st1.empty()){
st2.push(st1.top());
st1.pop();
}
}
int res = st2.top();
st2.pop();
return res;
}
/** Get the front element. */
int peek() {
if (st2.empty()){
while (!st1.empty()){
st2.push(st1.top());
st1.pop();
}
}
int res = st2.top();
return res;
}
/** Returns whether the queue is empty. */
bool empty() {
return st1.empty() && st2.empty();
}
private:
stack<int> st1;
stack<int> st2;
};
2. 用队列实现栈(NO.225)
题目描述:使用队列实现栈的下列操作:
push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
解题思路:出栈:将非空队列中的除队尾元素外的所有元素转移至另一个队列中,然后将最后一个元素出队;入栈:将元素压入到非空队列的队尾。
class MyStack {
public:
/** Initialize your data structure here. */
MyStack() {
queue<int> qu1;
queue<int> qu2;
}
/** Push element x onto stack. */
void push(int x) {
if (qu1.empty())
qu2.push(x);
else
qu1.push(x);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
int res;
if (qu1.empty()){
while (qu2.size() > 1){
qu1.push(qu2.front());
qu2.pop();
}
res = qu2.front();
qu2.pop();
}
else if (qu2.empty()){
while (qu1.size() > 1){
qu2.push(qu1.front());
qu1.pop();
}
res = qu1.front();
qu1.pop();
}
return res;
}
/** Get the top element. */
int top() {
int res;
if (qu1.empty()){
while (qu2.size() > 1){
qu1.push(qu2.front());
qu2.pop();
}
res = qu2.front();
qu1.push(res);
qu2.pop();
}
else if (qu2.empty()){
while (qu1.size() > 1){
qu2.push(qu1.front());
qu1.pop();
}
res = qu1.front();
qu2.push(res);
qu1.pop();
}
return res;
}
/** Returns whether the stack is empty. */
bool empty() {
return qu1.empty() && qu2.empty();
}
private:
queue<int> qu1;
queue<int> qu2;
};
3. 最小值栈(NO.155)
题目描述:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。
解题思路:使用一个栈minValue记录数据栈的最小值,数据栈添加或者删除元素时,minValue栈也做相应的操作,使用变量min记录栈的最小值。
class MinStack {
private:
stack<int> data;
stack<int> minValue;
int min = 0x7FFFFFFF;
public:
/** initialize your data structure here. */
MinStack() {
}
void push(int x) {
data.push(x);
min = min < x ? min : x;
minValue.push(min);
}
void pop() {
data.pop();
minValue.pop();
min = minValue.empty() ? 0x7FFFFFFF : minValue.top();
}
int top() {
return data.top();
}
int getMin() {
return min;
}
};
4. 用栈实现括号匹配(NO.20)
题目描述:给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:左括号必须用相同类型的右括号闭合。左括号必须以正确的顺序闭合。注意空字符串可被认为是有效字符串。
解题思路:创建一个栈。遍历字符串,如果遇到的是左括号,则将其压入栈中,如果遇到的是右括号,分以下几种情况:(1)栈为空,肯定不匹配,返回false;(2)栈非空,且该右括号也栈顶的左括号匹配,则将栈顶元素弹出,继续遍历;(3)栈非空,但该右括号也栈顶左括号不匹配,则字符串无效,返回false。
class Solution {
public:
bool isValid(string s) {
stack<char> st;
for (int i = 0; i < s.size(); i++){
if (s[i] == '(' || s[i] == '{' || s[i] == '[')
st.push(s[i]);
else{
if (st.empty())
return false;
else if ((s[i] == ')' && st.top() == '(') || (s[i] == ']' && st.top() == '[') || (s[i] == '}' && st.top() == '{'))
st.pop();
else
return false;
}
}
return st.empty();
}
};
5. 数组中元素与下一个比它大的元素之间的距离(NO.739)
题目描述:请根据每日 气温 列表,重新生成一个列表。对应位置的输出为:要想观测到更高的气温,至少需要等待的天数。如果气温在这之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
解题思路一:从后往前遍历,便不用一个一个的比较,只考虑一个递增的子列,从而找到比当前值大的值的位置。最后一个元素对应的结果为0。要求出第i天对应的结果,只需要知道第i+1天对应的结果就可以:(1)若T[i] < T[i+1],那么res[i]=1;(2)若T[i] > T[i+1]:若res[i+1]=0,那么res[i]=0;若res[i+1]!=0,那就比较T[i]和T[i+1+res[i+1]](即将第i天的温度与比第i+1天大的那天的温度进行比较)
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
vector<int> res(T.size(),0);
for (int i = T.size() - 2; i >= 0; i--){
for (int j = i + 1; j < T.size(); j += res[j]){
if (T[i] < T[j]){
res[i] = j - i;
break;
}
else if (res[j] == 0){
res[i] = 0;
break;
}
}
}
return res;
}
};
解题思路二:使用一个栈存储尚未找到较大值的下标。遍历数组,如果当前数字大于栈顶数字,则可求得栈顶数字与比其大的值的距离,然后将栈顶元素弹出,继续比较栈中下一个元素。如果当前数字小于栈顶元素,则将其入栈。可以发现栈中元素是递减的。
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
vector<int> res(T.size(),0);
stack<int> st;
for (int i = 0; i < T.size(); i++){
while (!st.empty() && T[i] > T[st.top()]){
res[st.top()] = i - st.top();
st.pop();
}
st.push(i);
}
return res;
}
};
6. 循环数组中比当前元素大的下一个元素(NO.503)
题目描述:给定一个循环数组(最后一个元素的下一个元素是数组的第一个元素),输出每个元素的下一个更大元素。数字 x 的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1。
解题思路:与上一题相似,只不过是循环数组,且找的是元素值而不是位置。令i的取值为0到2n,取其对应于循环数组中的值与栈顶元素比较,如果大于,弹出栈顶元素,如果小于且i小于n,入栈。
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int n = nums.size();
vector<int> res(n,-1);
stack<int> st;
for (int i = 0; i < n * 2; i++){
int num = nums[i % n];
while (!st.empty() && num > nums[st.top()]){
res[st.top()] = num;
st.pop();
}
if (i < n)
st.push(i);
}
return res;
}
};
7. 最长和谐子序列(NO.594)
题目描述:和谐数组是指一个数组里元素的最大值和最小值之间的差别正好是1。现在,给定一个整数数组,你需要在所有可能的子序列中找到最长的和谐子序列的长度。
输入: [1,3,2,2,5,2,3,7]; 输出: 5; 原因: 最长的和谐数组是:[3,2,2,2,3].
解题思路:使用一个哈希表,记录每个元素出现的次数,求相邻元素出现次数的和。这里使用unordered_map创建哈希表。
class Solution {
public:
int findLHS(vector<int>& nums) {
unordered_map<int,int> mymap;
int res = 0;
for (int num : nums){
mymap[num]++;
if (mymap[num-1] > 0)
res = max(res,mymap[num-1]+mymap[num]);
if (mymap[num+1] > 0)
res = max(res,mymap[num+1]+mymap[num]);
}
return res;
}
};
8. 最长连续序列(NO.128)
题目描述:给定一个未排序的整数数组,找出最长连续序列的长度。要求算法的时间复杂度为 O(n)。
输入: [100, 4, 200, 1, 3, 2];输出: 4;解释: 最长连续序列是 [1, 2, 3, 4]。它的长度为 4。
解题思路一:使用动态规划,令dp[i]表示以第i个元素结尾的连续序列长度。首先对数组排序,遍历数组,如果nums[i]=nums[i-1],则dp[i]=dp[i-1];如果nums[i]=nums[i-1]+1,则dp[i]=dp[i-1]+1,否则,dp[i]=1.但是时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn).
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
int n = nums.size();
if (n <= 1)
return n;
sort(nums.begin(),nums.end());
vector<int> dp(n,1);
int max = 1;
for (int i = 1; i < n; i++){
if (nums[i] == nums[i-1])
dp[i] = dp[i-1];
else if (nums[i] == nums[i-1] + 1)
dp[i] = dp[i-1] + 1;
if (dp[i] > max)
max = dp[i];
}
return max;
}
};
解题思路二:题目要求 O(n) 复杂度。
用哈希表存储每个端点值对应连续区间的长度。遍历数组:
(1)若数已在哈希表中:跳过不做处理
(2)若是新数加入:判断其左右相邻数是否在哈希表中,如果在,计算当前数的区间长度curLength,并更新最大长度和区间两边端点的长度值。
class Solution {
public:
int longestConsecutive(vector<int>& nums) {
unordered_map<int,int> mymap;
int maxLength = 0;
for (int num : nums){
if (mymap.find(num) == mymap.end()){//新数
int curLength = 0;
if (mymap.find(num-1) == mymap.end() && mymap.find(num+1) == mymap.end())
curLength = 1;
else if (mymap.find(num-1) == mymap.end()){//右相邻数在哈希表中
curLength = mymap[num+1] + 1;
mymap[num+mymap[num+1]] = curLength;//更新右区间端点的长度值
}
else if (mymap.find(num+1) == mymap.end()){//左相邻数在哈希表中
curLength = mymap[num-1] + 1;
mymap[num-mymap[num-1]] = curLength;//更新左区间端点的长度值
}
else{//左右相邻数都在哈希表中
curLength = mymap[num-1] + mymap[num+1] + 1;
mymap[num-mymap[num-1]] = curLength;
mymap[num+mymap[num+1]] = curLength;
}
mymap[num] = curLength;
if (curLength > maxLength)
maxLength = curLength;
}
}
return maxLength;
}
};