思路:
从题中给出的有效信息:
- 子数组是连续不重复的
判断子集的问题,一般采用dp的思路来解决
方法一:遍历
具体做法:
遍历搜索,遍历出所有连续的字符串,并判断是否符合要求,记录最长字符串的长度,最后返回
import java.util.*; public class Solution { /** * * @param arr int整型一维数组 the array * @return int整型 */ public int maxLength (int[] arr) { // write code here if (arr.length == 0) { return 0; } int len = arr.length; List<Integer> list = new ArrayList<>(); int count = 0; for (int i = 0; i < len; i++) { //找出以i位置开头的最长的不重复子串 for (int j = i; j < len; j++) { if (list.contains(arr[j])) { //有重复的就退出循环 break; } else { list.add(arr[j]); //不重复就一直add } } count = Math.max(count, list.size()); //当count大于等于剩下的长度时,不再遍历 if (count >= len - 1 - i) { break; } //清空记录 list.clear(); } return count; } }
复杂度分析:
- 时间复杂度:O(n^3) 两次遍历加上集合操作
- 空间复杂度:O(n) 申请了一个n大小的集合
方法二:动态规划
具体做法:
dp状态定义:以i下标元素为结尾字符的无重复数字的子集合最大长度
遍历到 arr[j] 时,初始化索引 i = j - 1 ,向左遍历搜索第一个满足 s[i] = s[j] 的数字即可
具体过程如下图所示:
import java.util.*; public class Solution { /** * * @param arr int整型一维数组 the array * @return int整型 */ public int maxLength (int[] arr) { // write code here int res = 0, tmp = 0; for(int j = 0; j < arr.length; j++) { int i = j - 1; while(i >= 0 && arr[i] != arr[j]) i--; // 遍历查找 i tmp = tmp < j - i ? tmp + 1 : j - i; // dp[j - 1] -> dp[j] res = Math.max(res, tmp); // max(dp[j - 1], dp[j]) } return res; } }
复杂度分析:
- 时间复杂度:O(n^2) n为数组长度,每轮计算 dp[j] 时搜索 i 需要遍历 j 个字符
- 空间复杂度:O(1) 常数空间复杂度
方法三:哈希+双指针
具体做法:
使用 哈希表统计字符 s[j]s[j] 最后一次出现的索引,每轮更新左边界 i=max(dic[s[j]],i) ,更新结果 res=max(res,j−i)
class Solution { public int lengthOfLongestSubstring(String s) { Map<Character, Integer> dic = new HashMap<>(); int i = -1, res = 0; for(int j = 0; j < s.length(); j++) { if(dic.containsKey(s.charAt(j))) i = Math.max(i, dic.get(s.charAt(j))); // 更新左指针 i dic.put(s.charAt(j), j); // 哈希表记录 res = Math.max(res, j - i); // 更新结果 } return res; } }
复杂度分析:
- 时间复杂度:O(n) 动态规划需遍历计算 dpdp 列表
- 空间复杂度:O(1) 哈希表使用了常数项的空间(0 — 127)