最近在刷面试题,以下是对链表面试题的总结:
1.从尾部到头部打印链表;
主要有3种办法:
(1)创建一个栈,遍历链表,将链表值压入栈中,遍历结束后,将栈中的值压出,重新构建新链表;时间复杂度o(n),空间复杂度o(n);
(2)遍历链表,在遍历链表时,将链表进行反转;时间复杂度o(n),空间复杂度o(1);
(3)采用递归的方式,进行链表反转;
1 public class Solution { 2 public ListNode ReverseList(ListNode head) { 3 return reverseListFunc(head, null); 4 } 5 6 public ListNode reverseListFunc(ListNode head,ListNode newHead){ 7 if(head == null){ 8 return newHead; 9 } 10 ListNode next = head.next; 11 ListNode cur = reverseListFunc(next,head); 12 head.next = newHead; 13 return cur; 14 } 15 }
3.链表合并
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)
主要有2种方法:
方法一:将list1添加到集合中,查看list2中第一个属于list1集合中的数据,即是公共节点;
方法二:将list1+list2和list2+list1两个同时进行向后移,第一个相等的即是公共节点;
5.链表中环的入口结点
给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。
主要有两种方法:
方法一:使用一个集合,遍历list,将list中的数据添加到集合中,第一次发现集合的已经存在的节点,即是环的入口;
方法二:设立快慢指针,快指针fast,满指针slow,快指针一次走两步,慢指针一次走一步,当快慢指针第一次相遇后,快指针回到头节点,此后快指针回到头节点,两个指针每次都走一步,再次相遇的地方即是环的入口;
6.链表中倒数最后k个结点
7.复杂链表的复制
输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针random指向一个随机节点),请对此链表进行深拷贝,并返回拷贝后的头结点。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)。
主要有两种方法:
方法一:借助map,创建当前节点和映射节点的映射关系;通过两次遍历,确定next和random;
方法二:先在链表的每个节点之后复制出一个新的节点,主要是配置next,第二步是配置新节点的random的节点,最后将链表拆开返回;
/*
public class RandomListNode {
int label;
RandomListNode next = null;
RandomListNode random = null;
RandomListNode(int label) {
this.label = label;
}
}
*/
import java.util.Map;
import java.util.HashMap;
public class Solution {
public RandomListNode Clone(RandomListNode pHead) {
if(pHead == null){
return null;
}
RandomListNode cur = pHead;
// 进行链表的插入
while(cur != null){
RandomListNode node = new RandomListNode(cur.label);
RandomListNode next = cur.next;
cur.next = node;
node.next = next;
cur = next;
}
//配置random
cur = pHead;
while(cur != null){
if(cur.random != null){
cur.next.random = cur.random.next;
}
cur = cur.next.next;
}
//最后进行链表的拆分
cur = pHead;
RandomListNode result = pHead.next;
while(cur != null){
RandomListNode node = cur.next;
RandomListNode next = node.next;
cur.next = next;
if(next != null){
node.next = next.next;
}
cur= next;
}
return result;
}
}
8.删除链表中的重复节点
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
*/
import java.util.Set;
import java.util.HashSet;
public class Solution {
public ListNode deleteDuplication(ListNode pHead) {
if(pHead == null || pHead.next == null){
return pHead;
}
if(pHead.val != pHead.next.val){
pHead.next = deleteDuplication(pHead.next);
return pHead;
}else{
ListNode cur = pHead;
while(cur != null){
if(cur.val == pHead.val){
cur = cur.next;
}else{
break;
}
}
return deleteDuplication(cur);
}
}
}
8.删除链表的节点
给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。