文章目录

  • 一、剑指offer:50道金典面试题
    • 面试题1:赋值运算符函数
    • 面试题2:实现单例模式
    • 面试题3:二维数组中的查找
    • 面试题4:替换空格
    • 面试题5:反向打印链表
    • 面试题6:重建二叉树
    • 面试题7:用两个栈实现队列(附带用两个队列实现栈)
    • 面试题8:旋转数组的最小数字
    • 面试题9:斐波那契数列
    • 面试题10:二进制中 1 的个数
    • 面试题11:数值的整数次方
    • 面试题12:打印 1 到最大的 n 位数
    • 面试题13:在O(1)时间删除链表结点
    • 面试题14:调整数组顺序使数组中奇数位于偶数前
    • 面试题15:链表中倒数第K个结点
    • 面试题16:反转链表
    • 面试题17:合并两个排序的链表
    • 面试题18:树的子结构
    • 面试题19:二叉树的镜像
    • 面试题20:顺时针打印矩阵
    • 面试题21:包含 min 函数的栈
    • 面试题22:栈的压人、弹出序列
    • 面试题23:从上往下打印二叉树
    • 面试题24:二叉搜索树的后序遍历序列
    • 面试题25:二叉树中和为某一值的路径
    • 面试题26:复杂链表的复制
    • 面试题27:二叉搜索树和双向链表
    • 面试题28:字符串的排序
    • 面试题29:数组中出现次数超过一半的数字
    • 面试题30:最小的 k 个数
    • 面试题31:连续子数组的最大和(动态规划思想)
    • 面试题32:从1到n整数中1出现的次数
    • 面试题33:把数组排成最小的数
    • 面试题34:丑数
    • 面试题35:第一个只出现一次的字符
    • 面试题36:数组中的逆序对
    • 面试题37:两个链表的第一个公共节点
    • 面试题38:数字在排序数组中出现的次数
    • 面试题39:二叉树的深度
    • 面试题40:数组中只出现一次的数字
    • 面试题41:和为s的两个数字与和为s的连续正数序列
    • 面试题42:翻转单词顺序与左旋转字符串
    • 面试题43:n个骰子的点数(动态规划)
    • 面试题44:扑克牌的顺子
    • 面试题45:圆圈中最后剩下的数字(约瑟夫环问题)
    • 面试题46:求1+2+...+n
    • 面试题47:不用加减乘除做加法(位运算)
    • 面试题48:设计一个不能被继承的类(final修饰 )
    • 面试题49:字符串转整数
    • 面试题50:二叉树两个结点的最低公共祖先
  • 二、LeetCode上经典题目
  • 三、其他面试题(理论知识)
    • 1.说说常见的集合有哪些。
    • 2. HashMap 与 HashTable 的区别。
    • 3. HashMap 是怎么解决哈希冲突的
    • 4. HashMap 中为什么数组长度要保证 2 的幂次方。
    • 5.什么是 Java 集合的快速失败机制“fail-fast”, 以及安全失败“fail-safe”。
    • 6. ArrayList 和 LinkedList 的区别。
    • 7. HashSet 是如何保证数据不可重复的。
    • 8. BlockingQueue 是什么。
    • 9. JDK8 中 HashMap 为什么选用红黑树而不是 AVL 树
    • 10. JDK8 中 HashMap 链表转红黑树的阈值为什么选 8?
    • 11. 说下几种常见的排序算法及其复杂度
    • 12. Hashmap 什么时候进行扩容呢?
    • 13. HashSet 和 TreeSet 有什么区别?
    • 14. LinkedHashMap 的实现原理?
    • 15. 什么是迭代器 (Iterator)?
    • 16. Iterator 和 ListIterator 的区别是什么?
    • 17. Collection 和 Collections 的区别。

前    言

本文将收录《剑指offer:50道金典面试题》、LeetCode上部分经典题目以及其他【据结构和算法】数面试题。

PS:目录中有粉红色标注的题目是已经附带答案


正    文

一、剑指offer:50道金典面试题

面试题1:赋值运算符函数

class CMyString
{public:CMyString(char* pData = NULL);CMyString(const CMyString& str);~CMyString(void);private:char* m_pData;
}

\qquad

解题思路

java只能重载“+”和“+=”两个运算符,别的都不可以。


面试题2:实现单例模式


