中级算法中,多循环解题思路多数优化会应用到指针算法,经典就是双指针(vue的diff也采用了双指针对比),注意中级算法题禁止双for无优化处理-经不住测试用例方案
算法逻辑题整理-初级(1)
1.最长回文子串
// 这里用了双for,因为我目前没发现其他方案,指针当然不适合
回文就是一段字符正与反时他们都一样,如abcba
var longestPalindrome = function (s) {
let num = s.length;
if (num <= 1) return s;
let maxStr = "";
for (let i = 0; i < num; i++) {
for (let j = 1; j < num; j++) {
let str = s.substring(i, j + 1);
let ceArr = str.split("").reverse().join("");
if (ceArr === str && str.length > maxStr.length) {
maxStr = str;
}
}
}
return maxStr == "" ? "" : maxStr;
};
// 后期出新解决方案
2.给你 n 个非负整数 a1,a2,…,an,每个数代表坐标中的一个点 (i, ai) 。在坐标内画 n 条垂直线,垂直线 i 的两个端点分别为 (i, ai) 和 (i, 0) 。找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
根据解析循环+双指针
[1,8,6,2,5,4,8,3,7]左右各取出元素计算面积,然后再对比两个元素哪个小,
左边1小那么左指针向中间移动一位,右指针不动,依次循环计算并移动指针
var maxArea = function (height) {
let num = height.length;
let sum = 0; // 最大面积
let end = num - 1; // 右指针
let start = 0; // 左指针
for (let i = 0; i < num; i++) {
let H = height[start] > height[end] ? height[end] : height[start]; // 容器高度当然以小的一方为准才能装水,取出高
let S = H * Math.abs(end - start); // 这里直接取到宽计算面积
sum = sum > S ? sum : S; //保留最大面积
// 判定移动指针
if (height[start] > height[end]) {
end--;
} else {
start++;
}
}
return sum;
};
3.给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
// 这道题我也是错了好多次才写出,主要应用技术点,循环,双指针,去重,进行层次化处理过滤
var threeSum = function (nums) {
// 数组排序这步非常重要,将会作用在去重上
nums = nums.sort((a, b) => {
return a - b;
});
let num = nums.length;
let arr = [];//接收结果值
if (num < 3 || nums[0] > 0) return [];//不满足题目条件的数组直接返回空数组,避免不必要/错误计算
for (let a = 0; a < num; a++) {
if (nums[a] > 0) return arr;//这体现了排序的作用,如果最小的数都大于0就没必要计算了
if (a > 0 && nums[a] == nums[a - 1]) continue;// 循环中去除外循环第一参数重复值
let b = a + 1;//左指针
let c = num - 1;//右指针
while (b < c) {//二级循环作用到指针移动这里注意使用的while更为合适,
let sum = nums[a] + nums[b] + nums[c];// 计算和
// 得出结果将对值进行(=,<,>)3种可能进行处理
if (sum == 0) {
let newarr = [nums[a], nums[b], nums[c]];
arr.push(newarr);
// 此次循环拿到合适的值必定移动左右指针,为了去重因此使用do while的特性,跳过重复的元素
do {
b++;
} while (b < c && nums[b] == nums[b - 1]);
do {
c--;
} while (b < c && nums[c] == nums[c + 1]);
} else if (sum > 0) {
// 和值大于0右指针是大到小,移动一次减小值再进入while循环
c--;
} else {
// 和值小于0左指针是小到大,移动一次增加值再进入while循环
b++;
}
}
}
return arr;
};
4.给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
//这道题与第三题解法类似,但要注意细节
var threeSumClosest = function (nums, target) {
// 数组排序这步非常重要,将会作用在去重上
nums = nums.sort((a, b) => {
return a - b;
});
let num = nums.length;
let result = 0;// 结果值
let diff = 0; // 结果值与目标值的差异
for (let a = 0; a < num; a++) {
if (a > 0 && nums[a] == nums[a - 1]) continue; // 循环中去除外循环第一参数重复值
let b = a + 1; //左指针
let c = num - 1; //右指针
while (b < c) {
//二级循环作用到指针移动这里注意使用的while更为合适
let sum = nums[a] + nums[b] + nums[c]; // 计算和
let news = Math.abs(sum - target); // 计算当前sum与目标的差异
if (sum == target) {
return sum;
} else if ((a == 0 && b == 1 && c == num - 1) || news < diff) {
//第一次循环与比上次更符合目标值的结果都将获取
diff = news;
result = sum;
}
// 根据和值与目标值的差异情况移动指针
if (b < c && sum < target) {
b++;
} else {
c--;
}
}
}
return result;
};
5.电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
var letterCombinations = function (digits) {
if (!digits) {
return [];
}
const strMap = ["", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"];//空格占位用,校准2-9
let result = [""]; //初始化一个空字符,作为中间储存值
for (let num of digits) {
//遍历输入的数字
let nextResult = [];
let str = strMap[num]; //找到数字可能对应的字符
for (let t of result) {
//遍历上一循环生成的字符串列表
for (let s of str) {
//遍历当前数字可能对应的字符
nextResult.push(t + s); //拼接字符串
}
}
result = nextResult; //替换原字符串列表
}
return result;
};
6.四数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
待定,空时间完成