最近在笔试和看面经的时候经常会碰到几道算法题目,决定记录下来和大家分享以下。
求数组的最大字段和
比如:arr=[1,-2,3,10,-4,7,2,-5],求它的最大的和是多少,答案是18 。问题来了:那为什么最后结果是18呢?思考… …?
一波分析:首先,sum = 1+(-2)< 0,这种情况下sum = 0 ,并且从3开始加。
总结:遇到正数直接加上,遇到负数先判断加上当前的元素后和是不是小于0,是的话就重新计算,否则直接加上。
// 最大字段和
function maxNumber(arr) {
var max=0; //保存最大值
var sum=0; //保存当前值
for(let i=0;i<arr.length;i++){
if(arr[i]>=0){ //正数的情况
sum+=arr[i];
max=sum>max?sum:max; //判断,改变max值
}else{ //负数情况
if(sum+arr[i]>0){
sum+=arr[i];
}else{
sum=0;
}
}
}
return max;
}
两个字符串的最长公共子串
最长公共子串是指两个字符串中相同的字符串,同时还是最长的。比如:“abcdef” 和 “defg” 公共且最长是 “def”。
过程:先找到长度最短的字符串,把短字符串的子序列枚举出来,依次到长字符串中进行判断是否存在,每次从最长的开始判断,存在就直接返回。
function MaxCommon(str1,str2) {
if(str1.length > str2.length){
var temp = str1;
str1 = str2;
str2 = temp;
}
let len1 = str1.length;
let len2 = str2.length;
for(let i=len1; i>0; i--){
for(let j=0; j<=len1-i; j++){
let str = str1.substr(j,i);
if(str2.indexOf(str)>=0){
return str;
}
}
}
return "";
}
最长递增子序列
最长递增子序列意思是在一组数字中,找出最长一串递增的数字,比如:0, 3, 4, 17, 2, 8, 6, 10 对于以上这串数字来说,最长递增子序列就是 0, 3, 4, 8, 10
function Lengthest(nums){
let array = Array(nums.length).fill(1); //以1填充数组
for(let i = 1;i<array.length;i++){
for(let j = 0;j<i;j++){ //和之前的所有元素进行比较
if(nums[i]>nums[j]){
array[i] = Math.max(array[i],1+array[j]); //取最大值
}
}
}
return Math.max(...array); //返回长度
}
var arr = [0, 3, 4, 17, 2, 8, 6, 10];
console.log(Lengthest(arr)); //5
柯里化
经典考题:add(1)(2)(3)(),add(1,2,3)都返回6。
柯里化是将一个n元函数转为n个一元函数
函数柯里化好处:1、提高参数复用性 2、延迟执行(累计传入参数,最后执行)
//先来个 add(1,2)和add(1)(2)
function add(){
var sum=0;
if(arguments.length ===1){
sum = arguments[0];
return function(y){
return sum+=y;
}
}else{
return sum=arguments[0]+arguments[1];
}
}
上面的只能实现两个参数的情况,当参数再增加的情况就不适用了。add(1)(2)(3)会报错 Uncaught TypeError: add(…)(…) is not a function 。所以应该封装一个都通用的函数。
function sum(...args){//这里的三个点...是扩展运算符,该运算符将一个数组,变为参数序列。
if([...args].length==1){//判断参数个数的形式是否为1个,即第二种形式
var cache = [...args][0];//将第一个参数的值暂存在cache中
var add = function (y){//创建一个方法用于实现第二个条件,最后并返回这个方法
cache += y;
return add;
}
add.toString = function () { return cache }
return add;
}else{
var res = 0;//这里最好先声明要输出的变量,并给其赋值,不然值定义而不赋值会输出NaN,因为js将undefined+number两个数据类型相加结果为NaN
for(var i = 0;i<[...args].length;i++){
res += [...args][i]; //参数累加
}
return res;
}
}
console.log(sum(2,3,4));
console.log(sum(2)(3)(4)(5));
原生js实现splice()函数
这一题是我今天看牛客面经的时候看到的一道题,挺不错的,实习的话就需要对splice函数中的每一项参数都特别理解,之前可能对每一项参数都特别模糊,趁着现在好好复习一下。
splice(参数一,参数二,参数三),要了解的是该函数会改变原数组。。。
参数一:如果只有该参数,则删除从该值后的所有元素,splice返回的是被删除的元素
参数二:如果为0,不操作数组,返回空数组,否则表示删除数组的长度
参数三:表示要插入的值。
// 实现splice()
Array.prototype.mySplice = function () {
var arr = this;
var res = [], temp = [];
if (arguments.length == 1) { //存在第一个参数情况
for (let i = arguments[0]; i < arr.length; i++) {
res.push(arr[i]);
}
for (let i = 0; i < arguments[0]; i++) {
temp.push(arr[i]);
}
arr = temp; //改变原数组
return res;
} else {
if (arguments[1] == 0 || arguments[1] > arr.length) {
return []; //第二个参数为0,或者超过原数组的情况
} else {
let k = arguments[1]; //保存下来,后面取值会用到
let n = arguments[0]
for (let i = n; i < arr.length; i++) {
res.push(arr[i]);
arguments[1]--; //第二个参数减减
if (arguments[1] <= 0) {
var array = Object.assign([], arr); //浅拷贝
//会有删除中间元素的情况,这样的话就要取到第一个被删除元素前的,和最后被删除后的元素
//比如[1, 2, 4, 5, 8, 7] 删除[2,4,5] ,那么原数组为[1,8,7]
for (let i = 0; i < n; i++) { //取到[1]
temp.push(array[i])
}
for (let i = k; i < array.length; i++) { //取到[8,7]
temp.push(array[i])
}
arr = temp; //赋值给原数组
break;
}
}
if (arguments[2]) { //存在第三个函数的情况,做插入
arr[n] = arguments[2];
}
}
return res;
}
}
var arr = [1, 2, 4, 5, 8, 7];
console.log(arr.mySplice(1,3,44));
实现splice是我自己实现的,程序可能存在不完美的之处,欢迎指出。
期待大家共同进步?