文章目录
3. 无重复字符的最长子串-中等
题目
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
示例 2:输入: “bbbbb”
输出: 1
解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。
示例 3:输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,“pwke” 是一个子序列,不是子串。来源:力扣(LeetCode)
代码
官方解法
暴力法
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
int ans = 0;
//遍历一个字符串里面的不同区间
for (int i = 0; i < n; i++)
for (int j = i + 1; j <= n; j++)
if (allUnique(s, i, j)) ans = Math.max(ans, j - i);
return ans;
}
public boolean allUnique(String s, int start, int end) {
Set<Character> set = new HashSet<>();
//遍历此区间的符号
//如果在里面就返回flase,这个区间不符合条件
//如果不在里面,就加入进去。
for (int i = start; i < end; i++) {
Character ch = s.charAt(i);
if (set.contains(ch)) return false;
set.add(ch);
}
return true;
}
}
滑动窗口
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
//逐渐扩大区间范围
//判断纳入了集合没有
//如果纳入了的话就一直移除最左边的对象-直到集合里面没有哪个元素
//如果没有纳入就插入集合,更改最大值
//补充:1、无论删除一个还是删除多个,都会比上一个最大值小,所以j-i可以和最大值比较
//补充:2、if条件语句用j,而代码段里面用的是j++,其实本质都是同一个j,只不过j++的j先使用了,随后再进行+1操作,交给下一次循环使用
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
}
else {
set.remove(s.charAt(i++));
}
}
return ans;
}
}
优化滑动窗口(使用HashMap)
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
//遍历字符串
//判断是否在map里面,如果在就在map里面搜索元素对象的value值(也就是记下来的索引),存到i中保存
//因为取得i是元素实际位置的下一个位置,字符串长度是需要+1的,要比较此长度是否比上一个长度要长,是则保存下来
//把元素都放入map里面,相同的更新value值也就是索引值,注意:这时候value记下的是真实位置的下一个位置,方便定位字符串长度的(也就是变化i值)
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
//设计原因:过去的不重复的字符串,一是已经记录了最大长度,二是与前面重复了的话,那么这个就不能纳入进去(比这个更前面的更是,因为她们之间的不重复字符串肯定比之前她们所在的字符串长度要小),所以定位到后面。
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
桶
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
int[] index = new int[128]; // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
i = Math.max(index[s.charAt(j)], i);
ans = Math.max(ans, j - i + 1);
index[s.charAt(j)] = j + 1;
}
return ans;
}
}
知识点
// 暴力匹配(伪码)
int search(String pat, String txt) {
int M = pat.length;
int N = txt.length;
for (int i = 0; i < N - M; i++) {
for (int j = 0; j < M; j++) {
if (pat[j] != txt[i+j])
break;
}
// pat 全都匹配了
if (j == M) return i;
}
// txt 中不存在 pat 子串
return -1;
}
这里的两层循环是
for ( int i =0 ; i<N-M; i++){
for (int j =0 ; j<M; j++) {
//此处写 利用 j和i+j当index的代码
}
}
理解:
1,第一层循环用Ni的完整长度是因为,循环体中i+j会帮助把所有的元素遍历完
2,i+j 相当于i+0,i+1……因为i的变化速度慢,j的变化速度快(变化在i之前)
常见的两层循环是
for(int i =0 ; i< N; i++){
for ( int j = i+1 ; j <M j ++){
//然后就是利用i,j做index的代码(对于数组)
}
}
for(int i =0 ; i< N; i++){
for ( int j = i+1 ; j <M j ++){
//然后就是利用i,j做index的代码(对于字符串)
}
}
理解:
1,数组里面不重复的一个一个的去连线匹配
2,字符串里面i和j可以看作是两个点之间的距离,取一段长度当中落在不同两点的距离。
两者区别:
第一个只能一一对比固定长度(内循环所限定的长度)的元素
第二个把所有元素都相互对比了。
java中Set的用法
Set集合的特点:
不能存储相同的元素。
同时因为其是一个抽象的接口:所以不能直接实例化一个set对象。(Set s = new Set() )错误
该接口主要继承于Collections接口,所以具有Collection的一些常见的方法。
Sr.No. | Method & Description |
---|---|
1 | add( ) 向集合中添加元素 |
2 | clear( ) 去掉集合中所有的元素 |
3 | contains( ) 判断集合中是否包含某一个元素 |
4 | isEmpty( ) 判断集合是否为空 |
5 | iterator( ) 主要用于递归集合,返回一个Iterator()对象 |
6 | remove( ) 从集合中去掉特定的对象 |
7 | size( ) 返回集合的大小 |
5.最长回文子串-中等
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:输入: “cbbd”
输出: “bb”
暴力法//超时了
public boolean isPalindromic(String s) {
int len = s.length();
//这是一个很有趣的循环,遍历一半,剩下的一半靠数学
//注解:len-i-1的原因,len-1是最后一个元素的索引值,相对与在开头的指针,头指针移动一步,尾指针也往前移动一步
for (int i = 0; i < len / 2; i++) {
if (s.charAt(i) != s.charAt(len - i - 1)) {
return false;
}
}
return true;
}
// 暴力解法
public String longestPalindrome(String s) {
String ans = "";
int max = 0;
int len = s.length();
for (int i = 0; i < len; i++)
for (int j = i + 1; j <= len; j++) {
//这种结构的双重循环
//1,不重复的组合各种元素(对于数组,内循环不能等于,不然越界
//2,不重复的任取区间的子区间(对于字符串,内循环需要等于,不然区间为0
//然后判断字符串是否对称以及,字符串长度是否大于上一个回文子串长度
//yes->替代最长回文子串;更改最大值
String test = s.substring(i, j);
if (isPalindromic(test) && test.length() > max) {
ans = test;
max = test.legth();
}
}
return ans;
}