\qquad

解法一:饿汉式(线程安全,效率高,不能延时加载,典型的以空间换时间)
public class Singleton {private static Singleton instance = new Singleton();// 私有化构造方法private Singleton() {}public static Singleton getInstance() {return instance;}}

饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要判断了,节省了运行时间。

\qquad

解法二:懒汉式(线程不安全,能延时加载,以时间换空间)
public class Singleton {//2.本类内部创建对象实例private static Singleton instance = null;/*** 1.构造方法私有化,外部不能new*/private Singleton() {}//3.提供一个公有的静态方法,返回实例对象public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

调用顺序时序图:

单例模式的懒汉式体现了缓存的思想,延时加载就是一开始不要加载资源或者数据,一直 等,等到马上就要使用这个资源的或者数据了,躲不过去了才去加载。

懒汉式是定性的时间换空间,不加同步的懒汉式是线程不安全的,如下示例:

那么如何解决这个问题呢?
就是接下来我们要讲的解法三——使用双重检查加锁机制实现单例模式

\qquad

解法三:Double CheckLock实现单例(线程安全,能延时加载,以时间换空间)——面试官期待的解法之一
public class Singleton {private volatile static Singleton instance = null;// 私有化构造方法private Singleton() {}public static Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}}

\qquad

解法四:静态内部类实现(线程安全,效率高,可延时加载)——面试官期待的解法之一
public class Singleton {private static class SingletonHoler {/*** 静态初始化器,由JVM来保证线程安全*/private static Singleton instance = new Singleton();}private Singleton() {}public static Singleton getInstance() {return SingletonHoler.instance;}}

\qquad

解法五:枚举类(线程安全,效率高,不能延时加载,可以天然的防止反射和反序列化调用)
public enum Singleton {uniqueInstance;// 定义一个枚举的元素,它 就代表了Singleton的一个实例public void singletonOperation() {// 功能处理System.err.println("功能处理");}}

\qquad

扩展阅读

java 单例模式的几种实现方式(包含防止单例模式被破坏的解决方案)


面试题3:二维数组中的查找

解题思路

别从左到右一个一个比,先比右上角的或左下角的,如果要找的数比这个数小,剔除这一列,比较前一列的第一个数。如果大,剔除这一行,再比较该列下一个数。

注意:如果先比左上角或右下角的是不行的。

代码实现
import java.util.Scanner;public class Find{public static void main(String[] args){int[][] array = input();if(array != null){System.out.println("请输入要找的数:");Scanner sc = new Scanner(System.in);int target = sc.nextInt();   if(find(array,target) == true){System.out.println("找到了!");}else{System.out.println("没找到!");}}}static int[][] input(){Scanner sc = new Scanner(System.in);System.out.println("请输入二维数组行数:");int rowNumber = sc.nextInt();System.out.println("请输入二维数组列数:");int colNumber = sc.nextInt();int[][] array = new int[rowNumber][colNumber];if(rowNumber != 0 && colNumber != 0){for(int i=0;i<rowNumber;i++){System.out.println("请输入第"+(i+1)+"行的"+(colNumber)+"个数。");for(int j=0;j<colNumber;j++){array[i][j] = sc.nextInt();}}return array;}else {System.out.println("输入有误!数组为空!");return null;}}static boolean find(int[][] array,int target){int row = 0;int col = array[0].length-1;while(row<array.length && col>=0){if(array[row][col] == target){return true;}else if(array[row][col] > target){col--;}else{row++;}}return false;}
}

面试题4:替换空格


面试题5:反向打印链表


面试题6:重建二叉树


面试题7:用两个栈实现队列(附带用两个队列实现栈)


\qquad

解题思路

添加元素即压入一个栈s1,删除元素的话,把s1中的元素按顺序先弹出再压入栈s2中,这是弹出栈s2的元素就能实现先进先出了。

\qquad

代码实现
public class CQueue {private Stack<Integer> stack1 = new Stack<>();private Stack<Integer> stack2 = new Stack<>();public void appendTail(int elem){//添加元素就直接向stack1添加stack1.push(elem);System.out.println("stack1:" + stack1.toString());}public void deleteHead(){//删除分三种情况:1,stack2不空,直接从它里头弹出。2,stack2空,stack1不空,把1中先弹再压到2,再从2弹出。3,两都空。if(!stack2.isEmpty()){stack2.pop();}else if(!stack1.isEmpty()){while(!stack1.isEmpty()){stack2.push(stack1.pop());}stack2.pop();}else{System.out.println("两个栈都空了");}System.out.println("stack1:" + stack1.toString());System.out.println("stack2:" + stack2.toString());}public static void main(String[] args) {CQueue test = new CQueue();test.appendTail(1);test.appendTail(2);test.appendTail(3);test.deleteHead();test.deleteHead();test.appendTail(4);test.deleteHead();}
}

\qquad

相关题:用两个队列实现栈

\qquad

解题思路

添加元素即向一个队列q1添加元素,删除元素的话,把q1的元素按顺序出队然后入队到q2,最后q1剩下一个元素,就是要出栈的元素,再添加元素的话,向非空的队列添加。

\qquad

代码实现
import java.util.Queue;
import java.util.LinkedList;//以下是相关题,两个队列实现栈。
public class CStack {//是LinkedList类实现了Queue接口private static Queue<Integer> queue1 = new LinkedList<>();private static Queue<Integer> queue2 = new LinkedList<>();private void appendTail(int elem){//Queue使用时要尽量避免Collection的add()和remove()方法,而是要使用offer()来加入元素,使用poll()来获取并移出元素。//它们的优点是通过返回值可以判断成功与否,add()和remove()方法在失败的时候会抛出异常。 //如果要使用前端而不移出该元素,使用element()或者peek()方法。//这里是向非空的队列里添加值。都为空的话向队列1添加。if(!queue2.isEmpty()){queue2.offer(elem);}else{queue1.offer(elem);}System.out.println("queue1:" + queue1.toString());System.out.println("queue2:" + queue2.toString());}private void deleteHead(){//一个表示空队列,一个表示非空队列Queue<Integer> emptyQueue = queue1;Queue<Integer> notEmptyQueue = queue2;if(!emptyQueue.isEmpty()){emptyQueue = queue2;notEmptyQueue = queue1;}//除了非空队列的最后一个元素,别的都按顺序移到空队列while(notEmptyQueue.size()!=1){emptyQueue.offer(notEmptyQueue.poll());}//删除刚才留下的最后一个元素notEmptyQueue.poll();System.out.println("queue1:" + queue1.toString());System.out.println("queue2:" + queue2.toString());}public static void main(String[] args) {CStack test = new CStack();test.appendTail(1);test.appendTail(2);test.appendTail(3);test.deleteHead();test.appendTail(4);test.deleteHead();}
}

面试题8:旋转数组的最小数字


\qquad

面试题9:斐波那契数列


\qquad

被面试官鄙视的解法
public class Fibonacci {/*** 递归实现*/public static long fib_rec(int n){int[] arr = {0,1};if(n <= 2){return arr[n-1];}return fib_rec(n-1)+fib_rec(n-2);}
}

\qquad

面试官期待的解法
public class Fibonacci {/*** 数组+for循环实现(其实就是 动态规划 思想)*/public static long fib_for(int n){int[] arr = {0,1};if(n < 2){return arr[n];}long first,sencond,res;first=0;sencond=1;res=0;for (int i=2;i<n;i++){res = first + sencond;first = sencond;sencond = res;}return res;}
}

\qquad

这个题目可以使用动态规划来求解,可以参考我的 动态规划? so easy!!!
这篇文章里的 【题目实战】中的 【爬楼梯】的例子。


面试题10:二进制中 1 的个数


面试题11:数值的整数次方


面试题12:打印 1 到最大的 n 位数


面试题13:在O(1)时间删除链表结点


面试题14:调整数组顺序使数组中奇数位于偶数前


面试题15:链表中倒数第K个结点


面试题16:反转链表


面试题17:合并两个排序的链表



面试题18:树的子结构


面试题19:二叉树的镜像


面试题20:顺时针打印矩阵



面试题21:包含 min 函数的栈


面试题22:栈的压人、弹出序列


面试题23:从上往下打印二叉树


面试题24:二叉搜索树的后序遍历序列


面试题25:二叉树中和为某一值的路径


面试题26:复杂链表的复制


面试题27:二叉搜索树和双向链表


面试题28:字符串的排序


面试题29:数组中出现次数超过一半的数字


面试题30:最小的 k 个数


面试题31:连续子数组的最大和(动态规划思想)


这个题目可以使用动态规划来求解,可以参考我的 动态规划? so easy!!!
这篇文章里的 【题目实战】中的 【最大子序和】的例子。


面试题32:从1到n整数中1出现的次数


面试题33:把数组排成最小的数


面试题34:丑数


面试题35:第一个只出现一次的字符


面试题36:数组中的逆序对


面试题37:两个链表的第一个公共节点


面试题38:数字在排序数组中出现的次数


面试题39:二叉树的深度


面试题40:数组中只出现一次的数字


面试题41:和为s的两个数字与和为s的连续正数序列


面试题42:翻转单词顺序与左旋转字符串



面试题43:n个骰子的点数(动态规划)


面试题44:扑克牌的顺子


面试题45:圆圈中最后剩下的数字(约瑟夫环问题)


面试题46:求1+2+…+n


面试题47:不用加减乘除做加法(位运算)


面试题48:设计一个不能被继承的类(final修饰 )


面试题49:字符串转整数


面试题50:二叉树两个结点的最低公共祖先


二、LeetCode上经典题目

三、其他面试题(理论知识)

1.说说常见的集合有哪些。

Map 接口和Collection 接口是所有集合类框架的父接口:
Collcetion 接口的子接口包括:Set 接口和List 接口。
Map 接口的实现类主要有:HashMap、HashTable、ConcurrentHashMap 以及Properties
等。
Set 接口的实现类主要有:HashSet、TreeSet、LinkedHashSet 等。
List 接口的实现类主要有:ArrayList、LinkedList、Stack 以及 Vector 等。

2. HashMap 与 HashTable 的区别。

主要有以下几点区别。
HashMap 没有考虑同步,是线程不安全的;HashTable 在关键方法(put、get、contains、
size 等)上使用了Synchronized 关键字,是线程安全的。
HashMap 允许Key/Value 都为null,后者Key/Value 都不允许为null。
HashMap 继承自AbstractMap 类;而HashTable 继承自Dictionary 类。
在jdk1.8 中,HashMap 的底层结构是数组+链表+红黑树,而HashTable 的底层结构是
数组+链表。
HashMap 对底层数组采取的懒加载,即当执行第一次put 操作时才会创建数组;而
HashTable 在初始化时就创建了数组。
HashMap 中数组的默认初始容量是 16 ,并且必须是 2 的指数倍数,扩容时
newCapacity=2oldCapacity;而HashTable 中默认的初始容量是11,并且不要求必须是2 的
指数倍数,扩容时newCapacity=2
oldCapacity+1。 在hash 取模计算时,HashTable 的模数一般为素数,简单的做除取模结果会更为均匀,
int index = (hash & 0x7FFFFFFF) % tab.length;
HashMap 的模数为2 的幂,直接用位运算来得到结果,效率要大大高于做除法,i = (n - 1) & hash。

3. HashMap 是怎么解决哈希冲突的

哈希冲突:当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,我们
就把它叫做哈希碰撞。
在Java 中,保存数据有两种比较简单的数据结构:数组和链表。数组的特点是:寻址
容易,插入和删除困难。链表的特点是:寻址困难,但插入和删除容易。所以我们将数组和
链表结合在一起,发挥两者的优势,使用一种叫做链地址法的方式来解决哈希冲突。这样我
们就可以拥有相同哈希值的对象组织成的一个链表放在hash 值对应的bucket 下,但相比
Key.hashCode() 返回的 int 类型,我们 HashMap 初始的容量大小
DEFAULT_INITIAL_CAPACITY = 1 << 4(即2 的四次方为16)要远小于int 类型的范围,所
以我们如果只是单纯的使用hashcode 取余来获取对应位置的bucket,这将会大大增加哈希
碰撞的几率,并且最坏情况下还会将HashMap 变成一个单链表。所以肯定要对hashCode 做
一定优化。
来看HashMap 的hash()函数。上面提到的问题,主要是因为如果使用hashCode 取余,
那么相当于参与运算的只有hashCode 的低位,高位是没有起到任何作用的,所以我们的思
路就是让**hashCode 取值出的高位也参与运算,进一步降低hash 碰撞的概率,使得数据分
布更平均,我们把这样的操作称为扰动,在JDK 1.8 中的hash()函数相比在JDK 1.7 中的4 次
位运算,5 次异或运算(9 次扰动),在1.8 中,只进行了1 次位运算和1 次异或运算(2 次
扰动),更为简洁了。两次扰动已经达到了高低位同时参与运算的目的,提高了对应数组存
储下标位置的随机性和均匀性。
通过上面的链地址法(使用散列表)和扰动函数,数据分布更为均匀,哈希碰撞也减少
了。但是当HashMap 中存在大量的数据时,假如某个bucket 下对应的链表中有n 个元素,
那么遍历时间复杂度就变成了O(n),针对这个问题,JDK 1.8 在HashMap 中新增了红黑树的
数据结构,进一步使得遍历复杂度降低至O(logn)。
简单总结一下HashMap 是如何有效解决哈希碰撞的:
使用链地址法(散列表)来链接拥有相同hash 值的元素;
使用2 次扰动(hash 函数)来降低哈希冲突的概率,使得概率分布更为均匀;
引入红黑树进一步降低遍历的时间复杂度。

4. HashMap 中为什么数组长度要保证 2 的幂次方。

只有当数组长度为 2 的幂次方时,h&(length-1)才等价于 h%length,可以用位运算来
代替做除取模运算,实现了 key 的定位,2 的幂次方也可以减少冲突次数,提高 HashMap 的
查询效率;
当然,HashTable 就没有采用 2 的幂作为数组长度,而是采用素数。素数的话是用简
单做除取模方法来获取下标 index,而不是位运算,效率低了不少,但分布也很均匀。

5.什么是 Java 集合的快速失败机制“fail-fast”, 以及安全失败“fail-safe”。

“fail-fast”是Java 集合的一种错误检测机制,当多个线程对集合进行结构上的改变
的操作时,有可能会产生fail-fast 机制。
例如:假设存在两个线程(线程1、线程2),线程1 通过Iterator 在遍历集合A 中的
元素,在某个时候线程2 修改了集合A 的结构(是结构上面的修改,而不是简单的修改集合
元素的内容),那么这个时候程序就会抛出ConcurrentModificationException 异常,从而
产生fail-fast 机制。
原因:迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount 变
量。集合在被遍历期间如果内容发生变化,就会改变odCount的值。每当迭代器使用
hashNext()/next()遍历下一个元素之前,都会检测modCount 变量是否为expectedmodCount
值,是的话就返回遍历;否则抛出异常ConcurrentModification,终止遍历。
Java.util 包下的集合类都是快速失败机制,不能在多线程下发生并修改(迭代
过程中被修改)。
与“fail-fast”对应的是“fail-safe”。
采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先copy 原
有集合内容,在拷贝的集合上进行遍历。由于迭代时是对原集合的拷贝的值进行遍历,所以在
遍历过程中对原集合所作的修改并不能被迭代器检测到 , 所以不会触发
ConcurrentModificationException 异常。
基于拷贝内容的迭代虽然避免了ConcurrentModificationException 异常,但同样地,
迭代器并不能访问到修改后的内容,简单来说,迭代器遍历的是开始遍历那一刻拿到的集合
拷贝,在遍历期间原集合发生的修改迭代器行为是不知道的。
Java.util.concurrent 包下的容器都是安全失败的,可以在多线程下并发使用,并发修
改。

6. ArrayList 和 LinkedList 的区别。

主要有以下几点区别:
LinkedList 实现了List 和Deque 接口,一般称为双向链表;ArrayList 实现了List 接
口,是动态数组。
LinkedList 在插入和删除数据时效率更高,ArrayList 在查找某个index的数据时效率
更高。
LinkedList 比ArrayList 需要更多内存。

7. HashSet 是如何保证数据不可重复的。

HashSet 的底层其实就是HashMap,只不过HashSet 是实现了Set 接口,并且把数据作
为Key 值,而Value 值一直使用一个相同的虚值来保存。由于ashMap 的K 值本身就不允许
重复,并且在HashMap 中如果K/V 相同时,会用新的V 覆盖掉旧的V,然后返回旧的V,那么
在HashSet 中执行这一句话始终会返回一个false,导致插入失败,这样就保证了数据的不
可重复性。

8. BlockingQueue 是什么。

Java.util.concurrent.BlockingQueue 是一个队列,在进行检索或移除一个元素的时
候,它会等待队列变为非空;当添加一个元素时,它会等待队列中的可用空间。BlockingQueue
接口是Java 集合框架的一部分,主要用于实现生产者-消费者模式。这样我们就不需要担心
等待生产者有可用的空间,以及消费者有可用的对象。因为它们都在BlockingQueue 的实现
类中被处理了。
Java 提供了几种 BlockingQueue 的实现,比如 ArrayBlockingQueue 、
LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue 等。

9. JDK8 中 HashMap 为什么选用红黑树而不是 AVL 树

在平常我们用HashMap的时候,HashMap里面存储的key是具有良好的hash算法的key(比
如String、Integer等包装类),冲突几率自然微乎其微,此时链表几乎不会转化为红黑树,
但是当key为我们自定义的对象时,我们可能采用了不好的hash算法,使HashMap中key的冲
突率极高,但是这时HashMap为了保证高速的查找效率,引入了红黑树来优化查询了。
因为从时间复杂度来说,链表的查询复杂度为o(n);而红黑树的复杂度能达到o(logn);
比如若hash算法写的不好,一个桶中冲突1024个key,使用链表平均需要查询512次,但是红
黑树仅仅10次,红黑树的引入保证了在大量hash冲突的情况下,HashMap还具有良好的查询
性能。
红黑树相比avl树,在检索的时候效率其实差不多,都是通过平衡来二分查找。但对于
插入删除等操作效率提高很多。红黑树不像avl树一样追求绝对的平衡,他允许局部很少的
不完全平衡,这样对于效率影响不大,但省去了很多没有必要的调平衡操作,avl树调平衡
有时候代价较大,所以效率不如红黑树。

10. JDK8 中 HashMap 链表转红黑树的阈值为什么选 8?

HashMap 在jdk1.8 之后引入了红黑树的概念,表示若桶中链表元素超过8 时,会自动
转化成红黑树;若桶中元素小于等于6 时,树结构还原成链表形式。
HashMap源码作者通过泊松分布算出,当桶中结点个数为8时,出现的几率是亿分之6的,
因此常见的情况是桶中个数小于8的情况,此时链表的查询性能和红黑树相差不多,因为红黑
树的平均查找长度是log(n),长度为8 的时候,平均查找长度为3,如果继续使用链表,平
均查找长度为8/2=4,这才有转换为树的必要。链表长度如果是小于等于6,6/2=3,虽然速
度也很快的,但是转化为树结构和生成树的时间并不会太短。
亿分之6这个几乎不可能的概率是建立在良好的hash算法情况下,例如String,Integer
等包装类的hash算法,如果一旦发生桶中元素大于8,说明是不正常情况,可能采用了冲突
较大的hash算法,此时桶中个数出现超过8的概率是非常大的,可能有n个key冲突在同一个
桶中,这个时候就必要引入红黑树了。
另外,上下阈值选择6 和8 的情况下,中间有个差值7 可以防止链表和树之间频繁的转
换。假设一下,如果设计成链表个数超过8 则链表转换成树结构,链表个数小于8 则树结构
转换成链表,如果一个HashMap 不停的插入、删除元素,链表个数在8 左右徘徊,就会频繁
的发生树转链表、链表转树,效率会很低。

11. 说下几种常见的排序算法及其复杂度

a. 快速排序:
i. 原理:快速排序采⽤用的是⼀种分治的思想,它先找⼀个基准数(⼀般选择第⼀个值),
然后将⽐这个基准数⼩的数字都放到它的左边,然后再递归调⽤,分别对左右两边快速排序,
直到每⼀边只有⼀个数字.整个排序就完成了.
1.选定⼀个合适的值(理想情况中值最好,但实现中⼀般使⽤用数组第⼀个值),称为
“枢轴”(pivot)。
2.基于这个值,将数组分为两部分,较⼩的分在左边,较⼤的分在右边。
3.可以肯定,如此⼀轮下来,这个枢轴的位置⼀定在最终位置上。
4.对两个⼦数组分别重复上述过程,直到每个数组只有⼀个元素。
5.排序完成。
ii. 复杂度:O(n)
b. 冒泡排序:
i. 原理:冒泡排序其实就是逐⼀⽐较交换,进⾏⾥外两次循环,外层循环为遍历所有数
字,逐个确定每个位置,⾥层循环为确定了了位置后,遍历所有后面没有确定位置的数字,与
该位置的数字进⾏⽐较,只要⽐该位置的数字⼩,就和该位置的
数字进⾏交换.
ii. 复杂度:O(n^2),最佳时间复杂度为O(n)
c. 直接插⼊入排序:
i. 原理:直接插⼊入排序是将从第⼆个数字开始,逐个拿出来,插⼊到之前排好序的数
列列⾥.
ii. 复杂度:O(n^2),最佳时间复杂度为O(n)
d. 直接选择排序:
i. 原理:直接选择排序是从第⼀个位置开始遍历位置,找到剩余未排序的数据⾥里里最 ⼩的,找到最⼩的后,再做交换。
ii. 复杂度:O(n^2)

12. Hashmap 什么时候进行扩容呢?

当 hashmap 中的元素个数超过数组大小 loadFactor 时,就会进行数组扩容,
loadFactor 的默认值为 0.75,也就是说,默认情况下,数组大小为 16,那么当 hashmap 中
元素个数超过 160.75=12 的时候,就把数组的大小扩展为 216=32,即扩大一倍,然后重新
计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知
hashmap 中元素的个数,那么预设元素的个数能够有效的提高 hashmap 的性能。
比如说,我们有 1000 个元素 new HashMap(1000), 但是理论上来讲 new HashMap(1024)
更合适,不过上面已经说过,即使是 1000,hashmap 也自动会将其设置为 1024。 但是 new
HashMap(1024) 还不是更合适的,因为 0.75*1000 < 1000, 也就是说为了让 0.75 * size >
1000, 我们必须这样 new HashMap(2048) 才最合适,既考虑了 & 的问题,也避免了 resize
的问题。

13. HashSet 和 TreeSet 有什么区别?

HashSet 是由一个 hash 表来实现的,因此,它的元素是无序的。
TreeSet 是由一个树形的结构来实现的,它里面的元素是有序的。

14. LinkedHashMap 的实现原理?

LinkedHashMap 也是基于 HashMap 实现的,不同的是它定义了一个 Entry header,这
个 header 不是放在 Table 里,它是额外独立出来的。
LinkedHashMap 通过继承 hashMap 中 的 Entry, 并添加两个属性 Entry
before,after, 和 header 结合起来组成一个双向链表,来实现按插入顺序或访问顺序排
序。LinkedHashMap 定义了排序模式 accessOrder,该属性为 boolean 型变量,对于访问
顺序,为 true;对于插入顺序,则为 false。一般情况下,不必指定排序模式,其迭代顺
序即为默认为插入顺序。

15. 什么是迭代器 (Iterator)?

Iterator 接口提供了很多对集合元素进行迭代的方法。每一个集合类都包含了可以返
回迭代 器实例的迭代方法。迭代器可以在迭代的过程中删除底层集合的元素, 但是不可以
直接调用集合的 remove(Object Obj) 删除,可以通过迭代器的 remove() 方法删除。

16. Iterator 和 ListIterator 的区别是什么?

下面列出了他们的区别:
Iterator 可用来遍历 Set 和 List 集合,但是 ListIterator 只能用来遍历 List。
Iterator 对集合只能是前向遍历,ListIterator 既可以前向也可以后向。
ListIterator 实现了 Iterator 接口,并包含其他的功能,比如:增加元素,替换元
素,获取前一个和后一个元素的索引,等等。

17. Collection 和 Collections 的区别。

collection 是集合类的上级接口, 继承与它的接口主要是 set 和 list。
collections 类是针对集合类的一个帮助类. 它提供一系列的静态方法对各种集合的
搜索, 排序, 线程安全化等操作。

\qquad

总    结

本文主要汇总了《剑指offer》50道金典面试题,及部分LeetCode上经典题目。

PS 答案还在整理中,敬请期待~~

【数据结构与算法_java】面试题及答案汇总相关推荐

