Leetcode刷题笔记之 栈与优先队列

155. 最小栈

设计一个支持 pushpoptop 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) —— 将元素 x 推入栈中。
  • pop() —— 删除栈顶的元素。
  • top() —— 获取栈顶元素。
  • getMin() —— 检索栈中的最小元素。

示例:

输入:
["MinStack","push","push","push","getMin","pop","top","getMin"]
[[],[-2],[0],[-3],[],[],[],[]]

输出:
[null,null,null,null,-3,null,0,-2]

解释:
MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin();   --> 返回 -3.
minStack.pop();
minStack.top();      --> 返回 0.
minStack.getMin();   --> 返回 -2.

提示:

  • poptopgetMin 操作总是在 非空栈 上调用。
class MinStack {
public:
    /** initialize your data structure here. */
    stack<int> myStack;
    stack<int> minStack;
    MinStack() {

    }
    
    void push(int x) {
        myStack.push(x);
        if(minStack.empty() || minStack.top() >= x) minStack.push(x);
    }
    
    void pop() {
        if(myStack.top()==minStack.top()) minStack.pop();
        myStack.pop();
    }
    
    int top() {
        return myStack.top();
    }
    
    int min() {
        return minStack.top();
    }
};

特别注意:if(minStack.empty() || minStack.top() >= x)在最小栈为空时,要先push进一个最小值

剑指 Offer 40. 最小的k个数

输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。

示例 1:

输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]

示例 2:

输入:arr = [0,1,2,1], k = 1
输出:[0]

限制:

  • 0 <= k <= arr.length <= 10000
  • 0 <= arr[i] <= 10000
 vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> res;
        priority_queue<int, vector<int>, greater<int> > c; 
        for(auto i:arr)
        c.push(i);

        for(int i=0;i<k;i++){
            res.push_back(c.top());
            c.pop();
        }
        return res;
       
    }
    vector<int> getLeastNumbers(vector<int>& arr, int k) {
        vector<int> res;
        priority_queue<int> c; 
        if(k==0)return res;
        
        for(int i=0;i<k;i++)
        c.push(arr[i]);

        for(int i=k;i<arr.size();i++){
            if(arr[i]<c.top()){
                c.pop();
                c.push(arr[i]);
            }   
        }-
        for(int i=0;i<k;i++){
            res.push_back(c.top());
            c.pop();
        }   

        return res;  
    }

快排法???

232. 用栈实现队列

难度简单287

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列的支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你只能使用标准的栈操作 —— 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

进阶:

  • 你能否实现每个操作均摊时间复杂度为 O(1) 的队列?换句话说,执行 n 个操作的总时间复杂度为 O(n) ,即使其中一个操作可能花费较长时间。

示例:

输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]

解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示:

  • 1 <= x <= 9
  • 最多调用 100pushpoppeekempty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)
class MyQueue {
public:
    /** Initialize your data structure here. */
    stack<int> pushStack;
    stack<int> popStack;
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        pushStack.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int res = peek();
        popStack.pop();
        return res;
    }
    
    /** Get the front element. */
    int peek() {
        if(popStack.empty()){
            while(!pushStack.empty()){
                popStack.push(pushStack.top());
            pushStack.pop();
            } 
        }

        return popStack.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        if(pushStack.empty()&&popStack.empty())
        return true;
        return false;
    }
};
71. 简化路径

难度中等250

给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,'//')都被视为单个斜杠 '/' 。 对于此问题,任何其他格式的点(例如,'...')均被视为文件/目录名称。

请注意,返回的 规范路径 必须遵循下述格式:

  • 始终以斜杠 '/' 开头。
  • 两个目录名之间必须只有一个斜杠 '/'
  • 最后一个目录名(如果存在)不能'/' 结尾。
  • 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.''..')。

返回简化后得到的 规范路径

示例 1:

输入:path = "/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。 

示例 2:

输入:path = "/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根目录是你可以到达的最高级。

示例 3:

输入:path = "/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。

示例 4:

输入:path = "/a/./b/../../c/"
输出:"/c"

提示:

  • 1 <= path.length <= 3000
  • path 由英文字母,数字,'.''/''_' 组成。
  • path 是一个有效的 Unix 风格绝对路径。
