• 2021春招冲刺-12.29-算法、原型与原型链、文档流


    2021春招冲刺

    12.29日

    1.算法 | 合并两个有序数组,计算其中位数

    // [1,2,4,5,6,8,11] m
    // [2,5,6,8,10] n
    // 1.偶数个时,取中间两个数的平均值
    // 2. 时间复杂度不超过O(m+n)

    时间复杂度不超过m+n的时候,同时由于两个数组是有序的,因此不需要消耗复杂度对两个数组进行排序。最基础的思路是利用两个下标从0号位开始将两个数组合并成一个新的数组,然后利用数学方法求新数组的中位数。

    看了一下leetcode,如果要满足时间复杂度不超过O(log(m+n))的话就需要用到二分法。

    • 第一种思路 寻找分界线
      先找到数组A中的一条分界线i,使得数组A分为A_left,和A_right两部分,那么因为时要找到中位数,我们可以直接计算出B数组的一条分界线j,使得size(Aleft)+size(Bleft)=size(Aright)+size(Bright)
      max(A_left,B_left)<=min(A_right,B_right)的时候就代表找到了中位数。
      即在A中随机找一个划分线,并找到B中对应的划分线让两个数组都分成左右两部分,保证左右两部分的总长度相等。
      当左部分有数字大于右部分的时候,就说明左右部分有重叠的数字域,需要重新找分界线。
      当做左部分的所有数字都小于等于右部分的数字的时候,那么这个划分线就刚好从中位数划分开。

      具体步骤如下

      • 令imin = 0, imax = m,在[imin, imax]中开始寻找
      • 令i = (imin + imax)/2, j = (m + n + 1)/2 - i
      • 至此,len(left_part)==len(right_part),共3种情况:
        • B[j-1] <= A[i] and A[i-1] <= B[j],满足目标,停止
        • B[j-1] > A[i],需要增加i,在[i+1, imax]中寻找,则令imin = i+1, 重复步骤2
        • A[i-1] > B[j],需要在[imin, i-1]中寻找,则令imax = i-1,重复步骤2

      本质还是对A数组进行二分法查询合适的位置,找到保证A的左边不大于B的右边,B的左边也不大于A的右边,此时则无重叠

    代码实现:

    class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { 
            return findMedianSortedArrays(B,A); // 保证 m <= n
        }
        int iMin = 0, iMax = m;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = (m + n + 1) / 2 - i;
            if (j != 0 && i != m && B[j-1] > A[i]){ // i 需要增大
                iMin = i + 1; 
            }
            else if (i != 0 && j != n && A[i-1] > B[j]) { // i 需要减小
                iMax = i - 1; 
            }
            else { // 达到要求,并且将边界条件列出来单独考虑
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; } // 奇数的话不需要考虑右半部分
    
                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }
    
                return (maxLeft + minRight) / 2.0; //如果是偶数的话返回结果
            }
        }
        return 0.0;
    }
    } 
    
    • 第二种思路 第k小数解法
      leetcode解题思路指路
      • 定义两个数组合并后第k个数字是中位数。比较两个数组的第 k/2 个数字,如果 k 是奇数,向下取整。
      • A 数组中比 A[k/2] 小的数有 k/2 - 1 个,B数组中比A[k/2]小的数也有 k/2 - 1 个。
      • 如果B[k/2]小于等于A[k/2],那么B数组中 1 ~ k/2-1 个数都必定比 A[K/2] 小 。同时A数组中 1 ~ k/2-1 也肯定比 A[K/2] 小。此时,有 (k/2-1)+(k/2-1)= k-2 个数比 A[k/2]小。所以 A[k/2] 最多是第 k-1 小的数。
      • 那么,不论是B[k/2]小于还是等于A[k/2],它也必定小于第k个数。所以可以把B数组中前 k/2 个数字全部排除。
      • 此时,已经排除了k/2个数,那么再新的两个数组中,只需要找到第(k - k/2)个小的数就好。
        因此本思路的实质是对k进行二分,使得 k=k/2 ,并不断在新数组中进行排除,直到找到这个数。

    2.JS | 原型与原型链

    下面三个分别与什么相等
    function foo(){}
    const bar = new foo()
    bar.__proto__ === // ?
    foo.__proto__ === // ?
    foo.prototype.constructor === // ?

    帮你彻底搞懂JS中的prototype、__proto__与constructor 参考博客

    什么是prototype和proto?

    每当我们创建一个函数,就会在该函数内创建一个prototype属性,prototype就是通过调用构造函数产生的 实例的原型对象。只有函数才有,并且通过bind()绑定的也没有。

    在上述代码中,prototype是foo的原型属性,而foo.prototype是新产生的实例bar的原型属性。所有的原型对象都会获得一个constructor属性,该属性是一个指针,执行prototype所在的函数,在这个例子中即函数foo。因此foo.prototype.constructor === foo

    当通过构造函数产生一个实例后,该实例内部会生成一个内部属性 __proto__,它是指向构造函数原型对象的指针。可以看到,图中实例对象person1下面有一个 [[prototype]] ,实际上,它是__proto__在ES标准定义中的名字,其功能一样。

    这个连接是 实例 构造函数的原型对象 之间的, 即 bar 和foo.prototype之间的联系,而不是实例和构造函数的联系。因此bar.__proto__ === foo.prototype

    而js中JS中函数也是一种对象,所以函数也拥有__proto__和constructor属性,因此foo.__proto__ === Function.prototype

    总结
    原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。函数创建的对象.__proto__ === 该函数.prototype,该函数.prototype.constructor===该函数本身

    • __proto__

      • 它是对象所独有的,总是由一个对象指向其原型对象(父对象)
      • 作用是当寻找底层对象的属性时,如果该对象内部不存在这个属性,就会一层层向上根据__proto__指向的对象中寻找。直到找到原型链顶端为null。
      • 由以上这种通过__proto__属性来连接对象直到null的一条链即为我们所谓的原型链,平时调用的字符串方法、数组方法、对象方法、函数方法等都是靠__proto__继承而来的。
    • prototype

      • 它是函数所独有的,从一个函数指向一个对象。它的含义是函数的原型对象。
      • 作用是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。
        function foo(){}
        foo.prototype.name='father'
        var f1 = new foo();
        var f2 = new foo();
        //f1.name == f2.name == 'father'
        
    • constructor

      • 它是对象所独有的,从一个对象指向一个函数,含义就是指向该对象的构造函数.
      • 每个对象都可以找到其对应的constructor,这个constructor可能是对象自己本身显式定义的或者通过__proto__在原型链中找到。单从constructor这个属性来讲,只有prototype对象才有。

    3.HTML/CSS

    一个div的高度100px是被其内容撑开的,如果为其添加样式height:50px;overflow:hidden,会触发回流重绘吗?如果其先有样式position:absolute,再添加上述样式会触发哪些?

    在12.25的内容中我们已经谈过什么是回流与重绘->2021春招冲刺-12.25

    由于定义了height:50px;overflow:hidden,超出50px的范围的内容会隐藏,使得div容器的可见尺寸发生变化,因此会发生回流与重绘。
    当为绝对定位时,div宽度也由默认100%变为由其内容撑开。而height:50px;overflow:hidden还是会影响其可见高度,可见尺寸发生变化会触发回流重绘。

    文档流有哪几种

    • 标准文档流
    • 浮动文档流
    • 定位文档流

    标准流的层级最低,浮动流的层级第二,定位流的层级最高(可以使用z-index调整定位盒子的层级)。

    脱离普通文档流有哪些方式

    • 浮动 float
      使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在该元素的周围。
    • 绝对定位 position:absolute
      使用absolute脱离文档流后的元素,是相对于该元素的父类进行定位的,并且这个父类元素的position必须是非默认定位的,当父级元素的position全是static的时候,absolute将相对于html来进行定位的。若html没有提供相对位置,则只能浮动在原来该元素在文档流中的位置上方。
    • 固定定位 position:fixed;
      完全脱离文档流,相对于浏览器窗口进行定位(也就是相对于html)。因此这个div固定在浏览器窗口上了,不论我们怎么拖动滚动条都无法改变它在浏览器窗口的位置。
  • 相关阅读:
    C#调用VC++.net托管库程序集DLL
    SQL Server 2008 评估期已过期解决办法
    TFS2010安装(转)
    将dll添加到GAC(Global Assembly Cache)中
    LINQ to SQL with NOLOCK
    SQL Server 2008创建定期自动备份任务(转)
    问题解决记录(一)
    控制台读入
    数据库
    a标签的onclick与href的执行顺序
  • 原文地址:https://www.cnblogs.com/banshanliang/p/14251850.html
Copyright © 2020-2023  润新知