1.解释数组和链表的区别。
答:主要区别在于内存分布结构和元素访问方式。数组在内存中是连续的,访问元素的时间复杂度为O(1);但是插入和删除元素需要整个数组移动,时间复杂度为O(n)。链表在内存中是离散的,插入和删除元素的时间复杂度为O(1);但是访问元素需要从头节点开始遍历,时间复杂度为O(n)。
2.什么是哈希表?它的工作原理是什么?
答:哈希表是一种实现了关联数组的抽象的数据类型,也就是说,它可以通过键映射到值。哈希表的工作原理是使用一个哈希函数将键转换为索引,然后在索引位置存储值。
3.什么是二叉树?
答:二叉树是一种树形结构,其中每个节点最多包含两个子节点(通常被称为左子节点和右子节点)。
示例代码:
class Node {
int key;
Node left, right;
public Node(int item) {
key = item;
left = right = null;
}
}
class BinaryTree {
Node root;
BinaryTree(int key) {
root = new Node(key);
}
BinaryTree() {
root = null;
}
}
4.描述如何实现深度优先搜索和广度优先搜索。
答:在二叉树中,深度优先搜索包括:先序遍历、中序遍历和后序遍历。广度优先搜索即层次遍历。
示例代码:
void printPreorder(Node node) {
if (node == null)
return;
System.out.print(node.key + " ");
printPreorder(node.left);
printPreorder(node.right);
}
void printInorder(Node node) {
if (node == null)
return;
printInorder(node.left);
System.out.print(node.key + " ");
printInorder(node.right);
}
void printPostorder(Node node) {
if (node == null)
return;
printPostorder(node.left);
printPostorder(node.right);
System.out.print(node.key + " ");
}
void printLevelOrder() {
int h = height(root);
int i;
for (i = 1; i <= h; i++)
printGivenLevel(root, i);
}
void printGivenLevel(Node root, int level) {
if (root == null)
return;
if (level == 1)
System.out.print(root.key + " ");
else if (level > 1) {
printGivenLevel(root.left, level - 1);
printGivenLevel(root.right, level - 1);
}
}
5.你能解释一下堆和栈吗?
答:堆和栈都是一种数据存储结构。堆是动态分配的,大小不固定,可以随时变化。而栈是LIFO(后进先出)的数据结构,有固定的大小,不能动态扩展。
6.如何检测链表中的循环?
答:我们可以使用两个指针,一个快指针和一个慢指针。如果在链表中有循环,那么这两个指针最终会相遇。
class Node {
int num;
Node next;
}
boolean hasCycle(Node head) {
if (head==null || head.next==null) return false;
Node slow = head;
Node fast = head.next;
while(slow != fast) {
if(fast==null || fast.next==null) return false;
slow = slow.next;
fast = fast.next.next;
}
return true;
}
7.什么是红黑树?
答:红黑树是一种自平衡的二叉搜索树,每个节点都带有一个颜色属性,为红色或黑色。在树的每次修改后,都会通过颜色更改和旋转来自动调整,以达到平衡。由于涉及到的代码太多,这里暂时不提供Java代码示例。
8.如何实现二叉搜索树?
class Node {
int value;
Node left;
Node right;
Node(int value) {
this.value = value;
left = null;
right = null;
}
}
class BinarySearchTree {
Node root;
void insert(int value) {
root = insertRec(root, value);
}
Node insertRec(Node root, int value) {
if (root == null) {
root = new Node(value);
return root;
}
if (value < root.value)
root.left = insertRec(root.left, value);
else if (value > root.value)
root.right = insertRec(root.right, value);
return root;
}
}
9.解释树、图和链表的区别。
答:树是一种分层的数据结构,具有一个顶部节点(根),每个节点具有零个或多个子节点,并且没有节点具有两个父节点。
图是一种更复杂的数据结构,可以通过边将任何两个节点连接起来,图可以是连通的也可以是非连通的,并且边可以有方向也可以无方向。
链表是最简单的数据结构之一,它是一系列节点的集合,每个节点都有指向下一个节点的指针。
10.如何反转链表?
class Node {
int value;
Node next;
}
Node reverse(Node node) {
Node previous = null;
Node current = node;
Node forward = null;
while (current != null) {
forward = current.next;
current.next = previous;
previous = current;
current = forward;
}
node = previous;
return node;
}
11.如何查找数组中的重复元素?
答案:可以使用HashSet来找到数组中的重复元素。HashSet是一个不包含重复元素的集合。
示例代码:
import java.util.HashSet;
void printDuplicates(int[] arr) {
HashSet<Integer> set = new HashSet<>();
for(int i: arr) {
if(set.contains(i)) {
System.out.println(i);
} else {
set.add(i);
}
}
}
12.如何查找字符串中最长的不重复子字符串?
答案:这是一个经典的滑动窗口问题,我们可以使用HashSet来做一个滑动窗口,从左到右扫描字符串。
示例代码
import java.util.HashSet;
int lengthOfLongestSubstring(String s) {
int n = s.length();
HashSet<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
if (!set.contains(s.charAt(j))) {
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
} else {
set.remove(s.charAt(i++));
}
}
return ans;
}
13.如何有效地对链表进行排序?
答案:合并排序是一种被广泛应用于链表的排序算法,它的平均和最差时间复杂度为线性对数级。
示例代码:
class Node {
int value;
Node next;
Node(int value) {
this.value = value;
}
}
Node sortedMerge(Node a, Node b) {
Node result = null;
if (a == null)
return b;
else if (b == null)
return a;
if (a.value <= b.value) {
result = a;
result.next = sortedMerge(a.next, b);
} else {
result = b;
result.next = sortedMerge(a, b.next);
}
return result;
}
Node mergeSort(Node h) {
if (h == null || h.next == null) {
return h;
}
Node middle = getMiddle(h);
Node nextOfMiddle = middle.next;
middle.next = null;
Node left = mergeSort(h);
Node right = mergeSort(nextOfMiddle);
Node sortedList = sortedMerge(left, right);
return sortedList;
}
Node getMiddle(Node h) {
if (h == null)
return h;
Node fastptr = h.next;
Node slowptr = h;
while (fastptr != null) {
fastptr = fastptr.next;
if(fastptr != null) {
slowptr = slowptr.next;
fastptr = fastptr.next;
}
}
return slowptr;
}