因为某大厂的算法没有撕出来,怒而整理该贴。部分题目有AC代码。
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
感觉和堆也没多大关系,当然,可以用堆。但是我选择快排(
面试有考到这个场景题。
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
提示:
进阶:你所设计算法的时间复杂度 必须 优于 O(n log n) ,其中 n 是数组大小。
使用 Counter 计算每个数字的频率,然后创建大小为k的小顶堆。如果堆未满,直接添加元素。如果当前元素的频率大于堆顶元素的频率,则弹出堆顶元素,并将当前元素加入堆中。最后返回堆中的元素,因为可能有相同频次的元素。
中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
例如 arr = [2,3,4] 的中位数是 3 。
例如 arr = [2,3] 的中位数是 (2 + 3) / 2 = 2.5 。
实现 MedianFinder 类:
MedianFinder() 初始化 MedianFinder 对象。
void addNum(int num) 将数据流中的整数 num 添加到数据结构中。
double findMedian() 返回到目前为止所有元素的中位数。与实际答案相差 10-5 以内的答案将被接受。
提示:
-10^5
<= num <= 10^5
为什么不能直接快排?因为快排不能保证插入有序。而我们维护小顶堆可以保证插入有序。
建立一个 小顶堆 A 和 大顶堆 B ,各保存列表的一半元素,且规定:
A 保存 较大 的一半,长度为M/2
( N 为偶数)或 (M+1)/2
( M 为奇数)。
B 保存 较小 的一半,长度为N/2
( N 为偶数)或 (N+1)/2
( N 为奇数)。
随后,中位数可仅根据 A,B 的堆顶元素计算得到
中位数为 A的堆顶元素(M≠N)或者 (A的堆顶元素+B的堆顶元素)/ 2(M==N)
时间复杂度 O(logN) :
空间复杂度 O(N) : 其中 N 为数据流中的元素数量,小顶堆 A 和大顶堆 B 最多同时保存 N 个元素。
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
提示:
一看就知道用dp,dp[i][0]
代表第i
天持有股票的最大利润,dp[i][1]
代表第i
天不持有股票的最大利润,最后根据贪心思想可知,答案返回dp[length-1][1]
。
给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。
判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。
提示:
从左到右遍历数组,用一个变量记录当前能到达的最远位置。在遍历过程中,每次都尝试更新这个最远位置。如果在遍历结束前,最远位置已经超过或等于数组的最后一个下标,那就说明可以到达最后一个下标。时间复杂度为O(N)
也可以用动态规划,但是很麻烦,因为状态转移很麻烦,而且时间复杂度为O(n)
- 核心思想:从数组的最后一个位置开始向前推导,判断每个位置是否能到达最后一个下标,利用前面位置的结果来计算当前位置的结果。
- 具体过程:
- 创建一个长度为数组 nums 长度的列表 dp
- 初始值都为 False ,dp[i] 表示从位置 i 出发能否到达最后一个下标。
- 将 dp 数组的最后一个元素设为 True ,因为最后一个位置本身就在最后一个下标处,肯定能到达。
- 从倒数第二个位置开始向前遍历数组,对于每个位置 i :
- 遍历从 1 到 nums[i] 的所有可能跳跃距离 j ,如果 i + j 不超过数组长度,并且 dp[i + j] 为 True ,说明从位置 i 跳跃 j 步后能到达最后一个下标,那么 dp[i] 为 True ,并跳出当前循环(因为只要有一种跳跃方式能到达就可以了)。
- 最后返回 dp[0] ,即从起始位置是否能到达最后一个下标。
给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。
每个元素 nums[i] 表示从索引 i 向后跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:
0 <= j <= nums[i]
i + j < n
返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]。
最开始肯定想到的是dp,但是这个时间复杂度为也为O(n^2)
dp[i] = 从索引i跳到最后一个位置的最小跳跃次数
倒数开始遍历dp,dp[length-1] = 0
对每个i
for j in range(i-nums[i], i):
dp[i] = dp[j]+1
返回dp[0]
所以我们用贪心 + 层次遍历,模拟跳跃过程,按跳跃次数分层,每次记录当前层能到达的最远范围。
给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。例如,字符串 “ababcc” 能够被分为 [“abab”, “cc”],但类似 [“aba”, “bcc”] 或 [“ab”, “ab”, “cc”] 的划分是非法的。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
示例 1:
输入:s = “ababcbacadefegdehijhklij”
输出:[9,7,8]
解释:
划分结果为 “ababcbaca”、“defegde”、“hijhklij” 。
每个字母最多出现在一个片段中。
像 “ababcbacadefegde”, “hijhklij” 这样的划分是错误的,因为划分的片段数较少。
提示:
1 <= s.length <= 500
s 仅由小写英文字母组成
记录每个字符最后出现的位置:首先遍历字符串,用哈希表记录每个字符最后一次出现的索引。