Skip to content

Latest commit

 

History

History
275 lines (228 loc) · 7.71 KB

File metadata and controls

275 lines (228 loc) · 7.71 KB
comments difficulty edit_url tags
true
困难
哈希表
字符串
二分查找
前缀和

English Version

题目描述

给定字符串 s,你需要找到 s 的 最长自包含 子串 的长度。

如果 s 的一个子串 t 满足 t != s 且 t 中的每一个字符在 s 的剩余部分都不存在,则被称为是 自包含 的。

如果存在  s 的最长自包含子串,返回它的长度,否则返回 -1。

 

示例 1:

输入:s = "abba"

输出:2

解释:
让我们检查子串 "bb"。你可以发现子串外没有其它 "b"。因此答案为 2。

示例 2:

输入:s = "abab"

输出:-1

解释:
我们选择的每一个子串都不满足描述的特点(子串内外包含有一些字母)。所以答案是 -1。

示例 3:

输入:s = "abacd"

输出:4

解释:
让我们检查子串 "abac"。子串之外只有一个字母 "d"。子串内没有 "d",所以它满足条件并且答案为 4。

 

提示:

  • 2 <= s.length <= 5 * 104
  • s 只包含小写英文字母。

解法

方法一:枚举

我们注意到,满足条件的子串的开头一定是某个字符第一次出现的位置。

因此,我们可以用两个数组或哈希表 firstlast 分别记录每个字符第一次和最后一次出现的位置。

接下来,我们枚举每个字符 c,假设 c 第一次出现的位置是 $i$,最后一次出现的位置是 $mx$,那么我们可以从 $i$ 开始向后遍历,对于每个位置 $j$,我们找到 $s[j]$ 第一次出现的位置 $a$ 和最后一次出现的位置 $b$,如果 $a &lt; i$,说明 $s[j]$$c$ 的左边,不符合枚举条件,我们可以直接退出循环。否则,我们更新 $mx = \max(mx, b)$。如果 $mx = j$$j - i + 1 &lt; n$,我们更新答案为 $ans = \max(ans, j - i + 1)$

最后返回答案即可。

时间复杂度 $O(n \times |\Sigma|)$,空间复杂度 $O(|\Sigma|)$。其中 $n$ 是字符串 $s$ 的长度;而 $|\Sigma|$ 是字符集的大小,本题中字符集为小写字母,所以 $|\Sigma| = 26$

Python3

class Solution:
    def maxSubstringLength(self, s: str) -> int:
        first, last = {}, {}
        for i, c in enumerate(s):
            if c not in first:
                first[c] = i
            last[c] = i
        ans, n = -1, len(s)
        for c, i in first.items():
            mx = last[c]
            for j in range(i, n):
                a, b = first[s[j]], last[s[j]]
                if a < i:
                    break
                mx = max(mx, b)
                if mx == j and j - i + 1 < n:
                    ans = max(ans, j - i + 1)
        return ans

Java

class Solution {
    public int maxSubstringLength(String s) {
        int[] first = new int[26];
        int[] last = new int[26];
        Arrays.fill(first, -1);
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            int j = s.charAt(i) - 'a';
            if (first[j] == -1) {
                first[j] = i;
            }
            last[j] = i;
        }
        int ans = -1;
        for (int k = 0; k < 26; ++k) {
            int i = first[k];
            if (i == -1) {
                continue;
            }
            int mx = last[k];
            for (int j = i; j < n; ++j) {
                int a = first[s.charAt(j) - 'a'];
                int b = last[s.charAt(j) - 'a'];
                if (a < i) {
                    break;
                }
                mx = Math.max(mx, b);
                if (mx == j && j - i + 1 < n) {
                    ans = Math.max(ans, j - i + 1);
                }
            }
        }
        return ans;
    }
}

C++

class Solution {
public:
    int maxSubstringLength(string s) {
        vector<int> first(26, -1);
        vector<int> last(26);
        int n = s.length();
        for (int i = 0; i < n; ++i) {
            int j = s[i] - 'a';
            if (first[j] == -1) {
                first[j] = i;
            }
            last[j] = i;
        }
        int ans = -1;
        for (int k = 0; k < 26; ++k) {
            int i = first[k];
            if (i == -1) {
                continue;
            }
            int mx = last[k];
            for (int j = i; j < n; ++j) {
                int a = first[s[j] - 'a'];
                int b = last[s[j] - 'a'];
                if (a < i) {
                    break;
                }
                mx = max(mx, b);
                if (mx == j && j - i + 1 < n) {
                    ans = max(ans, j - i + 1);
                }
            }
        }
        return ans;
    }
};

Go

func maxSubstringLength(s string) int {
	first := [26]int{}
	last := [26]int{}
	for i := range first {
		first[i] = -1
	}
	n := len(s)
	for i, c := range s {
		j := int(c - 'a')
		if first[j] == -1 {
			first[j] = i
		}
		last[j] = i
	}
	ans := -1
	for k := 0; k < 26; k++ {
		i := first[k]
		if i == -1 {
			continue
		}
		mx := last[k]
		for j := i; j < n; j++ {
			a, b := first[s[j]-'a'], last[s[j]-'a']
			if a < i {
				break
			}
			mx = max(mx, b)
			if mx == j && j-i+1 < n {
				ans = max(ans, j-i+1)
			}
		}
	}
	return ans
}

TypeScript

function maxSubstringLength(s: string): number {
    const first: number[] = Array(26).fill(-1);
    const last: number[] = Array(26).fill(0);
    const n = s.length;
    for (let i = 0; i < n; ++i) {
        const j = s.charCodeAt(i) - 97;
        if (first[j] === -1) {
            first[j] = i;
        }
        last[j] = i;
    }
    let ans = -1;
    for (let k = 0; k < 26; ++k) {
        const i = first[k];
        if (i === -1) {
            continue;
        }
        let mx = last[k];
        for (let j = i; j < n; ++j) {
            const a = first[s.charCodeAt(j) - 97];
            if (a < i) {
                break;
            }
            const b = last[s.charCodeAt(j) - 97];
            mx = Math.max(mx, b);
            if (mx === j && j - i + 1 < n) {
                ans = Math.max(ans, j - i + 1);
            }
        }
    }
    return ans;
}