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固定在浏览器窗口上了,不论我们怎么拖动滚动条都无法改变它在浏览器窗口的位置。