常见算法技巧之——双指针思想 (3)

​ 将一个数组进行反转,只需要设置好前后两个指针,一个初始化指头,另一个初始化指尾,然后交换两个指针指向的内容,然后前面的指针+1,后面的指针-1,直到两指针相遇(数组大小为奇数),或者两指针相差1(数组大小为偶数)。

public void reverse (int[] nums) { int l = 0, r = nums.length-1; while (l < r) { int temp = nums[l]; nums[l] = nums[r]; nums[r] = temp; l++; r--; } } 滑动窗口

​ 其实滑动窗口应该也是左右指针中的一种,但因为它相对来说难以理解,所以单独拎出来做一讨论。

​ 滑动窗口大概理解起来很简单,但就是自己动手写的时候会遇到很多问题,正所谓熟能生巧,笔者也才开始练这些算法题,希望记录下学习的过程。

1、无重复字符的最长子串

​ 滑动窗口就是维护一个窗口,然后根据题目和新遇到的情况不断更新这个窗口,不断优化可能的解。举个例子,比如leetcode上的无重复字符的最长子串问题。

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。 示例 1: 输入: "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。 示例 2: 输入: "bbbbb" 输出: 1 解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。 示例 3: 输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。   请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters

​ 利用滑动窗口可以完美的解决这个问题,用左指针指示窗口的最左端,右指针指示窗口的最右端,初始左指针指示第0个元素,右指针指示-1,定义一个set集合存储当前解(即当前窗口中包含的字符),然后开始一直移动右指针,使其向右移动,直到碰到一个已经添加到当前解中的字符,这时记录下当前的set的大小为当前最优解,然后将左指针向右移动一个,并在当前解set中移出窗口最左边的字符。之后就是继续移动右指针,更新当前解,每次右指针碰到当前解中已存在的字符时,判断一下当前解的大小,如果比之前的最优解更优,则更新,反之不更新,继续移出窗口中最左边的字符,然后继续重复上述操作,直到右指针到达字符串末尾。

class Solution { public int lengthOfLongestSubstring(String s) { Set<Character> ss = new HashSet(); //定义右指针 int res = 0, r = -1; for(int i = 0; i < s.length(); i++) { if (i != 0) { ss.remove(s.charAt(i-1)); //去掉上次最左边的元素 } while (r+1 < s.length() && !ss.contains(s.charAt(r+1))) { ss.add(s.charAt(r+1)); ++r; //移动右指针 } res = Math.max(res,r-i+1); //上次的最优和这次的最优进行对比,每次子串的开头不一样 if (r == s.length()-1) { //r右指针已经到了最右边,所以直接break出来,因为后面不会再有向当前解中增加元素,只会慢慢弹出当前解的元素,所以不必再继续 break; } } return res; } } 2、最小覆盖子串 给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。 示例: 输入:S = "ADOBECODEBANC", T = "ABC" 输出:"BANC" 提示: 如果 S 中不存这样的子串,则返回空字符串 ""。 如果 S 中存在这样的子串,我们保证它是唯一的答案。 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/minimum-window-substring

​ 1. 这道题利用滑动窗口也可以很优雅的解决,还是先初始化两个指针l = 0, r = 0指向字符串S,开始先向右移动右指针使得窗口增大,而右指针停止移动的条件是当前左指针到右指针,即窗口内已经包含了字符串T,接着开始向右移动左指针,使得窗口尽可能的小,但要确保窗口中始终是包含字符串T的,等到左指针移动到不能再移动的时候,也就是若左指针再移动一次,则窗口中将不能包含字符串T的所有字符。这时的窗口是当前解,也就是当前最优解。

​ 2. 将其保存下来,之后向右移动一下左指针,使得窗口中不再包含T的所有字符,也就是移出去了一个T中的字符,继续向右移动右指针使其扩张,直到窗口再次包含了字符串T,然后继续移动左指针直到窗口最小,比较当前解和前面的最优解,保存下更优的。

​ 3. 接下来就是重复操作2,直到右指针到最后一个字符后,再移动左指针,得到窗口最小的时候的解,并继续比较之前的最优解,保存更优的。

​ 上面大概写完滑动的过程,再来说说针对这个题,实现的时候的一些细节。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwywzf.html