【刷题之路】LeetCode 2073. 买票需要的时间

news2024/12/22 19:26:01

【刷题之路】LeetCode 2073. 买票需要的时间

  • 一、题目描述
  • 二、解题
    • 1、方法1——记录每个人需要的时间
      • 1.1、思路分析
      • 1.2、代码实现
    • 2、方法2——队列+记录下标
      • 2.1、思路分析
      • 2.2、先将队列实现一下
      • 2.3、代码实现

一、题目描述

原题连接: 2073. 买票需要的时间
题目描述:
有 n 个人前来排队买票,其中第 0 人站在队伍 最前方 ,第 (n - 1) 人站在队伍 最后方 。
给你一个下标从 0 开始的整数数组 tickets ,数组长度为 n ,其中第 i 人想要购买的票数为 tickets[i] 。
每个人买票都需要用掉 恰好 1 秒 。一个人 一次只能买一张票 ,如果需要购买更多票,他必须走到 队尾 重新排队(瞬间 发生,不计时间)。如果一个人没有剩下需要买的票,那他将会 离开 队伍。
返回位于位置 k(下标从 0 开始)的人完成买票需要的时间(以秒为单位)。

示例 1:

输入: tickets = [2,3,2], k = 2
输出: 6
解释:

  • 第一轮,队伍中的每个人都买到一张票,队伍变为 [1, 2, 1] 。
  • 第二轮,队伍中的每个都又都买到一张票,队伍变为 [0, 1, 0] 。
    位置 2 的人成功买到 2 张票,用掉 3 + 3 = 6 秒。

示例 2:

输入: tickets = [5,1,1,1], k = 0
输出: 8
解释:

  • 第一轮,队伍中的每个人都买到一张票,队伍变为 [4, 0, 0, 0] 。
  • 接下来的 4 轮,只有位置 0 的人在买票。
    位置 0 的人成功买到 5 张票,用掉 4 + 1 + 1 + 1 + 1 = 8 秒。

提示:
n == tickets.length
1 <= n <= 100
1 <= tickets[i] <= 100
0 <= k < n

二、解题

1、方法1——记录每个人需要的时间

1.1、思路分析

很显然,我们的程序是要在第k个人买完票的时候停止。那么在第k个人买完票的时候,其他的所有人能买到的票数,也即买票的时间也就已经确定了(包括买完票和未买完票)。
具体的:
1、对于排在第k个人前面的或者第k个人(即i <= k),因为他们的买票顺序一定先于第k个人(即使是重排到队尾也还是前面的人先重排)。
在这里插入图片描述
如果他们其中一人要买的票数小于第k个人要买的票数,那么他在第k个人买完票之前就能先买完票。而如果他要买的票数大于或等于第k个人需要买的票数,那么在第k个人买完票时他能买到的票数也和第k个人的相同。
所以对于位置小于或等于k的人,他在第k个人买完票时能买到的票数是min(tickets[i], tickets[k])。
2、而对于排在第k个人后面的人,如上面所说的,他们买票的顺序一定是在第k个人之后。所以当第k个人买完票时,如果他们中的每一个最多能买到的票数为tickets[k] - 1,而如果小于tickets[k] - 1,那就能买完。
所以对于位置大于k的人,他在第k个人买完票时能买到的票数是min(tickets[i], tickets[k] - 1)。

有题目所述我们得知,每个人买到的票数即是每个人所花的时间,所以我们可以先统计完每个人所花的时间,然后再算出这些事件的总和,最后返回这个总和即可。

1.2、代码实现

有了以上思路,那我们写起代码来也就水到渠成了:

int min(int x, int y) {
    return x < y ? x : y;
}
int timeRequiredToBuy(int* tickets, int ticketsSize, int k) {
    assert(tickets);
    int *time = (int*)malloc(ticketsSize * sizeof(int));
    if (NULL == time) {
        perror("malloc fail!\n");
        exit(-1);
    }
    int i = 0;
    for (i = 0; i < ticketsSize; i++) {
        if (i <= k) {
            time[i] = min(tickets[i], tickets[k]);
        } else {
            time[i] = min(tickets[i], tickets[k] - 1);
        }
    }
    int totalTime = 0; // 统计总时间
    for (i = 0; i < ticketsSize; i++) {
        totalTime += time[i];
    }
    free(time);
    return totalTime;
}

2、方法2——队列+记录下标

