小言_互联网的博客

滑动窗口(用到Set和Map)

468人阅读  评论(0)

滑动窗口(用到Set和Map)

例题

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

示例 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

题解

1.暴力解题法(简单)

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main{
    public static void main(String[] args) {
    	Scanner scan = new Scanner(System.in);
    	String s = scan.nextLine();
    	int n = s.length();
    	int ans = 0;
    	for (int i = 0; i < n; i++) {
    		for(int j = i; j < n; j++) {
    			if(allUnique(s,i,j)) {
    				ans = Math.max(ans, j - i + 1);
    			}
    		}
    	}
    	System.out.println(ans);
    	scan.close();
    }
	private static boolean allUnique(String s, int start, int end) {
		Set<Character> set = new HashSet<Character>();
		for(int i = start; i <= end; i++) {
			Character ch = s.charAt(i);
			if(set.contains(ch)) {
				return false;
			}
			set.add(ch);
		}
		return true;
	}
}

时间复杂度太高,会超时。

注:Java Character 类 ->https://www.runoob.com/java/java-character.html

2.滑动窗口(HashSet)

import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class Main{
    public static void main(String[] args) {
    	Scanner scan = new Scanner(System.in);
    	String s = scan.nextLine();
    	int n = s.length();
    	Set<Character> set = new HashSet<>();
    	int ans = 0, i = 0, j = 0;
    	while(i < n && j < n) {
    		if(!set.contains(s.charAt(j))) {
    			set.add(s.charAt(j));
    			j++;
    			ans = Math.max(ans, j-i);
    		} else {
    			set.remove(s.charAt(i++)); 
    		}
    	}
    	System.out.println(ans);
    	scan.close();
    }
}

3.优化后的滑动窗口(HashMap)

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Main{
    public static void main(String[] args) {
    	Scanner scan = new Scanner(System.in);
    	String s = scan.nextLine();
    	int n = s.length(), ans = 0;
    	Map<Character,Integer> map = new HashMap<>();
    	for(int j = 0, i = 0; j < n; j++) {
    		if(map.containsKey(s.charAt(j))) {
    			i = Math.max(map.get(s.charAt(j))+1, i);
    			//abccad,i指向第二个c的时候,要判断是否包含a,这个时候发现已包含的a的位置是0,这个时候就需要指向两者的最大值了。
    		}
    		ans = Math.max(ans, j - i + 1);
    		map.put(s.charAt(j),j); //会更新重复元素的位置,其他元素还在里边
    	}
    	System.out.println(ans);
    	scan.close();
    }
}

唉,这个i = Math.max(map.get(s.charAt(j))+1, i);语句真的是难住我了好一会,好久没想过来,不过还好一个评论点通了我。

前两种解法用HashSet来判断是否已经存在该字符

最后一种用HashMap来判断是否已存在该字符,并且可以知道该字符的位置。

注:这几个算法的代码和leedcode官方答案会有一丢丢的不同,有的设置是按照我自己习惯来的(比如i,j是否+1),不过算法思想是相同的。


转载:https://blog.csdn.net/weixin_40736438/article/details/102575659
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场