场景
- 很多人会说刷题是为了面试这是结果导向型的没毛病。
- 更多时候我们要明白为什么要考算法,核心考点是什么?
- 我自己作为面试官考算法有哪些考核点
- 对应异常情况以及边界值的考虑
- 算法的执行效率,算法之所以称之为算法,就是一种之前高效执行程序的总结
- 发散性创造性不拘泥现在,对事情有更多创造性的想法
- 最重要的一点先解决这个问题,再去想优化解决,不管工作和生活都是一定程度的结果导向,先解决眼前的问题,后面再优化一定是在这个阶段最好的方式,而不是上来就放弃!!!
- 这些品质在开发过程中,都是难能可贵的,对应一个需求开发,一个架构设计都需要这些底层的品质与思维方式
前端有必要学习吗?
- 首先场景上是有可能的,之前自己就做过一个需求:最大匹配度的场景,其实抽象到最后就是一个最大共有字符串的这样算法。
- 如果是多端的场景还是服务端实现会更合适一点
- 学海无涯,持续学习是开发者,也是人生最重要一件事情,拥抱变化,畅想未来。
方法论及算法索引
- 使用一次循环或者减少循环提升执行效率,举例:两数之和,无重复字符的最长子串
- 以空间换时间,使用缓存机制可以大幅度提升执行效率,有损内存,举例:两数之和,无重复字符的最长子串
言归正传
1. 两数之和
给定一个整数数组 nums 和一个整数目标值 target请,你在该数组中找出和为目标值 target的那两个整数并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。 你可以按任意顺序返回答案。
示例
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
解题思路一:两层循环求和跟目标值比较,显然不够高效,复杂度为
- 代码如下
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
for(let i = 0 ; i<nums.length;i++){
let child1 = nums[i];
for(let k = i+1 ; k<nums.length;k++){
let child2 = nums[k];
if(child1+child2 === target){
return [i,k]
}
}
}
return []
};
-
执行结果:执行用时: 132 ms;内存消耗: 38.6 MB
-
图解
解题思路二:一次循环缓,存有效数据,比较差值,效果更佳
-
思路 其实我们都清楚,一次循环的时候,我们知道当前的索引值,以及当前值,目标值减去当前值是不是在我们之前缓存的数据当中,如果不在就把当前值缓存
-
代码如下
/**
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
var twoSum = function(nums, target) {
var map = {};
for (let i = 0; i < nums.length; i++) {
var child1 = nums[i];
var key = target - child1;
if (map[key] !== undefined) {
return [map[key], i];
}
map[child1] = i;
}
return [];
};
-
执行结果: 执行用时: 80 ms;内存消耗: 39.6 MB
-
图解
3. 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的最长子串的长度。
示例
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
解题思路一:两层循环求,第一层循环字符串与第二次字符串拼接,第二层判断字符串是否已经包含在之前的拼接数据中,比较每个不重复字符串的长度,复杂度为
- 代码如下
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function(s) {
if(s.length ==0){
return 0
}else{
var array = s.split("")
var num = 0
if(array.length == 1){
return 1
}
for(let i=0;i<array.length;i++){
var map = array[i]
var cn = 1
for(let k=i+1;k<array.length;k++){
var child1 = array[k]
if(!map.includes(child1)){
map = map+child1
cn++
}else{
break;
}
}
num = num > cn?num:cn
}
return num
}
};
-
执行结果:执行用时: 352 ms;内存消耗: 44.2 MB
-
图解
解题思路二:一层循环,字符串拼接,进入缓存,发现后面字符串已经在前面拼接中出现,截取出前面已经出现的字符串位置后面的字符串,加上当前的字符串,更新缓存字符串,继续循环,这样效率更高。
- 代码如下
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
if (s.length == 0) {
return 0;
} else {
var array = s.split("");
var num = 0;
var cn = 0;
var map = "";
for (let i = 0; i < array.length; i++) {
var str = array[i];
if (!map.includes(str)) {
map = map + str;
cn++;
} else {
var index = map.indexOf(str);
map = map.substring(index + 1) + str;
cn = map.length;
}
num = num > cn ? num : cn;
}
return num;
}
};
-
执行结果:执行用时: 128 ms;内存消耗: 43.7 MB
-
图解
总结
- 持续学习,每天都要有驱动力,不能间歇性踌躇满志,持续性坐吃等死!
- 算法小程序加入动画模式是自己的todo
- 35岁之后学习分享不失为我人生一个选择的方向