JS数组去重的方法总结/题目

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();

数组去重方法总结

双层循环,外层循环元素,内层循环时比较值。如果有相同的值则跳过,不相同则push进数组。

此时的跳过不是跳出内层循环,如果内层比较有重复则把当前元素忽略,跳到下一个元素去做循环比较。

Array.prototype.distinct = function(){
    var arr = this,
     result = [],
    for(let i = 0; i < arr.length; i++){
     for(let j = i + 1; j < arr.length; j++){
      if(arr[i] === arr[j]){
       j = ++i;
      }
     }
     result.push(arr[i]);
    }
    return result;
   }
   var arra = [1,2,3,4,4,1,1,2,1,1,1];
   arra.distinct();    //返回[3,4,2,1]

i++和++i又分不清了

let i=1;
let a=0;
  i++  先运算再赋值  a=i++ =>  a=i, i=i+1   =>  a===1;
  ++i  先赋值再运算  a=++i =>  i=i+1 , a=i   =>  a===2;

在清除的解释一下原理,以一个简单的数组为例。

function distinct(){
   var arr = [1,2,2,1,3];
    result = [];
    for(let i = 0; i < arr.length; i++){
     for(let j = i + 1; j < arr.length; j++){
      if(arr[i] === arr[j]){
        console.log('内层循环的j-前',j);
         j = ++i;
         console.log('内层循环的j',j);
         console.log('内层循环的i',i);
      }
     }
     console.log('外层循环的i',i);
     result.push(arr[i]);
    }
    document.getElementById("shuzuquchong").innerHTML=result;
    return result;
   };
//  打印如下
//  内层循环的j-前 3
//  内层循环的j 1
//  内层循环的i 1
//  内层循环的j-前 2
//  内层循环的j 2
//  内层循环的i 2
//  外层循环的i 2
//  外层循环的i 3
//  外层循环的i 4

方法二:利用splice直接在原数组进行操作

双层循环,外层循环元素,内层循环时比较值;值相同时,则删去这个值(删除后面(和前面重复)的值);注意点:删除元素之后,需要将数组的长度也减1.

function distinct(){
    var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
   for(let i = 0; i < a.length; i++){
   for(let j = i + 1; j < a.length; j++){
   if(a[i] == a[j]){
    a.splice(j,1);  //splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。该方法会改变原始数组。
    a.length--;
    j--;
   }
  }
 }
 document.getElementById("shuzuquchong").innerHTML=a;
    return a;
};

splice()方法和slice()方法区别一下

arrayObject.splice(index,howmany,item1,.....,itemX)  注释:该方法会改变原始数组。

splice() 方法向/从数组中添加/删除项目,然后返回被删除的项目。

ndex 必需。整数,规定添加/删除项目的位置,使用负数可从数组结尾处规定位置。
howmany 必需。要删除的项目数量。如果设置为 0,则不会删除项目。
item1, ..., itemX 可选。向数组添加的新项目。
arrayObject.slice(start,end)  slice() 方法可从已有的数组中返回选定的元素。
start 必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end 可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

方法三:利用对象的属性不能相同的特点进行去重

对象的属性不能相同。

   function distinct(){
    var arr = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
        obj = {},
        result = [];
   for(let i = 0; i< arr.length; i++){
       if(!obj[arr[i]]){ //如果能查找到,证明数组元素重复了
        console.log('obj[arr[i]]',obj[arr[i]]);
        obj[arr[i]] = 1;
         result.push(arr[i]);
  }
 }
 document.getElementById("shuzuquchong").innerHTML=result;
 return result;
};

方法四:数组递归去重

运用递归的思想

先排序,然后从最后开始比较,遇到相同,则删除

什么是递归?:

那么什么是递归呢? 要理解递归,就得先了解什么是递归,实际上这句话就是一个递归.这么说可能不好理解,接下来我举个简单的例子来解释这段话的意义。

假设我们现在都不知道什么是递归,我们自然想到打开浏览器,输入到谷歌的网页,我们点击搜索递归,然后我们在为维基百科中了解到了递归的基本定义,在了解到了递归实际上是和栈有关的时候,你又蒙圈了,什么是栈呢?数据结构没学清楚,此时的你只能又打开谷歌,搜索什么是栈.接下来你依次了解了内存/操作系统.在你基本了解好知识之后,你通过操作系统了解了内存,通过内存了解了栈,通过栈了解了什么是递归这下你恍然大悟!原来这就是递归啊!

这下应该有点明白了吧,这个过程其实就是递归的过程,如果不了解递归,那就先了解什么是递归,可能你会说这是个循环并不是递归,我们前面说到,递归是需要终止条件的,那么你明白递归是什么其实就是终止条件。整个过程,搜索引擎充当递归函数(只是形象的假设);在你去依次查找递归/栈/内存/操作系统的过程为前行阶段,在你都了解完之后,反回去了解含义的过程为退回阶段。

递归和循环区别在于,循环是执行一段代码,仅仅参数不同;递归要调用到自己。
打个比方:
循环就像在同一个地方打转;递归是一层一层进入,再原路返回,虽然每一层都一样。

 

 

 

你可能感兴趣的:(JavaScript)