力扣爆刷第1567之TOP100五连刷51-55(滑动窗口、零钱兑换、最小覆盖子串)

力扣爆刷第1567之TOP100五连刷51-55(滑动窗口、零钱兑换、最小覆盖子串)

一、239. 滑动窗口最大值

题目链接:https://leetcode.cn/problems/sliding-window-maximum/description/
思路:求滑动窗口最大值,需要维护一个队列,队列大小就是窗口大小,要能保证每次都可以获取最大值,只需要让入队时弹出小于当前元素的元素,这样可以保证队列一段添加元素,从另一端获取最大值。

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int[] res = new int[nums.length - k + 1];
        MyQueue queue = new MyQueue();
        int j = 0;
        for(int i = 0; i < nums.length; i++) {
            queue.add(nums[i]);
            if(i + 1 >= k) {
                res[j++] = queue.getMax();
                queue.remove(nums[i-k+1]);
            }
        }
        return res;
    }

}

class MyQueue {
    LinkedList<Integer> queue = new LinkedList<>();
    public MyQueue() {}

    void add(int v) {
        while(!queue.isEmpty() && v > queue.peekLast()) queue.pollLast();
        queue.addLast(v);
    }

    void remove(int v) {
        if(!queue.isEmpty() && queue.peekFirst() == v) queue.pollFirst();
    }

    int getMax() {
        return queue.peekFirst();
    }
}

二、41. 缺失的第一个正数

题目链接:https://leetcode.cn/problems/first-missing-positive/description/
思路:求缺失的第一个正数,要求时间复杂度o(n),本身不能排序,但是可以借助数组的索引来做一个映射关系,对于如何求缺失的第一个正数,对于固定长度的数组来说,如果数组中的元素值存在超出数组长度的情况,那么数组中就一定在[1, len]不是连续的,那么我们只需要把超出范围的给排除掉,然后把位于范围内的与数组的索引进行映射,但凡能映射上的,也给进行区别标识,比如设置为负数,然后再从头到尾遍历,第一个大于0的元素所对应的索引就是缺失的第一个正数。

class Solution {
    public int firstMissingPositive(int[] nums) {
        int k = nums.length+1;
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] <= 0) nums[i] = k;
        }
        for(int i = 0; i < nums.length; i++) {
            int t = Math.abs(nums[i]);
            if(t < k) {
                nums[t-1] = -Math.abs(nums[t-1]);
            }
        }
        for(int i = 0; i < nums.length; i++) {
            if(nums[i] > 0) return i+1;
        }
        return k;
    }
}

三、LCR 140. 训练计划 II

题目链接:https://leetcode.cn/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/description/
思路:本题为求倒数第N个节点,很简单,经典快慢指针,快指针先走N步,然后快慢同步走,当快指针抵达结尾时,慢指针指向的就是倒数第N个节点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode trainingPlan(ListNode head, int cnt) {
        ListNode slow = head, fast = head;
        while(cnt > 0) {
            fast = fast.next;
            cnt--;
        }
        while(fast != null) {
            slow = slow.next;
            fast = fast.next;
        }
        return slow;
    }
}

四、322. 零钱兑换

题目链接:https://leetcode.cn/problems/coin-change/
思路:本题是完全背包,求装满背包所需物品的最少数量,完全背包不求排列组合数时是不讲究物品和背包的内外顺序的,求最小数量,定义dp[j]表示装满容量为j的背包所需的最少物品数量,那么对于每一个物品nums[i]来说,将其放入后,填满背包的最少数量为dp[j] = min(dp[j], dp[j - nums[i]] + 1),但要注意依赖的前一个位置,是否填充了物品。

**关于背包问题的小总结:**
01背包:先遍历物品后遍历背包,物品正序,背包逆序。正常背包装物品为dp[j] = Math.max(dp[j], dp[j-nums[i]] + nums[i])。求排列组合数为:p[j] += dp[j - nums[i]]。
完全背包:完全背包正常装物品不讲究物品和背包的顺序,求组合数:物品在外背包在内。求排列数:背包在外,物品在内。
class Solution {
    public int coinChange(int[] coins, int amount) {
        int[] dp = new int[amount+1];
        Arrays.fill(dp, Integer.MAX_VALUE);
        dp[0] = 0;
        for(int i = 0; i < coins.length; i++) {
            for(int j = coins[i]; j <= amount; j++) {
                if(dp[j - coins[i]] == Integer.MAX_VALUE) continue;
                dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
            }
        }
        return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
    }
}


五、76. 最小覆盖子串

题目链接:https://leetcode.cn/problems/minimum-window-substring/description/
思路:求一个字符串在另一个字符串中的最小覆盖子串,也是非常经典的题目,典型的使用滑动窗口的题,先用一个needmap记录下来所需的元素个数,然后维护一个滑动窗口,该窗口也有windowmap,然后一直扩大窗口,直到size相同开始缩小窗口并记录下来最小窗口即可。

class Solution {
    public String minWindow(String s, String t) {
        Map<Character, Integer> need = new HashMap<>();
        Map<Character, Integer> window = new HashMap<>();
        for(int i = 0; i < t.length(); i++) {
            need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1);
        }
        int valid = 0, min = Integer.MAX_VALUE, init = 0;
        int left = 0, right = 0;
        while(right < s.length()) {
            char rc = s.charAt(right++);
            if(need.containsKey(rc)) {
                window.put(rc, window.getOrDefault(rc, 0)+1);
                if(window.get(rc).equals(need.get(rc))) valid++;
            }
            while(valid == need.size()) {
                if(right - left < min) {
                    min = right - left;
                    init = left;
                }
                char lc = s.charAt(left++);
                if(need.containsKey(lc)) {
                    if(need.get(lc).equals(window.get(lc))) valid--;
                    window.put(lc, window.get(lc)-1);
                }
            }
        }
        return min == Integer.MAX_VALUE ? "" : s.substring(init, init+min);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当年拼却醉颜红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值