Day03【链表】203.移除链表元素 | 707.设计链表 | 206.反转链表

1.链表基础知识

1.1什么是链表

  • 定义
    是通过指针串联在一起的线性结构。每节点有两部分:数据域+指针域(存放指向下一个节点的指针),最后一个节点的指针指向null。
  • 头节点
    链表的入口,给出头节点,就可以根据头节点中的next指针找到下一个节点,以后的每个节点以此类推,就能得到整个链表。
    单链表示意图

1.2链表的类型

  • 单链表
    刚刚的内容就是单链表。

  • 双链表
    每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。
    双链表示意图

  • 循环链表
    链表的首尾节点相连。
    循环链表可以用于结局约瑟夫环问题。
    循环列表示意图

1.3链表的存储方式

  • 数组在内存中连续分布,链表在内存中不是连续分布
  • 链表通过指针域的指针链接在内存中的各个节点,所以链表中的节点在内存中不是连续分布的,而是散乱分布在某地址上,分配机制取决于操作系统的内存管理
    链表的存储方式

1.4 常用的一些思路(自己的总结)

  1. 链表中的题,多数要定义一个节点cur,用于移动找到符合条件的节点。
  2. 定义一个虚拟头节点dummyHead,不对此进行移动,只用于返回最终的结果链表,常返回dummyHead.next(真正的头节点)。
  3. 有时定义一个节点pre,让pre跟着cur一起动(正好是pre在前cur在后),这样cur定好位后,pre也定好位了,且能方便的对它的下一个节点(cur)进行操作。
  4. 有时会定义一个临时节点temp,为cur.next。
  5. 以上方法需真正掌握链表的思想后灵活加以使用。

203.移除链表元素

  • 203.移除链表元素 | 题目链接

  • 题意:删除链表中等于给定值 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 输出:[]\
    
  • 思路
    用cur.next找到符合题意的节点后,让cur.next = cur.next.next,即跳过这个符合条件的节点,也就移除了。
    移除链表元素示意图

/**
 * 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 dummyHead = new ListNode(0, head); //设置虚拟头节点,能以相同的逻辑移除头节点。
        ListNode cur = dummyHead; //设置一个用于遍历的节点。虚拟头节点不能动,最后要返回dummHead.next以返回最终答案链表。

        while(cur.next != null) { //想:假设链表中只有一个节点,应如何写控制循环的条件。
            if(cur.next.val == val) {
                cur.next = cur.next.next; 
            } else {
                cur = cur.next;
            }
        }
        return dummyHead.next;
    }
}

707.设计链表

  • 707.设计链表 | 题目链接

  • 题意:在链表类中实现以下功能:

      ① get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
      ② addAtHead(val):在链表的第一个元素之前添加一个				值为 val 的节点。插入后,新节点将成为链表的第一个节点。
      ③ addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
      ④ addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val  的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
      ⑤ deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。
    
  • 思路

    1. 思路和上一题很像。想清楚每个节点的的指针应该只想哪里。
    2. 此题涉及到如何实现一个链表。
      ①需要定义节点,每个节点中有val和next,各种构造方法。
      ②需要定义链表,链表中有size和head;
class MyLinkedList {
    int size;
    ListNode head;
	
	/** 定义链表中的节点,是链表的内部类 */
    class ListNode {
        int val;
        ListNode next;

        public ListNode() {};

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

        public ListNode(int val, ListNode next) {
            this.val = val;
            this.next = next;
        }
    }
    
	/**构造MyLinkedList方法。初始化链表的size和head */
    public MyLinkedList() {
        this.size = 0;
        this.head = new ListNode(0);//这个head算是虚拟头节点
    } 
    
    /** 获取链表中第index个节点的值,如果索引无效,则返回-1 */
    public int get(int index) {
        if(index < 0 || index > size - 1) {
            return -1;
        }

        ListNode cur = this.head;
        for(int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.next.val;
    }
    
    /** 在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点 */
    public void addAtHead(int val) {
        addAtIndex(0, val);
    }
    
    /** 将值为 val 的节点追加到链表的最后一个元素 */
    public void addAtTail(int val) {
        addAtIndex(size, val);
    }
    
     /** 在链表中的第 index 个节点之前添加值为val的节点
     如果 index 等于链表的长度,则该节点将附加到链表的末尾
     如果 index 大于链表长度,则不会插入节点
     如果index小于0,则在头部插入节点 */
    public void addAtIndex(int index, int val) {
        if(index > size) {
            return;
        }
        
        ListNode cur = this.head;
        ListNode target = new ListNode(val);
        for(int i = 0; i < index; i++) {
            cur = cur.next;
        }
        target.next = cur.next;
        cur.next = target;
        size++;
    }
    
    /** 如果索引 index 有效,则删除链表中的第 index 个节点 */
    public void deleteAtIndex(int index) {
        if(index < 0 || index > size - 1) {
            return;
        }

        ListNode cur = this.head;
        for(int i = 0; i < index; i++) {
            cur = cur.next;
        }
        cur.next = cur.next.next;
        size--;
    }
}

/**
 * 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);
 */

206.反转链表

  • 206.反转链表 | 题目链接

  • 题意:反转一个单链表。

      示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL
    
  • 思路
    1. 首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
    2. 然后开始反转,首先要把 cur.next 节点用tmp指针保存一下,也就是保存一下这个节点。
    3. 为什么要保存一下这个节点呢,因为接下来要改变 cur.next 的指向了,将cur.next 指向pre ,此时已经反转了第一个节点了。此时如何移动cur呢?就让cur = tmp即可也就是原来的cur.next。
    4. 接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。
    5. 最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时pre指向最后一个节点,return pre指针就可以了,pre指针就指向了新的头结点。

  • 双指针法

/**
 * 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 reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        ListNode temp = null;

        while(cur != null) {
            temp = cur.next; 
            cur.next = pre;//反转指针的指向
            pre = cur;//向后移动pre和cur
            cur = temp;
        }
        return pre;
    }
}
  • 递归法
/**
 * 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 reverse(ListNode cur, ListNode pre) {
        if(cur == null) {
            return pre;
        }
        ListNode temp = cur.next;
        cur.next = pre;
        return reverse(temp, cur);
    }

    public ListNode reverseList(ListNode head) {
        return reverse(head, null);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xuwuuu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值