zoukankan      html  css  js  c++  java
  • 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固定在浏览器窗口上了,不论我们怎么拖动滚动条都无法改变它在浏览器窗口的位置。
  • 相关阅读:
    UVA 408 (13.07.28)
    linux概念之用户,组及权限
    Java实现 蓝桥杯 历届试题 网络寻路
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 约数倍数选卡片
    Java实现 蓝桥杯 历届试题 九宫重排
    Java实现 蓝桥杯 历届试题 九宫重排
  • 原文地址:https://www.cnblogs.com/banshanliang/p/14251850.html
Copyright © 2011-2022 走看看