  1. 关于数据结构和算法的面试题

    关于数据结构和算法的面试题 查看全文 http://www.taodudu.cc/news/show-6227980.html 相关文章: 数据结构与算法精选面试50题(附答案) 面试中常见的数据结构 ...

  2. mooc数据结构与算法python版第十一周作业_中国大学 MOOC_数据结构与算法Python版_2020最新答案学习指南...

    中国大学 MOOC_数据结构与算法Python版_2020最新答案学习指南 更多相关问题 [判断题]实际集成运放的上限截止频率为无穷大 [多选题]现代城市的发展凸现出与以往不同的动力机制包括 教师在引 ...

  3. python可以在多种平台运行、体现了_2020年智慧树数据结构与算法第二单元章节测试答案...

    2020年智慧树数据结构与算法第二单元章节测试答案 更多相关问题 为了寻找和选择通讯的报道对象,当你获知省教育招生考试院发布了<关于调整普通高等教育专科升本科考试录取办法的通知>后,应该熟 ...

  4. MySQL常见面试题及答案汇总1000道(春招+秋招+社招)

    MySQL面试题以及答案整理[最新版]MySQL高级面试题大全(2021版),发现网上很多MySQL面试题都没有答案,所以花了很长时间搜集,本套MySQL面试题大全,汇总了大量经典的MySQL程序员面 ...

