--刷题日常

两个栈实现队列

class MyQueue {
public:

    stack<int> In;
    stack<int> Out;

    MyQueue() {

    }
    
    void push(int x) {
        In.push(x);

    }
    
    int pop() {
        if(Out.empty())
        {
            while(!In.empty())
            {
                Out.push(In.top());
                In.pop();
            }
        }
        int res = Out.top();
        Out.pop();
        return res;

    }
    
    int peek() {
        int res = this->pop();
        Out.push(res);
        return res;

    }
    
    bool empty() {
        return In.empty() && Out.empty();

    }
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue* obj = new MyQueue();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->peek();
 * bool param_4 = obj->empty();
 */

两个队列实现栈

class MyStack {
public:

    queue<int> Q1;
    queue<int> Q2;
    MyStack() {

    }
    
    void push(int x) {
        Q1.push(x);

    }
    
    int pop() {
        int size = Q1.size();
        size--;
        while(size--)
        {
            Q2.push(Q1.front());
            Q1.pop();  
        }
        int res = Q1.front();
        Q1.pop();
        Q1=Q2;
        while(!Q2.empty())
        {
            Q2.pop();
        }
        return res;

    }
    
    int top() {
        return Q1.back();

    }
    
    bool empty() {
        return Q1.empty();

    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

一个队列模拟栈

class MyStack {
public:

    queue<int> q1;
    MyStack() {

    }
    
    void push(int x) {
        q1.push(x);

    }
    
    int pop() {
        int size = q1.size();
        size--;
        while(size--)
        {
            q1.push(q1.front());
            q1.pop();
        }
        int res = q1.front();
        q1.pop();
        return res;
    }
    
    int top() {
        return q1.back();

    }
    
    bool empty() {
        return q1.empty();

    }
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack* obj = new MyStack();
 * obj->push(x);
 * int param_2 = obj->pop();
 * int param_3 = obj->top();
 * bool param_4 = obj->empty();
 */

买卖股票的最佳时机II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
贪心

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;

        for(int i = 0;i < prices.size() - 1;++i)
        {
            res += max(prices[i+1] - prices[i],0);
        }
    return res;
    }
};

最大子序和
给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例: 输入: [-2,1,-3,4,-1,2,1,-5,4] 输出: 6 解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
1.暴力:

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        int count = 0;
        int res = INT_MIN;
        for(int i = 0;i < nums.size();++i)
        {
            count = 0;
            for(int j = i;j < nums.size();++j)
            {
                count += nums[j];
                res =  count >  res? count : res;
            }
        }
        return res;
    }
};

2.贪心

class Solution {
public:
    int maxSubArray(vector<int>& nums) {

        int Max = 0;
        int res = nums[0];

        for(auto &i:nums)
        {
            Max = max(Max + i,i);
            res = max(res,Max);
        }
        return res;
    }
};

摆动序列
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。

例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。

给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。

示例 1:

输入: [1,7,4,9,2,5]
输出: 6
解释: 整个序列均为摆动序列。
示例 2:

输入: [1,17,5,10,13,15,10,5,16,8]
输出: 7
解释: 这个序列包含几个长度为 7 摆动序列,其中一个可为[1,17,10,13,10,16,8]。
示例 3:

输入: [1,2,3,4,5,6,7,8,9]
输出: 2

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {

        int cur = 0;//当前差值
        int pre = 0;//前一个差值
        int res = 1;//峰值个数

        if(nums.size() == 1)  return nums.size();

        for(int i = 0; i < nums.size() - 1; ++i)
        {
            cur = nums[i+1] - nums[i];

            if((cur > 0 && pre <= 0) || (cur < 0 && pre >= 0))
            {
                res++;
                pre = cur;
            }
        }
        return res;
    }
};

分发饼干
假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1 解释:你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。所以你应该输出1。
示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释:你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。你拥有的饼干数量和尺寸都足以让所有孩子满足。所以你应该输出2.

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {

        sort(g.begin(),g.end());
        sort(s.begin(),s.end());

        int size = s.size() - 1;//饼干的下标
        int res = 0;
        for(int i = g.size() - 1; i >= 0;i--)
        {
            if(size >= 0 && s[size] >= g[i])
            {
                size--;
                res++;
            }
        }
        return res;
    }
};

跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个位置。

示例 1:

输入: [2,3,1,1,4]
输出: true
解释: 我们可以先跳 1 步,从位置 0 到达 位置 1, 然后再从位置 1 跳 3 步到达最后一个位置。
示例 2:

输入: [3,2,1,0,4]
输出: false
解释: 无论怎样,你总会到达索引为 3 的位置。但该位置的最大跳跃长度是 0 , 所以你永远不可能到达最后一个位置

class Solution {
public:
    bool canJump(vector<int>& nums) {
        int cover = 0;

        if(nums.size() == 1) return true;

        for(int i = 0; i <= cover;++i)
        {
            cover = max(i + nums[i],cover);
            if(cover >= nums.size() - 1) return true;
        }
        return false;
    }
};

跳跃游戏II
给你一个非负整数数组 nums ,你最初位于数组的第一个位置。

数组中的每个元素代表你在该位置可以跳跃的最大长度。

你的目标是使用最少的跳跃次数到达数组的最后一个位置。

假设你总是可以到达数组的最后一个位置。

示例 1:

输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:

输入: nums = [2,3,0,1,4]
输出: 2

class Solution {
public:
    int jump(vector<int>& nums) {
        if(nums.size() == 1) return 0;
        int Curcover = 0;
        int Nextcover = 0;
        int res = 0;
        for(int i = 0;i < nums.size();++i)
        {
            Nextcover = max(i + nums[i],Nextcover);
            if(i == Curcover)
            {
                if(Curcover != nums.size() - 1)//当前距离无法覆盖整个数组
                {
                    res++;
                    Curcover = Nextcover;
                    if(Nextcover >= nums.size() - 1) break;
                }
                else break;
            }
        }
        return res;
    }
};

K次取反后最大化的数组和
给定一个整数数组 A,我们只能用以下方法修改该数组:我们选择某个索引 i 并将 A[i] 替换为 -A[i],然后总共重复这个过程 K 次。(我们可以多次选择同一个索引 i。)

以这种方式修改数组后,返回数组可能的最大和。

示例 1:

输入:A = [4,2,3], K = 1
输出:5
解释:选择索引 (1,) ,然后 A 变为 [4,-2,3]。
示例 2:

输入:A = [3,-1,0,2], K = 3
输出:6
解释:选择索引 (1, 2, 2) ,然后 A 变为 [3,1,0,2]。
示例 3:

输入:A = [2,-3,-1,5,-4], K = 2
输出:13
解释:选择索引 (1, 4) ,然后 A 变为 [2,3,-1,5,4]。
思路:
第一步:将数组按照绝对值大小从大到小排序,注意要按照绝对值的大小
第二步:从前向后遍历,遇到负数将其变为正数,同时K–
第三步:如果K还大于0,那么反复转变数值最小的元素,将K用完
第四步:求和

class Solution {
public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        int res = 0;
        sort(nums.begin(),nums.end(),[](int a,int b){return abs(a) > abs(b);});
        for(int i = 0;i < nums.size();++i)
        {
            if(nums[i] < 0 && k > 0)
            {
                nums[i] *= -1;
                k--;
            }
        }
        if(k % 2 == 1)  nums[nums.size() -1] *= -1;
        for(auto i:nums)
        {
            res += i;
        }
    return res;
    }
};

加油站问题(贪心)
原题链接

1.暴力:

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost)
    {
        for (int i = 0; i < cost.size(); ++i)
        {
            int res = gas[i] - cost[i];
            int index = (i + 1) % cost.size();
            while (res > 0 && index != i)
            {
                res += gas[index] - cost[index];
                index = (index + 1) % cost.size();
            }
            if (res >= 0 && index == i) return i;
        }
        return -1;
    }
};

2.贪心(全局贪心):
思路:
情况一:如果gas的总和小于cost总和,那么无论从哪里出发,一定是跑不了一圈的

情况二:rest[i] = gas[i]-cost[i]为一天剩下的油,i从0开始计算累加到最后一站,如果累加没有出现负数,说明从0出发,油就没有断过,那么0就是起点。

