任务队列+力扣刷题集

本文介绍了队列的基本概念,包括单向队列和双向队列的操作,并展示了如何用数组和链表实现循环队列。此外,还探讨了队列在CPU超线程、任务调度等场景的应用,并通过具体编程题目(如力扣641、622、969、859等)展示了队列的实际运用,如循环队列、柠檬水找零问题、煎饼翻转排序等。文章最后提到了如何设计循环双端队列,并给出相关解题思路。
摘要由CSDN通过智能技术生成

队列基础知识

(1)队列用head指向第一个结点,用tail指向最后一个结点的下一个结点。(为了避免当head和tail指向同一个结点时,俩个所指的值相等
。人为规定当队列的头部和尾部重合的时候,队列为

(2)单向队列只能在头部进行删除操作(入队),在尾部进行插入操作(入队),双向队列可以在头尾俩端进行操作

删除头部元素的操作:head++;
加入尾部元素的操作:q[tail]=x;tail++
在这里插入图片描述

队列的实现

struct queue
{
  int a[100];
  int head;
  int tail;
 }
struct queue q;

scanf("%d",&q.a[q.tail]);
//向队列插入数字
class Queue{
public:
class Queue(int n):arr(n),head(0),tail(0)

int pop()
{
  if(tail>arr.size()-1)
   return -1;
  a[tail]=x;
  tail++;
  return 0;
}

int push()
{
  return arr[head++];
}

队列的应用

(1)CPU的超线程技术。
线程队列,可以按照队列的元素进行管理
(2)线性池的任务队列。

力扣 641 622循环队列

数组建立队列。
用俩个指针front和rear来进行元素的增加和删除。front指向队首,rear指向队尾的下一个位置,也就是下一个元素插入的位置。
count记录队列元素的数量。
max记录队列的最大容量。

思考一:数组实现

(1)拿到队首的元素:A[front]
(2) 拿到队尾元素:A[(rear-1+k)%k]请添加图片描述

(3)从尾部插入的时候,插入一次rear后移一位 (rear+1)%k防止下标越界。
(4)从队首删除的时候,删除一个一个元素front后移,(front+1)%k防止下标越界。

class MyCircularQueue {
    int queue[];
    int front;
    int rear;
    int count;
    int max;

    public MyCircularQueue(int k) {
        queue=new int[k];
        front=0;
        rear=0;
        count=0;
        max=k;
    }
    
    public boolean enQueue(int value) {
      if(isFull()) return false;
      queue[rear]=value;
      rear++;
      rear%=max;
      count++;
      return true;
    }
    
    public boolean deQueue() {
    if(isEmpty()) return false;
    front++;
    front%=max;
    count--;
    return true;
    }
    
    public int Front() {
     if(isEmpty()) return -1;
     return queue[front];
    }
    
    public int Rear() {
     if(isEmpty()) return -1;
     return queue[(rear-1+max)%max];
    }
    
    public boolean isEmpty() {
       return count==0;
    }
    
    public boolean isFull() {
       return count==max;
    }
}

思考二:链表
用front和rear分别指向队列的头元素和尾元素,添加的时候将rear指向下一个值,删除的时候将front向后移动一位。
用count记录链表的结点数量。

class MyCircularQueue {
 
  class Node{
      int val;
      Node next;

      public Node(int val)
      {
          this.val=val;
          this.next=next;
      }
  }

  Node front,rear;
  int count,max;

    public MyCircularQueue(int k) {
       max=k;
       count=0;
    }
    
    public boolean enQueue(int value) {
     if(isFull()) return false;
     Node node=new Node(value);
     if(count==0)
       front=rear=node;
    else{
        //连接到队尾后面
        rear.next=node;
        rear=rear.next;
    }
       count++;
       return true;
    }
    
    public boolean deQueue() {
    if(isEmpty()) return false;
    count--;
    front=front.next;
    return true;
    }
    
    public int Front() {
      if(isEmpty()) return -1;
      return front.val;
    }
    
    public int Rear() {
    if(isEmpty()) return -1;
       return rear.val;
    }
    
    public boolean isEmpty() {
       return count==0;
    }
    
    public boolean isFull() {
    return count==max;
    }
}

设计循环双端队列:
思路一:链表

class MyCircularDeque {
     class Node{
         int val;
         Node pre;
         Node next;

         public Node(int val)
         {
             this.val=val;
         }
     }

     int count,max;
     Node head,tail;

    public MyCircularDeque(int k) {
          count=0;
          max=k;
    }
    
    public boolean insertFront(int value) {
        if(isFull()) return false;
        Node node=new Node(value);

        if(isEmpty())
        head=tail=node;
        else
        {
            node.next=head;
            head.pre=node;
            //head向前走一步,指向新链表的首元素
            head=head.pre;
        }
        count++;
        return true;
    }
    
    public boolean insertLast(int value) {
       if(isFull()) return false;
        Node node=new Node(value);

        if(isEmpty())
        head=tail=node;
        else
        {
          tail.next=node;
          node.pre=tail;

          tail=tail.next;
        }
        count++;
        return true;
    }
    
    public boolean deleteFront() {
      if(isEmpty()) return false;
      head=head.next;
      count--;
      return true;
    }
    
    public boolean deleteLast() {
      if(isEmpty()) return false;
      tail=tail.next;
      count--;
      return true;
    }
    
    public int getFront() {
        if(isEmpty()) return -1;
       return head.val;
    }
    
    public int getRear() {
        if(isEmpty()) return -1;
        return tail.val;
    }
    
    public boolean isEmpty() {
        return count==0;
    }
    
    public boolean isFull() {
       return count==max;
    }
}

思路二:数组

向后走:(下标+1)%k
向前走:(下标-1+k)%k

class MyCircularDeque {
     int []queue;
     int front;
     int rear;
     int max;
     int count;

    public MyCircularDeque(int k) {
      queue=new int[k];
      front=0;
      rear=0;
      max=k;
      count=0;
    }
    
    public boolean insertFront(int value) {
     if(isFull()) return false;
     front=(front-1+max)%max;
     queue[front]=value;
     count++;
     return true;
    }
    
    public boolean insertLast(int value) {
     if(isFull()) return false;
     queue[rear]=value;
     rear++;
     rear%=max;
     return true;
    }
    
    public boolean deleteFront() {
    if(isEmpty()) return false;
    front++;
    front%=max;
    count--;
    return true;
    }
    
    public boolean deleteLast() {
     if(isEmpty()) return false;
     rear=(rear-1+max)%max;
     count--;
     return true;
    }
    
    public int getFront() {
      if(isEmpty()) return -1;
      return queue[front];
    }
    
    public int getRear() {
      if(isEmpty()) return -1;
      return queue[(rear-1+max)%max];
    }
    
    public boolean isEmpty() {
      return count==0;
    }
    
    public boolean isFull() {
     return count==max;
    }
}

小题狂刷

面试17.09:第k个数

有些数的素因子只有 3,5,7,请设计一个算法找出第 k 个数。注意,不是必须有这些素因子,而是必须不包含其他的素因子。例如,前几个数按顺序应该是 1,3,5,7,9,15,21。

想法
这些数字只能通过3,5,7自乘或者互乘得到.
p3,p5,p7代表357应该和哪个位置上的数计算

//第一个都和0下标相乘之后得到3,5,7
//和1下标的数字相乘之后得到9(p3=2),15(p3=3 p5=2)
//继续相乘之后得到9,25,21(p7=1) 此时由于21<25把21入队

1.建立3,5,7和哪个位置上的数字做计算的数组dp dp[0]=1;
2.将3 5 7运算之间最小的值加入到数组中
3.判断运算结果因子有谁,让因子运算步数向后走

class Solution {
 

    public int getKthMagicNumber(int k) {
        //创建一个长度为k的队列,找到最后一个元素
         int p3=0,p5=0,p7=0;
         int [] dp=new int[k];
         dp[0]=1;

         for(int i=1;i<k;i++)
         {
             dp[i]=Math.min(dp[p3]*3,Math.min(dp[p5]*5,dp[p7]*7));
             if(dp[i]%3==0) p3++;
             if(dp[i]%5==0) p5++;
             if(dp[i]%7==0) p7++;
         }
        return dp[k-1];

    }
}

力扣969:煎饼翻转

给你一个整数数组 arr ,请使用 煎饼翻转 完成对数组的排序。

一次煎饼翻转的执行过程如下:

选择一个整数 k ,1 <= k <= arr.length
反转子数组 arr[0...k-1](下标从 0 开始)

例如,arr = [3,2,1,4] ,选择 k = 3 进行一次煎饼翻转,反转子数组 [3,2,1] ,得到 arr = [1,2,3,4] 。

数组形式返回能使 arr 有序的煎饼翻转操作所对应的 k 值序列.

解法
(3241)
(1)找到待排序区间的最大值,移动到头部(4231)
(2)翻转一次(4231)再翻转一次(1324)
(3)则整个数组部分有序,部分无序,继续重复操作(21 34)(1234)
(4)直到待排序区间只有一个数的时候,整体已经排序完成。

找到待排序区的最大值翻转到头部,将待排序区整体翻转,使得最大值归位。重复步骤。

class Solution {
    list<Integer> ret=new ArrayList<>();

    public List<Integer> pancakeSort(int[] arr) {
          int n=arr.length;
          sort(arr,n);
          return ret;
      }

    public void sort(int [] arr,int n)
    {
        if(n==1) return;
        int max=0,maxidx=0;
        for(int i=0;i<n;i++)
        {
            if(arr[i]>max)
            {
                max=arr[i];
                maxidx=i;
            }
        }
        reverse(arr,0,maxidx);
        ret.add(maxidx+1);
        reverse(arr,0,n-1);
        ret.add(n);
        sort(arr,n-1);
        }

        public void reverse(int arr[],int start,int end)
        {
            while(start<=end)
            {
                int t=arr[start];
                arr[start]=arr[end];
                arr[end]=t;
                start++;
                end--;
            }
            return arr;
        }
    }

力扣860 柠檬水找零

顾客钱找零
50
10有5元 √
2010+5或者3*5

把五块钱作为最小基数,先找十块钱的钱。

class Solution {
    public boolean lemonadeChange(int[] bills) {
      int five=0,ten=0;
      for(int bill:bills)
      {
          if(bill==5)
          five++;

          if(bill==10)
          {
              if(five==0)
              return false;
              five--;
              ten++;
          }
          
          if(bill==20)
          {
              if(ten!=0&&five!=0)
              {
                  ten--;
                  five--;
              }else if(five>=3)
              five-=3;
              else return false;
          }
      }
      return false;
    }
}

力扣859:亲密字符串

class Solution {
    //true:
    //A和B只有俩处不同
    //A和B相同,字串必有重复字符
    public boolean buddyStrings(String s, String goal) {
       if(s.length()!=goal.length()) return false;
       if(s.equals(goal))
       {
           Set<Character> set=new HashSet<>();
           for(char c:s.toCharArray())
           {
               set.add(c);
           }
           return s.length()>set.size();
       }
       
       int first=-1,second=-1;
       for(int i=0;i<s.length();i++)
       {
           if(s.charAt(i)!=goal.charAt(i))
           {
               if(first==-1)
                first=i;
               else if(second==-1)
                second=i;
                else{
                   return false;
               }
           }
       }

       return second!=-1&&s.charAt(first)==goal.charAt(second)&&s.charAt(second)==goal.charAt(first);
    }
}

933最近请求次数

class RecentCounter {

//创建队列,记录当前时间的有效次数
//添加一个请求后,要从队首开始判断请求是否有效
//返回队列长度

 Queue<Integer> queue=new LinkedList<>();

    public RecentCounter() {

    }
    
    public int ping(int t) {
     queue.add(t);
     while(queue.peek()<t-3000)
     {
         queue.poll();
     }
     return queue.size();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

太一TT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值