目录
一、什么是尺取法
尺取法(Two Pointers Technique)是一种常用的算法技巧,用于解决一些数组或字符串相关的问题。该方法通过使用两个指针(尺子),分别指向数组或字符串的不同位置,通过调整两个指针的位置来解决问题。
尺取法的基本思想是,通过对数组或字符串的遍历,将问题转化为两个指针之间的某种关系。通过移动指针的位置,不断调整两个指针之间的距离,以满足问题的要求。
尺取法常见的应用场景包括以下几种:
- 滑动窗口问题:通过维护两个指针来定义一个窗口,通过不断调整窗口的位置和大小,解决相关的问题。例如,最小覆盖子串、最长无重复字符子串等问题。
- 快慢指针问题:通过维护两个指针,一个快指针和一个慢指针,通过不同的移动策略,解决相关问题。例如,判断链表是否有环、寻找链表的中间节点等问题。
- 两个有序数组合并问题:通过维护两个指针,分别指向两个有序数组的末尾,通过比较大小并将较大的元素依次放入合并后的数组中,解决合并问题。
尺取法的优势在于其简单、高效的算法思想,适用于许多问题的解决。通过合理地设置两个指针的起始位置,并根据问题的要求调整指针的移动策略,可以快速解决一些复杂的数组或字符串相关问题。
二、如何使用尺取法
以下是一个使用尺取法的Java样例代码,解决滑动窗口问题(找到最小覆盖子串)的示例:
import java.util.HashMap;
import java.util.Map;
public class TwoPointersExample {
public static String minWindow(String s, String t) {
// 使用HashMap存储目标字符串中每个字符的出现次数
Map<Character, Integer> target = new HashMap<>();
for (char c : t.toCharArray()) {
target.put(c, target.getOrDefault(c, 0) + 1);
}
int left = 0; // 左指针
int right = 0; // 右指针
int count = 0; // 计数器,用于记录满足条件的字符个数
int minLen = Integer.MAX_VALUE; // 最小覆盖子串的长度
int minStart = 0; // 最小覆盖子串的起始位置
Map<Character, Integer> window = new HashMap<>(); // 存储当前窗口内的字符及其出现次数
while (right < s.length()) {
char c = s.charAt(right); // 移动右指针,扩展窗口
window.put(c, window.getOrDefault(c, 0) + 1);
if (target.containsKey(c) && window.get(c).intValue() == target.get(c).intValue()) {
// 当窗口内某个字符数量满足要求时,更新计数器
count++;
}
while (count == target.size()) {
// 当窗口内的字符满足要求时,移动左指针,缩小窗口
if (right - left + 1 < minLen) {
minLen = right - left + 1;
minStart = left;
}
char leftChar = s.charAt(left);
window.put(leftChar, window.get(leftChar) - 1);
if (target.containsKey(leftChar) && window.get(leftChar).intValue() < target.get(leftChar).intValue()) {
// 当窗口内某个字符数量不满足要求时,更新计数器
count--;
}
left++;
}
right++;
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen);
}
public static void main(String[] args) {
String s = "ADOBECODEBANC";
String t = "ABC";
String result = minWindow(s, t);
System.out.println("最小覆盖子串为: " + result);
}
}
以上代码通过维护一个滑动窗口(左指针和右指针),并使用HashMap来统计窗口内字符的出现次数。当窗口内的字符满足条件时,移动左指针缩小窗口,同时记录最小覆盖子串的起始位置和长度。最后返回最小覆盖子串。这是一个典型的尺取法的应用示例。
三、尺取法的优势和应用场景
尺取法的优势包括以下几点:
-
时间复杂度较低:尺取法通常通过维护两个指针来遍历数组或字符串,每个元素最多被处理一次,因此时间复杂度通常是O(N),其中N是元素的数量。
-
空间复杂度较低:尺取法通常只需要使用常数级别的额外空间(如两个指针),不需要额外的数组或数据结构。
-
算法思路简单:尺取法的思路相对直观,易于理解和实现。
尺取法适用于以下场景:
-
滑动窗口问题:尺取法常用于解决滑动窗口问题,即在一个固定大小的窗口中滑动,通过调整窗口的位置和大小来解决问题。例如,找到最小覆盖子串、最长连续子数组等问题。
-
快慢指针问题:尺取法也常用于解决快慢指针问题,通过维护两个指针,一个快指针和一个慢指针,通过不同的移动策略解决相关问题。例如,判断链表是否有环、寻找链表的中间节点等问题。
-
有序数组合并问题:尺取法可以用于合并两个有序数组的问题,通过维护两个指针,分别指向两个有序数组的末尾,通过比较大小并将较大的元素依次放入合并后的数组中,解决合并问题。
总的来说,尺取法适用于需要遍历数组或字符串,并通过维护两个指针的位置来解决问题的场景。它的优势在于简单、高效,并且适用于多种实际问题的解决。