情况三:如果累加的最小值是负数,汽车就要从非0节点出发,从后向前,看哪个节点能这个负数填平,能把这个负数填平的节点就是出发节点。

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {

        int res = 0;
        int MIN = INT_MAX;

        for(int i = 0;i < gas.size();++i)
        {
            int abc = gas[i] - cost[i];
            res += abc;

            if(res < MIN) MIN = res;
        }
        if(res  < 0) return -1;
        if(MIN >= 0) return 0;

        for(int i = gas.size() - 1;i >= 0;i--)
        {
            int abc = gas[i] - cost[i];
            MIN += abc;
            if(MIN >= 0) return i;
        }
        return -1;
    }
};

贪心(局部最优)
思路:
首先看每一次加油与使用油的差值总和是否大于0,如果大于0,则一定存在从某一点出发使得可以走完全程,否则就不存在;
统计当前的差值总和,如果小于0,则起点一定在当前位置的下一个位置。

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int cur = 0;
        int total = 0;
        int start = 0;

        for(int i = 0;i < gas.size();++i)
        {
            cur += gas[i] - cost[i];
            total += gas[i] - cost[i];

            if(cur < 0)
            {
                start = i + 1;
                cur = 0;
            } 
        }
        if(total >= 0) return start;
        return -1;

    }
};

分发糖果
原题链接
思路:
两次贪心
第一次:左<右 从左到右遍历,则局部贪心为arr[i] = arr[i-1] + 1;
第二次:左>右 从右向左遍历,因为如果从前向后遍历,根据 ratings[i + 1] 来确定 ratings[i] 对应的糖果,那么每次都不能利用上前一次的比较结果,此时arr[i]有两个选择 (1)上次循环右大于左所得的糖果,(2)arr[i+1] +1 的糖果,取最大 则可以推出局部最优为 arr[i] = max(arr[i],arr[i + 1] + 1);

class Solution {
public:
    int candy(vector<int>& ratings) {

        vector<int> arr(ratings.size(),1);

        for(int i = 1;i < ratings.size();++i)//左 < 右
        {
            if(ratings[i] > ratings[i-1]) arr[i] = arr[i - 1] + 1;
        }
        for(int i = ratings.size() - 2;i >= 0;i--)
        {
            if(ratings[i] > ratings[i+1]) 
                arr[i] = max(arr[i],arr[i + 1] + 1);
        }
        int res = 0;
        for(int i:arr)
        {
            res += i;
        }
        return res;
    }
};

柠檬水找零
原题链接

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {

        int Sum_five = 0,Sum_ten = 0,Sum_twanty = 0;
        for(auto i:bills)
        {
            if(i == 5) Sum_five++;
            if(i == 10) 
            {
                if(Sum_five == 0) return false;
                Sum_five--;
                Sum_ten++;
            }

            if(i == 20)
            {
                if(Sum_ten > 0 && Sum_five > 0)
                {
                    Sum_ten--;
                    Sum_five--;
                }
                else if(Sum_five >= 3)
                {
                    Sum_five -= 3;
                }
                else return false;
            }
        }
        return true;

    }
};

根据身高重建队列
原题链接
思路:
如果按照k来从小到大排序,排完之后,会发现k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。

那么按照身高h来排序呢,身高一定是从大到小排(身高相同的话则k小的站前面),让高个子在前面。

此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!
在这里插入图片描述
按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点,最终按照k的规则完成了队列。

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(),people.end(),[](vector<int> a,vector<int> b){if(a[0] == b[0]) return a[1] < b[1];return a[0] > b[0];});

        vector<vector<int>> que;

        for(int i = 0;i < people.size();++i)
        {
            int pos = people[i][1];
            que.insert(que.begin() + pos,people[i]);
        }
        return que;
    }
};

用最少数量的箭引爆气球
原题链接
思路:数组排序,从前向后遍历气球数组,靠左尽可能让气球重复
如果气球重叠了,重叠区间一定需要一个弓箭。

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {

	if (points.size() == 0) return 0;

	sort(points.begin(), points.end(), [](vector<int>& a, vector<int>& b) {return a[0] < b[0]; });
	int res = 1;
	for (int i = 1; i < points.size(); ++i)
	{
		if (points[i][0] > points[i - 1][1])
			res++;
		else points[i][1] = min(points[i - 1][1], points[i][1]);
	}
	return res;
}
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值