【编程练习】链表专题

151 阅读2分钟

1. 反转链表

练习地址

image.png

/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode nex = null;
        while(cur != null){
            nex = cur.next;//用于保存下一节点
            cur.next = pre;//翻转指针
            //指针后移
            pre = cur;
            cur = nex;
        }
        //突破循环时cur = null,因此pre不为null,为头部节点
        return pre;
    }
}

2. 合并有序链表

练习地址

3. 链表中的节点每k个一组翻转

练习地址

image.png

public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param k int整型 
     * @return ListNode类
     */
    public ListNode reverseKGroup (ListNode head, int k) {
        // 扩展首节点,方便返回
        ListNode root = new ListNode(-1);
        root.next = head;
        //用于储存头节点的前一个节点,用于连接时使用
        ListNode pre = root;
        while(head != null){
            //每一段的最后一个节点,翻转时使用
            ListNode tail = pre;
            for(int i = 0 ; i < k ; i++){
                tail = tail.next;
                if(tail == null){
                    //不足k时,直接返回
                    return root.next;
                }
            }
            //储存下一次翻转的第一个节点
            ListNode nex = tail.next;
            //进行翻转
            ListNode[] nodeList = reverseList(head,tail);
            head = nodeList[0];
            tail = nodeList[1];
            //将返回的反转链表拼接在一起
            pre.next = head;
            tail.next = nex;
            pre = tail;
            head = tail.next;
        }
        return root.next;
    }
    
    //翻转链表,返回翻转后的首节点和尾节点
    public ListNode[] reverseList (ListNode head,ListNode tail){
        ListNode pre = null;
        ListNode cur = head;
        ListNode nex = null;
        while(cur != null && pre != tail){
            nex = cur.next;
            cur.next = pre;
            pre = cur;
            cur = nex;
        }
        return new ListNode[]{tail,head};
    }
}

4. 判断链表是否有环

练习地址

public class Solution {
    public boolean hasCycle(ListNode head) {
        //设置快慢指针,慢指针走一步,快指针走两步,相遇则代表有环
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                return true;
            }
        }
        return false;
    }
}

5. 链表环入口节点

练习地址

设置快慢指针,都从链表头出发,快指针每次走两步,慢指针一次走一步,假如有环,一定相遇于环中某点。接着让两个指针分别从相遇点和链表头出发,两者都改为每次走一步,最终相遇于环入口。

image.png

public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode slow = pHead;
        ListNode fast = pHead;
        ListNode meet = null;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            if(slow == fast){
                meet = slow;
                break;
            }
        }
        //如果没有相遇,则返回空
        if(meet == null){
            return null;
        }
        //两个指针,分别从头和相遇节点出发,相遇时的节点为入口节点
        ListNode node = pHead;
        while(meet != null){
            if(node == meet){
                return node;
            }
            node = node.next;
            meet = meet.next;
        }
        return null;
    }
}

6. 删除链表倒数第n个节点

练习地址

7. 两个链表第一个公共节点

练习地址

8.链表相加

练习地址