每日刷题记录(十五)

第一题:数组中的第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

解题思路:

  1. 先用大小为k的最小堆存放前k个元素
  2. 循环判断剩余元素,若大于堆顶元素,则弹出堆顶元素,放入该元素
  3. 最后返回堆顶元素

代码实现:

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

解题思路:

本题为一个回溯问题,实际上就是一个决策树的遍历过程。

  1. 路径:用双向队列sub接收已经做出的选择。
  2. 选择列表:当前可以做的选择。
  3. 结束条件:当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]]

这样就转变为环形链表的问题:而要找到环形链表的入口,采用快慢双指针即可实现:

  1. 定义快慢两个指针 slow 、 fast ,开始都是 0 表示在链表头部。
  2. 一直循环,让慢指针走一步,即 slow=nums[slow] ;让快指针走两步,即 fast=nums[fast] 执行两次,也即fast=nums[nums[fast]] 。
  3. 再使用一个指针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”

解题思路:

  1. 将时间字符串变为分钟储存在数组里进行比较
  2. 定义min = Integer.MAX_VALUE,min等于min和minutes[i+1]-minutes[i]的最小值
  3. 最后再判断一下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]);
    }
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值