算法打卡day03|链表专题01:虚拟头节点使用、单链表查找删除元素、链表设计通过索引(add、delete、get)、使用双指针思路实现链表反转|Leetcode203、707、206

1.基础知识——链表

  • 是由指针串联在一起的线性结构
  • 分类:

(1)单链表:每个节点由数据域与指针域组成{data,next}

算法打卡day03|链表专题01:虚拟头节点使用、单链表查找删除元素、链表设计通过索引(add、delete、get)、使用双指针思路实现链表反转|Leetcode203、707、206_第1张图片

(2)双链表:每个节点由数据域及指针域(两个指针)组成{data,pre,next}

算法打卡day03|链表专题01:虚拟头节点使用、单链表查找删除元素、链表设计通过索引(add、delete、get)、使用双指针思路实现链表反转|Leetcode203、707、206_第2张图片

(3)循环链表:节点结构与单链表一致,但是首尾相连

算法打卡day03|链表专题01:虚拟头节点使用、单链表查找删除元素、链表设计通过索引(add、delete、get)、使用双指针思路实现链表反转|Leetcode203、707、206_第3张图片

  • 存储:内存分布不是连续的
  • 链表定义代码※
  • 链表优点在于长度不固定,能够实现动态增删,适用于 增删频繁但是查询频率比较低的情景

Leetcode203.移除链表元素

题目链接:https://leetcode.cn/problems/remove-linked-list-elements/description/

分析:经典链表操作,主要需要考虑两种场景

  1. 当前节点为头节点,满足条件需要删除此元素: head = head.next
  2. 不为头节点,满足条件需要删除此元素 :node.next = node.next.next(此处表示对node是需要删除节点的前一个节点)

解1:Java正常删除节点法

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        while((head!=null)&&(head.val == val)){
            //直到找到一个不等于val的节点值,作为头节点
            head=head.next;
        }
        ListNode nownode = head;
        while((nownode != null)&&(nownode.next != null)){
            //第一个null 指空链表
            //第二个null 指遍历到链表末端的结束标志
            if(nownode.next.val==val){
                nownode.next = nownode.next.next;
            }else{
                nownode = nownode.next;
            }
        }
        return head;
    }
}

解2:Java自创方法-如果头节点为需要删除的值,最后处理,代码如下:

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        boolean headvalflag = false;
        if(head == null){
            return head;
        }else if(head.val == val){headvalflag =true;}
        ListNode nownode = head; 
        while(nownode.next!=null){
           if(nownode.next.val == val){
               nownode.next = nownode.next.next;
           }else{
               nownode = nownode.next;
           }
        }
        if(headvalflag == true){
            return head.next;
        }else{
            return head;
        }
    }
}

解3:Java构建虚拟头节点,统一后续操作(比较推荐)-画了个图示,如下:

算法打卡day03|链表专题01:虚拟头节点使用、单链表查找删除元素、链表设计通过索引(add、delete、get)、使用双指针思路实现链表反转|Leetcode203、707、206_第4张图片

class Solution {
    public ListNode removeElements(ListNode head, int val) {
        ListNode virtuallyHeadNode =  new ListNode(val+1,head);
        //此处虚拟节点的数据可以随机取,没有影响
        ListNode nownode = virtuallyHeadNode;
        while(nownode.next != null){
            if(nownode.next.val == val){
                nownode.next = nownode.next.next;
            }else{
                nownode = nownode.next;
            }
        }
        return virtuallyHeadNode.next;
    }
}

Leetcode.707设计链表

题目链接:https://leetcode.cn/problems/design-linked-list/description/

题目分析:设计链表实现以下几个函数:(使用添加虚头节点方式实现简化以下操作)

        类成员定义,构造函数

//java节点的实现类
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; 
}
//MyLinkedList 类内属性及构造函数
class MyLinkedList {
    int size;
    ListNode head;
    public MyLinkedList() {
        this.head = new ListNode(0);
        size = 0;
    }
}
  • get(index):根据索引获得元素
  • 分析:要分为合法与不合法情况,不合法返回-1,合法返回对应索引处的值
  • public int get(int index) {
            //非法:
            //index(max) = size-1;索引size处取不到
            //index(min) = 0;
            if((index<0)||(index>=size)){
                return -1;
            }
            //获取head节点;----thesizeIndex=0
            ListNode currentN = head;
            //获取index处 节点----thesizeIndex=index+1
            for (int i = 0; i <= index; i++) {
                currentN = currentN.next;
            }
            return currentN.val;
    }
  • add:  addAtHead(val) 在头部添加 ;addAtTail(val) 在尾部添加;addAtIndex(index,val)在index索引前添加
  • 分析:将三个add方法均看作为一个方法
    • index = 0头部插入 addAtTail(val)
    • index = size尾部插入 addAtTail(val)
    • 0
    • index<0  或者 index>size 为不合法范围
  • public void addAtIndex(int index, int val) {
            //不合法范围
            if (index > size) {
                return;
            }
            if (index < 0) {
                index = 0;
            }
            //找index-1位置元素---sizeindexI = index;
            //sizeindexI = 0;
            ListNode pred = head;
            //如果在头部,就不进入for循环
            //sizeindexI = index;   index-1
            for (int i = 0; i < index; i++) {
                pred = pred.next;
            }
            //连接
            ListNode toAdd = new ListNode(val);
            toAdd.next = pred.next;//如果在尾部的时候,pred.next =null
            pred.next = toAdd;
            size++;
        }
        public void addAtHead(int val) {
            addAtIndex(0, val);
        }
        
        public void addAtTail(int val) {
            addAtIndex(size, val);
        }
  • deleteAtIndex(index) 删除对应索引处元素
    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) {
            return;
        }
        size--;
        //如果删除的是头节点,直接执行
        if (index == 0) {
            head = head.next;
	        return;
        }
        //非头节点 找到index-1  sizeIndexI=index;
        //sizeIndexI=0;
        ListNode pred = head;
        //sizeIndexI=index;
        for (int i = 0; i < index ; i++) {
            pred = pred.next;
        }
        //删除
        pred.next = pred.next.next;
    }

总结:在添加虚拟头节点后,主要需要注意 合法范围、边界点的处理,还有就是添加到是很好语句顺序不能颠倒;明天补充学习用双向链表的题解


Leetcode206.链表翻转

题目链接:https://leetcode.cn/problems/reverse-linked-list/description/

题目分析:使用双指针链表思想实现翻转,大致步骤如下

  1. 初始化ListNode pre、cur  分别为null 、head
  2. 取cur.next 的值,存为临时变量,放置后面cur-》pre时失去连接;temp  = cur.next
  3. cur,pre移动:先移动pre pre = cur; 再移动 cur cur = temp;(如果先移动cur temp会无法找到前一个cur,失去连接)
  4. tips:终止条件 pre指向最后一个元素即新的head,此时 cur也就指向了NULL;
  5. 故返回到条件是 pre(head)
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur != null){
            ListNode temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        return pre; 
    }
}

总结:206,203两题思路比较清晰,但是707再写还是很混乱在边界点处 size 与 index关系容易判断不好,还需要再练,明天要把707双向链表的题解消化实现,还有就是206链表翻转 还可以使用递归的方法实现,听了一次视频讲解还是很晕,明天梳理之后看看能不能理解,如果可以再补充实现代码。

视频链接我也放在下面了:https://www.bilibili.com/video/BV1nB4y1i7eL/?vd_source=83dc9f68f506e8a2be88d095001c1ba5 

你可能感兴趣的:(算法,链表,数据结构)