- leetcode 203 移除链表元素 easy
题目链接: leetcode.com/problems/re…
思路: 利用dummynode方便实现全部节点共同操作,用pre节点和cur节点根据不同条件的改变而调节链表的链接关系。
代码:
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummynode = new ListNode(-1, head);
ListNode pre = dummynode;
ListNode cur = head;
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
} else {
pre = pre.next;
}
cur = cur.next;
}
return dummynode.next;
}
}
提交报错 (2):
第1次: 错误总结,pre节点的改变需要分为不同情况,而不是像cur一样每次都改变。
第2次: 返回链表, dummynode是为了方便操作所创建的虚拟头结点,返回结果列表应从next起始。
- leetcode 707 设计链表 medium
题目链接: leetcode.com/problems/de…
思路: 链表题优先使用dummynode,但要想清楚在实际操作中dummynode会引起哪些变化,尤其在边界值问题。实现数据结构的题目代码量一定很大,耐住性子一点点根据需求补足所需代码也是关键点。链表结构的特殊属性就是size和虚拟头结点。
代码:
class LinkNode {
int val;
LinkNode next;
public LinkNode () {}
public LinkNode (int val) {
this.val = val;
}
public LinkNode (int val, LinkNode next) {
this.val = val;
this.next = next;
}
}
class MyLinkedList {
ListNode node;
private int size = 0;
public MyLinkedList () {
this.size = 0;
node = new ListNode(-1, null);
}
public int get (int index) {
ListNode cur = this.node;
if (index >= this.size || index < 0) {
return -1;
}
while (index >= 0) {
cur = cur.next;
index--;
}
return cur.val;
}
public void addAtHead (int val) {
addAtIndex(0, val);
}
public void addAtTail (int val) {
addAtIndex(this.size, val);
}
public void addAtIndex (int index, int val) {
if (index > this.size) return;
if (index < 0) index = 0;
this.size++;
ListNode cur = this.node;
while (index > 0) {
cur = cur.next;
index--;
}
ListNode newNode = new ListNode(val);
newNode.next = cur.next;
cur.next = newNode;
}
public void deleteAtIndex (int index) {
if (index < 0 || index >= this.size) return;
this.size--;
ListNode cur = this.node;
if (index == 0) {
this.node = this.node.next;
return;
}
while (index > 0) {
cur = cur.next;
index--;
}
cur.next = cur.next.next;
}
}
提交报错 (8):
第1次: LinkNode类缺失单val参数的构造函数,在代码量大,特殊情况多时,难以预料具体需要使用哪种constructor,可以把没种都实现一遍。
第2次: MyLinkedList构造函数无参生成虚拟头结点的构造方法没考虑清楚。
第3次: get方法写错。将index > this.size改成index >= this.size解决。
原因是边界值问题,在查询时,index == size的情况已经越界.
第4次: addAtTail是通过addAtIndex来实现的,在给addAtIndex传参时出现了错误。
将addAtIndex(this.size - 1, val);改成addAtIndex(this.size, val);解决。
原因是边界值问题,插入时index = size的情况正是尾插。
第5次: addAtIndex是整个代码的重点部分,理论上包含了3个函数的实现。而代码逻辑最为混乱,整个代码段参考卡哥重构。
第6次: deleteAtIndex和addAtIndex在while循环时没想清楚再增删时,要找到的节点正是index - 1。
第7次: get方法错将while(index >= 0)写成while(index > 0)导致输出错误。原因是没想清楚边界值,要找的位置是index本身,而不是index-1的位置。
第8次: deleteAtIndex方法想不清边界情况,加了dummy以后,cur=cur.next与给定链表index刚好一致。
index == 0的情况是例外,只有一个节点,需要特殊处理删除。
- leetcode 206 反转链表 easy
题目链接: leetcode.com/problems/re…
思路: 事先理清楚改变节点方向的过程是2个节点改变指向,然后改变节点位置。cur节点最终会出链表,因此返回pre才是改变后的头结点。
迭代代码:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode pre = null;
ListNode cur = head;
while (cur != null) {
ListNode tmp = cur.next;
cur.next = pre;
pre = cur;
cur = tmp;
}
return pre;
}
}
提交报错 (2):
第1次: 在改变前两个节点的指向后,画蛇添足改变了tmp第三节点的指向再移动节点,实际上只需要与tmp、cur交换变化节点即可。
第2次: 总结,dummynode需改用null,因为它最终会作为反转后链表的最后一个节点的指向。
递归代码:
class Solution {
public ListNode reverseList(ListNode head) {
return reverseNode(null, head);
}
public ListNode reverseNode(ListNode prev, ListNode cur) {
if (cur == null) {
return prev;
} else {
ListNode tmp = cur.next;
cur.next = prev;
return reverseNode(cur, tmp);
}
}
}
提交报错 (1):
第1次: 递归需要重新写一个函数能够交换两个节点形参,从头部位置开始传参,直到最终cur为null证明链表结束。递归在实现改变2个节点指向的同时,也需要递归交替移动2个节点位置。