1.理论部分
1. 串的定义与操作
- 定义:串(string)是由零个或多个字符组成的有限序列,又名字符串,记为S=”a0a1…an”;串是一种特殊的线性表;
- 串操作:(1)获取串的长度
(2)获取或设置指定索引处的字符
(3)在指定位置插入子串
(4)在指定位置移除给定长度的子串
(5)在指定位置取子串
(6)当前串的拷贝
(7)串连接
(8)串的匹配
2. 串的存储与实现
同理:串的存储分为两种:顺序存储和链式存储
顺序存储:char类型的数组。由于数组是定长的,就存在一个预定义的最大串长度,它规定在串值后面加一个不计入串长度的结束符,比如’\0’来表示串值的终结。
链式存储:SlinkList (浪费存储空间);
2.练习部分
2.1 无重复字符的最长子串
代码实现:
class Solution:
"""
:type s: str
:rtype: int
"""
def lengthOfLongestSubstring(self, s):
l = 0
r = 0
maxLength = 0
s_len = len(s)
usedChar = [0] * 256 #通过符号表记录符号出现次数
while l < s_len:
if r < s_len and usedChar[ord(s[r])] == 0:
usedChar[ord(s[r])] += 1
r += 1
else:
usedChar[ord(s[l])] -= 1
l += 1
maxLength = max(maxLength, r - l)
return maxLength
2.2 串联所有单词的子串
代码实现:
class Solution {
public:
vector<int> findSubstring(string s, vector<string>& words) {
if (s.empty() || words.empty()) return {};
vector<int> res;
int n = s.size(), cnt = words.size(), len = words[0].size();
unordered_map<string, int> m1;
for (string w : words) ++m1[w];
for (int i = 0; i < len; ++i) {
int left = i, count = 0;
unordered_map<string, int> m2;
for (int j = i; j <= n - len; j += len) {
string t = s.substr(j, len);
if (m1.count(t)) {
++m2[t];
if (m2[t] <= m1[t]) {
++count;
} else {
while (m2[t] > m1[t]) {
string t1 = s.substr(left, len);
--m2[t1];
if (m2[t1] < m1[t1]) --count;
left += len;
}
}
if (count == cnt) {
res.push_back(left);
--m2[s.substr(left, len)];
--count;
left += len;
}
} else {
m2.clear();
count = 0;
left = j + len;
}
}
}
return res;
}
};
2.3 替换子串得到平衡字符串
代码实现:
class Solution:
def balancedString(self, s: str) -> int:
n = len(s)
cnt, avg = [None] * (n + 1), n//4
cnt[0] = {'Q':0, 'W':0, 'E':0, 'R':0}
for i, v in enumerate(s):
cnt[i+1] = {k:v for k, v in cnt[i].items()}
cnt[i+1][v] += 1
def check(x):
for st in range(n - x + 1):
t = {k:cnt[n][k] - cnt[st+x][k] + cnt[st][k] for k in cnt[0].keys()}
if all(avg >= t[x] for x in 'QWER'):
return True
return False
l, r = 0, n
while l < r:
mid = l + r >> 1
if check(mid):
r = mid
else:
l = mid + 1
return l