美文网首页
算法记录 | Day03 (链表01)

算法记录 | Day03 (链表01)

作者: perry_Fan | 来源:发表于2022-10-27 21:32 被阅读0次
    • 203.移除链表元素
    • 707.设计链表
    • 206.反转链表

    【题目1 202. 移除链表元素】

    给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

    【思路】
    1)构建虚拟头结点。可以统一删除的策略,让next.next 去代替 next 元素。让辅助结点cur 来进行遍历(不是直接操作头结点,是因为最后往往需要返回头结点)。
    2)直接删除的方式。需要区别头结点和普通节点,因为删除需要找到当前的前一个结点,让它的后继节点指向当前的后一个结点。

    【心得】
    链表的题目需要自己手画一下图,理解得更加清晰透彻。

    【实现一】

      public ListNode removeElements(ListNode head, int val) {
          // 边界条件
            if (head == null){
                return head;
            }
            ListNode dummyHead = new ListNode(0,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;
        }
    

    【实现二 707.设计链表 】
    熟练链表的所有基本操作!

    直接删除结点

    //单链表
    class ListNode {
        int val;
        ListNode next;
        ListNode(){}
        ListNode(int val) {
            this.val=val;
        }
    }
    class MyLinkedList {
        //size存储链表元素的个数
        int size;
        //虚拟头结点
        ListNode head;
    
        //初始化链表
        public MyLinkedList() {
            size = 0;
            head = new ListNode(0);
        }
    
        //获取第index个节点的数值
        public int get(int index) {
            //如果index非法,返回-1
            if (index < 0 || index >= size) {
                return -1;
            }
            ListNode currentNode = head;
            //包含一个虚拟头节点,所以查找第 index+1 个节点
            for (int i = 0; i <= index; i++) {
                currentNode = currentNode.next;
            }
            return currentNode.val;
        }
    
        //在链表最前面插入一个节点
        public void addAtHead(int val) {
            addAtIndex(0, val);
        }
    
        //在链表的最后插入一个节点
        public void addAtTail(int val) {
            addAtIndex(size, val);
        }
    
        // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
        // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
        // 如果 index 大于链表的长度,则返回空
        public void addAtIndex(int index, int val) {
            if (index > size) {
                return;
            }
            if (index < 0) {
                index = 0;
            }
            size++;
            //找到要插入节点的前驱
            ListNode pred = head;
            for (int i = 0; i < index; i++) {
                pred = pred.next;
            }
            ListNode toAdd = new ListNode(val);
            toAdd.next = pred.next;
            pred.next = toAdd;
        }
    
        //删除第index个节点
        public void deleteAtIndex(int index) {
            if (index < 0 || index >= size) {
                return;
            }
            size--;
            if (index == 0) {
                head = head.next;
            return;
            }
            ListNode pred = head;
            for (int i = 0; i < index ; i++) {
                pred = pred.next;
            }
            pred.next = pred.next.next;
        }
    }
    
    //双链表
    class ListNode{
        int val;
        ListNode next,prev;
        ListNode() {};
        ListNode(int val){
            this.val = val;
        }
    }
    
    
    class MyLinkedList {  
    
        //记录链表中元素的数量
        int size;
        //记录链表的虚拟头结点和尾结点
        ListNode head,tail;
        
        public MyLinkedList() {
            //初始化操作
            this.size = 0;
            this.head = new ListNode(0);
            this.tail = new ListNode(0);
            //这一步非常关键,否则在加入头结点的操作中会出现null.next的错误!!!
            head.next=tail;
            tail.prev=head;
        }
        
        public int get(int index) {
            //判断index是否有效
            if(index<0 || index>=size){
                return -1;
            }
            ListNode cur = this.head;
            //判断是哪一边遍历时间更短
            if(index >= size / 2){
                //tail开始
                cur = tail;
                for(int i=0; i< size-index; i++){
                    cur = cur.prev;
                }
            }else{
                for(int i=0; i<= index; i++){
                    cur = cur.next; 
                }
            }
            return cur.val;
        }
        
        public void addAtHead(int val) {
            //等价于在第0个元素前添加
            addAtIndex(0,val);
        }
        
        public void addAtTail(int val) {
            //等价于在最后一个元素(null)前添加
            addAtIndex(size,val);
        }
        
        public void addAtIndex(int index, int val) {
            //index大于链表长度
            if(index>size){
                return;
            }
            //index小于0
            if(index<0){
                index = 0;
            }
            size++;
            //找到前驱
            ListNode pre = this.head;
            for(int i=0; i<index; i++){
                pre = pre.next;
            }
            //新建结点
            ListNode newNode = new ListNode(val);
            newNode.next = pre.next;
            pre.next.prev = newNode;
            newNode.prev = pre;
            pre.next = newNode;
            
        }
        
        public void deleteAtIndex(int index) {
            //判断索引是否有效
            if(index<0 || index>=size){
                return;
            }
            //删除操作
            size--;
            ListNode pre = this.head;
            for(int i=0; i<index; i++){
                pre = pre.next;
            }
            pre.next.next.prev = pre;
            pre.next = pre.next.next;
        }
    }
    
    /**
     * Your MyLinkedList object will be instantiated and called as such:
     * MyLinkedList obj = new MyLinkedList();
     * int param_1 = obj.get(index);
     * obj.addAtHead(val);
     * obj.addAtTail(val);
     * obj.addAtIndex(index,val);
     * obj.deleteAtIndex(index);
     */
    

    【题目2 】

    在链表类中实现这些功能:
    get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
    addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
    addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
    addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。

    deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

    
    

    【题目3】

    206. 反转单链表
    给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

    【思路】
    解决一个最小单元的指向问题,重复该调整,注意终止条件。

    // TODO

    // 双指针
    class Solution {
        public ListNode reverseList(ListNode head) {
            ListNode prev = null;
            ListNode cur = head;
            ListNode temp = null;
            while (cur != null) {
                temp = cur.next;// 保存下一个节点
                cur.next = prev;
                prev = cur;
                cur = temp;
            }
            return prev;
        }
    }
    

    相关文章

      网友评论

          本文标题:算法记录 | Day03 (链表01)

          本文链接:https://www.haomeiwen.com/subject/kicftdtx.html