可能方法一的思路会有点儿抽象,有的朋友可能会看不懂。
但没关系,我这里还准备了第二种思路更简单易懂的方法,保证你能听得懂,只不过代码比方法一要稍微复杂“一点儿”。

2.1、思路分析

其实题目中描述的未买完票的人继续回到队尾排理解起来并不难,用队列实现也非常简单。但最主要的问题是当队列重排了之后我们并不能知道之后买完票的人是最初始队列中的第几个。
这个问题其实很容易解决,我们可以采用类似键值对的方式,创建一个结构体,里面保存好最初始队列中每个人对应的位置(下标)和票数(值),就像下面这样:

typedef struct keyVal {
    int index;
    int val;
} keyVal;

然后我们再将队列保存的数据改成keyVal,再将初始队列中每个人对应的keyVal入队。这样在任何时候当队列中有人买完票,我们就知道是初始队列中的第几个人买完票了,那么这一题也就迎刃而解了。

2.2、先将队列实现一下

因为我是用的是C语言,所以没办法还是得先自己造轮子,先将队列实现一下。
(没想到吧,这年头还有人用纯C刷这么多的题)

// 创建一个结构体,保存数组中对应的之和下标
typedef struct keyVal {
    int index;
    int val;
} keyVal;

// 先将队列实现一下
// 重定义数据类型
typedef keyVal QDataType;
// 定义节点类型
typedef struct QueueNode {
	struct QueueNode* next;
	QDataType data;
} QueueNode;
// 定义队列类型
typedef struct Queue {
	QueueNode* head;
	QueueNode* tail;
} Queue;
// 队列的初始化
void QueueInit(Queue* pq);
// 队列的入队
void QueuePush(Queue* pq, QDataType x);
// 队列的出队
void QueuePop(Queue* pq);
// 返回队列的对头元素
QDataType QueueFront(Queue* pq);
// 返回队列的队尾元素
QDataType QueueBack(Queue* pq);
// 返回队列中的节点个数
int QueueSize(Queue* pq);
// 判断队列是否为空
bool QueueEmpty(Queue* pq);
// 销毁队列
void QueueDestroy(Queue* pq);
// 队列的初始化
void QueueInit(Queue* pq) {
	assert(pq);
	pq->head = NULL;
	pq->tail = NULL;
}
// 队列的入队
void QueuePush(Queue* pq, QDataType x) {
	assert(pq);
	// 创建一个新节点
	QueueNode* newNode = (QueueNode*)malloc(sizeof(QueueNode));
	if (NULL == newNode) {
		perror("malloc fail!\n");
		exit(-1);
	}
	newNode->data = x;
	if (NULL == pq->head) {
		pq->head = newNode;
		pq->tail = newNode;
		pq->tail->next = NULL;
	}
	else {
		pq->tail->next = newNode;
		pq->tail = pq->tail->next;
		pq->tail->next = NULL;
	}
}
// 队列的出队
void QueuePop(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	QueueNode* next = pq->head->next;
	free(pq->head);
	pq->head = next;
	// 如果对头为空了,我们也要把队尾也给置空,避免野指针
	if (NULL == pq->head) {
		pq->tail = NULL;
	}
}
// 返回队列的对头元素
QDataType QueueFront(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->head->data;
}
// 返回队列的队尾元素
QDataType QueueBack(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	return pq->tail->data;
}
// 返回队列中的节点个数
int QueueSize(Queue* pq) {
	assert(pq);
	assert(!QueueEmpty(pq));
	QueueNode* cur = pq->head;
	int size = 0;
	while (cur) {
		size++;
		cur = cur->next;
	}
	return size;
}
// 判断队列是否为空
bool QueueEmpty(Queue* pq) {
	assert(pq);
	return pq->head == NULL;
}
// 销毁队列
void QueueDestroy(Queue* pq) {
	assert(pq);
	if (!QueueEmpty(pq)) {
        QueueNode* cur = pq->head;
        QueueNode* next = cur->next;
        while (cur) {
            next = cur->next;
            free(cur);
            cur = next;
        }
    }
	
	pq->head = NULL;
	pq->tail = NULL;
}

其实这里也就是将以前写过的队列CV大法了一遍,也就只改了个数据类型。并没有什么复杂或难的。
熟悉队列这个数据结构的朋友完全可以不看这里的实现啦。

2.3、代码实现

有了以上的思路和队列的实现,那我们写起代码来也就水到渠成了:

