【前端学算法】从实际案例体验数据结构运用得当的魅力!

215 阅读3分钟

题目

销售主管的任务是出售一系列的物品,其中每个物品都有一个编号。

由于出售具有相同编号的商品会更容易,所以销售主管决定删除一些物品。

现在她知道她最多能删除多少物品,她想知道最终袋子里最少可以包含多少种不同编号的物品。

例如,最开始她有n = 6 个物品,编号为:ids = [1,1,1,2,2,3],她最多可以删除 m = 2 个物品。

如果删除两个物品 1,则剩下的物品 ids = [1,2,2,3],此时她拥有三种不同编号的物品。

如果删除两个物品 2,则剩下的物品 ids = [1,1,1,3],此时她拥有两种不同编号的物品。

如果删除物品 2 和物品 3 各 1个,则剩下的物品 ids = [1,1,1,2],此时她拥有两种不同编号的物品。

我们发现,物品最少可以剩下两种不同的编号,所以你的程序要返回 2。

其中,ids 的大小不超过 10^5

1 ≤ ids[i] ≤ 1000000

1 ≤ m ≤ 100000

样例 

输入: 
[1,1,1,2,2,3] 2 

输出: 
2

思路

上述题目文字那么多,我们来简化一下。

假设我们有一个数组中array ,现在删掉数组中的number个元素,要求数组剩余的元素中,相同的元素越多越好!

也就说,删掉的元素出现的次数越少越好,所以这道题其实是遍历array数组中的每个元素,统计每个元素出现的次数,然后根据 number 的值来删除次数出现少的元素。

好了,题意明白了,我们直接上代码。

const smartSale1 = (array=[], number=0)=>{ 
   //创建了一个名为 `resultArr` 的空数组,用于存储统计后的元素和数量。
   let resultArr = [];
   array.forEach( item => { 
     let obj = {name: item, num: 1};
     let i = resultArr.findIndex(element => element.name == item);
     //通过 `forEach` 遍历 `array` 中的每个元素,如果 `resultArr` 中不存在当前元素,将其添加到 `resultArr` 中,如果存在当前元素,则元素数量+1
     i !== -1 ? resultArr[i].num+=1 : resultArr.push(obj); 
   }); 
    // 接着,对 `resultArr` 中的每个元素按照数量升序排序。
    resultArr.sort((a,b)=>a.num-b.num);  
    //排序完成,从数量最小的元素开始删除
    // 声明一个变量`sum`赋值为0
    let sum = 0 ;
    for (let index = 0; index < resultArr.length; index++) { 
      // 从第一个元素开始,把元素的`num`累加给`sum`
      sum += resultArr[index].num;
      // 当sum大于给定数量number时跳出循环
      if(sum > number){ 
         break 
      }else{ 
        // 当sum小于等于给定数量number时,删除元素,resultArr数组数量减一
        resultArr.splice(index,1);
        index--     
      };
   };
   //函数返回删除元素后 `resultArr` 的长度,也就是上上述题目中剩余物品种类。
   return resultArr.length;
};

本来以为上述代码没啥毛病,结果将array 的数组数量放到很多,诸如99000个时,再将number=10000,此时运行代码,页面则会卡很久才会出结果。

QQ_1737114502035.png

那么,怎么优化此段代码呢?

经搜索发现,用数组来存储元素及其数量可能不是最优选择,而使用数据结构Map 来存储元素及其数量则更高效,尤其是在大数据量时尤为明显,以下是使用 Map 数据结构优化的代码示例:

const smartSale = (array = [], number = 0) => { 
   let count = new Map();
    for (let num of array) {
        if (count.has(num)) {
            count.set(num, count.get(num) + 1);
        } else {
            count.set(num, 1);
        }
    }
    
    let resultArr = Array.from(count.values()).sort((a, b) => a - b);
   
    let sum = 0 ;
   
    for (let index = 0; index < resultArr.length; index++) { 
      // 从第一个元素开始,把元素的`num`累加给`sum`
      sum += resultArr[index];
      // 当sum大于给定数量number时跳出循环
      if(sum > number){ 
         break 
      }else{ 
        // 当sum小于等于给定数量number时,删除元素,resultArr数组数量减一
        resultArr.splice(index,1);
        index--     
      };
   };
   return resultArr.length;
};

同等条件下,运行该代码,116.73291015625 ms就得出结果,如图:

QQ_1737115085236.png