代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、 206.反转链表

移除链表元素

【力扣】203.移除链表元素

/**
 * 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 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) {
        /*
         * 思路:添加一个虚拟头结点
         * 参考:
         * https://leetcode.cn/problems/remove-linked-list-elements/solutions/10957/203yi-chu-lian-biao-yuan-su-by-lewis-dxstabdzew/
         * https://www.bilibili.com/video/BV18B4y1s7R9/?vd_source=accc6a9ec558fa81b34f121125d4eff0
         *
         *
         * 对于链表,主要掌握添加一个虚拟结点的操作,才能统一删除第一个结点
         * 和除第一个结点外其他结点的操作。
         * 注意删除结点的核心语句cur.next = cur.next.next;
         * 
         */

        // 设置一个虚拟头结点,便于统一操作
        ListNode dummNode = new ListNode(0);
        dummNode.next = head;

        // 指向当前结点
        // 删除结点时必须知道它的前一个结点,如果是删除第一个结点,
        // 就需要知道dummyNode,所以最开始要用cur指向dummyNode而不是dummyNode.next
        ListNode cur = dummNode;
        // 确保当前结点后还有结点
        while (cur.next != null) {
            // 如果碰到相同的值,则跳过,否则继续向下遍历
            if (cur.next.val == val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }

        return dummNode.next; // 删除虚拟头结点
    }
}

设计链表

【力扣】707. 设计链表

// class ListNode {
//     int val;
//     ListNode next;

//     ListNode() {
//     }

//     ListNode(int val) {
//         this.val = val;
//     }
// }

class MyLinkedList {
    /*
     * 思路:
     * 
     * 参考:
     * https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E5
     * %85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC
     * 
     * 注意链表的index是从0开始计数的
     * 
     * 本题的不同方法:
     * 1、get:直接遍历到index的位置,返回该位置的元素。
     * 2、addAtHead:相当于在index=0的位置插入元素,即addAtIndex(0,val)
     * 3、addAtTail:相当于在index=链表长度的位置插入元素addAtIndex(链表长度),val)
     * 4、addAtIndex:排除异常情况,然后先遍历到index-1的位置,再在index处插入元素
     * 5、deleteAtIndex:排除异常情况,然后先遍历到index-1的位置,再在index处删除元素
     */

    ListNode head; // 虚拟头结点
    int size; // 链表长度

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

    public int get(int index) {

        // 排除异常:索引无效(注意链表结点的索引是0,1,……size-1,位置size没有结点)
        if (index < 0 || index >= size) {
            return -1;
        }

        ListNode cur = head; // 所遍历的结点
        // 注意为了遍历到index的位置,循环条件是i<=index,不是i<index
        for (int i = 0; i <= index; i++) {
            cur = cur.next;
        }
        return cur.val;
    }

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

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

    public void addAtIndex(int index, int val) {
        // 排除异常:如果 index 大于链表长度,则不会插入节点。
        if (index > size) {
            return;
        }

        // 排除异常:如果index小于0,则在头部插入节点。
        if (index < 0) {
            index = 0;
        }

        // 开始遍历到第index-1的位置
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }

        // 在第index的位置插入元素
        ListNode addNode = new ListNode(val);
        addNode.next = cur.next;
        cur.next = addNode;

        // 链表长度+1
        size++;

    }

    public void deleteAtIndex(int index) {

        // 排除异常:索引无效
        if (index < 0 || index >= size) {
            return;
        }

        // 开始遍历到第index-1的位置
        ListNode cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }

        // 删除元素关键语句
        cur.next = cur.next.next;

        // 链表长度-1
        size--;
    }

    // public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

    //     // 循环打印链表输出
    //     MyLinkedList linkedList = new MyLinkedList();
    //     Class myClass = linkedList.getClass();
    //     String methods[] = { "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get",
    //             "get", "deleteAtIndex", "deleteAtIndex", "get", "deleteAtIndex", "get" };
    //     Object params[][] = { { 1 }, { 3 }, { 1, 2 }, { 1 }, { 1 }, { 1 }, { 3 }, { 3 }, { 0 }, { 0 }, { 0 },
    //             { 0 } };
    //     for (int i = 0; i < methods.length; i++) {
    //         int param_length = params[i].length;
    //         Class c[] = new Class[param_length];
    //         for (int j = 0; j < param_length; j++) {
    //             c[j] = wrapperToPrimitive.get(params[i][j].getClass());
    //         }
    //         Method method = myClass.getDeclaredMethod(methods[i], c);
    //         method.invoke(linkedList, params[i]);
    //         System.out.print(methods[i]+" ");
    //         for(int k=0;k<params[i].length;k++){
    //             System.out.print(params[i][k]+" ");
    //         }
    //         System.out.println();
    //         for (int k=0;k<linkedList.size;k++) {
    //             System.out.print(linkedList.get(k)+" ");
    //         }
    //         System.out.println();
    //     }

    // }

    // private static final Map<Class, Class> wrapperToPrimitive = new HashMap<Class, Class>();
    // static {
    //     wrapperToPrimitive.put(Integer.class, int.class);
    //     // wrVoid.class, void.class,
    //     // Boolean.class, boolean.class,
    //     // Byte.class, byte.class,
    //     // Character.class, char.class,
    //     // Short.class, short.class,
    //     // , int.class,
    //     // Long.class, long.class,
    //     // Float.class, float.class,
    //     // Double.class, double.class)
    // }

}

反转链表

【力扣】206. 反转链表

// 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) {
        /*
         * 思路:双指针,一个指针指向原链表,另一个指针指向新的链表(倒序)
         * 
         * 参考:
         * https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html#%E5%8F%8C%E6%8C%87%E9%92%88%E6%B3%95
         * 
         * 首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null
         * 然后就要开始反转了,首先要把cur->next节点用tmp指针保存一下,也就是保存一下这个节点
         * 为什么要保存一下这个节点呢,因为接下来要改变cur->next的指向了,将cur->next指向pre,此时已经反转了第一个节点了
         * 接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针
         * 最后,cur指针已经指向了null,循环结束,链表也反转完毕了。此时我们return pre指针就可以了,pre指针就指向了新的头结点
         * 
         * p.s.本质上就是每一步从旧链表中摘出头结点,加在新链表的头结点之前
         */

        ListNode pre = null; // 新链表
        ListNode cur = head; // 原链表
        ListNode tmp = null;
        while (cur != null) {
            tmp = cur.next;// 保存下一个节点
            // 把旧链表(cur)的next从旧链表中断掉,重新连到新链表的头结点(pre)之前
            cur.next = pre;
            // 将pre指针移动到cur的位置,也即pre指向新链表的头结点处,
            // 以待下一次旧链表中取出一个头结点与其连接
            pre = cur;
            // 将cur指针移动到tmp(cur.next)的位置,也即cur指向旧链表的头结点处
            cur = tmp;
        }
        return pre;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值