int timeRequiredToBuy(int* tickets, int ticketsSize, int k) {
    assert(tickets);
    int time = 0;
    Queue queue;
    QueueInit(&queue);
    int i = 0;
    keyVal *keyArray = (keyVal*)malloc(ticketsSize *sizeof(keyVal));
    if (NULL == keyArray) {
        perror("malloc fail!\n");
        exit(-1);
    }
    // 先完善好keyArray
    for (i = 0; i < ticketsSize; i++) {
        keyArray[i].index = i;
        keyArray[i].val = tickets[i];
    }
    // 再将keyArray中的元素入队列
    for (i = 0; i < ticketsSize; i++) {
        QueuePush(&queue, keyArray[i]);
    }
    
    while (1) {
        keyVal front = QueueFront(&queue);
        QueuePop(&queue);
        front.val--;
        if (front.val > 0) {
            QueuePush(&queue, front);
        }
        time++;
        if (front.index == k && front.val == 0) {
            break;
        }
    }
    QueueDestroy(&queue);
    free(keyArray);
    return time;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/580021.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux---用户组命令(groupadd、groupdel、groupmod、newgrp、getent)

1. groupadd命令 [rootlocalhost ~]# groupadd [选项] 组名 [rootlocalhost ~]# groupadd group1 --向系统中增加了一个新组group1&#xff0c;新组的组标识号是在当前已有的最大组标识号的基础上加1。 [rootlocalhost ~]# groupadd -g 101 group2 --向系统中增加了一个新组gr…

MySQL5.7递归查询与CTE递归查询

文章目录 一、8.0版本的递归1、CTE递归2、举例3、递归CTE的限制 二、5.7版本的递归1、find_in_set 函数2、concat函数3、自定义函数实现递归查询4、向上递归5、可能遇到的问题 一、8.0版本的递归 1、CTE递归 先看8.0版本的递归查询CET。语法规则&#xff1a; WITH RECURSIVE…

深入浅出解析Stable Diffusion完整核心基础知识 | 【算法兵器谱】

Rocky Ding 公众号&#xff1a;WeThinkIn 写在前面 【算法兵器谱】栏目专注分享AI行业中的前沿/经典/必备的模型&论文&#xff0c;并对具备划时代意义的模型&论文进行全方位系统的解析&#xff0c;比如Rocky之前出品的爆款文章Make YOLO Great Again系列。也欢迎大家提…

笔试强训错题总结(一)

笔试强训错题总结 文章目录 笔试强训错题总结选择题编程题连续最大和不要二最近公共祖先最大连续的bit数幸运的袋子手套 选择题 以下程序的运行结果是&#xff08;&#xff09; #include <stdio.h> int main(void) {printf("%s , %5.3s\n", "computer&q…

<Linux开发>驱动开发 -之-基于pinctrl/gpio子系统的beep驱动

&#xff1c;Linux开发&#xff1e;驱动开发 -之-基于pinctrl/gpio子系统的beep驱动 交叉编译环境搭建&#xff1a; &#xff1c;Linux开发&#xff1e; linux开发工具-之-交叉编译环境搭建 uboot移植可参考以下&#xff1a; &#xff1c;Linux开发&#xff1e; -之-系统移植…

如何在华为OD机试中获得满分?Java实现【人民币转换】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

认识Servlet---1

hi ,大家好,今天为大家带来Servlet相关的知识,并且实现第一个程序 &#x1f389;1.什么是Servlet &#x1f389;2.使用Servlet写一个hello程序 &#x1f33b;&#x1f33b;&#x1f33b;1.创建项目 &#x1f33b;&#x1f33b;&#x1f33b;2.引入依赖 &#x1f33b;&…

GitHub基本概念

创建日期: 2018-09-22 09:50:06 Git & GitHub Git是一个版本控制软件&#xff1a; 读作[gɪt] ,拼音读作gē y te。 Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed an…

STM32之温湿度LCD显示并上传服务器

目录 项目需求 项目框图 硬件清单 LCD1602介绍及实战 硬件接线 引脚封装 代码实现 DHT11介绍及实战 硬件接线 引脚封装 代码实现 项目设计及实现 项目设计 项目实现 项目需求 使用温湿度传感器模块&#xff08; DHT11 &#xff09;获取温度及湿度&#xff0c…

推荐计算机领域的几本入门书籍

人工智能入门&#xff1a; 人工智能&#xff1a;现代方法&#xff08;第4版&#xff09;揭示AI与chatgpt的奥秘&#xff0c;详解人工智能的发展与未来&#xff01; 推荐理由&#xff1a;系统性总结人工智能的方方面面&#xff0c;国际人工智能领域专家斯图尔特罗素撰写人工智能…

YOLO-NAS对象检测算法再一次颠覆YOLO系列算法——已超越YOLOv8

对象检测彻底改变了机器感知和解释人类世界的方式。这是计算机视觉中一项特别关键的任务,使机器能够识别和定位图像或视频中的物体。如自动驾驶汽车、面部识别系统等。推动对象检测进步的一个关键因素是发明了神经网络架构。强大的神经网络推动了对象检测的进步,增强了计算机…

Meta Learning

Meta Learning&#xff08;元学习&#xff09;是一种机器学习技术&#xff0c;它的核心思想是学习如何学习。 Meta Learning的目标是从以前的学习经验中学习到通用的学习策略和模式&#xff0c;以便在新的任务上快速适应和学习。 Meta Learning的核心思想是将学习任务视为元任…

Vivado下阻塞赋值和非阻塞赋值的对比

Verilog 基础知识 中已经介绍过了阻塞赋值和非阻塞赋值的区别&#xff0c;下面通过一个在Vivado中的简单例子来直观的反映两者的不同。 首先给出设计源代码如下。 module block(a,b,c,clk,x);input x;input clk;output reg a,b,c;always(posedge clk) begina x; //阻塞赋值…

零钱兑换,凑零钱问题,从暴力递归到动态规划(java)

凑零钱问题&#xff0c;从暴力递归到动态规划 leetcode 322 题 零钱兑换暴力递归&#xff08;这个会超时&#xff0c;leetcode 跑不过去&#xff09;递归缓存 leetcode 322 题 零钱兑换 322 零钱兑换 - 可以打开链接测试 给你一个整数数组 coins &#xff0c;表示不同面额的硬…

[MAUI]模仿Chrome下拉标签页的交互实现

文章目录 创建粘滞效果的圆控件贝塞尔曲线绘制圆创建控件创建形变可控形变形变边界形变动画 创建手势控件创建页面布局更新拖拽物位置其它细节 项目地址 今天来说说怎样在 .NET MAUI 中制作一个灵动的类标签页控件&#xff0c;这类控件常用于页面中多个子页面的导航功能。 比如…

《数据库应用系统实践》------ 公园游客日流量管理系统

系列文章 《数据库应用系统实践》------ 公园游客日流量管理系统 文章目录 系列文章一、需求分析1、系统背景2、 系统功能结构&#xff08;需包含功能结构框图和模块说明&#xff09;3&#xff0e;系统功能简介 二、概念模型设计1&#xff0e;基本要素&#xff08;符号介绍说明…

【阅读笔记】概率预测之MQ-RNN(含Pytorch代码实现)

本文作为自己阅读论文后的总结和思考&#xff0c;不涉及论文翻译和模型解读&#xff0c;适合大家阅读完论文后交流想法&#xff0c;关于论文翻译可以查看参考文献。论文地址&#xff1a;https://arxiv.org/abs/1711.11053 MQ-RNN 一. 全文总结二. 研究方法三. 结论四. 创新点五…

谷歌推出免费AI编程神器Colab,欲将Copilot拉下神坛

在如今的AI编码工具领域&#xff0c;微软旗下的Github Copilot可以算得上是一家独大&#xff0c;而作为老对手的谷歌显然并不愿屈服于此。 近日&#xff0c;谷歌通过其官网高调发文宣布&#xff0c;将为研发工具Google Colaboratory&#xff08;Colab&#xff09;加入全新的AI…

DAY 68 redis高可用的主从复制、哨兵、cluster集群

Redis 高可用 什么是高可用 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务(99.9%、99.99%、99.999%等等)。 但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#xff0c;除了保证提供正常服…

RT-Thread memheap 开启多块 SRAM的方法

验证环境 NUCLEO-L476RG 开发板&#xff0c;板载 STM32L476RGT6&#xff08;96K SARM1 32K SRAM2&#xff09; Win10 64 位 Keil MDK 5.36 RT-Thread 5.0.1 版本&#xff08;2023-05-28 master 主线&#xff09; 功能描述 最近在研究 RT-Thread 内存的管理&#xff0c;熟…