五月训练 Day14

五月训练 Day14,第1张

文章目录
    • 0. Leetcode [1441. 用栈 *** 作构建数组](https://leetcode.cn/problems/build-an-array-with-stack-operations/)
      • 分析与解答
    • 1. Leetcode [1021. 删除最外层的括号](https://leetcode.cn/problems/remove-outermost-parentheses/)
      • 分析与解答
    • 2. Leetcode [1700. 无法吃午餐的学生数量](https://leetcode.cn/problems/number-of-students-unable-to-eat-lunch/)
      • 分析与解答
    • 3. Leetcode [1381. 设计一个支持增量 *** 作的栈](https://leetcode.cn/problems/design-a-stack-with-increment-operation/)
      • 分析与解答
    • 总结

0. Leetcode 1441. 用栈 *** 作构建数组

给你一个目标数组 target 和一个整数 n。每次迭代,需要从 list = {1,2,3…, n} 中依序读取一个数字。
请使用下述 *** 作来构建目标数组 target :
Push:从 list 中读取一个新元素, 并将其推入数组中。
Pop:删除数组中的最后一个元素。
如果目标数组构建完成,就停止读取更多元素。
题目数据保证目标数组严格递增,并且只包含 1 到 n 之间的数字。
请返回构建目标数组所用的 *** 作序列。
题目数据保证答案是唯一的。

分析与解答

由于题目要求依序读取数字,因此每次调用 Push 将数字放入数组,若该数字不在 target 中,则调用 Pop d出,若该数字在 target 中,继续判断下一个即可:

class Solution {
public:
    vector buildArray(vector& target, int n) {
        // 依序放入数字 1-n
        // 若数字 i 不在 target 中,放入后 pop,否则继续
        vector result;
        int tarIdx(0);
        for (int i = 1; i <= n; ++i) {
            result.push_back("Push"); // 所有数字均先 push
            // 判断是否需要 pop
            if (i == target[tarIdx]) {
                tarIdx++;
                if (tarIdx == target.size()) {
                    break;
                }
            } else {
                result.push_back("Pop");
            }
        }
        
        return result;
    }
};

算法时间复杂度为 O ( N ) O(N) O(N)

1. Leetcode 1021. 删除最外层的括号

有效括号字符串为空 “”、“(” + A + “)” 或 A + B ,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接。
例如,“”,“()”,“(())()” 和 “(()(()))” 都是有效的括号字符串。
如果有效字符串 s 非空,且不存在将其拆分为 s = A + B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。
给出一个非空有效字符串 s,考虑将其进行原语化分解,使得: s = P 1 + P 2 + . . . + P k s = P_1 + P_2 + ... + P_k s=P1+P2+...+Pk,其中 P i P_i Pi 是有效括号字符串原语。
对 s 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 s 。

分析与解答

由于栈可以匹配括号,一开始做题时想用该方法直接匹配括号构造结果字符串,但发现该方法无法处理形如 ((())) 的原语,因此改变思路,只要用该方法找出原语在字符串中的起始与结束下标,就可以直接将字符串字串放入结果中:

class Solution {
public:
    const char leftCh = '(';
    const char rightCh = ')';
    string removeOuterParentheses(string s) {
        // 用栈找出每个原语后删除最外层括号即可
        string result;
        stack st;
        int oriS(0);
        int oriCount(0);
        for (int i = 0; i < s.size(); ++i) {
            if (s[i] == leftCh) {
                // 按规则,栈为空时应该遇到左括号
                // 直接放入左括号
                st.push(s[i]);
            } else {
                // 由于字符匹配,栈中只可能有左括号
                // 遇到右括号,从栈中弹出一个左括号
                st.pop();
                if (st.size() == 0) {
                    // 找到一个原语
                    oriCount = i - oriS + 1; // 原语长度
                    // 去除原语最外层括号
                    result += s.substr(oriS + 1, oriCount - 2); 
                    oriS = i + 1; // 移动原语起始偏移
                }
            }
        }
        
        return result;
    }
};

算法时间复杂度为 O ( N ) O(N) O(N)

2. Leetcode 1700. 无法吃午餐的学生数量

学校的自助午餐提供圆形和方形的三明治,分别用数字 0 和 1 表示。所有学生站在一个队列里,每个学生要么喜欢圆形的要么喜欢方形的。
餐厅里三明治的数量与学生的数量相同。所有三明治都放在一个 栈 里,每一轮:
如果队列最前面的学生 喜欢 栈顶的三明治,那么会 拿走它 并离开队列。
否则,这名学生会 放弃这个三明治 并回到队列的尾部。
这个过程会一直持续到队列里所有学生都不喜欢栈顶的三明治为止。
给你两个整数数组 students 和 sandwiches ,其中 sandwiches[i] 是栈里面第 i​​​​​​ 个三明治的类型(i = 0 是栈的顶部), students[j] 是初始队列里第 j​​​​​​ 名学生对三明治的喜好(j = 0 是队列的最开始位置)。请你返回无法吃午餐的学生数量。

分析与解答

对该题使用模拟法即可。使用队列模拟学生队列;使用指针模拟三明治栈。若学生队列队首元素与三明治栈顶元素匹配,则d出队首元素与栈顶元素;若不匹配则d出队首元素并将队首元素送入队尾。重复上述 *** 作,直至所有元素匹配完成或不匹配数量与队列长度相等为止,此时学生队列长度即为最终答案:

class Solution {
public:
    int countStudents(vector& students, vector& sandwiches) {
        int noSatisfy(0); // 无人取走三明治的次数
        int sanIdx(0); // 当前三明治下标
        // 构造队列
        deque st;
        for (auto stu: students) {
            st.push_back(stu);
        }
        
        while (sanIdx < sandwiches.size()) { // 对所有三明治进行匹配
            if (st.front() == sandwiches[sanIdx]) {
            	// 匹配成功
                st.pop_front();
                sanIdx++;
                // 有人取走,重置计数器
                noSatisfy = 0;
            } else {
            	// 匹配失败
                int stu = st.front();
                st.pop_front();
                st.push_back(stu);
                // 无人取走,计数器+1
                noSatisfy++;
                // 计数器与队列大小相等时表明无人取走
                if (noSatisfy == st.size()) {
                    break;
                }
            }
        }
        
        return st.size();
    }
};
3. Leetcode 1381. 设计一个支持增量 *** 作的栈

请你设计一个支持下述 *** 作的栈。
实现自定义栈类 CustomStack :
CustomStack(int maxSize):用 maxSize 初始化对象,maxSize 是栈中最多能容纳的元素数量,栈在增长到 maxSize 之后则不支持 push *** 作。
void push(int x):如果栈还未增长到 maxSize ,就将 x 添加到栈顶。
int pop():d出栈顶元素,并返回栈顶的值,或栈为空时返回 -1 。
void inc(int k, int val):栈底的 k 个元素的值都增加 val 。如果栈中元素总数小于 k ,则栈中的所有元素都增加 val 。

分析与解答

为实现栈 *** 作,我们只需要一个数组与栈顶元素指针即可。

  1. 由于最大大小不确定,因此可以使用指针实现数组,在初始化时分配内存。
  2. push *** 作需要比较当前元素与 maxSize 的大小,因此需要记录 maxSize,添加元素 x 即将栈顶指针向后移动并放入 x
  3. pop *** 作d出元素,将栈顶指针位置向前移动并返回栈顶指针位置 + 1 处的元素即可
  4. 为改变栈底的 k 个元素,只需要从指针头空间开始向后寻找 k 个改变即可
class CustomStack {
    int* _data;
    int _topIdx; // 栈顶元素位置
    int _maxSize;
    
public:
    CustomStack(int maxSize)
        : _data(nullptr)
        , _topIdx(-1)
        , _maxSize(maxSize)
    {
        _data = new int[maxSize];
    }
    
    ~CustomStack() {
        delete[] _data;
    }
    
    void push(int x) {
        // 栈内元素没超过指定大小,可以放入 x
        if (_topIdx < _maxSize - 1) {
            _topIdx++;
            _data[_topIdx] = x;
        }
    }
    
    int pop() {
        // 栈顶元素不为空,弹出
        if (_topIdx >= 0) {
            int idx = _topIdx;
            _topIdx--;
            return _data[idx];
        } else {
            return -1;
        }
    }
    
    void increment(int k, int val) {
        // 要改变的元素数量
        int num = k > _topIdx? _topIdx + 1: k;
        // 改变栈底 num 个元素
        for (int i = 0; i < num; ++i) {
            _data[i] += val;
        }
    }
};

/**
 * Your CustomStack object will be instantiated and called as such:
 * CustomStack* obj = new CustomStack(maxSize);
 * obj->push(x);
 * int param_2 = obj->pop();
 * obj->increment(k,val);
 */
总结

今天的题目难度都不高,最后一个设计题很有意思,值得尝试~

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/921839.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-16
下一篇 2022-05-16

发表评论

登录后才能评论

评论列表(0条)

保存