前沿:撰写博客的目的是为了再刷时回顾和进一步完善,其次才是以教为学,所以如果有些博客写的较简陋,是为了保持进度不得已而为之,还请大家多多见谅。
预:看到题目后的思路和实现的代码。
见:参考答案展示。
感思:对比答案后的思考,与之前做过的题目是否有关联。
行:
(1)对于没做出来的题目,阅读答案后重新做一遍;
(2)下次做题可以尝试改善的方向;
(3)有助于理解的相关的题目
优先级:做题进度>学习&总结>默写回顾>做题数量
链表基础
为什么使用链表?
链表相对于数组的优势在于其便于插入和删除,而数组存储在连续的地址中,全部替换才能达到“删除”效果。
为什么链表便于插入和删除/时间复杂度n(1)?
与链表的存储和获取下一链表的方式有关。因为链表的存储是不连续的,而数组则是连续存储,链表其通过指针来获取下个节点的位置,所以只需要直接修改指针域则能够插入和删除指针。
链表的定义:链表结构中有指针域和val,val存储对于值,通过指针域来连接下个节点,单链表只有next,而双链表的指针域还有pre。
如何使用链表?
类似数组的创建形式:ListNode 名称 = new ListNode();
203. 移除链表元素
题目链接: 203. 移除链表元素
给你一个链表的头节点
head
和一个整数val
,请你删除链表中所有满足Node.val == val
的节点,并返回 新的头节点 。
输入:head = [1,2,6,3,4,5,6], val = 6 输出:[1,2,3,4,5]提示:
- 列表中的节点数目在范围
[0, 104]
内1 <= Node.val <= 50
0 <= val <= 50
实现代码
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode pre = dummyNode;
ListNode cur = dummyNode.next;
while(cur != null){
if(cur.val == val){
pre.next = cur.next; // pre.next.next = pre.next;
}else{ // 没有否定,直接后面增加pre = pre.next;
pre = cur;
}
cur = cur.next;
}
return dummyNode.next;
}
}
与题解区别
ListNode dummyNode = new ListNode();
dummyNode.next = head;
上面的代码块能够通过直接调用构造函数实现
ListNode dummyNode = new ListNode(-1,head);
707. 设计链表
思路图
实现代码
链表的定义+链表实现相关操作类
class ListNode{
int val;
ListNode next;
public ListNode(){
}
public ListNode(int val){
this.val = val;
}
}
class MyLinkedList {
ListNode head = new ListNode();
int len = 0;
public MyLinkedList() {
}
public int get(int index) {
if(index < 0 || index >= len){
return -1;
}
ListNode cur = head.next;
while(index != 0 && cur != null){
cur = cur.next;
index--;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0,val);
}
public void addAtTail(int val) {
addAtIndex(len,val);
}
public void addAtIndex(int index, int val) {
if(index < 0){
index = 0;
}else if(index > len){
return;
}
ListNode cur = head.next;
ListNode pre = head;
ListNode temp = new ListNode(val);
while(index != 0 && cur != null){
cur = cur.next;
pre = pre.next;
index--;
}
temp.next = cur;
pre.next = temp;
len++;
}
public void deleteAtIndex(int index) {
if(index < 0 || index >= len){
return;
}
ListNode cur = head;
while(index != 0 && cur.next != null){
cur = cur.next;
index--;
}
cur.next = cur.next.next;
len--;
}
}
与题解的区别
1.定义中少了构造器初始多属性的方法
- 无参构造器为属性设置默认初始值
class ListNode{
public ListNode(int val,ListNode next}{
this.val = val;
this.next = next;
}
}
class MyLinkedList {
int len;
ListNode head;
public MyLinkedList() {
head = new ListNode(0);
len = 0;
}
2. 能够直接通过改动变量+前节点变量直接添加新变量
public void addAtIndex(int index, int val) {
ListNode pre = head;
for(int i = 0;i < index;i++){
pre = pre.next;
}
ListNode toAdd = new ListNode(val);
toAdd.next = pre.next; //可能会空指针报错
pre.next = toAdd;
len++;
}
206. 反转链表
思路图
题解代码
class Solution {
public ListNode reverseList(ListNode head) {
// ListNode dummyNode = new ListNode(-1,head);
ListNode pre = null;
ListNode cur = head;
ListNode temp = null;
while(cur != null){
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
为什么二刷时仍然画不出来呢?
二刷:思考10分钟,感觉总是画不出循环遍历的闭环。
看完题解总结后,重新思考一下子就顺着题解写出来,但对于当时为什么画不出来就想不到了。
所以,当思考后做不出来时,要将画的思路图拍照或写下来的形式记录下来,因为问题是顽固的。
为什么三刷时画出来了还做不出来?
三刷:
看到这题就想到要画出来再实现,前面10分钟画出来的有问题,之后找到的正确画法(如下图),但仍实现有问题,就在纠结是否是顺序问题。
有问题代码如下
class Solution {
public ListNode reverseList(ListNode head) {
ListNode dummyNode = new ListNode();
dummyNode.next = head;
ListNode pre = dummyNode;
ListNode cur = head;
ListNode temp = head;
while(temp.next != null){
temp = temp.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return cur;
}
}
代码实现与画图不一致
实现代码中是dummyNode指向head,并不是如图上面的head指向dummyNode;
- cur.next = pre→导致dummyNode和cur成环了;