标签8滑动窗口与岛屿问题
滑动窗口
[left,right]左闭右闭区间表示一个滑动窗口。
1.初始化为left,right都是“小的”,保证left和right都是向右滑动,也就是得left ++,right ++。
2.其次就是判断什么时候left ++,什么时候right ++。
3.终止条件一般是right小于一个阈值,但是有的问题left 小于一个阈值也是可以的。
4.字符串类的滑动窗口的题目中map可以使用int[256]数组来代替,java里char是一个字节,8位。可以把空间复杂度降低为O(1)
int[X] = 1;代表阿西克码是X的字符对应最近出现的下标,类似于HashMap的key和value(这里的value也是用来记录最近出现的下标)
3. 无重复字符的最长子串
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() <= 1) {
return s.length();
}else {
int left = 0;
int right = 0;
int maxlength = 1;
//map.put(s.charAt(right),right);
HashMap<Character,Integer> map = new HashMap<>();
while(right < s.length()) {
//下面两个while可以改成if
while( right < s.length() && (! map.containsKey(s.charAt(right)) || map.get(s.charAt(right)) < left)) {
maxlength = Math.max(maxlength,right - left + 1);
map.put(s.charAt(right),right);
right ++;
}
while(right < s.length() && map.containsKey(s.charAt(right))
&& map.get(s.charAt(right)) >= left) {
/*
left = right;
right = left;
*/
//left ++;
left = Math.max(left + 1,map.get(s.charAt(right)));
//right = left;
}
}
return maxlength;
}
}
}
解法:上面的改进
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() <= 1) {
return s.length();
}else {
int left = 0;
int right = 0;
int maxlength = 1;
char tem;
//模拟一下先放进去肯定不对
//map.put(s.charAt(right),right);
//map存储的是字符靠近right出现的位置
HashMap<Character,Integer> map = new HashMap<>();
while(right < s.length()) {
tem = s.charAt(right);
//map中含有tem关键字,可能这个关键字的下标小于left
//就是和s.charAt(right)重复的不在滑动窗口之内,不用理睬
if(map.containsKey(tem)) {
left = Math.max(left,map.get(tem) + 1);
}
//直接put即可,不用关心tem这个关键字是否已经存在,即使存在也要覆盖
map.put(tem,right);
maxlength = Math.max(maxlength,right - left + 1);
right ++;
}
return maxlength;
}
}
}
解法:HashMap的改进,空间复杂度降为O(1) ,用int[256]来代替hashmap,作用一样,初始化int数组为-1,不能是0
class Solution {
public int lengthOfLongestSubstring(String s) {
if(s.length() <= 1) {
return s.length();
}else {
int left = 0;
int right = 0;
int maxlength = 1;
char tem;
//int数组是用来代替map的
int[] indexes = new int[256];
//数组的初始值应该是-1,表示初始的时候,阿西克码对应的下标不存在
//初始化化为0,代表indexes[X],阿西克码为X的下标是0,显然不对
for(int i = 0;i < 256;i ++) {
indexes[i] = -1;
}
while(right < s.length()) {
tem = s.charAt(right);
//map中含有tem关键字,可能这个关键字的下标小于left
//就是和s.charAt(right)重复的不在滑动窗口之内,不用理睬
//之前判断是indexes[tem] == 0这是不对的,因为之前把indexes数组的值初始化为0,
if(indexes[tem] != -1) {
left = Math.max(left,indexes[tem] + 1);
}
indexes[tem] = right;
maxlength = Math.max(maxlength,right - left + 1);
right ++;
}
return maxlength;
}
}
}
剑指 Offer 57 - II. 和为s的连续正数序列
解法:滑动窗口,终止条件是left < (target + 1) / 2,因为再大就没有意义了;其次找到等于target的组合,right或者left要增加,否则死循环。
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> answer = new ArrayList<>();
if(target <= 0) {
return null;
}else {
int left = 1;
int right = 2;
int currentsum = left + right;
//当small大于stopflag的时候,区间[left,right]的和肯定大于target
int stopflag = (target + 1) / 2;
while(left < stopflag) {
if(currentsum == target) {
//每个list都得新new
int[] array = new int[right - left + 1];
for(int i = left;i <= right;i ++) {
array[i - left] = i;
}
answer.add(array);
//相等的时候,一定要移动left或者right,要不然程序一直循环
//移动left,right都可以
/*
right ++;
currentsum += right;
*/
currentsum -= left;
left ++;
}
//下面两个的while改成else if也可以,不过while更快
while(currentsum < target) {
right ++;
currentsum += right;
}
while(currentsum > target && left < stopflag) {
//这个得先减去
currentsum -= left;
left ++;
}
}
return answer.toArray(new int[answer.size()][]);
}
}
}
岛屿问题
待完成