问:
- 给定一个只由0,1,&,|,^组成的字符串str,给再给一个布尔值flag。返回str形成的布尔值等于flag的组合方式的个数
- 最长无重复字符子串长度
- 编辑距离
- 给定一个全是小写字母的str。删除多余字符,使得每种字符只保留一个。并且让最终结果的字典序最小。譬如:str=‘acbc’删除第一个‘c’得到‘abc’比删除第二个‘c’得到‘acb’字典序更小。
解: 1.
function getAllNums(str, flag) {
// 判断字符串合法性
if (!checkRight(str)) return 0
return getRes(0, str.length - 1, flag)
function getRes(left, right, type) {
if (left === right) {
// 字符串转为数字再转布尔
return Boolean(+str[left]) === type ? 1 : 0
}
let res = 0
for (let i = left + 1; i < right; i += 2) {
if (flag) {
if (str[i] === '&') {
res += getRes(left, i - 1, flag) * getRes(i + 1, right, flag)
}
if (str[i] === '|') {
res += getRes(left, i - 1, flag) * getRes(i + 1, right, flag)
res += getRes(left, i - 1, !flag) * getRes(i + 1, right, flag)
res += getRes(left, i - 1, flag) * getRes(i + 1, right, !flag)
}
if (str[i] === '^') {
res += getRes(left, i - 1, flag) * getRes(i + 1, right, !flag)
res += getRes(left, i - 1, !flag) * getRes(i + 1, right, flag)
}
} else {
if (str[i] === '&') {
res += getRes(left, i - 1, flag) * getRes(i + 1, right, flag)
res += getRes(left, i - 1, flag) * getRes(i + 1, right, !flag)
res += getRes(left, i - 1, !flag) * getRes(i + 1, right, flag)
}
if (str[i] === '|') {
res += getRes(left, i - 1, flag) * getRes(i + 1, right, flag)
}
if (str[i] === '^') {
res += getRes(left, i - 1, flag) * getRes(i + 1, right, flag)
res += getRes(left, i - 1, !flag) * getRes(i + 1, right, !flag)
}
}
}
return res
}
function checkRight(str) {
str = str.split('')
return str.some((item, idx) => {
if (idx % 2 === 1) {
return ['&', '|', '^'].includes(item);
}
return ['0', '1'].includes(item);
})
}
}
function getMaxLength(str) {
// 每一个以当前字符为结尾时的子串长度
const idxMap = new Map()
const dp = []
let max = 1
dp[0] = 1
idxMap.set(str[0], 0)
for (let i = 1; i < str.length; i++) {
const preIdx = idxMap.get(str[i])
// 当前字符上一次出现的位置
if (preIdx !== undefined) {
dp[i] = Math.min(dp[i - 1] + 1, i - preIdx)
} else {
dp[i] = dp[i - 1] + 1
}
max = Math.max(max, dp[i])
idxMap.set(str[i], i)
}
return max
}
function minDistance(str1, str2) {
const dp = []
// dp[i][j]的含义为
// str1的前i个字符,变为str2的前j个字符的代价
// 譬如dp[0][3]表明str1中前0个字符,变为str2中前三个字符的代价
for (let i = 0; i <= str1.length; i++) {
dp[i] = []
for (let j = 0; j <= str2.length; j++) {
if (i === 0) {
dp[i][j] = j
}
if (j === 0) {
dp[i][j] = i
}
}
}
for (let i = 1; i <= str1.length;i++) {
for (let j = 1; j <= str2.length; j++) {
// 如果最后一个字符相同(因为dp表的i,j代表长度。所以对应str中的位置要-1)
if (str1[i - 1] === str2[j - 1]) {
// 那么当前代价就可以忽略掉这个字符
dp[i][j] = dp[i - 1][j - 1]
} else {
// 最后一个字符替换
const p1 = dp[i - 1][j - 1]
// str1 把i 位置字符删除
const p2 = dp[i - 1][j]
// str1 把 0~i变成 str2的0~j-1。最后增加一个str2的j位置字符
const p3 = dp[i][j - 1]
dp[i][j] = Math.min(p1, p2, p3) + 1
}
}
}
return dp[str1.length][str2.length]
}
function getMinDictionaryOrder(str) {
let res = ''
getRes(str)
return res
function getRes(curStr) {
if (!curStr) return
const hashMap = new Map()
let tempStr = ''
let minDicChar = null
// 建立词频表
for (let i of curStr) {
hashMap.set(i, (hashMap.get(i) ?? 0) + 1)
}
// 每遇到一个字符就词频减一
for (let i = 0; i < curStr.length; i++) {
if (minDicChar === null) {
minDicChar = i
} else {
// 判断字典序,找到到当前位置为止,最小字典序的字符坐标
minDicChar = curStr[minDicChar].localeCompare(curStr[i]) > 0 ? i : minDicChar
}
hashMap.set(curStr[i], hashMap.get(curStr[i]) - 1)
// 当词频减少到0,说明以后再也不会有这个字符了,说明在0~当前字符时,删掉重复字符可以保证剩余所有字符都有一份及以上的
if (hashMap.get(curStr[i]) === 0) {
if (!res.includes(curStr[minDicChar])) res = res + curStr[minDicChar]
// 删除最小字典序之前的字符
const reg = new RegExp(`${curStr[minDicChar]}`, 'g')
tempStr = curStr.substring(minDicChar, i + 1).replace(reg, '') + curStr.substring(i+1)
break
}
}
getRes(tempStr)
}
}