剑指offer(关于摩尔投票法)

9.用两个栈实现队列用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )示例 1:输入:[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”][[],[3],[],[]]输出...
摘要由CSDN通过智能技术生成

9.用两个栈实现队列

用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )

示例 1:

输入:
[“CQueue”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[3],[],[]]
输出:[null,null,3,-1]
示例 2:

输入:
[“CQueue”,“deleteHead”,“appendTail”,“appendTail”,“deleteHead”,“deleteHead”]
[[],[],[5],[2],[],[]]
输出:[null,-1,null,null,5,2]

分析

这道题的意图是要求我们操作两个“先进后出”的栈实现一个“先进先出”的队列CQueue.
在这里插入图片描述
在这里插入图片描述

class CQueue {
public:
    CQueue() {

    }
    
    void appendTail(int value) {
        stack1.push(value);
    }
    
    int deleteHead() {
        // 先检查stack2是否为空,如果stack2为空,需要stack1传过来
        if(stack2.empty()){
            if(stack1.empty()) return -1;
            while(!stack1.empty()){
                // int& data = stack1.top();
                // stack2.push(data);
                // stack1.pop();
                stack2.push(stack1.top());  
                // 将stack1栈顶元素压栈到stack2,以实现队列功能
                stack1.pop();
                
            }
        }

        // 因为stack2中的元素比stack1中的元素先进去,所以
        //当stack2中有元素的时候,可以直接出栈
        
        // 反证法:如果stack2中的元素不比stack1中的元素靠前,那么当
        //stack2中有元素时,stack1中又进来一个元素,这时如果先把stack1
        //中的栈顶元素移动到stack2中时,就实现了后进先出了,矛盾

        // if(!stack2.empty()),栈2不为空,直接返回栈2的栈顶元素
        int& head = stack2.top();
        stack2.pop();
        return head;
    }
private:
    stack<int> stack1;
    stack<int> stack2;
};

/**
 * Your CQueue object will be instantiated and called as such:
 * CQueue* obj = new CQueue();
 * obj->appendTail(value);
 * int param_2 = obj->deleteHead();
 */

面试题31. 栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

分析

该题的思路:
借助辅助栈,按照压栈序列pushed依次输入辅助栈,再将栈顶元素与popped序列比较,若元素对应相等,则弹出该栈顶元素,否则继续压栈

时间复杂度:O(N) 将所以元素一遍入栈,一遍出栈,需要 O(2N)。
空间复杂度:O(N)。使用了辅助栈 res。

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> res;
        if(pushed.size() != popped.size())//首先判断两栈大小是否相同
            return false;
        
        int i=0;//用popped[i]记录popped中被弹出的元素
        
        for(auto m:pushed)
        {
            res.push(m);//按照压栈序列入辅助栈
            while(!res.empty() && res.top()==popped[i])
            {//若栈顶元素与弹出序列元素相同则弹出,i指向下一个要弹出的元素
                res.pop();
                i++;
            } 
        }
        return res.empty();//最后操作完成,栈为空即合法
    }
};

面试题39. 数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

限制:

1 <= 数组长度 <= 50000

分析:

方法一:摩尔投票法

摩尔投票算法是基于这个事实:每次从序列里选择两个不相同的数字删除掉(或称为“抵消”),最后剩下一个数字或几个相同的数字,就是出现次数大于总数一半的那个。

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int ans,cnt=0;

        for(auto num:nums)
        {
            if(cnt == 0)
            {
                ans = num;
                ++cnt;
            }else{
                if(ans == num) ++cnt;
                else 
                --cnt;
            }
        }
        return ans;
    }
};

方法二:采用map

class Solution {
public:
    int majorityElement(vector<int>& nums) {
      
       map<int,int> res;//定义map
       int len = nums.size();

       for(auto i:nums)
       {
           res[i]++;//遍历数组,统计每个元素出现的次数
       }

       for(auto i:nums)
       {
       //再次遍历数组,判断每个元素出现次数与len的大小
           if(res[i]*2 > len)
           return i;
       }
       return -1;
    }

};
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        //方法1:排序后中间的元素一定是出现超过一半的数字
        sort(nums.begin(),nums.end());
        return nums[nums.size()/2];

        //方法2:哈希表
        unordered_map<int,int>mp;
        for(auto it : nums){
            mp[it]++;
            if(mp[it]>nums.size()/2) return it;
        }
        return 0;

        //方法3:超过一半的数字比其他所有数字的总和次数多
        int n=1;
        int result=nums[0];
        for(int i=1;i<nums.size();i++){
            if(n==0){
                result=nums[i];
                n=1;
            }
            else if(result==nums[i])n++;
            else n--;
        }
        return result;
    }
};


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值