IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 代码随想录算法训练营第三天| 203.移除链表元素 707.设计链表 206.反转链表 -> 正文阅读

[数据结构与算法]代码随想录算法训练营第三天| 203.移除链表元素 707.设计链表 206.反转链表

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
输出:[]

看到题目第一想法

最直观的想法,分情况讨论是否是头节点。是头节点,直接改变头结点位置。不是头结点,就将应删除节点上一个节点直接指向下下个节点。
注意:操作节点前要判断是否为空。

//伪代码
//移除头节点
//判断头节点不为空,不然就是操纵空指针了,编译报错
//if(head!=null&&head->val==target)不对头节点应持续移除,例如1 1 1 1 1 100 移除1
while(head!=null&&head->val==target)
  head=head->next
cur=head;//临时指针指向头节点  定义临时指针用来遍历,不能用头结点遍历,最后返回不了应该返回的头节点
while(cur!=null &&cur->next!=null )//cur不能为空 cur->next也不为空 因为我们要取值和target对比,不然就是操纵空指针了,编译报错
    if(cur->next==target)  //cur的下一个节点应删除
       cur->next=cur->next->next//cur的下一个节点为当前cur的下一个下一个节点
    else cur=cur->next
    //必须放else  cur当前节点前面判断过不是val;只有cur下一个经过if判断也不是才能将临时指针后移
    /* 若 if(cur->next==target) 
       cur->next=cur->next->next/
     cur=cur->next         则未判断下一个的下一个要不要删除*/
return 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 removeElements(ListNode head, int val) {
     //不采用虚拟头节点
     while(head!=null && head.val==val){
         head=head.next;
     }
    ListNode cur=head;
    while(cur!=null&&cur.next!=null){//cur!=null要加上 不判断的话 cru=null那么不存在next
        if(cur.next.val==val){
            cur.next=cur.next.next;
        }else{cur=cur.next;}
    }
    return head;
    }
}


学习之后

发现通过引入虚拟节点可以不用单独分出头节点来讨论。
在这里插入图片描述
这里来给链表添加一个虚拟头结点为新的头结点,此时要移除这个旧头结点元素1。
这样就可以使用和移除链表其他节点的方式了,最后在题目中,return 头结点的时候,别忘了 return dummyNode->next;, 这才是新的头结点。

//伪代码
//虚拟头节点dummy head  统一链表操作操作
dummy head=new();
dummyhead->next=head;
cur=dummyhead//不等于dummyhead->next 因为要删的是cur->next,当前是head
while(cur->next!=null)
    if (cur->next->val==target)
        cur->next=cur->next->next;
    else cur=cur->next
return dammyhead->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 (1,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; }

虚拟头节点,cur临时指针=虚拟头节点。

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获取第n各节点的值(节点地址从0开始)
2头部插入节点
3尾部插入节点
4第n个节点前插入节点
5删第n个节点*/
//本题均采用虚拟头节点
//1
cur =dummyhead.next//遍历链表一定新建临时指针不能直接操作头指针 因为最后要返回头指针
while(n){//循环条件带入边界验证是否满足  n=0头节点 跳出循环; n=1第二个节点 
    cur=cur.next
    n--
}
return cur.val
//2
ListNode newNode= new ListNode();
newNode.next=dummyhead.next;//先后后前 
 dummyhead.next=newNode;
return dummyhead.next
//3
cur=dummyhead
while(cur.next!=null){
    cur=cur.next
}
ListNode newNode =new ListNode()
cur.next=newnode
//4  在第n个节点前插入  即 cur n-1    cur.next n 这两个节点之间操作  第n个节点为cur.next
cur=dummyhead
while(n--){//举极端例子验证
    cur=cur.next
}
newNode.next=cur.next;
cur.next=newNode
size++
//5  n为cur.next  才能删掉  直接cur.next=cur.next.next; 写之前先想明白 n是cur.next
cur=dummyhead 
while(n){//极端例子 只有一个节点 删除第0个节点 
    cur=cur.next
    n--
}
cur.next=c
size--

 //写了之后发现报错查了半天发现忘了更新size大小了
class ListNode{    
    int val ;
    ListNode next;
    public ListNode(){};
    public ListNode(int val){
        this.val=val;
    }}
class MyLinkedList {
    int size;//记录链表大小          
    ListNode dummyHead;//虚拟头节点
    
