昨天出去旅游了,Day2的任务留到周末再完成吧,今天学习链表!
链表理论基础
借着训练营进度借着再复习一遍数据结构哈哈哈,链表是线性结构,分为以下几种:(图都是用的卡哥资料里的)
分类:
单链表:
双链表:既可以向前查询也可以向后查询
循环链表:首尾相连,可以解决约瑟夫环问题。
构造结点代码:
差不多就这几个分类了,下面是Java中构造链表结点的部分代码:
public 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;
}
}
部分操作:
删除节点:
添加节点:
开始做题!
203.移除链表元素(简单)
给你一个链表的头节点 head
和一个整数 val
,请你删除链表中所有满足 Node.val == val
的节点,并返回 新的头节点 。
示例 1:
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]
思考:之前只是学了些数据结构的理论知识,真正上手做还是拔剑四顾心茫然。。首先创建链表,然后把head中的数逐个加入,最后进行删除操作。
代码实现:
不添加虚拟头结点(简单)
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){//z注意这个循环
head=head.next;
}
if(head==null){//这里别用head.val==null
return head;
}
ListNode node=head;//确保当前结点后还有结点(这一步很关键,勿忘!!)
while (node.next!=null){//注意null情况,勿忘!!这里判断的是node.next而不是node
if(node.next.val==val){
node.next=node.next.next;
}
else node=node.next;//链接下一节点
}
return head;
}
}
添加虚拟头结点(重点!!)
class Solution {
public ListNode removeElements(ListNode head, int val) {
//创建一个虚拟头结点
ListNode dummyNode=new ListNode(val-1);
dummyNode.next=head;
ListNode prev=dummyNode;
//确保当前结点后还有结点
while(prev.next!=null){
if(prev.next.val==val){
prev.next=prev.next.next;
}else{
prev=prev.next;
}
}
return dummyNode.next;
}
}
总结:return的是头结点。链表一定要留意头结点!第一次做这道题真是漏洞百出啊,链表问题总是忘记判断结点是否为空。创建结点部分一定一定要熟练掌握!一些易出错地方也已经标记出来了,以此为例,多加复习吧!
707.设计链表(中等)
你可以选择使用单链表或者双链表,设计并实现自己的链表。
单链表中的节点应该具备两个属性:val
和 next
。val
是当前节点的值,next
是指向下一个节点的指针/引用。
如果是双向链表,则还需要属性 prev
以指示链表中的上一个节点。假设链表中的所有节点下标从 0 开始。
实现 MyLinkedList
类:
MyLinkedList()
初始化MyLinkedList
对象。int get(int index)
获取链表中下标为index
的节点的值。如果下标无效,则返回-1
。void addAtHead(int val)
将一个值为val
的节点插入到链表中第一个元素之前。在插入完成后,新节点会成为链表的第一个节点。void addAtTail(int val)
将一个值为val
的节点追加到链表中作为链表的最后一个元素。void addAtIndex(int index, int val)
将一个值为val
的节点插入到链表中下标为index
的节点之前。如果index
等于链表的长度,那么该节点会被追加到链表的末尾。如果index
比长度更大,该节点将 不会插入 到链表中。void deleteAtIndex(int index)
如果下标有效,则删除链表中下标为index
的节点。
示例:
输入 ["MyLinkedList", "addAtHead", "addAtTail", "addAtIndex", "get", "deleteAtIndex", "get"] [[], [1], [3], [1, 2], [1], [1], [1]] 输出 [null, null, null, null, 2, null, 3]
思考:这个题就是让你自己写一个链表小项目,这个题我花了不少时间自己写的,结果最后超出时间限制了(心酸Ծ‸Ծ),借鉴了一下标答,也收获了很多。
代码实现:
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
public int get(int index) {
if (index < 0 || index >= size) {
return -1;
}
ListNode cur = head;
for (int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
}
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
index = Math.max(0, index);
size++;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pred.next;
pred.next = toAdd;
}
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
ListNode pred = head;
for (int i = 0; i < index; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}
class ListNode {
int val;
ListNode next;
public ListNode(int val) {
this.val = val;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/design-linked-list/solutions/1840997/she-ji-lian-biao-by-leetcode-solution-abix/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
收获:这个题,我知道了
1.提前要定义好链表大小size和头结点。
2.循环for (int i = 0; i < index; i++) 找到的是目标结点的前一个结点。
虽然收获的知识都挺的。。。。但是有收获才有动力!下一题再战!
206.反转链表(不易)
给你单链表的头节点 head
,请你反转链表,并返回反转后的链表。
思考:初见想新建一个链表,但是太费内存,索性直接去看了卡尔视频。帮你拿下反转链表 | LeetCode:206.反转链表 | 双指针法 | 递归法_哔哩哔哩_bilibili
代码实现:(双指针法)
// 双指针
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;
}
}
首先画图找出规律,再对指针进行初始化,最后循环进行每一步操作。
总结:该题给我最大的收获是学会画图,以及灵活解题,双指针大法高高挂起~明天继续冲冲冲!