你不贪心,便是礼物,你若还期待,便是惩罚。|

颜欢兮

园龄:2年1个月粉丝:1关注:0

代码随想录算法Day03| 链表理论基础 203.移除链表元素 707.设计链表 206.反转链表

链表理论基础

  • 链表分为 单链表双链表循坏链表。
  • 链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。
  • 链表的长度可以是不固定的,并且可以动态增删, 适合数据量不固定,频繁增删,较少查询的场景

203.移除链表元素

题目链接: 203. 移除链表元素 - 力扣(LeetCode)

题目

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == 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
输出:[]

思路

在该题中只需要让节点next指针直接指向下下一个节点就可以了。

但要注意,如果移除的是头结点时该如何操作?

可以考虑两种方法

  • 直接使用原来的链表来进行删除操作 
  • 设置置一个虚拟头结点在进行删除操作

代码

采用虚拟头节点的方式

时间复杂度O(1)

空间复杂度O(n)

复制代码
 1 class Solution {
 2     public ListNode removeElements(ListNode head, int val) {
 3         if (head == null) {
 4             return head;
 5         }
 6         // 因为删除可能涉及到头节点,所以设置dummy节点,统一操作
 7         ListNode dummy = new ListNode(-1, head);
 8         ListNode pre = dummy; // 进行操作的节点
 9         ListNode cur = head; // 当前访问的节点
10         while (cur != null) {
11             if (cur.val == val) {
12                 pre.next = cur.next; //让节点next指针直接指向下下一个节点,
13             } else {
14                 pre = cur; // 更新需要操作的节点
15             }
16             cur = cur.next; // 更新当前节点
17         }
18         return dummy.next;
19     }
20 }
复制代码

不添加虚拟节点的方式

时间复杂度O(1)

空间复杂度O(n)

复制代码
 1 class Solution {
 2     public ListNode removeElements(ListNode head, int val) {
 3         //确保头结点的val != val
 4         //当第一个节点等于 val 时,此时由于没有虚拟节点,无法移除第一个节点 
 5         //所以在前面要先确定第一个节点不等于val
 6         while(head != null && head.val == val){
 7             head = head.next;
 8         }
 9 
10         if(head == null){
11             return head;
12         }
13         //不添加虚拟节点
14         ListNode pre = head;
15         //确定头结点不为val
16         ListNode cur = head.next;
17         while(cur != null){
18             if(cur.val == val){
19                 pre.next = cur.next;
20             }else{
21                 pre = cur;
22             }
23             cur = cur.next;
24         }
25         return head;
26     }
27 }
复制代码

不使用 虚拟节点 和 pre 节点 的方式

复制代码
 1 public ListNode removeElements(ListNode head, int val) {
 2     while(head!=null && head.val==val){
 3         head = head.next;
 4     }
 5     ListNode curr = head;
 6     while(curr!=null){
 7         while(curr.next!=null && curr.next.val == val){
 8             curr.next = curr.next.next;
 9         }
10         curr = curr.next;
11     }
12     return head;
13 }
复制代码

707.设计链表

 

题目链接: 707. 设计链表 - 力扣(LeetCode)

题目

设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。

在链表类中实现这些功能:

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

示例:

MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //现在链表是1-> 3
linkedList.get(1); //返回3

思路

本题目考察对链表的常见操作。

设计一个 虚拟头节点 较容易解决。

代码

单链表

