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

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

前言

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

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

原题链接
在这里插入图片描述
思路如下:

  • 用一个滑动窗口,该窗口区间范围内[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;
}

二. 滑动窗口最大值

原题链接
在这里插入图片描述

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
滑动窗口法是一种用于解决字符串和数组相关问题的算法,它可以在O(n)的时间复杂度内解决这些问题。在无重复字符最长子串问题中,我们可以使用滑动窗口法来解决。 算法步骤如下: 1. 定义两个指针left和right,分别指向子串的左右边界。 2. 定义一个哈希表,用来存储子串中出现过的字符和它们的位置。 3. 遍历字符串,将字符和它们的位置存储到哈希表中。 4. 如果当前字符在哈希表中已经存在,说明出现了重复字符,此时需要更新left指针的位置,将left指针移到重复字符的下一个位置。 5. 计算当前子串的长度,如果比之前的最长子串长度还要长,更新最长子串长度。 6. 重复步骤3-5,直到遍历完整个字符串。 7. 返回最长子串长度。 下面是基于Qt实现的代码示例: ```cpp int lengthOfLongestSubstring(QString s) { if (s.isEmpty()) { return 0; } int left = 0, right = 0; int maxLength = 0; QHash<QChar, int> hash; while (right < s.length()) { QChar c = s.at(right); if (hash.contains(c) && hash.value(c) >= left) { left = hash.value(c) + 1; } hash.insert(c, right); int length = right - left + 1; maxLength = qMax(maxLength, length); ++right; } return maxLength; } ``` 在代码中,我们使用了QHash来存储子串中出现过的字符和它们的位置,QChar代表一个字符,QHash的key是字符,value是该字符字符串中的位置。在遍历字符串时,如果当前字符已经在哈希表中出现过,并且位置在[left, right]区间内,说明出现了重复字符,需要更新left指针的位置。 最后返回最长子串长度即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Zong_0915

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

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

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

打赏作者

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

抵扣说明:

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

余额充值