leetcode题目地址: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
的节点。1.就是简单的链表模拟实现,没什么逻辑上的难度。
class MyLinkedList {
private class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
ListNode head = null;
public MyLinkedList() {}
public int get(int index) {
ListNode temp = this.head;
for (int i = 0; i < index; i++) {
if (temp.next == null) { return -1; }
temp = temp.next;
}
return temp.val;
}
public void addAtHead(int val) {
if (this.head == null) {
ListNode newHead = new ListNode(val);
this.head = newHead;
} else {
ListNode newHead = new ListNode(val, this.head);
this.head = newHead;
}
System.out.println("add head"+head.val);
}
public void addAtTail(int val) {
if (head == null){
ListNode newHead = new ListNode(val);
head = newHead;
}
ListNode temp = this.head;
System.out.println("add tail head"+temp.val);
while (temp.next != null) {
System.out.println("add tailffffffffff"+temp.val);
temp = temp.next;
}
ListNode newTail = new ListNode(val);
temp.next = newTail;
System.out.println("add tail new"+newTail.val);
print();
}
public void addAtIndex(int index, int val) {
ListNode temp = this.head;
if (index == 0){
addAtHead(val);
return;
}
for (int i = 0; i < index - 1; i++) {
if (temp.next == null) {
if (i == index - 1) {
addAtTail(val);
}else {
return;
}
}
temp = temp.next;
}
System.out.println("add index now" + temp.val);
ListNode newNode = new ListNode(val, temp.next);
temp.next = newNode;
System.out.println("add index temp" + temp.val);
System.out.println("add index" + newNode.val);
print();
}
public void deleteAtIndex(int index) {
ListNode temp = this.head;
if (index == 0){
if (head.next == null){
head = null;
}else {
head = head.next;
}
return;
}
if (head.next == null && index >= 1){
return;
}
print();
for (int i = 0; i < index - 1; i++) {
if (i == index - 1 && temp.next != null && temp.next.next == null) {
temp.next = null;
System.out.println("delete a" + temp.val);
print();
return;
}
if (i <= index - 2 && temp.next.next == null) {
System.out.println("delete b" + temp.val);
print();
return;
}
temp = temp.next;
}
if (temp.next.next == null){
temp.next = null;
} else {
temp.next = temp.next.next;
}
System.out.println("delete c" + temp.val);
print();
}
public void print(){
ListNode temp = this.head;
while (temp.next != null){
System.out.println("ppppp"+temp.val);
temp = temp.next;
}
System.out.println("ppppp"+temp.val);
}
}
1.边界条件的处理,处理的很不清晰。。逻辑太混乱了
2. 改完大部分bug之后,显示“运行超出时间限制”。。(后来发现好像是我print太多了)
【解题思路】采用虚拟头节点统一操作,虚拟节点需要给它随便赋个值,如0。
【想法】
1. 解题的时候,定义while或for里面的变量更新情况时,需要经常考虑边界条件(“0”和最大值),最好想清楚之后再开始写代码。
2. 注意以 “第0个节点” 或 “只有一个节点” 等极端情况去(定位?)考虑其他情况。
3. 其实整个逻辑没什么难度,就是代码的边界条件处理上太差,以及没有使用虚拟头节点,导致无法ACC。看完代码之后,发现整个链表结构还可以存一个size来存储链表的长度。果然选择很重要啊,之前因为不熟悉虚拟节点的具体实现,打算直接用头节点开写,却更麻烦。
class MyLinkedList {
private class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
ListNode head = new ListNode(0);
int size = 0;
public MyLinkedList() {}
public int get(int index) {
if (index >= size){
return -1;
}
ListNode temp = this.head;
for (int i = 0; i <= index; i++) {
temp = temp.next;
}
return temp.val;
}
public void addAtHead(int val) {
ListNode newHead = new ListNode(val);
if (size == 0) {
this.head.next = newHead;
this.size++;
//print();
return;
}
newHead.next = this.head.next;
this.head.next = newHead;
this.size++;
//print();
}
public void addAtTail(int val) {
if (size == 0){
ListNode newTail = new ListNode(val);
this.head.next = newTail;
this.size++;
//print();
return;
}
ListNode temp = this.head;
while (temp.next != null) {
temp = temp.next;
}
ListNode newTail = new ListNode(val);
temp.next = newTail;
this.size++;
//print();
}
public void addAtIndex(int index, int val) {
if (index > size){
return;
}
if (size == 0) {
if (index != 0) {
return;
}else {
addAtHead(val);
this.size++;
return;
}
}
ListNode temp = this.head;
for (int i = 0; i < index ; i++) {
temp = temp.next;
}
ListNode newNode = new ListNode(val);
if (size == index){
temp.next = newNode;
this.size++;
}else {
newNode.next = temp.next;
temp.next = newNode;
this.size++;
//print();
}
}
public void deleteAtIndex(int index) {
if (size == 0 || index >= size) {
return;
}
ListNode temp = this.head;
for (int i = 0; i < index; i++) {
temp = temp.next;
}
if (size - 1 == index){
temp.next = null;
size--;
}else {
temp.next = temp.next.next;
size--;
}
//print();
}
public void print(){
ListNode temp = this.head;
while (temp.next != null){
temp = temp.next;
System.out.println("ppppp"+temp.val);
}
System.out.println("ppppp------------------");
}
}
//单链表
class ListNode {
int val;
ListNode next;
ListNode(){}
ListNode(int val) {
this.val=val;
}
}
class MyLinkedList {
//size存储链表元素的个数
int size;
//虚拟头结点
ListNode head;
//初始化链表
public MyLinkedList() {
size = 0;
head = new ListNode(0);
}
//获取第index个节点的数值,注意index是从0开始的,第0个节点就是头结点
public int get(int index) {
//如果index非法,返回-1
if (index < 0 || index >= size) {
return -1;
}
ListNode currentNode = head;
//包含一个虚拟头节点,所以查找第 index+1 个节点
for (int i = 0; i <= index; i++) {
currentNode = currentNode.next;
}
return currentNode.val;
}
//在链表最前面插入一个节点,等价于在第0个元素前添加
public void addAtHead(int val) {
addAtIndex(0, val);
}
//在链表的最后插入一个节点,等价于在(末尾+1)个元素前添加
public void addAtTail(int val) {
addAtIndex(size, val);
}
// 在第 index 个节点之前插入一个新节点,例如index为0,那么新插入的节点为链表的新头节点。
// 如果 index 等于链表的长度,则说明是新插入的节点为链表的尾结点
// 如果 index 大于链表的长度,则返回空
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
if (index < 0) {
index = 0;
}
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;
}
//删除第index个节点
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
if (index == 0) {
head = head.next;
return;
}
ListNode pred = head;
for (int i = 0; i < index ; i++) {
pred = pred.next;
}
pred.next = pred.next.next;
}
}
8:55 ~ 10:40 解题失败,放弃
16:30 ~ 16:50 + 17:40~19:45 看视频题解、写博客
1. 类实例的初始化不要忘记“new”关键字,ListNode newNode = new ListNode(val, temp.next);。
2. java里“this.para”指的是引用本类的全局变量,应该在类里定义,而不是在构造函数里定义。
3. 链表赋值的时候,node.next 可以暂时为空?
如果node.next为null,可以用在赋值号的右侧代替“null”,但是不能用在赋值号的左侧作为变量。此外,node.next为null时,node.next.next也会报错,因为null不能作为变量(但是可以作为被赋予的值)。