算法训练营打卡Day11

今天我们继续来学习栈和队列

目录

150. 逆波兰表达式求值
239. 滑动窗口最大值--> 队列的应用
347.前 K 个高频元素

题目1.150. 逆波兰表达式求值

题目链接/讲解链接:代码随想录

. - 力扣(LeetCode)

python(双指针)

这是笔者第一个版本,超出了时间限制ww

class Solution(object):
    def evalRPN(self, tokens):
        res = 0
        while tokens != None or len(tokens) != 1:
            #快慢指针,每次循环都会重置快慢指针
            fast = 1
            slow = 0
            #快指针向前移动一个单位,如果快指针移动后指向的是数字,慢指针也移动
            #如果快指针移动后指向的是运算符,慢指针不动,进行运算后移除数字和符号,然后重置指针
            if type(tokens[fast + 1]) == int:
                fast += 1
                slow += 1
            if type(tokens[fast + 1]) != int:
                if tokens[fast + 1] == '+':
                    #加法
                    temp = tokens[fast] + tokens[slow]
                    #还要对数字和符号作替换操作,替换成运算后的结果
                    del tokens[slow + 1 : fast + 1] #end的位置是开区间
                    tokens[slow] = temp  #慢指针的位置替换成temp即可
                if tokens[fast + 1] == '-':
                    temp = tokens[fast] - tokens[slow]
                    del tokens[slow + 1 : fast + 1] 
                    tokens[slow] = temp
                if tokens[fast + 1] == '*':
                    temp = tokens[fast] * tokens[slow]
                    del tokens[slow + 1 : fast + 1] 
                    tokens[slow] = temp
                if tokens[fast + 1] == '/':
                    temp = tokens[fast] / tokens[slow]
                    del tokens[slow + 1 : fast + 1]
                    tokens[slow] = temp
        #当tokens中只有一个元素时,循环结束,直接返回列表中的值即可
        return tokens[0] 

python(栈)

优化一下代码,使用stack来完成:

class Solution(object):  
    def evalRPN(self, tokens):
        #初始化一个栈  
        stack = []  
        operators = {'+', '-', '*', '/'}  
        for token in tokens:  
            if token not in operators:  
                # 如果是数字,则转换为整数(假设所有数字都是整数)  
                stack.append(int(token))  
            else:  
                # 如果是运算符,则从栈中弹出两个数字进行计算  
                num2 = stack.pop()  
                num1 = stack.pop()  
                if token == '+':  
                    stack.append(num1 + num2)  
                elif token == '-':  
                    stack.append(num1 - num2)  
                elif token == '*':  
                    stack.append(num1 * num2)  
                elif token == '/':  
                    # 注意处理除数为0的情况  
                    if num2 == 0:  
                        raise ValueError("除数或被除数不能为0")  
                    stack.append(num1 / num2)  # 如果需要整数除法 
        # 栈中最后剩下的元素就是表达式的结果  
        return stack[0]

C(栈)

#include <stdio.h>  
#include <stdlib.h>  
#include <ctype.h> // 用于isdigit函数  
  
#define MAX_SIZE 1000 // 假设输入的tokens数量不会超过这个值  
  
// 函数声明  
int evalRPN(char** tokens, int tokensSize);  
  
int main() {  
    // 示例:tokens数组和大小,注意C语言中字符串是以null结尾的  
    char* tokens[] = {"2", "1", "+", "3", "*"};  
    int tokensSize = sizeof(tokens) / sizeof(tokens[0]);  
  
    // 调用evalRPN函数并打印结果  
    int result = evalRPN(tokens, tokensSize);  
    printf("Result: %d\n", result);  
  
    return 0;  
}  
  
// 逆波兰表达式求值函数  
int evalRPN(char** tokens, int tokensSize) {  
    int stack[MAX_SIZE]; // 使用静态数组作为栈  
    int top = -1; // 栈顶指针,初始化为-1表示栈为空  
  
    for (int i = 0; i < tokensSize; i++) {  
        if (isdigit(tokens[i][0])) { // 如果当前token是数字  
            // 将数字转换为整数并入栈  
            stack[++top] = atoi(tokens[i]);  
        } else { // 如果当前token是运算符  
            int num2 = stack[top--]; // 弹出栈顶元素作为第二个操作数  
            int num1 = stack[top--]; // 弹出新的栈顶元素作为第一个操作数  
  
            switch (tokens[i][0]) { // 根据运算符执行相应的运算  
                case '+':  
                    stack[++top] = num1 + num2;  
                    break;  
                case '-':  
                    stack[++top] = num1 - num2;  
                    break;  
                case '*':  
                    stack[++top] = num1 * num2;  
                    break;  
                case '/':  
                    if (num2 == 0) {  
                        // 处理除数为0的情况  
                        fprintf(stderr, "Error: Division by zero\n");  
                        exit(EXIT_FAILURE);  
                    }  
                    stack[++top] = num1 / num2;  
                    break;  
                default:  
                    // 未知运算符  
                    fprintf(stderr, "Error: Unknown operator '%c'\n", tokens[i][0]);  
                    exit(EXIT_FAILURE);  
            }  
        }  
    }  
  
    // 栈中最后剩下的元素就是表达式的结果  
    return stack[top];  
}