  5. 最新Java面试题2021年,常见面试题及答案汇总

    2021最新Java面试题[附答案解析]java面试题及答案2021,java2021最新面试题及答案汇总,2021最Java面试题新答案已经全部更新完了,有些答案是自己总结的,也有些答案是在网上搜集 ...

  6. 大数据面试题及答案 汇总版

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/albg_boy/article/det ...

  7. Java多线程常见面试题及答案汇总1000道(春招+秋招+社招)

    Java多线程面试题以及答案整理[最新版]Java多线程高级面试题大全(2021版),发现网上很多Java多线程面试题都没有答案,所以花了很长时间搜集,本套Java多线程面试题大全,汇总了大量经典的J ...

  8. Jvm常见面试题及答案汇总1000道(春招+秋招+社招)

    Jvm面试题以及答案整理[最新版]Jvm高级面试题大全(2021版),发现网上很多Jvm面试题都没有答案,所以花了很长时间搜集,本套Jvm面试题大全,汇总了大量经典的Jvm程序员面试题以及答案,包含J ...

  9. 2019前端面试题及答案汇总

    2019前端面试题及答案汇总 DOM事件流包含几个阶段 事件委托(代理)的原理是什么?它有什么优势和缺点? 使用原生JS为以下li实现事件委托,点击后打印对应的node-type属性值. 使用jQue ...

