刷题之路——简单篇
文章平均质量分 92
刷题的艰辛路程
林先生-1
佛系……但致力于提高文章的文字水平。
展开
-
【刷题之路】LeetCode 2073. 买票需要的时间
所以当第k个人买完票时,如果他们中的每一个最多能买到的票数为tickets[k] - 1,而如果小于tickets[k] - 1,那就能买完。而如果他要买的票数大于或等于第k个人需要买的票数,那么在第k个人买完票时他能买到的票数也和第k个人的相同。那么在第k个人买完票的时候,其他的所有人能买到的票数,也即买票的时间也就已经确定了(包括买完票和未买完票)。有题目所述我们得知,每个人买到的票数即是每个人所花的时间,所以我们可以先统计完每个人所花的时间,然后再算出这些事件的总和,最后返回这个总和即可。原创 2023-05-28 17:51:32 · 700 阅读 · 4 评论 -
【刷题之路】LeetCode 面试题 03.02. 栈的最小值
我们可以借助一个辅助的栈minStack,来存储当前栈中最小的值当我们每次执行push时候,就相应的将当前栈中最小的值也入到minStack中。既然题目应经明确要求了,min操作的时间复杂度必须为O(1),那我们想用遍历的方法来找到最小值的想法也就不现实了,那我们应该怎样解决这个O(1)的问题呢?而当我们执行Pop弹栈操作时,则需要让Stack和minStack同步弹栈,以确保在任何情况下minStack的栈顶元素都为Stack中的最小值。--> 返回 -3.--> 返回 -2.原创 2023-05-27 16:49:37 · 1080 阅读 · 1 评论 -
【刷题之路】LeetCode 1700. 无法吃午餐的学生数量
给你两个整数数组 students 和 sandwiches ,其中 sandwiches[i] 是栈里面第 i 个三明治的类型(i = 0 是栈的顶部), students[j] 是初始队列里第 j 名学生对三明治的喜好(j = 0 是队列的最开始位置)。因为队列的规则是先进先出,所以我们每次只能知道队头学生喜欢的三明治类型,而不能知道具体每个学生的喜好,而且根据题目描述队列的长度有可能时时在变化,所以我们也不能单纯的统计个数。的个数为队列长度的学生都不喜欢栈顶的三明治。原创 2023-05-27 14:29:58 · 1425 阅读 · 0 评论 -
【刷题之路】LeetCode 232. 用栈实现队列
而在后面的出队操作中,如果“出队栈”不为空,我们就可以直接将“出队栈”的栈顶数据弹出并返回了,直到“出队栈”再次为空,那我们就要再次将“入队栈”清空。出队就要分两种情况,如果“出队栈”不为空,就直接将“出队栈”的栈顶元素弹出即可,如果为空,这要将“入队栈”清空,将数据压入到“出队栈”中。我们可以假设“入队栈”的数据是通过下边的弯的管道“流”过去的,这样即完成了“入队栈”的数据的逆序,并且也符合了先进先出。这其实就等于将“入队栈”中的数据给逆置了,然后我们就可以将“出队栈”的栈顶数据弹栈,最后返回了。原创 2023-05-15 17:04:43 · 760 阅读 · 2 评论 -
【刷题之路】LeetCode 225. 用队列实现栈
因为我们事先要把数据从不为空的队列中出队在入队到为空的队列中,所以和push一样,我们还是先假设其中一个队列不为空,然后在经过后面的判断,确保NonEmptyQueue 和EmptyQueue 指向正确的队列。其实这里的栈的结构体里面的两个队列也可以使用指针的,但这样会比较麻烦一些,因为如果写成指针的话就需要在额外的开辟两个队列的空间,最后也要额外的销毁这两个队列指针,所以这里就直接创建成变量了。而对于栈指针的置空,我们这里没有选用二级指针,所以在这个接口内部是置空不了的,但这里是oj,所以我们并不需要。原创 2023-05-14 21:03:04 · 404 阅读 · 0 评论 -
【刷题之路】LeetCode 234. 回文链表
其实这一步是可有可无的,而我们必须要做的是将后半部分反转后的链表的尾节点的next置空。我们需要额外创建一个全局的指针,在每次递归中,如果本次递归满足前面的节点的val和后面的节点的val相同,就让前面的节点往后走一步。递归的思路其实类似于双指针,先让递归一层层深入,直到走到链表的尾,在通过一层层的返回来模拟指针从后往前走的动作。空间复杂度:O(n),空间复杂度主要取决于递归的最大深度,这里的最大深度就是链表的长度,故空间复杂度为O(n)。所以说,将前半部分的尾置空的操作是可有可无的。原创 2023-05-09 14:59:09 · 907 阅读 · 1 评论 -
【刷题之路】LeetCode 21. 合并两个有序链表
空间复杂度:O(m+n),m和n分别为两个链表的长度,空间复杂度递归调用的层数,最坏情况下,对于两个链表的每个节点我们都要调用一次,因此空间复杂度为O(m+n)。所以我们可以将思路转化为,每次调用只需要选出较小的节点然后让较小的节点连接上后面合并后的链表即可,而后面的链表的合并也是用同样的递归方式来完成。其实从上面的解法中我们也能得到启发想出一个大事化小的解法,因为我们每次的遍历只需要选出一个较小的节点,然后尾插到新链表之中。时间复杂度:O(m+n),其中m和n分别为两个链表的长度。原创 2023-05-07 09:17:47 · 880 阅读 · 1 评论 -
【刷题之路】LeetCode 206. 反转链表
给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。空间复杂度:O(1),我们只需要用到常数级的额外空间。空间复杂度:O(1),我们只需要用到常数级的额外空间。有了以上思路,那我们写起代码来也就水到渠成了。链表中节点的数目范围是 [0, 5000]所以我们之后返回pre作为新的头节点即可。最后我们返回新的头指针newhead即可。时间复杂度:O(n),n为链表的长度。时间复杂度:O(n),n为链表的长度。原创 2023-04-26 14:46:02 · 491 阅读 · 1 评论 -
【刷题之路】LeetCode 203. 移除链表元素
我们可以创建一个新的链表,用一个新的头指针newhead指向。给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点。然后每次的尾插我们就只需要执行tail->next = cur,然后执行tail = tail->next即可。这时候的cur就没有前驱节点pre了,所以这时候就应该直接执行头删。空间复杂度:O(1),我们只需要用到常数级的额外空间。然后再使cur = pre->next即可。O(n),n为链表的长度。原创 2023-04-26 08:30:04 · 695 阅读 · 0 评论 -
【刷题之路】LeetCode 程序员面试金典 08.03. 魔术索引
给定一个有序整数数组,编写一种方法找出魔术索引,若有的话,在数组A中找出一个魔术索引,如果没有,则返回-1。空间复杂度:O(n),空间复杂度主要取决于递归调用的次数,最坏的情况下我们每个元素都要判断一次,故需要调用n次,空间复杂度为O(n)。最简单的方法就是直接遍历数组的每个元素,找到第一个nums[i] = i的元素,直接返回其下标即可。时间复杂度:O(n),n为数组的长度,最坏情况下,我们还是需要遍历完数组中的所有元素。时间复杂度:O(n),n为数组长度,最坏情况下我们需要遍历完数组中的所有元素。原创 2023-04-15 07:20:56 · 280 阅读 · 0 评论 -
【刷题之路】LeetCode 2389. 和有限的最长子序列
时间复杂度:O((n+m)logn),其中n为数组nums的长度,m为数组queries的长度,对数组nums进行排序的复杂度为nlogn,二分查找的复杂度为logn,故总的时间复杂度为O((n+m)logn)。返回一个长度为 m 的数组 answer ,其中 answer[i] 是 nums 中 元素之和小于等于 queries[i] 的 子序列 的 最大 长度。由题目描述我们可知,对于每个queries[i],我们都需要找到一个子序列,使得该子序列的元素之和不超过queries[i],原创 2023-04-12 07:04:49 · 559 阅读 · 1 评论 -
【刷题之路】LeetCode LCP 18. 早餐组合
第 2 种方案:staple[0] + drinks[1] = 10 + 5 = 15;第 5 种方案:staple[2] + drinks[1] = 5 + 5 = 10;第 6 种方案:staple[2] + drinks[2] = 5 + 2 = 7。第 1 种方案:staple[0] + drinks[2] = 2 + 5 = 7;第 2 种方案:staple[0] + drinks[3] = 2 + 1 = 3;第 5 种方案:staple[1] + drinks[3] = 1 + 1 = 2;原创 2023-04-11 08:32:44 · 138 阅读 · 1 评论 -
【刷题之路】LeetCode 1351. 统计有序矩阵中的负数
首先我们计算left到right的中间行mid行的第一个负数的位置pos(使用二分法完成),当我们找到pos,就可以确定pos左端的数字全都是小于0的,pos下边的数字也都是全部小于0的。给你一个 m * n 的矩阵 grid,矩阵中的元素无论是按行还是按列,都以非递增顺序排列。而对于下半部分,我们则可以放心的求find_negative(mid + 1, right, L, R, grid)的值。而对于负数个数的统计,我们是通过在每一次的递归中累加R - pos + 1来统计的。原创 2023-04-07 14:57:50 · 360 阅读 · 0 评论 -
【刷题之路】LeetCode 1539. 第 k 个缺失的正整数
而如果arr[arrSize - 1] - (arrSize - 1 + 1) < k的话,说明数组arr内丢失的数字还不够k个,此时就可以直接返回arr[arrSize - 1] + (k - (arr[arrSize - 1] - (arrSize - 1 + 1) ) )。由于数组时严格升序的,所以对于每个arr[i],我们都可以唯一确定到第i个元素为止缺少的数字个数为arr[i] - (i + 1) = arr[i] - i - 1。如果arr[p1]!解释:缺失的正整数包括 [5,6,7,…原创 2023-04-06 08:00:40 · 494 阅读 · 2 评论 -
【刷题之路】LeetCode 1346. 检查整数及其两倍数是否存在
当arr[p] < 0时,则需利用q指针向后遍历,当出现arr[q] == arr[p] / 2时,则直接返回true,当出现arr[q] > arr[p] / 2时,则说明数组中已不可能存在arr[p] / 2,则让p后移一位,q保持原位。当arr[p] > 0时,就使用q指针向后遍历,当出现arr[q] == 2 * arr[p]时,直接返回true即可,当出现arr[q] > 2 * arr[p]时候,arr[p]也在不断地减小,当然2 * arr[p]也在不断的减小,所以指针q也可以原地不动。原创 2023-04-03 09:05:43 · 471 阅读 · 1 评论 -
【刷题之路】LeetCode 349(350). 两个数组的交集Ⅰ(Ⅱ)
[TOC](【刷题之路】LeetCode 349(350). 两个数组的交集Ⅰ(Ⅱ))原创 2023-03-27 09:27:26 · 245 阅读 · 1 评论 -
【刷题之路】LeetCode 278. 第一个错误的版本
当isBadVersion(mid - 1) == false && isBadVersion(mid) == false时,执行left = mid + 1;所以我们其实可以直接就判断left是否为错误版本,当第一次出现 isBadVersion(left) == true时,就说明left就是第一个出错的版本,当isBadVersion(mid) == true时,说明第一个错误的版本可能出现在mid的左侧,也有可能此时的mid就是第一个错误的版本,不幸的是,你的产品的最新版本没有通过质量检测。原创 2023-03-26 10:17:52 · 217 阅读 · 0 评论 -
【刷题之路】LeetCode 268. 丢失的数字
我们设数组arr中存放的是从0到n的n + 1个数字,我们在将数组nums中的元素全部异或在一起后,再追加异或上数组arr中的全部元素,则异或的最终结果就是那个丢失的数字,因为其他数字均在数组nums和数组arr中出现了一次,总共两次。1 是丢失的数字,因为它没有出现在 nums 中。时间复杂度:O(n),n为数组元素个数,我们最多只需要遍历数组的n - 1个元素即可,股时间复杂度为O(n)。时间复杂度:O(n),n为数组元素个数,我们总共需要异或n + (n + 1)个数字,故时间复杂度为O(n)。原创 2023-03-24 14:40:02 · 245 阅读 · 0 评论 -
【刷题之路】LeetCode 746. 使用最小花费爬楼梯
注意到上面的代码在当2原创 2023-03-23 21:10:41 · 686 阅读 · 0 评论 -
【刷题之路】牛客剑指offer JZ42 连续子数组的最大和
在求最长回文子串的时候当一个子串的长度增加时,只可能有两种情况增长后的字串不是回文串和是回文串,如果是回文串,那么最长回文串的长度就一定会增加。而现在我们求的最大子串总和当子串的长度增加时,总和有可能是减小的,因为在子串增长的时候后面又可能遇到的是负数。每求出一个dp[i],我们都将它与现已有的最大子串总和max_sum进行比较,当我们遍历完数组之后,我们就求出了连续子数组的最大和。枚举出所有的子数组,求出子数组中元素的总和,每次都跟已有的最大子数组元素总和max_sum进行对比。原创 2023-03-17 10:41:35 · 765 阅读 · 1 评论 -
【刷题之路】LeetCode 26. 删除有序数组中的重复项
想一下有什么方法能在一层循环中直接找出数组中不同元素的个数而又不需要借助标记值呢?其实我们可以通过循环找到一个相同元素的序列中最后被遍历到的那个元素:即当nums[i]!时,nums[i]就是那最后一个元素。把他们依次写入数组的前半部分,最后再返回不同元素的个数即可。但是对于数组的最后两个元素,则需要进行特殊处理,因为对于最后一个元素,就无法判断nums[i]!= nums[i + 1],若是nums[i]!原创 2023-03-16 08:54:48 · 194 阅读 · 0 评论 -
【刷题之路】LeetCode 14. 最长公共前缀
我们可以把整个字符串数组分成两部分,分别求出各个部分的最长公共前缀,最后再对这两部分的最长公共前缀求最长公共前缀,其结果就是整个数组的最长公共前缀。我们用strs[0]来保存我们的最长公共前缀,将strs[0]与后面的所有字符串求最长公共前缀,扫描完所有字符串之后,strs[0]中的结果即为所有字符串的最长公共前缀。时间复杂度:O(mn),其中m为字符串数组中的字符串平均长度,n为字符串数量,在最坏的情况下(每个字符串都相同)。字符串数组中的每个字符串的每个字符我们都要比较一次。解释:输入不存在公共前缀。原创 2023-03-11 15:59:54 · 159 阅读 · 0 评论 -
【刷题之路】牛客 NC156 数组中只出现一次的数(其它数出现k次)
所以,我们完全可以只用一个变量sum来存储所有数字在某一位上的总和,具体做法是在外层循环中遍历32个二进制序列的每一位,在内层循环中遍历数组中的每个元素,利用内层循环求出所有元素在第i位上的总和,每次计算完一位上的总和时,再对sum进行取余k,由题目可知余数只能是0或1,那我们可以从最低位开始求和,每次求和完就计算answer = 2 * answer + sum % k,即可直接算出answer十进制的结果。空间复杂度:O(1),我们只需要用到常数级的额外空间,只不过这次使用的空间明显比上一次要少得多。原创 2023-03-10 08:08:34 · 169 阅读 · 0 评论 -
【刷题之路】LeetCode 9.回文数
思路和方法1的改进版的思路差不多,只不过我们这次是直接取出x两端的数字进行比较(即取出最高位和最低位)。时间复杂度:O(log10(N)),N为数字x的值,每取一个数字,我们都要对x进行除10操作,所以时间复杂度为O(log10(N))。时间复杂度:O(n),n为数字的位数或字符串的长度,转化时的复杂度为log10n,逆序时的复杂度为n/2故复杂度为O(n)。时间复杂度:O(n),n为数字的位数或字符串的长度,转化时的复杂度为log10n,比较时的复杂度为n/2故复杂度为O(n)。因此它不是一个回文数。原创 2023-03-09 08:22:17 · 355 阅读 · 2 评论 -
【刷题之路】牛客 NC74 数字在升序数组中出现的次数
那么查找k + 0.5时返回的left指向的就是第一个大于k的数,查找k - 0.5的时候返回的left指向的就是k本身。所以我们分别进行正向遍历和逆向遍历,正向遍历找到第一个大于k的数,并返回其下标,逆向遍历则找到第一个小于k的数,时间复杂度:O(log2N),N为数组元素个数,两次二分查找,二分查找的复杂度为O(log2N)。那我们就可以找到这一堆紧挨在一起的元素的边界,然后在将两个边界相减,其绝对值再减1就是k的个数。时间复杂度:O(n),n为数组元素个数,最坏的情况下,我们还是要遍历一遍数组。原创 2023-03-07 08:31:23 · 225 阅读 · 0 评论 -
【刷题之路】二分法的妙用 LeetCode 35. 搜索插入位置
当我们停下循环的时候,一定是left > right 的时候,这也一定是left向后移动的结果,而且只有当nums[mid] > target的时候才执行的left = mid + 1 (这里的mid是上一轮的mid,也即left == right时mid)直接遍历数组,如果找到target就返回其下标,当出现nums[i] < target && nums[i + 1] > target时,i + 1就是我们要顺序插入的下标。所以可以肯定的是,上一轮mid指向的元素小于target,原创 2023-03-06 09:06:37 · 143 阅读 · 3 评论 -
【刷题之路】LeetCode 27. 移除元素
我们让left指针指向数组的开头,right指针指向数组的末尾,left向右遍历,找到一个val后停下,此时将right指向的元素赋值到左指针指向的位置,然后右指针向左移动一位,如果赋值过来的元素恰好也等于val,则可以继续把right指向的元素赋值到left指向的位置,直到左指针指向的元素不等于val时,让left向右移动一位。很显然,去除val值后的数组的长度一定小于或等于原来数组的长度,所以我们可以直接把去掉val后的数组写到原来的数组中,这个过程可以通过两个指针来完成。元素的顺序可以改变。原创 2023-03-05 15:52:44 · 120 阅读 · 1 评论 -
【刷题之路】LeetCode 169 多数元素
如果将数组中的元素按升序或降序的顺序排序,那么下下标为⌊ n/2 ⌋(数组的下标从0开始,那么下标为⌊ n/2 ⌋相当于第⌊ n/2 ⌋ + 1个元素)的元素就一定是出现次数超过⌊ n/2 ⌋的元素,因为在排序后相同的元素一定是紧挨在一起的,因为那一串出现次数大于⌊ n/2 ⌋的元素的长度一定大于数组长度的一半,所以不管那一串是排在开头、中间、还是末尾。当下一个上台的元素与台上的是同一队时,count++,否则count–,当count=0时,就将令牌交给下一个要遍历到的元素。“令牌”交给下一个上台的人。原创 2023-03-04 15:36:41 · 190 阅读 · 0 评论 -
【刷题之路】NC57 反转数字
其实,我们都忽略了一点,就是当一个类型的数据要存储一个超出此类型的最大值的数的时候,就会发生“截断”。我们仔细思考之后发现,还是溢出导致的问题,那是为什么呢?2、当出现ans == INT_MAX / 10且next > 7时,则一定溢出了。先通过循环把数字的每一位拆开,在计算时候每一步都判断是否溢出,若溢出就直接返回0,否则进行下一轮循环。给定一个32位的有符号整数num,将num中的数字部分反转,最后返回反转的结果。也就是说存入变量的是一个比最大数要小的数字了,这时候判断就会出错了。原创 2023-03-03 10:42:08 · 177 阅读 · 0 评论 -
【刷题之路】OR62 倒置字符串
很简单,当然是,只不过是顺序到过来了,举个最简单的例子就是“ab-cd”逆序之后变成了“dc-ba”,那若是我们在整体逆序的基础上在进行局部逆序是不是就能做到把单词的位置逆序,而单词本身不逆序了呢?所以将这个字符的地址加入到,字符指针数组中,将它的前一个字符改成字符串结束标志’\0’即可。时间复杂度:O(n),n为字符串的总长度,(虽然是两成循环,但temp是一直往前走,所以复杂度还是O(n).就是先局部还是先整体其实结果都是一样的,其中的原理很简单,大家用个很短的例子就能搞清楚。代表调用逆置函数的次数。原创 2023-03-02 18:23:33 · 87 阅读 · 0 评论 -
【刷题之路】不一样的二分法
有一个长度为 n 的非降序数组,比如[1,2,3,4,5],将它进行旋转,即把一个数组最开始的若干个元素搬到数组的末尾,变成一个旋转数组,比如变成了[3,4,5,1,2],或者[4,5,1,2,3]这样的。当mid在“大部分”中时,就算是mid已经指向了“大部分”中的最大值,那执行mid + 1跳过的也只是“大部分”中最大的之而已,对于我们找最小值没有任何影响。在“大部分”中最小的数也比“小部分”种最大的数要大,在“小部分”中最大的数也比“大部分”最小的数要小。输入:[3, 100, 200, 3]原创 2023-03-01 10:17:38 · 86 阅读 · 2 评论 -
【刷题启航!】只用一维数组完成杨辉三角的打印
KiKi知道什么叫杨辉三角之后对杨辉三角产生了浓厚的兴趣,他想知道杨辉三角的前n行,请编程帮他解答。杨辉三角,本质上是二项式(a+b)的n次方展开后各项的系数排成的三角形。从上面我们也知道,打印的每一行都是需要通过上一行计算得来的,而且每一行用于计算下一行是是不是只是用了一次,那就代表使用了这一次之后就可以把这些数据丢弃了。这样做的好处是完成打印的同时也完成了对杨辉三角的存储,若是要求查询,也能够做到。这是我的第一篇正式的题解,写的很拙劣,让大家见笑了。包含n行,为杨辉三角的前n行,每个数输出域宽为5。原创 2023-02-28 15:38:29 · 1258 阅读 · 2 评论