题目2.239. 滑动窗口最大值

题目链接/讲解链接:代码随想录

python

笔者刚开始没有注意到K的条件限制,无语了~

完成本题有几个注意点(基于个人的错误,第一个是错误版本,第二个是更改版本):

class Solution(object):
    def maxSlidingWindow(self, nums, k):
        i = 0
        #初始化一个队列
        Myqueue = []
        res = []
        while i <= (len(nums) - 3):
            for item in nums[i:i + 3]:
                #如果队列是空的
                if Myqueue == []:
                    Myqueue.append(item)
                if Myqueue[0] < item:
                    Myqueue.pop()
                    Myqueue.append(item)
                if Myqueue[0] == item or Myqueue[0] > item:
                    Myqueue.append(item)
                res.append(Myqueue.pop())
                Myqueue.clear()
        return res
char * removeDuplicates(char * s){
    //求出字符串长度
    int strLength = strlen(s);
    //开辟栈空间。栈空间长度应为字符串长度+1(为了存放字符串结束标志'\0')
    char* stack = (char*)malloc(sizeof(char) * strLength + 1);
    int stackTop = 0;

    int index = 0;
    //遍历整个字符串
    while(index < strLength) {
        //取出当前index对应字母,之后index+1
        char letter = s[index++];
        //若栈中有元素,且栈顶字母等于当前字母(两字母相邻)。将栈顶元素弹出
        if(stackTop > 0 && letter == stack[stackTop - 1])
            stackTop--;
        //否则将字母入栈
        else
            stack[stackTop++] = letter;
    }
    //存放字符串结束标志'\0'
    stack[stackTop] = '\0';
    //返回栈本身作为字符串
    return stack;
}
  1. 滑动窗口的大小是 k 而不是固定的 。

  2. 队列应该在添加新元素时保持队列的递减顺序(即队列头部始终是窗口中的最大值),并且在添加新元素前应该移除所有小于新元素的元素。

  3. 每次窗口滑动后,保存队列的头部元素(即当前窗口的最大值)到结果列表中,而不是在每次迭代中都清空队列和添加队列尾部元素到结果列表。

  4. 循环条件 i <= (len(nums) - 3) 应该是 i <= (len(nums) - k),以确保处理所有可能的窗口。

题目3.347.前 K 个高频元素

题目链接/讲解链接:代码随想录

优先级队列正式登场!大顶堆、小顶堆该怎么用?| LeetCode:347.前 K 个高频元素_哔哩哔哩_bilibili

. - 力扣(LeetCode)

这道题目主要涉及到如下三块内容:

  1. 要统计元素出现频率
  2. 对频率排序
  3. 找出前K个高频元素

python

class Solution(object):
    def topKFrequent(self, nums, k):
        # 使用字典统计数字出现次数
        time_dict = defaultdict(int)
        for num in nums:
            time_dict[num] += 1
        # 更改字典,key为出现次数,value为相应的数字的集合
        index_dict = defaultdict(list)
        for key in time_dict:
            index_dict[time_dict[key]].append(key)
        # 排序
        key = list(index_dict.keys())
        key.sort()
        result = []
        cnt = 0
        # 获取前k项
        while key and cnt != k:
            result += index_dict[key[-1]]
            cnt += len(index_dict[key[-1]])
            key.pop()

        return result[0: k]

C

 public int[] TopKFrequent(int[] nums, int k) {
        //哈希表-标权重
        Dictionary<int,int> dic = new();
        for(int i = 0; i < nums.Length; i++){
            if(dic.ContainsKey(nums[i])){
                dic[nums[i]]++;
            }else{
                dic.Add(nums[i], 1);
            }
        }
        //优先队列-从小到大排列
        PriorityQueue<int,int> pq = new();
        foreach(var num in dic){
            pq.Enqueue(num.Key, num.Value);
            if(pq.Count > k){
                pq.Dequeue();
            }
        }
        
        // //Stack-倒置
        // Stack<int> res = new();
        // while(pq.Count > 0){
        //     res.Push(pq.Dequeue());
        // }
        // return res.ToArray();

        //数组倒装
        int[] res = new int[k];
        for(int i = k - 1; i >= 0; i--){
            res[i] = pq.Dequeue();
        }
        return res;
    }

总结:1、在循环中直接修改列表 tokens 的长度和内容,这通常不是处理此类逆波兰表达式求值的问题的最佳方式,因为它可能导致索引错误或不必要的复杂性。

2、待续

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值