5.2打卡:剑指 offer两题:用两个栈实现队列/旋转数组最小数字

用两个栈实现队列

题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

思路:

1、当插入时,直接插入 stack1

2、当弹出时,当 stack2 不为空,弹出 stack2 栈顶元素,如果 stack2 为空,将 stack1 中的全部数逐个出栈入栈 stack2,再弹出 stack2 栈顶元素

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        //当弹出时,当 stack2 不为空,弹出 stack2 栈顶元素,
        //如果 stack2 为空,将 stack1 中的全部数逐个出栈入栈 stack2,
        //再弹出 stack2 栈顶元素
        if(stack2.empty())
        {
            while(!stack1.empty())
            {
                stack2.push(stack1.top());
                stack1.pop();
            }
        }
        int ret = stack2.top();
        stack2.pop();
        return ret;
        
    }

private:
    stack<int> stack1;
    stack<int> stack2;
};

注意:这里实际上我自己忘了C++ stack/vector/deque的一些操作,所以这里在记录一下巩固一下。

栈(stack)

//头文件
#include<stack>
//常用方法
empty() //堆栈为空则返回真
pop() //移除栈顶元素
push() //在栈顶增加元素
size() //返回栈中元素数目
top() //返回栈顶元素

队列(queue)

//头文件
#include<queue>
//常用方法
empty() 判断队列是否为空,返回类型为bool
size() 返回队列中元素的个数
front() 返回队列队首元素
back() 返回队列队尾元素
push(ele) 将元素ele插入到队尾
pop 队首元素出队

向量(vector)

#include<vector>//头文件
//常用方法
c.clear() 移除容器中所有数据。
c.empty() 判断容器是否为空。
c.erase(pos) 删除pos位置的数据
c.erase(beg,end) 删除[beg,end)区间的数据
c.front() 传回第一个数据。
c.insert(pos,elem) 在pos位置插入一个elem拷贝
c.pop_back() 删除最后一个数据。
c.push_back(elem) 在尾部加入一个数据。
c.resize(num) 重新设置该容器的大小
c.size() 回容器中实际数据的个数。
c.begin() 返回指向容器第一个元素的迭代器
c.end() 返回指向容器最后一个元素的迭代器

旋转数组最小数字

题目描述

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。

思路(二分查找思想):

参考:https://www.nowcoder.com/questionTerminal/9f3231a991af4f55b95579b44b7a01ba?answerType=1&f=discussion
二分查找的 mid 如果落在左半边,那么就 lo=mid+1,如果落在右半边,就减小 hi=mid。不断缩小范围,最终,lo 一定会掉到最低点。是要如何判断 mid 落在那一边呢。因为左半边 >= 右半边,如果原数组是严格递增的,你可以说,当 a[mid] > a[0] 那就是左半边。但是考虑下面这幅图:

如果原数组只有开始部分递增,之后很长一段都是平坦的,那么旋转后可能是上图的样子。a[mid] == a[lo] == a[hi],根本没法判断 mid 在那边。解决的方法很简单:

while(a[lo] == a[hi]){
    ++lo;
    --hi;
}

这样操作以后,一定有 a[lo] > a[hi],一旦 lo 掉到了最低点,这个条件就不成立了。判断 mid 在左在右也很简单了,如果 a[mid] >= a[lo] 那就是左边。如果 a[mid] <= a[hi] 那就是右边。

如果在左边,那就 lo=mid+1,这样把 lo 向右边推进。如果在右边,为了避免 hi 爬到了左边去 hi=mid 即可。最终终止条件,就是 lo 落到了最低点。

class Solution {
public:
    int minNumberInRotateArray(vector<int> a) {
        if(a.size() == 0) return 0;
        int lo = 0, hi = a.size() - 1;
        //防止原数组只有开始部分递增,之后很长一段都是平坦的
        while(a[lo] == a[hi])
        {
            ++ lo;
            -- hi;
        }
        /*
        if (a.size() == 0) return 0;
        int lo = 0, hi = a.size()-1;
        while(a[lo] == a[hi]){
            ++lo;
            --hi;
        }*/
        while(a[lo] > a[hi]){
            int mid = lo + (hi-lo) / 2;

            if(a[mid] >= a[lo]){
                lo = mid + 1;
            }else if(a[mid] <= a[hi]){
                hi = mid;
            }
        }
        return a[lo];
    }
};

 

 

 

 

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