力扣初级算法链表(一)
一.反转链表
使用递归方法对不含头结点的单链表进行反转。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null){
            return head;  //如果单链表为空或只有一个元素,不用反转。
        }
        else{
            return reverse(head,head.next,head);
        }
    }
    public ListNode reverse(ListNode l1,ListNode l2,ListNode head){   //表示在以head为首结点的链表中,反转l1和l2这两个相邻的结点
        if(l1 == head){
            l1.next = null;    //反转前首结点反转后的成为最后一个结点
        }
        if(l2.next == null){
            l2.next = l1;   //遍历至链表的最后,返回反转后的首结点
            return l2;
        }else{
            ListNode p = l2.next;     
            l2.next = l1;
            return reverse(l2,p,head);   //递归
        }
    }
}

二.合并两个不含头结点的有序链表(这里的head指首结点)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        if((list1 == null)||(list2 == null)){
            return (list1 == null)?list2:list1;  //有一个链表为null,不用合并,直接返回另一个链表。
        }else{
            ListNode head = (list1.val>list2.val)?list2:list1;   //先求出要返回的首结点
            ListNode l = new ListNode();
            while((list1!=null)&&(list2!=null)){  //当有一个链表插入完了,另一个链表剩余的部分自动摆在合并后链表的末尾
                if(list2.val>=list1.val){  //根据两个链表中的数的大小,进行插入操作。
                    l.next = list1;
                    l = list1;
                    list1 = list1.next;
                    l.next = list2;
                }else{
                    l.next = list2;
                    l = list2;
                    list2 = list2.next;
                    l.next = list1;
                }
            }
            return head;
        }
    }
}

三.判断回文链表
当一个链表从前到后和从后到前的顺序一致时,该链表为回文链表。
如链表 1 1 2 1不是回文链表,而1 2 2 1是回文链表。
要求编写一个简单算法判断一个单链表是否为回文链表,要求时间复杂度为O(n),空间复杂度为O(1).
解题思路:
1.对要判断的链表的后一半元素进行(一)中的反转操作。
2.两指针分别从链表两头开始,向中间移动,比较两个指针的数据是否相同,如果两个指针移动到正中间仍然相同,则该链表为回文链表,否则不是回文链表。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public boolean isPalindrome(ListNode head) {
        boolean result = true;  //判断是否为回文链表
        ListNode middle = head;  //用于记录链表正中间的结点。
        ListNode sequence = head;  //用于记录链表首结点
        int nodeCount = 0;       //计算链表中元素数量
        while(head!=null){
            nodeCount++;
            head = head.next;   //获取了结点的个数
        }
        for(int i=0;i<nodeCount/2;i++){
            middle = middle.next;   //找到正中间的结点
        }
        ListNode reverse = reverseList(middle);  //反转后一半链表
        for(int i = 0;i<nodeCount/2;i++){
            if(reverse.val == sequence.val){
                reverse = reverse.next;
                sequence = sequence.next;
            }else{
                result = false;   //如果有一组不一样,就不是回文。
                break;
            }
        }
        return result;
    }
    
    /*
    	以下代码和(一)中利用递归操作反转链表代码相同
    */
    public ListNode reverseList(ListNode head){
        if((head == null)||(head.next == null)){
            return head;
        }else{
            return reverse(head,head.next,head);
        }
    }

    public ListNode reverse(ListNode l1,ListNode l2,ListNode head){
        if(l1 == head){
            l1.next = null;
        }
        if(l2.next == null){
            l2.next = l1;
            return l2;
        }else{
            ListNode p = l2.next;
            l2.next = l1;
            return reverse(l2,p,head);
        } 
    }
}

四.给出某不含头结点的链表中某节点(不是尾结点),要求不访问该链表的首结点,删除该结点。
思路:这道题只需将后面的结点移动到前面来就可以了。但与平时我们删除结点的做法不同。平时我们需要知道要删除结点的头一个结点和后一个结点。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void deleteNode(ListNode node) {
        while(true){
            node.val = node.next.val; //将后一个值移动到前一个值的位置。
            if(node.next.next == null){
                node.next = null; //最后一个结点的next直接赋为null。
                break;
            }
            node = node.next;
        }
    }
}

注意这里题目中说的不是尾结点的含义,如果删除的是尾结点,那么就必须要知道要删除结点的前一个结点了。这种写法:node.next.next当node为最后一个结点时,编译也会抛出空指针异常。
五.删除某不含头结点的单链表中倒数第N个结点

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        int nodeNum = 1;  //记录单链表结点的个数
        ListNode p = head;
        while(true){
            if(p.next!=null){
                nodeNum++;   //计算单链表结点的个数
                p = p.next;
            }else{
                break;
            }
        }
        p = head;  //删除前的首结点
        if(nodeNum == n){  //如果要删除倒数第N个结点,就是删除第一个结点,直接返回链首指针的下一个结点。
            return p.next;
        }else{
            for(int i=0;i<nodeNum-n-1;i++){
                p = p.next; //否则找到要删除结点的前一个位置。
            }
            p.next = p.next.next; //删除该结点。
            return head;   //返回首结点。
        }
    }
}