Day03 | LeetCode 203 移除链表元素, LeetCode 206 反转链表, LeetCode 707 设计链表

LeetCode 203

203. 移除链表元素 - 力扣(LeetCode)

思路

  原链表法
  1. 直接在原链表上优先处理完head的情况
  2. 如果节点为目标值,那么就用cur.next = cur.next.next删除该节点,因为此时head已经保证不是目标值了,所以从cur.next开始删除判断
  3. 如果节点不是目标值,那么就正常移动节点
  虚拟头节点法
  1. 创建一个哨兵虚拟头节点dummyhead
  2. 所有节点都以cur.next = cur.next.next的逻辑进行处理,无需单独处理头节点

注意点

  原链表法
  1. 返回值就为head
  2. 循环结束条件为cur != null && cur.next != null
  虚拟头节点法
  1. 返回值为dummyhead.next,因为此时head可能已经被删除了
  2. 循环结束条件为cur.next != null

代码

  原链表法
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //原链表法
        if(head == null) {
            return head;
        }
        while(head != null && head.val == val) {        //处理头节点为目标值的情况
            head = head.next;
        }
        ListNode cur = head;
        while(cur != null && cur.next != null) {
            if(cur.next.val == val) {                   //处理当前节点为目标值的情况
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }
        return head;
    }
}
  虚拟头节点法
class Solution {
    public ListNode removeElements(ListNode head, int val) {
        //虚拟头节点法
        if(head == null) {
            return head;
        }
        ListNode dummyhead = new ListNode();
        dummyhead.next = head;                    //引入虚拟头节点
        ListNode cur = dummyhead;
        while(cur.next != null) { 
            if(cur.next.val == val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }
        return dummyhead.next;                    //注意此处的返回值
    }
}

LeetCode 206

206. 反转链表 - 力扣(LeetCode)

思路

  头插法
  1. 保存head.next的值
  2. 置空head
  3. 保存cur.next的值
  4. 将cur头插法插入head处
  5. 更新head, cur的值
  双指针法
  1. 引入虚拟头节点pre
  2. 保存head,cur.next的值
  3. 将head指向pre,实现逆置
  4. 更新pre, cur的值
  递归法
  1. 根据双指针法确定递归结束条件
  2. 递归步骤于双指针法while循环中类似的逆置
  3. 将更新操作改为递归操作

注意点

  头插法
  1. 一定要记得使用临时节点curN保存cur.next的值,否则会造成链表节点的丢失
  2. 返回的值为head
  双指针法
  1. pre不可以一开始就指向head,意思就是说不可以写成pre.next = head,因为这样会导致一个环的出现,我们在此方法下进行的是逆置而非头插
  2. 返回的值为pre,此时pre为链表的最后一个节点
  3. 图示:链表应该发生下面的变化

  递归法
  1. 递归结束时返回的时pre
  2. 循环开始的条件时null, cur

代码

  头插法
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null) {
            return head;
        }
        ListNode cur = head.next;        //注意此时cur的值时head.next而非head
        head.next = null;                //置空head
        while(cur != null) {
            ListNode curN = cur.next;
            cur.next = head;
            head = cur;
            cur = curN;
        }
        return head;
    }
}
  双指针法
class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null) {
            return head;
        }
        ListNode pre = null;
        ListNode cur = head;
        while(cur != null) {
            ListNode curN = cur.next;
            cur.next = pre;
            pre = cur;
            cur = curN;
        }
        return pre;
    }
}
  递归法
class Solution {
    //递归
    public ListNode reverseList(ListNode head) {
        return reverse(null, head);
    }

    public ListNode reverse(ListNode pre, ListNode cur) {
        if(cur == null) {
            return pre;
        }
        ListNode curN = cur.next;
        cur.next = pre;
        return reverse(cur, curN);
    }
}

LeetCode 707

707. 设计链表 - 力扣(LeetCode)

因为是链表的基本操作,这里就不讲思路了

注意点

  1. 注意判断Index的合法性
  2. 注意size大小的更新

代码

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

        }
    }

    ListNode dummyhead;
    int size;

    //初始化
    public MyLinkedList() {
        dummyhead = new ListNode();
        size = 0;
    }
    
    //获取index处节点的大小
    public int get(int index) {
        //合法性判断
        if(index < 0 || index > size-1) {
            return -1;
        }
        ListNode cur = dummyhead;
        while(index > 0) {
            cur = cur.next;
            index--;
        }
        return cur.next.val;
    }
    
    //头插法
    public void addAtHead(int val) {
        ListNode node = new ListNode(val);
        node.next = dummyhead.next;
        dummyhead.next = node;
        size++;
    }
    
    //尾插法
    public void addAtTail(int val) {
        ListNode cur = dummyhead;
        while(cur.next != null) {
            cur = cur.next;
        }
        ListNode node = new ListNode(val);
        cur.next = node;
        size++;
    }
    
    //在Index处插入元素
    public void addAtIndex(int index, int val) {
        //合法性判断
        if(index > size) {
            return;
        }
        if(index == size) {
            addAtTail(val);
            return;
        }
        ListNode cur = dummyhead;
        while(index > 0) {
            cur = cur.next;
            index--;
        }
        ListNode node = new ListNode(val);
        node.next = cur.next;
        cur.next = node;
        size++;
    }

    //在Index处删除元素    
    public void deleteAtIndex(int index) {
        if(index < 0 || index > size-1) {
            return;
        }
        ListNode cur = dummyhead;
        while(index > 0) {
            cur = cur.next;
            index--;
        }
        cur.next = cur.next.next;
        size--;
    }
}

总结

本次的算法练习主要是针对了一些关于链表的基本操作,重点是关于链表的反转,对于虚拟头节点的应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

TinaAmber

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

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

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

打赏作者

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

抵扣说明:

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

余额充值