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固定在浏览器窗口上了,不论我们怎么拖动滚动条都无法改变它在浏览器窗口的位置。
posted @ 2021-01-08 15:56  凉将  阅读(186)  评论(0编辑  收藏  举报