复制代码
  1 //单链表
  2 class ListNode {
  3     int val;
  4     ListNode next;
  5     ListNode(){}
  6     ListNode(int val) {
  7         this.val=val;
  8     }
  9     ListNode(int val,ListNode next) {
 10         this.val=val;
 11         this.next = next;
 12     }
 13 }
 14 class MyLinkedList {
 15     //size存储链表元素的个数
 16     int size;
 17     //虚拟头结点
 18     ListNode head;
 19 
 20     //初始化链表
 21     public MyLinkedList() {
 22         size = 0;
 23         head = new ListNode(0);
 24     }
 25 
 26     //获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
 27     public int get(int index) {
 28         //如果index非法,返回-1
 29         if (index < 0 || index >= size) {
 30             return -1;
 31         }
 32         ListNode currentNode = head;
 33         //包含一个虚拟头节点,所以查找第 index+1 个节点
 34         for (int i = 0; i <= index; i++) {
 35             currentNode = currentNode.next;
 36         }
 37         return currentNode.val;
 38     }
 39 
 40     //在链表最前面插入一个节点,等价于在第0个元素前添加
 41     public void addAtHead(int val) {
 42         addAtIndex(0, val);
 43     }
 44 
 45     //在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
 46     public void addAtTail(int val) {
 47         addAtIndex(size, val);
 48     }
 49 
 50     // 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
 51     // 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
 52     // 如果 index 大于链表的长度,则返回空
 53     public void addAtIndex(int index, int val) {
 54         if (index > size) {
 55             return;
 56         }
 57         if (index < 0) {
 58             index = 0;
 59         }
 60 
 61         size++;
 62         
 63         //找到要插入节点的前驱
 64         ListNode pred = head;
 65         for (int i = 0; i < index; i++) {
 66             pred = pred.next;
 67         }
 68         //插入节点
 69         ListNode toAdd = new ListNode(val);
 70         toAdd.next = pred.next;
 71         pred.next = toAdd;
 72     }
 73 
 74     //删除第index个节点
 75     public void deleteAtIndex(int index) {
 76         if (index < 0 || index >= size) {
 77             return;
 78         }
 79         size--;
 80         if (index == 0) {
 81             head = head.next;
 82         return;
 83         }
 84         ListNode pred = head;
 85         for (int i = 0; i < index ; i++) {
 86             pred = pred.next;
 87         }
 88         //删除节点
 89         pred.next = pred.next.next;
 90     }
 91 }
 92 
 93 
 94 /**
 95  * Your MyLinkedList object will be instantiated and called as such:
 96  * MyLinkedList obj = new MyLinkedList();
 97  * int param_1 = obj.get(index);
 98  * obj.addAtHead(val);
 99  * obj.addAtTail(val);
100  * obj.addAtIndex(index,val);
101  * obj.deleteAtIndex(index);
102  */
复制代码

双链表

 

206.反转链表 

题目链接: 206. 反转链表 - 力扣(LeetCode)

题目

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

示例 1:

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

示例 2:

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

示例 3:

输入:head = []
输出:[]

思路

改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。

方法:双指针法递归法

代码

双指针法

复制代码
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;
    }
}
复制代码

 

本文作者:颜欢兮

本文链接:https://www.cnblogs.com/xpp3/p/17092473.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   颜欢兮  阅读(15)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 《起风了》 林俊杰
  2. 2 晴天 (Live) 林俊杰,周杰伦
  3. 3 兰亭序 (Live) 周杰伦
  4. 4 反方向的钟 (Live) 我也不太了解她
晴天 (Live) - 林俊杰,周杰伦
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

晴天 (Live) - 林俊杰 (JJ Lin)/周杰伦 (Jay Chou)

词:周杰伦

曲:周杰伦

故事的小黄花

从出生那年就飘着

童年的荡秋千

随记忆一直晃到现在

Re so so si do si la

So la si si si si la si la so

唱好朋友写的歌

唱好朋友写的歌

其实我是来找你打电动的

为你翘课的那一天

花落的那一天

教室的那一间

我怎么看不见

消失的下雨天

我好想再淋一遍

没想到失去的勇气我还留着

没想到失去的勇气我还留着

好想再问一遍

好想再问一遍

你会等待还是离开

刮风这天我试着握着你手

刮风这天我试着握着你手

但偏偏雨渐渐大到我看你不见

还要多久我才能在你身边

还要多久我才能在你身边

等到放晴的那天

也许我会比较好一点

从前从前有个人爱你很久

但偏偏风渐渐把距离吹得好远

好不容易又能再多爱一天

好不容易又能再多爱一天

但故事的最后你好像还是说了拜拜

为你翘课的那一天

为你翘课的那一天

教室的那一间

花落的那一天

我怎么看不见

消失的下雨天

我好想再淋一遍

没想到失去的勇气我还留着

没想到失去的勇气我还留着

好想再问一遍

你会等待还是离开

刮风这天我试着握着你手

但偏偏雨渐渐大到我看你不见

还要多久我才能在你身边

还要多久我才能在你身边

等到放晴的那天

也许我会比较好一点

从前从前有个人爱你很久

但偏偏风渐渐把距离吹得好远

好不容易又能再多爱一天

好不容易又能再多爱一天

但故事的最后你好像还是说了拜拜

但故事的最后你好像还是说了拜拜

但故事的最后你好像还是说了拜拜