LeetCode刷题Day04——链表(设计单/双链表、移除、翻转、交换链表节点)

对于链表的操作大多有迭代和递归两种解决方法:

  1. 迭代法:首先创建一个临时的节点p用于遍历链表,其开始可以指向头节点,也可以让其next节点指向头节点(如果p指向头节点则while循环的判断条件是p!=null,反之则是p.next!=null),随后p不断地向后移动,在这个过程中进行要求的操作。如果结果要返回头指针,可以实现创建一个节点让其next指向头指针。
    • 如果是要删除元素,那么需要拥有前一个节点的指针,让其指向要删除的元素的下一个元素,所以此时则不能让p指向头节点,而应该是让next去指向,即判断的是下一个元素的值,这样才能够实现删除。
    • 如果是要翻转链表,那么需要不断改变指针的方向,即让next等于之前的元素,所以需要一个变量prev记录之前的元素,在循环内先将下一个元素保存到next变量之后再改变指针的指向,指向prev,然后将prev更改为p,将p更改为next,这样就能顺利遍历链表。
  2. 递归法:链表的递归实际上就是将链表拆为一个一个的子链表,不断缩小链表的长度,当到链表的最后一位(即p或p.next=null时),递归就到达了最底层,这时直接返回null或head。每一层递归传递给下一层的参数一般时子链表的头指针,拿到头指针后进行操作,之后根据题目要求进行操作并且返回上一层所需要的结果,一般是处理后新的头指针,用于给上一层的尾元素进行连接(比如进行交换顺序头指针发生改变时),或者一直返回最底层的指针(进行翻转头指针没有发生改变时(由于子链表的顺序没有改变,上一层可以直接拿到正确的下一个元素所以不需要下一层返回))

一、移出链表元素

题目链接:203.移出链表元素

/**
 * <pre>
 * <p>可以采用迭代,不断判断下一个节点是否要删除;或者采用递归,每次获取子链表的head,如果头节点的值如果等于val就说明返回的是子链表的头</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 10:45
 */
public class 移出链表元素203 {
    
    // 迭代
    public ListNode removeElements(ListNode head, int val) {
        ListNode res = new ListNode();
        res.next = head;
        ListNode p = res;
        while (p.next != null) {
            if (p.next.val == val) {
                p.next = p.next.next;
            } else { 
                p = p.next;
            }
        }
        return res.next;
    }
    
    // 递归
    public ListNode removeElements2(ListNode head, int val) {
        if (head == null) {
            return null;
        }
        head.next = removeElements2(head.next, val); // 每次删除子链表,返回子链表的头
        return head.val == val ? head.next : head;
    }
}

class ListNode {
    int val;
    ListNode next;
    ListNode() {}
    ListNode(int val) { this.val = val; }
    ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}

二、设计链表

题目链接:707.设计链表

/**
 * <pre>
 * <p>链表的设计:单链表和双链表</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 11:29
 */
// 单链表
class MyLinkedList {
    
    private int size;
    
    private MyListNode head;

    public MyLinkedList() {
        size = 0;
        head = new MyListNode(0);
    }

    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        MyListNode p = head;
        for (int i=0; i<=index; i++) {
            p = p.next;
        }
        return p.val;
    }

    public void addAtHead(int val) {
        addAtIndex(0, val);
    }

    public void addAtTail(int val) {
        addAtIndex(size, val);
    }

    public void addAtIndex(int index, int val) {
        if (index < 0 || index > size) {
            return;
        }
        MyListNode p = head;
        for (int i=0; i<index; i++) {
            p = p.next;
        }
        MyListNode newNode = new MyListNode(val);
        newNode.next = p.next;
        p.next = newNode;
        size++;
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        MyListNode p = head;
        for (int i=0; i<index; i++) {
            p = p.next;
        }
        p.next = p.next.next;
        size--;
    }
}

class MyListNode {
    
    int val;
    
    MyListNode next;

    public MyListNode() {
    }

    public MyListNode(int val) {
        this.val = val;
    }

