想要精通算法和SQL的成长之路 - 无重复字符的最长子串和滑动窗口最大值

想要精通算法和SQL的成长之路 - 无重复字符的最长子串

  • 前言
  • 一. 无重复字符的最长子串
  • 二. 滑动窗口最大值
    • 2.1 滑动窗口的基本操作

前言

想要精通算法和SQL的成长之路 - 系列导航

一. 无重复字符的最长子串

原题链接
想要精通算法和SQL的成长之路 - 无重复字符的最长子串和滑动窗口最大值_第1张图片
思路如下:

  • 用一个滑动窗口,该窗口区间范围内[left,right]的字符串我们认定为不包含重复字符。
  • 我们用一个HashMap存储每个字符最后一次出现的索引位置,left
  • 我们遍历字符串,下标是right。如果当前遍历的字符存在于我们这个HashMap中,说明遇到重复字符了。就需要计算当前窗口的无重复字符长度。
  • 开始计算当下窗口的长度,更新最大值。同时更新索引。
public int lengthOfLongestSubstring(String s) {
    HashMap<Character, Integer> dic = new HashMap<>();
    int length = s.length(), left = -1, max = 0;
    for (int right = 0; right < length; right++) {
        // 遇到重复字符了,更新最后一次出现的下标位置
        if (dic.containsKey(s.charAt(right))) {
            left = Math.max(left, dic.get(s.charAt(right)));
        }
        // 更新当前字符出现的最后一次位置
        dic.put(s.charAt(right), right);
        // 更新最大长度
        max = Math.max(max, right - left);
    }
    return max;
}

二. 滑动窗口最大值

原题链接
想要精通算法和SQL的成长之路 - 无重复字符的最长子串和滑动窗口最大值_第2张图片

2.1 滑动窗口的基本操作

首先说下滑动窗口的一个重要特性:

  • 左右侧边界都可以改变,达到一个滑动的效果。

那么在Java里面,我们可以利用双向队列的特性来代表滑动窗口。

LinkedList<Integer> queue = new LinkedList<>();

这么一个数据结构,它用文字表达就是:

  • 队首 <----> 队尾

相关的操作就是:

  • 获取队首元素或者移除:addFirst | pollFirst
  • 获取队尾元素或者移除:addLast | pollLast

再回归我们本题,我们在滑动窗口里面存储什么东西比较合适?我们可以存储数组的下标,它有这么几个作用或者特性:

  • 我们可以根据下标拿到对应的值。而且下标容易用来计算滑动窗口的大小和位置。
  • 我们让滑动窗口存储的下标,让其对应的值,按照从大到小的顺序来排序。这样队首下标对应的元素就是我们需要的滑动窗口的最大值。

我们来看代码,几个重要的点就是:

  1. 遇到比较大的元素(比队尾的大),就要以此从队尾移除元素。保证下标值对应的数组元素从大到小
  2. 如果滑动窗口的大小超过了k,就要把队首元素移除。
  3. 只要满足了滑动窗口的大小,就可以把对应的最大值添加到结果集中。
public int[] maxSlidingWindow(int[] nums, int k) {
    // 特判
    if (nums == null || nums.length < 2) {
        return nums;
    }
    // 双向队列,存储的是数组的下标,数组下标对应的值从大到小存储
    LinkedList<Integer> queue = new LinkedList<>();
    int[] res = new int[nums.length - k + 1];
    for (int i = 0; i < nums.length; i++) {
        // 1.把比当前元素值小的以此从队尾排出。队首(从大)--->队尾(到小)
        while (!queue.isEmpty() && nums[queue.peekLast()] <= nums[i]) {
            queue.pollLast();
        }
        // 将当前下标加入到队尾
        queue.addLast(i);
        // 2.若滑动窗口大小超了,把队首元素剔除
        if (queue.peek() <= i - k) {
            queue.poll();
        }
        // 3.如果满足了滑动窗口长度,取队首元素对应的值即可
        if (i + 1 >= k) {
            res[i + 1 - k] = nums[queue.peek()];
        }
    }
    return res;
}

你可能感兴趣的:(精通算法和SQL之路,算法,sql,数据库)