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

链表基础及练习题

目录

链表基础及练习题

1.链表

1.1 什么是链表?

1.2 链表的类型

1.3 两种链表节点的定义

1.4 链表和数组区别

1.5 链表的方法

2.相关例题

2.1 LeetCode203.移除链表元素

2.2 LeetCode206.反转链表

2.3 LeetCode707.设计链表


1.链表

1.1 什么是链表?

        链表(LinkdeList)是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。非线性的顺序存储。

1.2 链表的类型

        单链表:分为两部分,Value存储数据,Next存放指向下一节点的指针。一个单链表的第一个节点称作头节点,最后一个节点指向Null;

        

        双链表: 分为三个部分,Prev存储指向上一节点的指针,Value存储数据,Next存放指向下一节点的指针。头节点的Prev指向Null,尾节点的Next指向Null。

        

         两种方式相比:单链表只能单方向查找,删除的时候需要引入临时节点。

1.3 两种链表节点的定义

        单链表节点的定义:

class ListNode{
    //数据域Value
    int value;
    //指针域,存放下一个节点
    ListNode next;
    public ListNode() {}
    public ListNode(int value, ListNode next) {
        this.value = value;
        this.next = next;
    }
}

        双链表节点的定义:

class ListNode {
    int value;
    ListNode prev;
    ListNode next;
    public LinkedNode() {}
    pubilc LinkedNode(int value,ListNode prev,ListNode next) {
        this.value = value;
        this.prev = prev;
        this.next = next;
    } 

}

1.4 链表和数组区别

    查改:频繁使用查找时,更多使用数组。因为链表查找元素需要遍历链表。

    增删:频繁增删时,更多使用链表。数组长度不可变,每次增删需要创建新数组。

1.5 链表的方法

        Java8 LinkedList方法

2.相关例题

2.1 LeetCode203.移除链表元素

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

         输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]

         输入:head = [], val = 1 输出:[]

         输入:head = [7,7,7,7], val = 7 输出:[]

        思路:如果链表为空,直接返回Null。如果链表头head.val == val,则head = head.next,直到不同的头节点出现。head存储头节点,所以需要一个临时节点cur来操作。

class Solution {
   public ListNode removeElements(ListNode head, int val) {
    while(head!=null && head.val==val){
        head = head.next;
    }
    ListNode curr = head;
    while(curr!=null){
        while(curr.next!=null && curr.next.val == val){
            curr.next = curr.next.next;
        }
        curr = curr.next;
    }
    return head;
    }
}

        需要注意:[1,2,3,3,4,5],val = 3。第一次写的时候,直接用if判断,发现有多个连续的节点的值和val相等,则只会删除第一个。所以需要用while判断,直到出现值和val不同的节点。

while(curr.next!=null && curr.next.val == val){
            curr.next = curr.next.next;
}

        虚拟头节点法:普通方法中,开始时需要对头节点单独进行操作,所以添加一个虚拟头节点,把头节点也当成普通节点处理。

class Solution {
   public ListNode removeElements(ListNode head, int val) {
    if (head == null) {
        return null;
    }
    ListNode fakeHead = new ListNode(-1,head);
    ListNode curr = fakeHead;
    while(curr!=null){
        while(curr.next!=null && curr.next.val == val){
            curr.next = curr.next.next;
        }
        curr = curr.next;
    }
    return fakeHead.next;
    }
}

        注意:返回值是fakeHead.next而不是直接返回head。fakeHead.next才是新的头节点,

        cur临时节点:和当前节点指向同一块内存。如果cur.next = val,则cur = cur.next.next。即cur和cur.next之间的联系断开,但是cur.next和cur.next.next仍存在联系。这也是为什么返回值不能是head的原因。如[7,3,2,1],Val = 7。head.val = val。但是head.next仍然指向3。

 

2.2 LeetCode206.反转链表        

        题目描述:给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

/**
 * 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 cur = head;
        ListNode prev = null;
        ListNode temp = null;
        while (cur != null) {
            //1.将临时节点temp = cur.next。因为步骤2中,cur.next将要指向前一节点。防止
                和第二个节点的指针丢失,要进行保存。
            temp = cur.next;
            //2.将cur的下一指针指向前一节点。
            cur.next = prev;
            //3.更新指针
            prev = cur;
            cur = temp;
            //temp = null;让temp初始化
        }
        return prev;
    }
}

2.3 LeetCode707.设计链表

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

class MyLinkedList {
    int size = 0;
    
    //虚拟头节点,并不是真正的头节点,链表开始是空的,真正的头节点是第一次加入的节点。
    ListNode fakeHead;

    public MyLinkedList() {
        size = 0;
        fakeHead = new ListNode(0);
    }
    
    public int get(int index) {
       if(index < 0 || index >= size) {
           return -1;
        } 
       ListNode cur = fakeHead;
       while (index >= 0){
           cur = cur.next;
           index--;
        }
       return cur.val;
    }
    
    public void addAtHead(int val) {
        ListNode newNode = new ListNode(val);
        newNode.next = fakeHead.next;
        fakeHead.next = newNode;
        size++;
    }
    
    public void addAtTail(int val) {
        ListNode newNode = new ListNode(val);
        ListNode curNode = fakeHead;
        while(curNode.next != null){
            curNode = curNode.next;
        }
        curNode.next = newNode;
        size ++;
    }
    
    public void addAtIndex(int index, int val) {
      if (index > size) {
          return;
      }
      if(index < 0) {
          index = 0;
      }
      size++;
      ListNode newNode = new ListNode(val);
      ListNode curNode = fakeHead;
      for (int i = 0; i  < index; i++) {
          curNode  = curNode.next;
      }
      newNode.next = curNode.next;
      curNode.next = newNode;
    }
    
    public void deleteAtIndex(int index) {
        if(index < 0 || index >= size) {
           return;
        } 
        size --;
        ListNode curNode = fakeHead;
        for (int i = 0; i  < index; i++) {
          curNode  = curNode.next;
      }
          curNode.next = curNode.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);
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值