class Solution {
public:
    string simplifyPath(string path) {
        string res="";
        int pathSize = path.size();
        vector<string> pathStack;
        int start =0;
        int end =0;
        int i =0;
        while(i<pathSize){
            while(i<pathSize && path[i]=='/') i++;
            start = i;
            while(i<pathSize && path[i]!='/') i++;
            end = i;
            if(end==start) break;
            string word(path.begin()+start,path.begin()+end);
            if(word=="..")
            {
                if(!pathStack.empty())pathStack.pop_back();
            }
            else if(word!=".") pathStack.push_back(word);

        }
        for(auto j :pathStack){
            res.append("/");
            res.append(j);
        }
        return res=="" ? "/":res;
    }
};
388. 文件的最长绝对路径

难度中等67

假设文件系统如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fXISuphs-1627553827076)(栈与优先队列.assets/mdir.jpg)]

这里将 dir 作为根目录中的唯一目录。dir 包含两个子目录 subdir1subdir2subdir1 包含文件 file1.ext 和子目录 subsubdir1subdir2 包含子目录 subsubdir2,该子目录下包含文件 file2.ext

在文本格式中,如下所示(⟶表示制表符):

dir
⟶ subdir1
⟶ ⟶ file1.ext
⟶ ⟶ subsubdir1
⟶ subdir2
⟶ ⟶ subsubdir2
⟶ ⟶ ⟶ file2.ext

如果是代码表示,上面的文件系统可以写为 "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"'\n''\t' 分别是换行符和制表符。

文件系统中的每个文件和文件夹都有一个唯一的 绝对路径 ,即必须打开才能到达文件/目录所在位置的目录顺序,所有路径用 '/' 连接。上面例子中,指向 file2.ext 的绝对路径是 "dir/subdir2/subsubdir2/file2.ext" 。每个目录名由字母、数字和/或空格组成,每个文件名遵循 name.extension 的格式,其中名称和扩展名由字母、数字和/或空格组成。

给定一个以上述格式表示文件系统的字符串 input ,返回文件系统中 指向文件的最长绝对路径 的长度。 如果系统中没有文件,返回 0

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQo61Nhx-1627553827079)(栈与优先队列.assets/dir1.jpg)]

输入:input = "dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext"
输出:20
解释:只有一个文件,绝对路径为 "dir/subdir2/file.ext" ,路径长度 20
路径 "dir/subdir1" 不含任何文件

示例 2:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EJFANJNf-1627553827081)(栈与优先队列.assets/dir2.jpg)]

输入:input = "dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext"
输出:32
解释:存在两个文件:
"dir/subdir1/file1.ext" ,路径长度 21
"dir/subdir2/subsubdir2/file2.ext" ,路径长度 32
返回 32 ,因为这是最长的路径

示例 3:

输入:input = "a"
输出:0
解释:不存在任何文件

示例 4:

输入:input = "file1.txt\nfile2.txt\nlongfile.txt"
输出:12
解释:根目录下有 3 个文件。
因为根目录中任何东西的绝对路径只是名称本身,所以答案是 "longfile.txt" ,路径长度为 12

提示:

  • 1 <= input.length <= 104
  • input 可能包含小写或大写的英文字母,一个换行符 '\n',一个指表符 '\t',一个点 '.',一个空格 ' ',和数字。
class Solution {
public:
    string res;
    int lengthLongestPath(string input) {
        int inputSize = input.size();
        int maxLength = 0;
        int start = 0;
        int end =0;
        int i = 0;
        vector<int> pathLength(50,0);
        while(i<inputSize){
            int deepth =0;
             while(input[i]=='\t')
            {
                i++;
                deepth++;
            }
            start =i++;
            while(i<inputSize && input[i]!='\n')i++;
            end =i++;
            if(start!= end)
           { 
                string str(input.begin()+start, input.begin()+end);
                if(deepth == 0){
                    if(str.find(".")!=string::npos) maxLength = str.size() > maxLength ? str.size() : maxLength;
                    pathLength[deepth] = str.size() +1;

                }
                else{
                    if(str.find(".")!=string::npos){
                        maxLength = pathLength[deepth-1]+str.size() > maxLength ? pathLength[deepth-1]+str.size() : maxLength;
                    }
                    else{
                        pathLength[deepth] = pathLength[deepth-1] + str.size() +1;
                    }
                }
            }
        }
        return maxLength;
    }
};
358. K 距离间隔重排字符串

难度困难58

给你一个非空的字符串 s 和一个整数 k,你要将这个字符串中的字母进行重新排列,使得重排后的字符串中相同字母的位置间隔距离至少为 k

所有输入的字符串都由小写字母组成,如果找不到距离至少为 k 的重排结果,请返回一个空字符串 ""

示例 1:

输入: s = "aabbcc", k = 3
输出: "abcabc" 
解释: 相同的字母在新的字符串中间隔至少 3 个单位距离。

示例 2:

输入: s = "aaabc", k = 3
输出: "" 
解释: 没有办法找到可能的重排结果。

示例 3:

输入: s = "aaadbbcc", k = 2
输出: "abacabcd"
解释: 相同的字母在新的字符串中间隔至少 2 个单位距离。

// 本题用大顶堆存储数据和剩余次数,用窗口存储当前K个字符。基本思路是:
// 每次我们要取的是剩余次数的最大的字符
// 每取一次,将此字符加入窗口(窗口大小不大于K),记录下此字符,该字符次数减一,从堆中删除此字符;
// 当窗口中长度大于k,再将删除的字符加入到堆中。
class Solution {
public:
    string rearrangeString(string s, int k) {
        vector<int> lettersNum(26,0);
        string res;
        for(int i: s){
            lettersNum[i-'a']++;
        }
        priority_queue<pair<int,char>> lettersHeap;
        for(int i=0;i<26;i++){
            if(lettersNum[i]!=0)lettersHeap.push(make_pair(lettersNum[i],'a'+i));
        }
        queue<char> window;
        while(!lettersHeap.empty()){
            char maxChar = lettersHeap.top().second;
            lettersHeap.pop();
            lettersNum[maxChar-'a']--;
            res+=maxChar;

            window.push(maxChar);
            if(window.size()>=k){
                char temp = window.front();
                window.pop();
                if(lettersNum[temp-'a']>0)
                    lettersHeap.push(make_pair(lettersNum[temp-'a'],temp));  
            }
        }
        if(res.size()==s.size()) return res;
        return "";

    }
};
402. 移掉K位数字

难度中等533

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:

  • num 的长度小于 10002 且 ≥ k。
  • num 不会包含任何前导零。

示例 1 :

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219。

示例 2 :

输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。

示例 3 :

输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0。
class Solution {
public:
    string removeKdigits(string num, int k) {
        if(k==0) return num;
        vector<int> reservedNum;
        reservedNum.push_back(num[0]);
        int deleteNum=0;
        for(int i=1;i<num.size();i++){
            while(deleteNum<k && !reservedNum.empty() && num[i]<reservedNum.back()){
                reservedNum.pop_back();
                deleteNum++;
            }
            if(reservedNum.empty()&&num[i]=='0')continue;
            else
            reservedNum.push_back(num[i]);
        }

        string res;
        int n = reservedNum.size()>num.size()-k ?num.size()-k:reservedNum.size();  
        for(int i=0;i<n;i++){
            res+=reservedNum[i];
        }
        return res.size() == 0 ? "0" : res;
    }
};
316. 去除重复字母

难度中等490

给你一个字符串 s ,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证 返回结果的字典序最小(要求不能打乱其他字符的相对位置)。

**注意:**该题与 1081 https://leetcode-cn.com/problems/smallest-subsequence-of-distinct-characters 相同

示例 1:

输入:s = "bcabc"
输出:"abc"

示例 2:

输入:s = "cbacdcbc"
输出:"acdb"

提示:

  • 1 <= s.length <= 104
  • s 由小写英文字母组成
class Solution {
public:
    string removeDuplicateLetters(string s) {
        vector<int> chTimes(26,0);
        for(auto i : s){
            chTimes[i-'a']++;
        }
        vector<char> reserveCh;
        for(int i = 0;i<s.size();i++){
            if(find(reserveCh.begin(),reserveCh.end(),s[i])==reserveCh.end()){
                while(!reserveCh.empty() && s[i]<reserveCh.back() && chTimes[reserveCh.back()-'a']>0){     
                    reserveCh.pop_back();
                }
                reserveCh.push_back(s[i]);   
            }
            chTimes[s[i]-'a']--;
          }
        string res;
        for(auto i : reserveCh) res+=i;
        return res;
    }
};

uplicateLetters(string s) {
vector chTimes(26,0);
for(auto i : s){
chTimes[i-‘a’]++;
}
vector reserveCh;
for(int i = 0;i<s.size();i++){
if(find(reserveCh.begin(),reserveCh.end(),s[i])==reserveCh.end()){
while(!reserveCh.empty() && s[i]<reserveCh.back() && chTimes[reserveCh.back()-‘a’]>0){
reserveCh.pop_back();
}
reserveCh.push_back(s[i]);
}
chTimes[s[i]-‘a’]–;
}
string res;
for(auto i : reserveCh) res+=i;
return res;
}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值