最近在刷面试题,以下是对链表面试题的总结:

1.从尾部到头部打印链表;

输入一个链表的头节点,按链表从尾到头的顺序返回每个节点的值(用数组返回)。
 
主要有三种方法:
 (1)创建一个数组,遍历链表时,将链表值存入数组当中,遍历结束后,从尾部到头部遍历;时间复杂度o(n),空间复杂度o(n);
 (2)创建一个栈,遍历链表,将链表值压入栈中,遍历结束后,将栈中值压出;时间复杂度o(n),空间复杂度o(n);
 (3)采用递归的方式,将最先的数据最后打印;时间复杂度o(n),空间复杂度o(1);
    注:方式(3)在链表比较长时,会出现方法次数执行太多,无法执行成功的情况;
 
 
2.链表反转;
给定一个单链表的头结点pHead,长度为n,反转该链表后,返回新链表的表头。

主要有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.链表合并

输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。
 主要有3种方法:
  方法一:直接采用合并的方法,将找出头部指针,之后比较哪个数据小,小的接后面;
       方法二:借助数据,将数据按照从小到达的顺序写入到数组中,并拼接成新的链表;
       方法三:采用递归的方式;
 
4.计算两个链表的第一个公共结点

 输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。(注意因为传入数据是链表,所以错误测试数据的提示是用其他方式显示的,保证传入数据是正确的)

主要有2种方法:

      方法一:将list1添加到集合中,查看list2中第一个属于list1集合中的数据,即是公共节点;

      方法二:将list1+list2和list2+list1两个同时进行向后移,第一个相等的即是公共节点;

 

5.链表中环的入口结点

给一个长度为n链表,若其中包含环,请找出该链表的环的入口结点,否则,返回null。

主要有两种方法:

  方法一:使用一个集合,遍历list,将list中的数据添加到集合中,第一次发现集合的已经存在的节点,即是环的入口;

  方法二:设立快慢指针,快指针fast,满指针slow,快指针一次走两步,慢指针一次走一步,当快慢指针第一次相遇后,快指针回到头节点,此后快指针回到头节点,两个指针每次都走一步,再次相遇的地方即是环的入口;

 

6.链表中倒数最后k个结点

输入一个长度为 n 的链表,设链表中的元素的值为 ai ,返回该链表中倒数第k个节点。
如果该链表长度小于k,请返回一个长度为 0 的链表。
 
主要有以下几种方法:
  方法一:两次遍历链表,第一次获取链表的长度,第二次遍历到n-k个数据,即是倒数第k个节点;
       方法二:创建栈,将数据依次放入栈中,然后将所有数组出栈,第k个即是倒数第k个节点;
  方法三:创建快慢指针,快指针先移动k步,然后快指针和慢指针依次往后走,快指针走到最后,此时满指针所指的为止即是倒数第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.删除链表中的重复节点

在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表 1->2->3->3->4->4->5  处理后为 1->2->5;
有以下几种处理方法:
  方法一:记录前一个值和当前值,查看是否有重复,有重复则进行while循环,直到找到不重复的为止,此时再进行拼接;
   方法二:采用递归的方法;
/*
 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.删除链表的节点

给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。返回删除后的链表的头节点。

1.此题对比原题有改动
2.题目保证链表中节点的值互不相同
3.该题只会输出返回的链表和结果做对比,所以若使用 C 或 C++ 语言,你不需要 free 或 delete 被删除的节点
有以下几种方法:
  方法一:直接遍历即可;