    public MyListNode(int val, MyListNode next) {
        this.val = val;
        this.next = next;
    }
    
}

// 双链表
class BiLinkedList {

    private int size;

    private BiListNode head;
    
    private BiListNode tail;

    public BiLinkedList() {
        size = 0;
        head = new BiListNode(0);
        tail = new BiListNode(0);
        head.next = tail;
        tail.prev = head;
    }

    public int get(int index) {
        if (index < 0 || index >= size) {
            return -1;
        }
        BiListNode p;
        if (index < size/2) {
            p = head;
            for (int i=0; i<=index; i++) {
                p = p.next;
            }
        } else {
            p = tail;
            for (int i=0; i<size-index; i++) {
                p = p.prev;
            }
        }
        return p.val;
    }

    public void addAtHead(int val) {
        addAtIndex(0, val);
    }

    public void addAtTail(int val) {
        addAtIndex(size, val);
    }

    public void addAtIndex(int index, int val) {
        if (index < 0 || index > size) {
            return;
        }
        BiListNode p;
        if (index < size/2) {
            p = head;
            for (int i=0; i<index; i++) {
                p = p.next;
            }
        } else {
            p = tail;
            for (int i=0; i<=size-index; i++) {
                p = p.prev;
            }
        }
        BiListNode newNode = new BiListNode(val);
        newNode.next = p.next;
        newNode.prev = p;
        p.next.prev = newNode;
        p.next = newNode;
        size++;
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        BiListNode p;
        if (index < size/2) {
            p = head;
            for (int i=0; i<index; i++) {
                p = p.next;
            }
        } else {
            p = tail;
            for (int i=0; i<=size-index; i++) {
                p = p.prev;
            }
        }
        p.next = p.next.next;
        p.next.prev = p;
        size--;
    }
}

class BiListNode {

    int val;

    BiListNode next;
    
    BiListNode prev;

    public BiListNode() {
    }

    public BiListNode(int val) {
        this.val = val;
    }
    
}

三、翻转链表

题目链接:206.翻转链表

/**
 * <pre>
 * <p>翻转链表:迭代或递归</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 13:39
 */
public class 翻转链表206 {
    
    // 迭代法
    public ListNode reverseList(ListNode head) {
        ListNode prev=null, p=head, next;
        while (p != null) {
            next = p.next;
            p.next = prev;
            prev = p;
            p = next;
        }
        return prev;
    }
    
    // 递归法
    public ListNode reverseList2(ListNode head) {
        if (head == null || head.next == null) { // head == null 是用于0长度的链表直接返回
            return head; // 遍历到最后一个节点则返回,这个就是翻转后链表的头
        }
        ListNode newHead = reverseList2(head.next);
        // 如果是1->2->3->...->k->k+1->...->k+n
        // 执行到k时变为1->2->3->...->k->k+1<-...<-k+n
        // 那么k的next是k+1,需要将k+1的next改为k
        head.next.next = head;
        // 将k的next置为null,不然会成环,k指向k+1而k+1指向k
        head.next = null;
        return newHead;
    }
}

四、两两交换链表中的节点

题目链接:24.两两交换链表中的节点

/**
 * <pre>
 * <p>可以采用迭代也可以采用递归</p>
 * </pre>
 *
 * @author <a href="https://github.com/kil1ua">Ken-Chy129</a>
 * @date 2023/1/5 14:58
 */
public class 两两交换链表中的节点24 {

    public ListNode swapPairs(ListNode head) {
        ListNode p = new ListNode(), res = p;
        p.next = head;
        while (p.next != null  && p.next.next != null) {
            ListNode first = p.next, second = p.next.next;
            first.next = second.next;
            second.next = first;
            p.next = second;
            p = first;
        }
        return res.next;
    }

    // 递归
    public ListNode swapPairs2(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
        ListNode next = swapPairs(head.next.next);
        ListNode second = head.next;
        head.next = next;
        second.next = head;
        return second;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

得过且过的勇者y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值