  10. 21年最新Python面试题及答案汇总详解(上)

    错过三月找工作的机会,还要错过四月的好时期吗?Python面试你做准备了吗?下面小编整理了一套2021年最新Python常见面试题目,及Python面试题目答案汇总.希望能够帮助到大家. 21年最新P ...

最新文章

  1. 2019需要关注的几大AI趋势
  2. 从UV位置图获得3D人脸
  3. Rust 1.31正式发布,首次引入Rust 2018新功能
  4. c++ 显示三维散点图_【无机纳米材料科研制图——OriginLab 0210】Origin多组柱状图3D柱状图及3D散点图...
  5. Timer的schedule和scheduleAtFixedRate方法的区别解析(转)
  6. 21天jenkins打卡前置准备:linux环境
  7. flask 导出excel
  8. ARP协议格式和实例分析
  9. 阿里云盾(云安全)是什么?有什么作用?
  10. ++a与a++、--a与a--
  11. 建模师的前景怎么样?
  12. 挂载文件系统和查找文件
  13. Venom 内网穿透
  14. 电阻电容相同容量不同封装的区别
  15. STM32理论 —— 看门狗
  16. 【数据分析】:什么是数据分析?
  17. 微软出品·kubernetes学习路线
  18. KingbaseES共享集群中crm_mon命令失效原因分析
  19. masked_softmax掩蔽softmax操作实现
  20. 动态修改ListView文字大小

热门文章

  1. FireBlogging-我家的景色
  2. 汉字和数字站几个字节,估算内存占用情况
  3. FCM算法分割图像代码
  4. 【哈利波特】Sherbert Lemon对HP的解读之二
  5. IOS 大众点评 搜索界面实现
  6. SuperMap iDesktop场景崩溃合集(持续更新)
  7. pyinstaller打包exe程序闪退问题修复
  8. FOJ--1490--五子棋--解题报告
  9. VMware 8.0.2的license
  10. 【毕业设计】基于SSM的网络在线考试系统的设计与实现