    public MyLinkedList() {//初始化
      dummyHead=new ListNode(-1);
      size=0;//只有虚拟头节点所以大小为0
        }

    public int get(int index) {
        if(index<0||index>=size){
            return -1;
        }else{
            ListNode cur=dummyHead;//所有临时指针均指向虚拟头节点
            while(index!=0){
                cur=cur.next;
                index--; }
            return cur.next.val;
        }
    }
    
    public void addAtHead(int val) {
        ListNode newNode=new ListNode(val);
        newNode.next=dummyHead.next;
        dummyHead.next=newNode;
        size++;
        return ;
    }
    
    public void addAtTail(int val) {
        ListNode newNode= new ListNode(val);
        ListNode cur=dummyHead;
        while(cur.next!=null){
            cur=cur.next;
        }
        cur.next=newNode;
        size++;
        return;
    }
    
    public void addAtIndex(int index, int val) {
        if(index>size){return;}
        ListNode newNode=new ListNode(val);
        ListNode cur= dummyHead;
        if(index<0){
            addAtHead(val);
            return ;
        }        
        while(index--!=0){
            cur=cur.next;
        }
        newNode.next=cur.next;
        cur.next=newNode;
        size++;
        return;
    }
    
    public void deleteAtIndex(int index) {
        if(index<0||index>=size){//地址0开始最多size-1
        return ;}
        ListNode cur=dummyHead;
        while(index--!=0){//JAVA不能直接写while(index)
            cur=cur.next;
        }
        cur.next=cur.next.next;
        size--;
        return ;}
}

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

针对第n个数进行操作,让cur.next=该数。

206.反转链表

题意:反转一个单链表。
示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL

在这里插入图片描述
在这里插入图片描述

看到题目第一想法

只需要改变链表的next指针的指向,直接将链表反转,无需增加删除节点。
在这里插入图片描述
针对此题需要两个指针一个指当前节点,一个指当前节点的前节点,用来转换指针方向,还需要一个临时节点来寄存原来节点的下一个节点,用来移动前面两个定位的节点。
首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。
然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。
为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。
最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。
在这里插入图片描述

//伪代码
//双指针pre改方向 cur 遍历
//初始化  共需要三个临时指针
cur=head 
pre=null
while(cur==null){//终止条件cur=null 不能是null 空指针异常 也不能是cur.next=null 此时pre不是头节点,寻找不变量 
//一开始 pre=null cur=head,最后pre=head,cur=null
 temp=cur.next;//先保存原来下一个节点
 cur.next=pre;
 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 reverseList(ListNode head) {
        ListNode cur=head;
        ListNode pre=null;
        ListNode temp;
        while(cur!=null){
            temp=cur.next;
            cur.next=pre;
            pre=cur;
            cur=temp;
        }
        return pre;
    }
}

递归法

递归法相对抽象一些,但是其实和双指针法是一样的逻辑,同样是当cur为空的时候循环结束,不断将cur指向pre的过程。
关键是初始化的地方,可能有的同学会不理解, 可以看到双指针法中初始化 cur = head,pre = NULL,在递归法中可以从如下代码看出初始化的逻辑也是一样的,只不过写法变了。
递归法本质就是自己调用自己的方法。

//递归与双指针接法一一对应
//自定义reverse函数
reverse(cur,pre)
if(cur==null){
    return pre;
}
temp=cur.next;//先保存下一个节点的位置
cur.next=pre;//然后改变方向
reverse(temp,cur);//递归调用自己方法;

//输入函数reverseList(head)
reverseList(head){
   return  reverse(head,null)
}
//递归报错代码
/**
 * 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) {
     
        return reverse(head,null);}

    public ListNode reverse(ListNode cur,ListNode pre){
    ListNode temp=cur.next; //报错[]不符,要先判断 cur是否为[]
    cur.next=pre;
    if(temp!=null){
        return reverse(temp,cur);
    }
     return cur;}}


```//递归
/**
 * 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) {
     
        return reverse(head,null);}

    public ListNode reverse(ListNode cur,ListNode pre){
   if(cur==null){
       return pre;}
    ListNode temp=cur.next;
    cur.next=pre;
     return reverse(temp,cur);} 

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 21:19:25  更:2022-09-24 21:19:56 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:21:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码