算法-链表

1. 移除链表元素(LeetCode 233)

题目:删除链表中等于给定值 val 的所有节点。

示例 1: 输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
示例 2: 输入:head = [], val = 1 输出:[]
示例 3: 输入:head = [7,7,7,7], val = 7 输出:[]

思路

  • 设置虚拟节点:这样对头节点和后面节点的处理是一致的(都有前驱节点)
  • C++/C需要对删除的节点进行内存释放;java不需要程序员手动操作,内存机制会自动释放。
/**
 * 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 removeElements(ListNode head, int val) {
        // 在原来的链表前面设置一个虚拟头节点
        ListNode newhead = new ListNode(0,head);
        ListNode pre = newhead;
        ListNode current = newhead.next;
        while(current != null){
            if(current.val == val) {
                pre.next = current.next;
            }else {
                pre = current;
            }
            current = current.next;
        }
        return newhead.next;
    }
}

2. 设计链表(LeetCode 707)

题目:详见LeetCode
注意

  • 注意index的边界条件判断
  • 这里的index定义和数组相同,是从0开始的
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 MyLinkedList {
    ListNode dummy_head;    //虚拟头节点
    int size;

    public MyLinkedList() {
        this.dummy_head = new ListNode(0,null);
        this.size = 0;
    }
    
    public int get(int index) {
        int count = 0;
        if(index < 0 || index >= this.size ) return -1;
        ListNode cur = dummy_head.next;
        while(count < index){
            count++;
            cur = cur.next;
        }
        return cur.val;
    }
    
    public void addAtHead(int val) {
        ListNode newnode = new ListNode(val,dummy_head.next);
        this.dummy_head.next = newnode;
        this.size++;
    }
    
    public void addAtTail(int val) {
        ListNode newnode = new ListNode(val,null);
        ListNode cur = this.dummy_head.next;
        if(this.size == 0){
            dummy_head.next = newnode;
            this.size++;
            return;
        }
        while(cur.next != null){
            cur = cur.next;
        }
        cur.next = newnode;
        this.size++;
        return;
    }
    
    public void addAtIndex(int index, int val) {
        if(index > this.size) return;
        else if(index <= 0){
            addAtHead(val);
            return;
        }else if(index  == this.size){
            addAtTail(val);
            return;
        }
        int count = 0;
        ListNode cur = this.dummy_head.next;
        while(count < index-1) {
            cur = cur.next;
            count++;
        }
        ListNode newNode = new ListNode(val, cur.next);
        cur.next = newNode;
        this.size++;
    }
    
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= this.size) return;
        int count = -1;
        ListNode pre = this.dummy_head;
        while(count < index-1){
            pre = pre.next;
            count++;
        }
        pre.next = pre.next.next;
        this.size--;
    }
}

3. 反转链表(LeetCode 206)

题目:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

思路

  • 双指针
  • 需要存储cur.next否则会找不到后面的节点。
 //双指针pre and cur
 //用tmp存储cur.next
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode cur = head;
        ListNode pre = null;
        ListNode tmp;
        while(cur != null) {
            tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}

4. 两两交换链表中的节点

题目:给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
注意:操作的顺序,不要丢失指针导致链表断裂

输入:head = [1,2,3,4]
输出:[2,1,4,3]
//两两配对,进行交换
class Solution {
    public ListNode swapPairs(ListNode head) {
        ListNode dummy_head = new ListNode(-1, head);
        ListNode cur = dummy_head;
        ListNode tmp = null;
        while(cur!=null && cur.next != null && cur.next.next != null){
            tmp = cur.next;
            cur.next = cur.next.next;
            tmp.next = cur.next.next;
            cur.next.next = tmp;
            cur = cur.next.next;
        }
        return dummy_head.next;
    }
}

5. 删除链表的倒数第N个节点(LeetCode 19)

题目:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
思路:简单的快慢指针,注意处理第一个节点

class Solution {
    public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode slow = head;
        ListNode fast = head;
        ListNode pre = slow;
        int count = n;
        while(fast != null && count > 0){
            fast = fast.next;
            count--;
        }
        //要删除的是第一个节点
        if(fast == null){
            head = head.next;
        }
        //要删除的不是第一个节点
        while(fast != null){
            pre = slow;
            slow = slow.next;
            fast = fast.next;
        }
        pre.next = slow.next;
        return head;
    }
}

6. 链表相交

题目:见LeetCode
思路

  1. 确定链表长度
  2. 尾部对齐(长的指针先走len_long-len_short步)
  3. 查找相同的节点(值相同,next相同)
public class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        int lenA = 0;
        int lenB = 0;
        ListNode temp = headA;
        while(temp != null){
            lenA++;
            temp = temp.next;
        }
        temp = headB;
        while(temp != null){
            lenB++;
            temp = temp.next;
        }
        ListNode long_list = (lenA >= lenB) ? headA : headB;
        ListNode short_list = (lenA < lenB) ? headA : headB;
        int gap = Math.abs(lenA-lenB);
        while(gap != 0){
            long_list = long_list.next;
            gap--;
        }
        
        while(long_list!=null){
            //节点相等,而不仅仅是值相等
            if(long_list == short_list) return long_list;
            long_list = long_list.next;
            short_list = short_list.next;
        }
        return null;
    }
}

7. 环形链表II(LeetCode 142)

题目:给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null

public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode fast = head;
        ListNode slow = head;
        //退出循环的条件: 无环 或 fast、slow相遇
        while(fast != null && fast.next != null){
            fast = fast.next.next;
            slow = slow.next;
            if(fast == slow) break;
        }
        //无环返回null
        if(fast == null || fast.next == null) return null;
        //有环则令两个指针分别从 head 和 相遇点 出发
        //两者相等的节点即为环的起点
        ListNode index1 = head;
        ListNode index2 = fast;
        while(index1 != index2){
            index1 = index1.next;
            index2 = index2.next;
        }
        return index1;
    }
}
posted @ 2024-01-27 14:25  Frank23  阅读(7)  评论(0编辑  收藏  举报