目录
第一题:数组中的第K个最大元素
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
提示:
- 1 <= k <= nums.length <= 105
- -104 <= nums[i] <= 104
解题思路:
- 先用大小为k的最小堆存放前k个元素
- 循环判断剩余元素,若大于堆顶元素,则弹出堆顶元素,放入该元素
- 最后返回堆顶元素
代码实现:
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> queue = new PriorityQueue<>(k);
for(int i = 0;i < k;i++) {
queue.offer(nums[i]);
}
for(int i = k;i < nums.length;i++) {
if(queue.peek() < nums[i]) {
queue.poll();
queue.offer(nums[i]);
}
}
return queue.peek();
}
}
第二题:组合总和 III
找出所有相加之和为 n 的 k 个数的组合,且满足下列条件:
只使用数字1到9
每个数字 最多使用一次
返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次,组合可以以任何顺序返回。
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
解释: 1 + 2 + 4 = 7 没有其他符合的组合了。
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
解释: 1 + 2 + 6 = 9
1 +3 + 5 = 9
2 + 3 + 4 = 9 没有其他符合的组合了。
示例 3:
输入: k = 4, n = 1
输出: []
解释: 不存在有效的组合。在[1,9]范围内使用4个不同的数字,我们可以得到的最小和是1+2+3+4 = 10,因为10 > 1,没有有效的组合。
提示:
- 2 <= k <= 9
- 1 <= n <= 60
解题思路:
本题为一个回溯问题,实际上就是一个决策树的遍历过程。
- 路径:用双向队列sub接收已经做出的选择。
- 选择列表:当前可以做的选择。
- 结束条件:当sub的大小等于nums并且k个数的和为n时,无法再做选择。
代码实现:
class Solution {
List<List<Integer>> ret = new ArrayList<>();
Deque<Integer> sub = new ArrayDeque<>();
public List<List<Integer>> combinationSum3(int k, int n) {
dfs(n,k,1);
return ret;
}
private void dfs(int n,int k,int start) {
if(sub.size() == k && n == 0) {
ret.add(new ArrayList(sub));
return;
}
for(int i = start;i <= 9;i++) {
sub.addLast(i);
dfs(n-i,k,i+1);
sub.removeLast();
}
}
}
第三题:跳跃游戏II
给定一个长度为 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]。
示例 1:
输入: nums = [2,3,1,1,4]
输出: 2
解释: 跳到最后一个位置的最小跳跃数是 2。
从下标为 0 跳到下标为 1 的位置,跳 1 步,然后跳 3 步到达数组的最后一个位置。
示例 2:
输入: nums = [2,3,0,1,4]
输出: 2
提示:
- 1 <= nums.length <= 104
- 0 <= nums[i] <= 1000
- 题目保证可以到达 nums[n-1]
解题思路:
这道题是典型的贪心算法,通过局部最优解得到全局最优解。
我们的目标是到达数组的最后一个位置,因此我们可以先找最后一步跳跃前所在的位置,该位置通过跳跃能够到达最后一个位置,该位置的条件为i+nums[i] > nums.length-1,然后继续找最后一步跳跃前所在的位置,直到找到数组的开始位置
代码实现:
class Solution {
public int jump(int[] nums) {
int pos = nums.length-1;
int step = 0;
while(pos > 0) {
for(int i = 0;i < pos;i++) {
if(i+nums[i] >= pos) {
pos = i;
step++;
break;
}
}
}
return step;
}
}
第四题:寻找重复数
给定一个包含 n + 1 个整数的数组 nums ,其数字都在 [1, n] 范围内(包括 1 和 n),可知至少存在一个重复的整数。
假设 nums 只有一个重复的整数 ,返回这个重复的数 。
你设计的解决方案必须 不修改数组 nums且只用常量级 O(1) 的额外空间。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
提示:
- 1 <= n <= 105
- nums.length == n + 1
- 1 <= nums[i] <= n
- nums 中 只有一个整数出现两次或多次 ,其余整数均只出现 一次
解题思路:
将这个题目给的特殊的数组当作一个链表来看,数组的下标就是指向元素的指针,把数组的元素也看作指针。如0是指针,指向nums[0] ,而nums[0] 也是指针,指向 nums[nums[0]]
这样就转变为环形链表的问题:而要找到环形链表的入口,采用快慢双指针即可实现:
- 定义快慢两个指针 slow 、 fast ,开始都是 0 表示在链表头部。
- 一直循环,让慢指针走一步,即 slow=nums[slow] ;让快指针走两步,即 fast=nums[fast] 执行两次,也即fast=nums[nums[fast]] 。
- 再使用一个指针cur ,最开始为0表示在链表头部;随后,它和 slow 每次向后移动一个位置。最终,它们会在入环点相遇。
代码实现:
class Solution {
public int findDuplicate(int[] nums) {
int fast = 0;
int slow = 0;
while(true) {
slow = nums[slow];
fast = nums[nums[fast]];
if(fast == slow) break;
}
int cur = 0;
while(true) {
slow = nums[slow];
cur = nums[cur];
if(cur == slow) break;
}
return slow;
}
}
第五题:最小时间差
给定一个 24 小时制(小时:分钟 “HH:MM”)的时间列表,找出列表中任意两个时间的最小时间差并以分钟数表示。
示例 1:
输入:timePoints = [“23:59”,“00:00”]
输出:1
示例 2:
输入:timePoints = [“00:00”,“23:59”,“00:00”]
输出:0
提示:
- 2 <= timePoints.length <= 2 * 104
- timePoints[i] 格式为 “HH:MM”
解题思路:
- 将时间字符串变为分钟储存在数组里进行比较
- 定义min = Integer.MAX_VALUE,min等于min和minutes[i+1]-minutes[i]的最小值
- 最后再判断一下min和最大时间与最小时间差,返回最小值
代码实现:
class Solution {
public int findMinDifference(List<String> timePoints) {
int min = Integer.MAX_VALUE;
int[] minutes = new int[timePoints.size()];
for(int i = 0;i < timePoints.size();i++) {
minutes[i] = Integer.valueOf(timePoints.get(i).substring(0,2))*60
+ Integer.valueOf(timePoints.get(i).substring(3,5));
}
Arrays.sort(minutes);
for(int i = 0;i < minutes.length-1;i++) {
min = Math.min(min,minutes[i+1]-minutes[i]);
}
return Math.min(min,1440+minutes[0]-minutes[minutes.length-1]);
}
}