问:
-
一个字符串可以分解成多种二叉树结构,如果长度为1则不可继续分解。如果str长度为N,左边长度可以为[1,N-1],剩下的为右部分长度。左右部分都可以按照同样逻辑继续分解。当分解完毕后,假如允许从根节点开始每一层节点都可以互换位置(也可以不换)。换完后将返回到上一层。这样最终会形成一个新的字符串。这个新的字符串称为str的旋变串。给定str1和str2,判断它们是否互为旋变串
-
给定字符串str1和str2。求str1的子串中含有str2所有字符(顺序不作要求)的最小子串长度。
解:
- 递归含义为str1以left1开头,str2以left2开头,长度为length时是否互为旋变串。
function isMatch(str1, str2) {
if (str1.length !== str2.length) return false
function getRes(left1, left2, length) {
// 当长度为1时,字符相等就是旋变串
if (length === 1) {
return str1[left1] === str2[left2]
}
// 假设主函数来到了getRes(1, 2, 5)
// str1 = [a, b, c, d, e, f ,g]
// str2 = [h, i, j, k, l, m, n]
// 0 1 2 3 4 5 6
// 也就是对比str1的[b~f]和str2的[j~n]
// 遍历尝试左边应该分几个。
// 假设左边分4个
// 那么有以下几种情况
// str1的[b~c]和str2的[j~k]互为旋变串并且str1的[d~f]和str2的[l~n]互为旋变串
// str1的[e~f]和str2的[j~k]互为旋变串并且str1的[b~d]和str2的[l~n]互为旋变串
// 这两种情况下,都可以互换位置使得递归含义为true
for (let i = length - 1; i >= 1; i--) {
if (getRes(left1, left2, i) && getRes(left1 + i, left2 + i, length - i)
|| getRes(left1, left2 + length - i, i) && getRes(left1 + i , left2, length - i)
) {
return true
}
}
return false
}
return getRes(0, 0, str1.length)
}
- 滑动窗口
function getMinLength(str1, str2) {
// str2的词频表
const hashMap = new Map()
for (let i of str2) {
hashMap.set(i, (hashMap.get(i) ?? 0) + 1)
}
let all = str2.length
// 词频表和all的含义为
// 假设词频为 a: 2 b: 2 c:1
// 代表窗口中还需要2个a,2个b和1个c, all为窗口中需要的字符个数,初始为5
// 当窗口右扩时,找到词频表中的字符时,词频--,all--
// 当某个词频到0时,表明窗口中已经不缺少这个字符了
// 当某个词频减少到负数时,表明窗口中这个字符多出来了,词频--,all不需要减,因为这不是窗口需要的字符
// 当all减到0时,可以结算一次,因为此时窗口刚好拥有所有需要的字符,结算完毕,窗口左侧后移一位。
let left = 0
let right = 0
let minLength = Infinity
while (left < str1.length && right < str1.length) {
if (left > right) right = left
const temp = hashMap.get(str1[right])
// 如果窗口右边压中词频表中的字符
if (temp !== undefined) {
// 词频表对应字符--
hashMap.set(str1[right], temp - 1)
// 如果词频原本是大于1的,那么是有效词
if (temp >= 1) {
all--
}
// 代表窗口中此时包含str2的所有字符,结算一次
if (all === 0) {
minLength = Math.min(minLength, right - left + 1)
// 如果窗口左边框的字符在词频表中,词频+1
if (hashMap.get(str1[left]) !== undefined) {
hashMap.set(str1[left], hashMap.get(str1[left]) + 1)
// 如果此时这个字符词频 > 0,那么表明窗口中缺少了这个字符
if (hashMap.get(str1[left]) > 0) all++
}
left++
continue
}
}
right++
}
return minLength === Infinity ? -1 : minLength
}