每日一题——MP3

每日一题——MP3

本系列主要记录,我在刷题过程中的一些值得总结归纳的题

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

题目描述

MP3 Player因为屏幕较小,显示歌曲列表的时候每屏只能显示几首歌曲,用户要通过上下键才能浏览所有的歌曲。为了简化处理,假设每屏只能显示4首歌曲,光标初始的位置为第1首歌。

现在要实现通过上下键控制光标移动来浏览歌曲列表,控制逻辑如下:

  1. 歌曲总数<=4的时候,不需要翻页,只是挪动光标位置。

光标在第一首歌曲上时,按Up键光标挪到最后一首歌曲;光标在最后一首歌曲时,按Down键光标挪到第一首歌曲。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他情况下用户按Up键,光标挪到上一首歌曲;用户按Down键,光标挪到下一首歌曲。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. 歌曲总数大于4的时候(以一共有10首歌为例):

特殊翻页:屏幕显示的是第一页(即显示第1 – 4首)时,光标在第一首歌曲上,用户按Up键后,屏幕要显示最后一页(即显示第7-10首歌),同时光标放到最后一首歌上。同样的,屏幕显示最后一页时,光标在最后一首歌曲上,用户按Down键,屏幕要显示第一页,光标挪到第一首歌上。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

一般翻页:屏幕显示的不是第一页时,光标在当前屏幕显示的第一首歌曲时,用户按Up键后,屏幕从当前歌曲的上一首开始显示,光标也挪到上一首歌曲。光标当前屏幕的最后一首歌时的Down键处理也类似。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

其他情况,不用翻页,只是挪动光标就行。

数据范围:命令长度1≤s≤100 ,歌曲数量 1≤n≤150

进阶:时间复杂度: O(n) ,空间复杂度: O(n)

输入描述:

输入说明:
1 输入歌曲数量
2 输入命令 U或者D

输出描述:

输出说明
1 输出当前列表
2 输出当前选中歌曲

示例1

输入:

10
UUUU

复制

输出:

7 8 9 10
7

题目分析

这个是一道典型的滑动窗口问题,所谓的滑动窗口问题就是,用队列出队和入队操作来达到一个显示内容的变化。只不过是要进行一定的特别判断而已,因为题目中谈到,在第一页的时候,要翻到最后一页的最后一个歌曲,当你翻到最后一页的时候还要翻回第一页:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

类似于这种有一个框可以不断对内容进行框选,进行展示。明白了具体框架,我们还要对一些具体实现进行讨论,就比如具体显示我明白了,那它怎么来模拟光标呢,翻页的逻辑是怎么样的呢??我们可以这样来想,我们不是只是为了来确定光标的位置么,不妨用这个队列的头当作MP3窗口的起始点,锚定,如果要输出页面就从,队头取出四个元素进行输出就行了,然后把队尾当成要移动的光标,来执行命令,就可以了。

推理成立,实践开始;

代码实现

#include<string>
#include <iostream>
using namespace std;
//建立队列
int n;
int hh = 1;//队头
int tt = 1;//队尾
void up_judge()
{
    tt--;//光标上移
    if(hh == 1 && tt < hh)//如果是第一页就翻到最后一个元素 
    {
        hh = n >= 4? n - 3: 1;//在这里对是不是大于四 进行判断,看是否跳转页面
        tt = n;//让光标指向末尾
    }
    else
    {
        if(tt < hh) hh = tt;//如果队尾在对头的前面就要让锚定点向前走一个,让显示减少

    }

}
void down_judge()
{
    tt++;//光标后移
    if(tt > n)
    {
        hh = tt = 1;//如果是到了最后向下翻,回到第一页
    }
    else {
        if(tt - hh + 1 > 4) hh++;//如果是一般翻页就让窗口向后显示
    }
   

}
int main() {
    string order;
    cin >> n;
    cin >> order;//输入命令
    //初始化
  
    for(int i = 0;i < order.size();i++)//遍历命令
    {
        if(order[i] == 'U')
        {
            up_judge();

        }
        else 
        {
            down_judge();
        }

    }
    for(int j = hh,i = 1;i <= 4 && j <= n;i++,j++)
    {
        cout << j  << ' ' ;//因为队头其实是窗口的锚定点,所以包括它在内的后四个元素就是,当前窗口显示
    }
    cout << endl;
    cout << tt;//因为数字是连续的所以队尾的指向也是对应位置的元素,而且我们也是用队尾模拟的光标,所以可以
    return 0;
    
}
// 64 位输出请用 printf("%lld")

可以看到的是,我并没有真的开一个数组来模拟实现队列,而只是用了两个下标,利用队列的思想来进行模拟的。因为本题的数字是连续的,所以可以直接将队头队尾的位置当作元素进行输出,因为我的对头队尾是从1开始到n。

后记

其实单调队列也是在解题中的常用思想,所以多加练习,争取掌握。

最后附上罗老师的话和大家共勉

人最大的痛苦,就是无法跨越知道和做到的鸿沟。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 15
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值