问题描述:https://leetcode.com/problems/longest-substring-without-repeating-characters/
思路1:分治策略
按照算法导论上的分治算法框架强行写的。
class CommonUtil { static lightCopy(obj) { let result = {} Object.assign(result, obj); return result; } } // O(???), Runtime: 7792 ms, faster than 1.00% ... var lengthOfLongestSubstring = function(s) { if (s == "") return 0; let buildMaps = (symbol, p, q, r) => { let map = [], length = 0; let current = () => q - length; if (symbol == "right") { current = () => q - 1 + length; } let init = () => { // 创建一个空对象,免去繁琐的初始化过程 map[length++] = {}; }; let isSafe = () => { // 越界or字符重复返回false let out = symbol == "right" ? current() >= r : current() < p; let repeat = map[length - 1][s[current()]]; return !out && !repeat; }; let createMap = () => { // 复制map>>添加元素>>为下次调用做准备 map[length] = CommonUtil.lightCopy(map[length - 1]); map[length][s[current()]] = true; length++; }; init(); while (isSafe()) { createMap(); } return map; }; let combineMaps = (leftMaps, rightMaps, max) => { let compatible = (map1, map2) => { if (map1.length < map2.length) { let temp = map1; map1 = map2; map2 = temp; } let keys = Object.keys(map2); return !keys.some(x => map1[x]); }; let getPairs = (totalReduce) => { let reducePairs = []; for (let k = 0; k <= totalReduce; ++k) { reducePairs.push({ i: k, j: totalReduce - k, }); } return reducePairs; }; const leftLen = leftMaps.length - 1, rightLen = rightMaps.length - 1, baseLen = leftLen + rightLen; let sum = 0; let totalReduce = 0; while ((sum = baseLen - totalReduce) > max) { // 只检测比子问题解的值更大的情形,由大往小找,一旦找到立刻停止搜索 let reducePairs = getPairs(totalReduce); for (let k = 0; k != reducePairs.length; ++k) { let i = leftLen - reducePairs[k].i; let j = rightLen - reducePairs[k].j; if (i > 0 && j > 0 && compatible(leftMaps[i], rightMaps[j])) { return sum; } } totalReduce++; } return max; }; let findMaxCrossingSubstring = (p, q, r, subMaxLength) => { if (s[q - 1] == s[q]) { // 不可连接 return subMaxLength; } else { let leftMaps = buildMaps("left", p, q, r); let rightMaps = buildMaps("right", p, q, r); return combineMaps(leftMaps, rightMaps, subMaxLength); } }; let findMax = (start, end) => { if (start + 1 < end) { let mid = Math.floor((start + end) / 2); // Divide let maxLeft = findMax(start, mid); // Conquer let maxRight = findMax(mid, end); // Conquer const subMaxLength = Math.max(maxLeft, maxRight); // Combine return findMaxCrossingSubstring(start, mid, end, subMaxLength); // Combine } else { return 1; // basecase } }; return findMax(0, s.length); };
思路2:Brute Force - O(n^3)
let satisfyCondition = (i, j, s) => { let map = {}; for (let k = i; k <= j; ++k) { if (map[s[k]]) return false; map[s[k]] = true; } return true; }; var lengthOfLongestSubstring2 = function(s) { if (s == "") return 0; let max = 1, length, i, j; for (i = 0; i != s.length; ++i) { for (j = i + 1; j != s.length; ++j) { length = j - i + 1; if (length > max) { if (satisfyCondition(i, j, s)) { max = length; } else { break; } } } } return max; };
思路3
var lengthOfLongestSubstring = function(s) { if (s.length < 2) return s.length; let max = 0, lastBegin = 0, code, characterIndex = new Array(255), fresh; for (let i = 0; i !== s.length; ++i) { code = s.charCodeAt(i); if (characterIndex[code] >= lastBegin) { lastBegin = characterIndex[code] + 1; } fresh = i - lastBegin + 1; if (fresh > max) { max = fresh; } characterIndex[code] = i; } return max; };