今天面了一家武汉的公司,具体名字不说了,因为我是面实习生,心里就想着实习生问点简单地就好,然后就准备了关于安卓的一些基础知识.当时还专门去总结了下网上常见的面试题,面试前模拟题,就觉得差不多了,结果…一个都没问到…,一上来就是数据结构和算法…,所以这次面试我表现很差,我自己都看不下去,问题是我当时刷题就是做出来就可以,没想过非要最优解,结果面试官只问最优解的方法.所以总结一下,免得以后再在面试官面前丢脸.(答不出来支支吾吾是真得很丢脸,那种感觉好差)
1.自我介绍
2.要求从一个数组中找两个数和为100,但是要求复杂度必须是O(n)
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap<>();
for(int i=0;i<nums.length;i++){
map.put(nums[i],i);
}
for (int i=0;i<nums.length;i++){
int num = target - nums[i];
if (map.containsKey(num)&&map.get(num)!=i){
return new int[]{i,map.get(num)};
}
}
return new int[]{};
}
}
3.如何判断一个链表中有没有环
一个每次走一步,一个每次走两步,如果有环,走两步的肯定会追上走一步的
public static boolean hasCircle(ListNode head) {
if(null == head) {
return false;
}
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null){
fast = fast.next.next;
slow = slow.next;
if(fast == slow){
return true;//两个指针相遇
}
}
return false;
}
4.哈希表的算法是怎么实现的?
一般散列算法会根据输入值计算出输出应该存储的位置,这个位置如果和已经存储键值冲突则需进行重新映射.
当发生冲突时散列函数为:Di=(H(k)+di) mod m
m为存储空间
di取指:
a)1,2,3,…m-1,称线性探测再散列。
b)1,-1,2,-2,4,-4,9,-9,16,-16,…kk,-kk(k<=m/2)称二次探测再散列。
c)链地址法:把据哟相同散列地址的元素用一个线性链表链接在一起,每个线性链表称之为一个“桶”,为了处理方便每个链表前设置一个头结点,所有头结点存放于散列地址在[0,m-1]的散列表中。如下图所示:
5.HashMap多线程安全吗?为什么?Synchronized和Lock的区别?
- 线程不是安全的,因为假设有线程A和线程B同时对HashMap进行PUT操作,假设A和B插入的Key-Value中key的hashcode是相同的,这说明该键值对将会插入到Table的同一个下标的,也就是会发生哈希碰撞,此时HashMap按照平时的做法是形成一个链表(若超过八个节点则是红黑树),现在我们插入的下标为null(Table[i]==null)则进行正常的插入,此时线程A进行到了这一步正准备插入,这时候线程A堵塞,线程B获得运行时间,进行同样操作,也是Table[i]==null , 此时它直接运行完整个PUT方法,成功将元素插入. 随后线程A获得运行时间接上上面的判断继续运行,进行了Table[i]==null的插入(此时其实应该是Table[i]!=null的操作,因为前面线程B已经插入了一个元素了),这样就会直接把原来线程B插入的数据直接覆盖了,如此一来就造成了线程不安全问题.
- Synchronized持有锁资源,会自动释放锁;
- Lock要手工释放,而且必须在finally从句中释放,tryLock()方式可以非堵塞方式是拿锁;
- 当竞争激烈时,Synchronized会升级为重量级锁,出对速度比Lock要慢,所以Lock效率更高.
6.判断是否是回文,但是要求不用字符串解决
左边一半,右边一半相反,如果相同,就是回文
class Solution {
public boolean isPalindrome(int x) {
if(x < 0 || (x % 10 == 0 && x != 0))
return false;
int revertedNumber = 0;
while(x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
System.out.print(revertedNumber+" ");
}
//偶位数/奇位数
return x == revertedNumber || x == revertedNumber/10;
}
}
7.判断一个数据在一个数据中是否占据了一半,要求复杂度O(n)
class Solution {
public int majorityElement(int[] nums) {
Map<Integer,Integer> map = countNums(nums);
Map.Entry<Integer,Integer> majorentry = null;
for(Map.Entry<Integer,Integer> entry : map.entrySet()){
if(majorentry == null || entry.getValue() > majorentry.getValue()){
majorentry = entry;
}
}
return majorentry.getKey();
}
private Map<Integer,Integer> countNums(int[] nums){
Map<Integer,Integer> map = new HashMap();
for(int num : nums){
if(!map.containsKey(num)){
map.put(num,1);
}else{
map.put(num,map.get(num)+1);
}
}
return map;
}
}
8.现场手写一个排序算法,要求这个排序算法,是logn的复杂度
public class QuickSort {
public static int[] quicksort(int[] arr,int start,int end) {
int remark = arr[start];
int temp;
int left = start;
int right = end;
while (left<right) {
while (arr[left] < remark && left < right)
left++;
while (arr[right] > remark && left < right)
right--;
if (left<=right){
temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
if (right>start)
quicksort(arr,start,right);
if (left<end)
quicksort(arr,left,end);
return arr;
}
}
9.单例模式
https://blog.csdn.net/absolute_chen/article/details/93380566
10.有什么要问的
本次体会:
1.刷算法要掌握最优解法,不一定要难题,但一定要把一道简单地算法掌握最优的那种解法.因为考官只关注你的解法是不是最优的,基本解法谁都会,还有就是及时复习算法题,不然有些题我原来做过,但是面试时忘记了.
2.别把自己定义为实习生就不该了解那些难的,因为面试官似乎对难的东西才有问的热情,简单的不待问.
3.这是我第一次面试,可能以后面试会简单一些,但是只有提升自己才有进好公司的机会,继续加油吧.