围追堵截,或者说是查漏补缺,是将自己的面试问或者实际工作用到的一些小知识点,整理后记录下来。
1. 来自互联网的资料
在之前的代码中,无论是Python还是Java,基本在判断值相等的时候都用了“==”;但是也有刷到Java中一个判断相等的函数,.equals()
;但哪一个是值相等,哪一个是对象相等,今天仔细地探究一下。
1.1 Python
篇 - is
or ==
该文章指出,
Python
的is
代表判断对象的身份id
,该id
是唯一的,可以理解为在比较地址;而==
是标准操作符,判断的是值是否相等。从字面意义上理解,“
==
”与数学符号中“=”的定义一样为相等,不难理解是值相等;采用自然语言的is
判等,是判别身份,也挺好理解。1.2 Java
篇 - .equals()
or ==
该文章的观点与
Python中
的基本一致,即,==
是标准操作符,与数学=
符号意义相同,.equals()
表示判断对象是否一致;2. 大胆求证一番
2.1 Python求证
首先是
Python
的==
与Python
中的is
:测试环境,Python3.8
,所以其实都是在判值相等?当然不是。
可以看到,如果说is
是判断值相等,那么这里不应该出现False
,这说明Python
对常量,如3,不另外分配空间,而是直接指向一个地址;
最后是部分文章(非前面的链接)有关
Python
的判等中提到,六大基本类型中==
判断值相等,其他对象中,判断id
,这其实是因为(自己定义的类)对象没法取某一个值来判断,只能对比id
。Python中常用到
is
的时候都是在与None
结合,None
是常量,Python
不会额外分配内存。2.2 Java求证
首先是
Java
中的==
与Java
中的.equals()
:看到了这里,为我之前把
==
和.equals()
记错汗颜,不知道是哪一篇文章出错了还是真的我记错了,当时的我觉得Java
中这一点很反常,所以记得很清楚,结果还记错了。3. 为什么要区分
可能平常业务中不太用得到对象判等,这个区别(或者是对象判等这个方法)也就容易被忽略。这倒是可以帮我快速判断,函数中参数到底是引用传递还是参数传递(
Java
没有引用传递,但有时候无需返回又可以修改传入的参数,主要是数组,数组传入的是首地址,但Java
的数组不是一个对象?)。另外,使用对象判等(效果相同的前提下)在高频操作中比值相等高效一点?
4. 什么是线性规划?
待补充SVM
模型中目标函数 与 约束条件。
说起来好笑,明明
SVM
中就有用到线性规划相关的知识,用了目标函数跟约束函数,并且还用到了拉格朗日乘子法进行简化转换,自己却回答说不知道(没想到会直白地问运筹优化,然后对应不上什么是线性规划)。这说明基础知识还是不够扎实,所以下面会对机器学习中涉及到的统计学知识进行一次回顾。所以,什么是线性规划?
本科数学课有学过线性规划三要素,目标函数、约束条件、问题变量。以
SVM
举例,其中求解最大间隔为目标函数,约束条件为线性分隔函数需要满足的条件(最大间隔),问题变量为待求解的线性函数参数。线性规划中常用到原问题的对偶问题来求解,在
SVM
中使用了拉格朗日乘子法,将约束条件与目标函数放在一起(这样方便自动更新参数,变成损失函数):5. 线性规划该怎么求解?
在机器学习中,大多使用导数来更新参数值,逼近全局最优解,算是实践解法。常用的理论解法,记得有单纯形法,基本的步骤(贴一篇自己找到的详解,记录一下常用的步骤)是:
首先,将线性规划化为标准型。什么是标准型?标准型是指,约束条件的所有符号都为等号,目标值函数为
max
,决策变量取值范围非负。但实际情况中,大多时候都是不等号,这就需要引入松弛变量将不等式化为等式。目标函数为
min
也只需要取反即可转为max
,决策变量也可以通过变量代换,将取值可为负的决策变量取为正(实际问题中决策变量为非负的情况很多见)。其次,约束条件的个数为基变量的个数,不停求解基变量。假设存在
m
个约束条件,n
个决策变量(n
大于等于m
),此时可以确定m
个基变量,通过行列式的线性变换,将基变量用非基变量表示(目标函数),当基变量为0
时,可以得到一个定点值。非基变量可以计算出一个
,将
最大的选为入基变量,逐一计算替换后原有基的
最大的变量(比较拗口),作为入基。直到非基变量的
都小于等于0。那么,单纯形法是怎么计算的呢?很简单,将上述的值计算出来放在表里即可,例如
一行,选中变量之后,
再有一行。6. ACM模式刷题
之前一直用的是
leetcode
,只要写核心代码即可,但是当做春招的笔试时,发现是ACM
模式。还好我之前本科有上过ACM
的选修课,虽然算法没学到多少(那个时候只会C
),但是输入输出知道是怎么回事。记录下自己用
Java
写算法题的模板:public class Solution{
public static void main(String[] args){
Scanner sn = new Scanner(System.in);
int n = sn.nextInt();
sn.nextLine();
int[] nums = new int[n];
for(int i=0;i<n;i++){
nums[i] = sn.nextInt();
}
sn.close();
/**
核心代码部分
*/
}
}
大概需要注意的点在于需要在读取完一行数据之后,输入
sn.nextLine()
来完成换行,另外,保持close()
是一个好习惯。另外,记录下快排跟归并,有时候需要自己写多个数组的排序,有时候需要自己写类根据某个属性的排序,当然,也是为了面试。
// 快速排序,排两个数组
private void quickSorted(int[] numsX, int[] numsY, int low, int high){
System.out.println("I'm executing!");
if(low>=high) return;
int baseX = numsX[low], baseY = numsY[low];
int i=low, j=high;
while(i<j){
while(numsX[j]>=baseX && i<j){
j--;
}
while(numsX[i]<=baseX && i<j){
i++;
}
if(i<j){
int tempValueX = numsX[i], tempValueY = numsY[i];
numsX[i] = numsX[j];
numsX[j] = tempValueX;
numsY[i] = numsX[j];
numsY[j] = tempValueY;
}
}
numsX[low] = numsX[i];
numsX[i] = baseX;
numsY[low] = numsY[i];
numsY[i] = baseY;
quickSorted(numsX, numsY, low, i-1);
quickSorted(numsX, numsY, i+1, high);
}
这是从网上摘抄的一位大佬写的代码,很漂亮,我自己的话更加习惯下面那种分为两个函数的写法:
// 归并排序,比快排稳定,平均复杂度一致
public static int[] mergeSort(int[] nums, int l, int h) {
if (l == h)
return new int[] { nums[l] };
int mid = l + (h - l) / 2;
int[] leftArr = mergeSort(nums, l, mid); //左有序数组
int[] rightArr = mergeSort(nums, mid + 1, h); //右有序数组
int[] newNum = new int[leftArr.length + rightArr.length]; //新有序数组
int m = 0, i = 0, j = 0;
while (i < leftArr.length && j < rightArr.length) {
newNum[m++] = leftArr[i] < rightArr[j] ? leftArr[i++] : rightArr[j++];
}
while (i < leftArr.length)
newNum[m++] = leftArr[i++];
while (j < rightArr.length)
newNum[m++] = rightArr[j++];
return newNum;
}
private int[] merge(int[] left, int[] right){
// 结果数组
int i=0;
int[] result = new int[left.length + right.length];
// 循环获取两个数组之间最小的数值
while(left.length>0 && right.length>0){
if(left[0] <= right[0]){
result[i++] = left[0];
left = Arrays.copyOfRange(left, 1, left.length);
}else{
result[i++] = right[0];
right = Arrays.copyOfRange(right, 1, right.length);
}
}
// 填充剩下的所有数据
while(left.length>0){
result[i++] = left[0];
left = Arrays.copyOfRange(left, 1, left.length);
}
while(right.length>0){
result[i++] = right[0];
right = Arrays.copyOfRange(right, 1, right.length);
}
// 返回结果
return result;
}
后续
在这里记录一些杂乱的知识点确实很不错,但是目前来说太长了,可以考虑转到一个新的界面,按照类别去记录(也可以加快一点加载速度)。