前端开发面试笔试学习--算法01--数组求和/数组去重
2018-01-26 09:42
726 查看
1、有一个长度为n-1的数组,包含1-n中不重复的乱序的数,求寻找范围内不在数组中的数,考虑空间占用,性能优化,溢出等情况,至少写两个算法
当n不太大时,可以考虑求和。先算出1~n的所有数的和,然后减去数组中出现的所有自然数的和。时间复杂度为O(n),空间复杂度O(1)。这种方法的缺点是n不能太大,n比较大时,求和容易溢出。
用位图。从头到尾的扫描整个数组,把出现的数相应的位设置为1.然后再扫描位图,找出不为1的那一位,即为要找的数。这种方法的时间复杂度为O(n),空间复杂度为O(n)。
异或有个很巧妙的地方:同一变量和该变量与另一变量的异或值的异或等于这个变量自身。所以我们可以把1~n的所有数异或,再把数组中出现的所有数异或,然后再把这两个异或的结果异或,最后得到的值即为我们要找的值。这样时间复杂度为O(n),空间复杂度为O(1)。在空间上比第二种方法要好,而且不会出现第一种方法中所说的溢出问题。
解法一:用到数组求和 var arr = [9, 5, 7, 8, 6, 3, 4, 1]
var sum = 0; //数组的和
var sum1 = 0; //范围的和
var find = function() {
for (var i = 0; i < arr.length; i++) {
sum += parseInt(arr[i]);
};
for (var i = 1; i <= arr.length + 1; i++) {
sum1 += i;
};
var wow = sum1 - sum;
console.log(wow);
console.log(sum1);
console.log(sum);
};
find();
复习:
JavaScript中数组有很多种方法,下图能更好的向你阐述JavaScript有多少种方法,作用是什么:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202009/03/abda9e6d9ac70743b98dc6ce3cac9bb3)
简单点回顾一下前面学习的知识:push():向数组末尾添加一个或多个元素
unshift(): 向数组的开头添加一个或多个元素
pop(): 删除数组最后一个元素
shift(): 删除数组第一个元素
sort(): 给数组排序
reverse(): 颠倒数组项在数组中的位置
concat(): 合并数组
slice(): 指定的位置开始删除指定的数组项,并且将删除的数组项构建成一个新数组
splice(): 对一个数组做删除、插入和替换
indexOf(): 从前向后查找元素在数组中位置
lastIndexOf(): 从后向前查找元素在数组中位置
forEach()、every()、some()、filter()和map():数组迭代
reduce(): 数组中的每个值(从左到右)开始合并,最终为一个值
reduceRight(): 数组中的每个值(从右到左)开始合并,最终为一个值
数组求和:
假设有一个这样的数组var arr = [0,1,2,3,4,5,6,7,8,9];1、用for循环和while循环方式
var sum = 0;
function getSum (item, index, array){ sum += item; }
console.time("getSum");
for (var i = 0; i < 1000000; i++){
var sum = 0;
arr.forEach(getSum);
}
console.timeEnd("getSum"); // getSum: 1348.212ms
console.log("使用forEach循环:sum=" + sum); // 使用forEach循环:sum=45
})()some()方法(function (){
var sum = 0;
function getSum (item, index, array){ sum += item; }
console.time("getSum");
for (var i = 0; i < 1000000; i++){
var sum = 0;
arr.some(getSum);
}
console.timeEnd("getSum"); // getSum: 1038.737ms
console.log("使用some循环:sum=" + sum); // 使用some循环:sum=45
})()map()方法
1.遍历数组法
最简单的去重方法, 实现思路:新建一新数组,遍历传入数组,值不在新数组就加入该新数组中;
注意点:判断值是否在数组的方法“indexOf”是ECMAScript5 方法,IE 8以下不支持,需多写一些兼容低版本浏览器代码.indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。该方法将从头到尾地检索字符串 stringObject,看它是否含有子串 searchvalue。开始检索的位置在字符串的 fromindex 处或字符串的开头(没有指定 fromindex 时)。如果找到一个 searchvalue,则返回 searchvalue 的第一次出现的位置。stringObject 中的字符位置是从 0 开始的。如果在数组中没找到字符串则返回 -1。
最简单数组去重法: function unique1(array) {
var arr = [];
//遍历当前数组
for (var i = 0; i < array.length; i++) {
//如果当前数组的第i已经保存进了临时数组,那么跳过,
//否则把当前项push到临时数组里面
if (n.indexOf(array[i]) == -1) {
n.push(array[i]);
};
return n;
}
} 判断浏览器是否支持indexOf ,indexOf 为ecmaScript5新方法 IE8以下(包括IE8, IE8只支持部分ecma5)不支持
增加新的indexof方法:if (!Array.prototype.indexOf){
// 新增indexOf方法
Array.prototype.indexOf = function(item){
var result = -1, a_item = null;
if (this.length == 0){
return result;
}
for(var i = 0, len = this.length; i < len; i++){
a_item = this[i];
if (a_item === item){
result = i;
break;
} }
return result;
}}2.对象键值对法
该方法执行的速度比其他任何方法都快, 就是占用的内存大一些;
实现思路:新建一js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,不是的话给对象新增该键并放入新数组。
注意点: 判断是否为js对象键时,会自动对传入的键执行“toString()”,不同的键可能会被误认为一样;例如: a[1]、a["1"] 。解决上述问题还是得调用“indexOf”。// 速度最快, 占空间最多(空间换时间)
function unique2(array){
var n = {}, r = [], len = array.length, val, type;
for (var i = 0; i < array.length; i++) {
val = array[i];
type = typeof val; //当前值得类型
if (!n[val]) {
n[val] = [type];
r.push(val);
} else if (n[val].indexOf(type) < 0) {
n[val].push(type);
r.push(val);
}
}
return r;
}3.数组下标判断法
还是得调用“indexOf”性能跟方法1差不多,实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。function unique3(array){
var n = [array[0]]; //结果数组
//从第二项开始遍历
for(var i = 1; i < array.length; i++) {
//如果当前数组的第i项在当前数组中第一次出现的位置不是i,
//那么表示第i项是重复的,忽略掉。否则存入结果数组
if (array.indexOf(array[i]) == i) n.push(array[i]);
}
return n;
}4.排序后相邻去除法
虽然原生数组的”sort”方法排序结果不怎么靠谱,但在不注重顺序的去重里该缺点毫无影响。实现思路:给传入数组排序,排序后相同值相邻,然后遍历时新数组只加入不与前一值重复的值。// 将相同的值相邻,然后遍历去除重复值
function unique4(array){
array.sort(); //默认按照字符编码顺序进行排序
var re=[array[0]];
for(var i = 1; i < array.length; i++){
if( array[i] !== re[re.length-1])
{
re.push(array[i]);
}
}
return re;
}5.优化遍历数组法(不理解)
实现思路:获取没重复的最右一值放入新数组。(检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断)
当n不太大时,可以考虑求和。先算出1~n的所有数的和,然后减去数组中出现的所有自然数的和。时间复杂度为O(n),空间复杂度O(1)。这种方法的缺点是n不能太大,n比较大时,求和容易溢出。
用位图。从头到尾的扫描整个数组,把出现的数相应的位设置为1.然后再扫描位图,找出不为1的那一位,即为要找的数。这种方法的时间复杂度为O(n),空间复杂度为O(n)。
异或有个很巧妙的地方:同一变量和该变量与另一变量的异或值的异或等于这个变量自身。所以我们可以把1~n的所有数异或,再把数组中出现的所有数异或,然后再把这两个异或的结果异或,最后得到的值即为我们要找的值。这样时间复杂度为O(n),空间复杂度为O(1)。在空间上比第二种方法要好,而且不会出现第一种方法中所说的溢出问题。
解法一:用到数组求和 var arr = [9, 5, 7, 8, 6, 3, 4, 1]
var sum = 0; //数组的和
var sum1 = 0; //范围的和
var find = function() {
for (var i = 0; i < arr.length; i++) {
sum += parseInt(arr[i]);
};
for (var i = 1; i <= arr.length + 1; i++) {
sum1 += i;
};
var wow = sum1 - sum;
console.log(wow);
console.log(sum1);
console.log(sum);
};
find();
复习:
JavaScript中数组有很多种方法,下图能更好的向你阐述JavaScript有多少种方法,作用是什么:
简单点回顾一下前面学习的知识:push():向数组末尾添加一个或多个元素
unshift(): 向数组的开头添加一个或多个元素
pop(): 删除数组最后一个元素
shift(): 删除数组第一个元素
sort(): 给数组排序
reverse(): 颠倒数组项在数组中的位置
concat(): 合并数组
slice(): 指定的位置开始删除指定的数组项,并且将删除的数组项构建成一个新数组
splice(): 对一个数组做删除、插入和替换
indexOf(): 从前向后查找元素在数组中位置
lastIndexOf(): 从后向前查找元素在数组中位置
forEach()、every()、some()、filter()和map():数组迭代
reduce(): 数组中的每个值(从左到右)开始合并,最终为一个值
reduceRight(): 数组中的每个值(从右到左)开始合并,最终为一个值
数组求和:
假设有一个这样的数组var arr = [0,1,2,3,4,5,6,7,8,9];1、用for循环和while循环方式
// 求和:for循环遍历数组arr (function() { var sum = 0; function getSum(array){ for (var i = 0; i < array.length; i++){ sum += parseInt(array[i]);//解析字符串返回整数。 } return sum; } console.time("getSum"); for (var i = 0; i < 1000000; i++){ sum = 0; getSum(arr); } console.timeEnd("getSum"); // 7877.155ms console.log("使用for循环:sum = " + sum); // 45 })();再来换个while看看:
(function () { var sum = 0; function getSum(array) { var i = array.length; while (i--) { sum += parseInt(array[i]); } return sum; } console.time("getSum"); for (var i = 0; i < 1000000; i++) { var sum = 0; getSum(arr); } console.timeEnd("getSum"); // getSum: 7690.056ms console.log("使用while循环:sum=" + sum); // 使用while循环:sum=45 })();除了古老的for和while循环之外,在ES5中还新增加了其他的数组迭代方法,比如forEach()、every()、some()、filter()和map()等。而且这些方法都可以让数组中的每一个元素执行一次回调函数。如果一来,只需要对这个回调函数做一个数组项的累加功能:
function getSum (item, index, array){ sum += item; }forEach()方法forEach()方法让数组每一项执行给定的回调函数callbackfn。这样,我们可以在回调函数getSum做一个累加计算。(function (){
var sum = 0;
function getSum (item, index, array){ sum += item; }
console.time("getSum");
for (var i = 0; i < 1000000; i++){
var sum = 0;
arr.forEach(getSum);
}
console.timeEnd("getSum"); // getSum: 1348.212ms
console.log("使用forEach循环:sum=" + sum); // 使用forEach循环:sum=45
})()some()方法(function (){
var sum = 0;
function getSum (item, index, array){ sum += item; }
console.time("getSum");
for (var i = 0; i < 1000000; i++){
var sum = 0;
arr.some(getSum);
}
console.timeEnd("getSum"); // getSum: 1038.737ms
console.log("使用some循环:sum=" + sum); // 使用some循环:sum=45
})()map()方法
(function (){2、 编写一个方法去掉一个数组的重复元素
var sum = 0;
function getSum (item, index, array){ sum += item; }
console.time("getSum");
for (var i = 0; i < 1000000; i++){
var sum = 0;
arr.map(getSum);
}
console.timeEnd("getSum"); // getSum: 4568.558ms
console.log("使用map循环:sum=" + sum); // 使用map循环:sum=45
})()
1.遍历数组法
最简单的去重方法, 实现思路:新建一新数组,遍历传入数组,值不在新数组就加入该新数组中;
注意点:判断值是否在数组的方法“indexOf”是ECMAScript5 方法,IE 8以下不支持,需多写一些兼容低版本浏览器代码.indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。该方法将从头到尾地检索字符串 stringObject,看它是否含有子串 searchvalue。开始检索的位置在字符串的 fromindex 处或字符串的开头(没有指定 fromindex 时)。如果找到一个 searchvalue,则返回 searchvalue 的第一次出现的位置。stringObject 中的字符位置是从 0 开始的。如果在数组中没找到字符串则返回 -1。
最简单数组去重法: function unique1(array) {
var arr = [];
//遍历当前数组
for (var i = 0; i < array.length; i++) {
//如果当前数组的第i已经保存进了临时数组,那么跳过,
//否则把当前项push到临时数组里面
if (n.indexOf(array[i]) == -1) {
n.push(array[i]);
};
return n;
}
} 判断浏览器是否支持indexOf ,indexOf 为ecmaScript5新方法 IE8以下(包括IE8, IE8只支持部分ecma5)不支持
增加新的indexof方法:if (!Array.prototype.indexOf){
// 新增indexOf方法
Array.prototype.indexOf = function(item){
var result = -1, a_item = null;
if (this.length == 0){
return result;
}
for(var i = 0, len = this.length; i < len; i++){
a_item = this[i];
if (a_item === item){
result = i;
break;
} }
return result;
}}2.对象键值对法
该方法执行的速度比其他任何方法都快, 就是占用的内存大一些;
实现思路:新建一js对象以及新数组,遍历传入数组时,判断值是否为js对象的键,不是的话给对象新增该键并放入新数组。
注意点: 判断是否为js对象键时,会自动对传入的键执行“toString()”,不同的键可能会被误认为一样;例如: a[1]、a["1"] 。解决上述问题还是得调用“indexOf”。// 速度最快, 占空间最多(空间换时间)
function unique2(array){
var n = {}, r = [], len = array.length, val, type;
for (var i = 0; i < array.length; i++) {
val = array[i];
type = typeof val; //当前值得类型
if (!n[val]) {
n[val] = [type];
r.push(val);
} else if (n[val].indexOf(type) < 0) {
n[val].push(type);
r.push(val);
}
}
return r;
}3.数组下标判断法
还是得调用“indexOf”性能跟方法1差不多,实现思路:如果当前数组的第i项在当前数组中第一次出现的位置不是i,那么表示第i项是重复的,忽略掉。否则存入结果数组。function unique3(array){
var n = [array[0]]; //结果数组
//从第二项开始遍历
for(var i = 1; i < array.length; i++) {
//如果当前数组的第i项在当前数组中第一次出现的位置不是i,
//那么表示第i项是重复的,忽略掉。否则存入结果数组
if (array.indexOf(array[i]) == i) n.push(array[i]);
}
return n;
}4.排序后相邻去除法
虽然原生数组的”sort”方法排序结果不怎么靠谱,但在不注重顺序的去重里该缺点毫无影响。实现思路:给传入数组排序,排序后相同值相邻,然后遍历时新数组只加入不与前一值重复的值。// 将相同的值相邻,然后遍历去除重复值
function unique4(array){
array.sort(); //默认按照字符编码顺序进行排序
var re=[array[0]];
for(var i = 1; i < array.length; i++){
if( array[i] !== re[re.length-1])
{
re.push(array[i]);
}
}
return re;
}5.优化遍历数组法(不理解)
实现思路:获取没重复的最右一值放入新数组。(检测到有重复值时终止当前循环同时进入顶层循环的下一轮判断)
// 思路:获取没重复的最右一值放入新数组function unique5(array){ var r = []; for(var i = 0, l = array.length; i < l; i++) { for(var j = i + 1; j < l; j++) if (array[i] === array[j]) j = ++i; r.push(array[i]); } return r;}//不理解
相关文章推荐
- 前端开发面试笔试学习--JavaScript01
- 前端开发面试笔试学习--html/css-01
- 前端开发面试笔试题学习--额额
- 前端开发,面试笔试题学习---通信/原理02
- Web前端开发笔试&面试_01(mi:)
- 前端面试笔试题学习--后延/以后学习01
- 前端开发学习笔记01(大杂烩)
- GitHub最全的前端资源汇总仓库(包括前端学习、开发资源、求职面试等)
- 关于前端学习和笔试面试的总结
- 关于前端学习和笔试面试的总结
- 算法学习-连续子数组求和最大值
- 笔试面试算法经典-找到数组中出现次数大于N/k的数(Java)
- Web前端开发笔试&面试_05
- 笔试面试算法经典--连续子数组的最大乘积及连续子数组的最大和(Java)
- 算法学习-连续子数组求和最大值
- Web前端开发笔试&面试_04_20161019MTBS
- 前端开发(一)—— 数组学习
- java基础学习——java开发环境面试笔试题
- Web前端开发笔试&面试_05_other 2016104399MS
- 关于前端学习和笔试面试的总结