【leetcode必会经典题,双指针】前端er必会算法-数组基础篇

325 阅读3分钟

原文位于 github仓库-正在起步阶段的前端知识库,其中记录了一名前端初学者的学习日记🤔&学习之路点点滴滴的记录(练手demo🧑‍💻,必会知识点🧐)

欢迎大家来贡献更多“前端er必会知识点”🧑‍🎓/分享更多有意义的demo❤️!(请给这个年幼的小仓库更丰富的内容吧🥺🥺🥺)

单纯针对数组来考察的题目,总体来说,都比较基础——数组题目要想往难了出,基本都要结合排序、二分和动态规划这些相对复杂的算法思想才行。

本篇记录那些“不那么难,但是面试中很高频且可以考验你数组掌握程度”的题目

  • 不那么难,指的是这种题不需要用到困难的“解题技巧”,排序、二分思想、动态规划

  • 面试中高频,字面意思,面试经常考嘛(虽说感觉前端er的面试中链表会问的比较多?)

  • 考验数组掌握程度,这一点很重要,决定了面试官对你的看法——

    • 你是个不求甚解所有题目都暴力求解的选手
    • 还是会不断优化,充分利用数组API与一些简单技巧(例如双指针、哈希表)进行求解的选手?

下面开始 三道题入门数组题型,熟悉双指针技巧 涉及——

  • 同向正序双指针

  • 同向倒序双指针

  • 反向对撞双指针

1. 两数之和

题目直通车 1. 两数之和

哈希表

暴力解就不放上来了,直接看使用哈希表优化之后的一趟求解法

几乎所有求和问题,都可以转化为求差问题,不知道i如何优化?试着想想求差~

  • 借助哈希表一趟遍历解题

    • 新建一个空对象模拟哈希表
     var twoSum = function(nums, target) {
         let map = {};
         for(let i = 0; i < nums.length; i++){
             if(map[target - nums[i]] >= 0){
                 return [map[target - nums[i]], i];
             }
             else{
                 map[nums[i]] = i;
             }
         }
     };
    
    • 另外这题里面Map数据结构真不咋好使滴(这API完全没帮上忙,还不如原生写法😂),还是直接创建一个对象,在对象里维护键值对儿吧~(也就是上面那个方法)
 var twoSum = function(nums, target){
     let map = new Map();
     for(let i = 0; i < nums.length; i++){
         if(map.get(target - nums[i]) >= 0){
             return [i, map.get(target - nums[i])]
         }
         else{
             map.set(nums[i], i);
         }
     }
 }

88. 合并两个有序数组

88. 合并两个有序数组

同向正序双指针,同向倒序双指针

  • 笨拙的暴力法 纯属是为了提高数组相关API的熟练度😂主站上逛了一圈没见过有这么写的

面试时可以试着用下来展示自己对数组这个数据结构的熟悉?hh

 var merge = function(nums1, m, nums2, n) {
     nums1.splice(m);
     for(let j = 0; j < n; j++){
         for(let i = 0; i < m + n; i++){
             if(nums2[j] <= nums1[i]){
                 nums1.splice(i, 0, nums2[j]);
                 break;
             }
             if(nums2[j] > Math.max(...nums1)){
                 console.log(nums1)
                 nums1.push(...nums2.slice(j)) 
                 return nums1
             }
         }
     }
     // return nums1;// 如果走到这里 其实就不用return了哦
 };
  • 开辟新空间,常规双指针寻值

直接拿来官方题解的动图了 一目了然~

img

 var merge = function(nums1, m, nums2, n) {
     let p1 = 0, p2 = 0;
     let temp = [];
     while(p1 < m || p2 < n){
         // 如果nums1/nums2已经遍历完了,那么只能操作另外一个数组了~
         if(p1 === m){
             temp.push(nums2[p2++]);
         }
         else if(p2 === n){
             temp.push(nums1[p1++]);
         }
         // 较小的元素插入temp中(常规思路了这里~)
         else if(nums1[p1] < nums2[p2]){
             temp.push(nums1[p1++]);
         }
         else if(nums1[p1] >= nums2[p2]){
             temp.push(nums2[p2++]);
         }
     }
     for(let i = 0; i < m + n; i++){
         nums1[i] = temp[i];
     }
     // return nums1; // 题目就让把nums1修改下,没必要return了哈~核心代码模式就是爽XD
 };
  • 不必开辟新空间,巧妙逆向双指针!

ppt过程模拟看这里

面试能答出来这么个倒序双指针,不得起飞咯😎(好吧这其实是基操。)

 var merge = function(nums1, m, nums2, n) {
     let p1 = m - 1, p2 = n - 1;
     let tail = m + n - 1;
     let cur;// 参考了官方题解,设置一个cur记录每次要去进行插入的值,更加清晰勒!
     while(p1 >= 0 || p2 >= 0){
         if(p1 === -1){
             cur = nums2[p2--]; 
         }
         else if(p2 === -1){
             cur = nums1[p1--]; 
         }
         else if(nums2[p2] > nums1[p1]){
             cur = nums2[p2--];
         }
         else if(nums2[p2] <= nums1[p1]){
             cur = nums1[p1--]; 
         }
         // 每次迭代找出应该挪到后面的元素
         nums1[tail--] = cur;
     }
 };

15. 三数之和

15. 三数之和

反向对撞双指针

核心思想:对撞双指针 + 定指针分别挪动 & 保证获得的三个数不能重复(使用特殊判断跳过重复的值)

这里写了个题解 【JavaScript】对撞双指针 + 定指针 注释齐全

var threeSum = function(nums) {
    // 先排个序~
    nums = nums.sort((a, b) => {return a - b;})
    let res = [];
    // 定住的那个指针i
    for(let i = 0; i < nums.length - 2; i++){
        if(i >= 1 && nums[i - 1] === nums[i]){
            // 如果重复 则跳过本次循环 直接返回for语句
            continue;
        }
        // 每轮不断地动p1 p2来找答案
        let p1 = i + 1;
        let p2 = nums.length - 1;
        while(p1 < p2){
            let sum = nums[i] + nums[p1] + nums[p2];
            if(sum === 0){
                res.push([nums[i], nums[p1], nums[p2]]);
                // 找到一个答案,接着进行寻找,注意不要造成重复!
                // (第一次做就在这里不断错!其实想清楚还是很简单的——)
                p1++;
                while(nums[p1] === nums[p1 - 1]){
                    p1++;
                }
                p2--;
                while(nums[p2] === nums[p2 + 1]){
                    p2--;
                }
            }
            // 挪动双指针,为了防止重复,要跳过重复值
            else if(sum < 0){
                p1++;
                // 注意这里当新p1与上一个p1相同时 才会加
                while(nums[p1] === nums[p1 - 1]){
                    p1++;
                }
            }
            else if(sum > 0){
                p2--;
                // 注意这里当新p2与上一个p2相同时 才会减
                while(nums[p2] === nums[p2 + 1]){
                    p2--;
                }
            }
            // 一头一尾两个指针一轮的挪动完毕
        }
    }
    
    return res;
};