203.移除链表元素
题目链接:203. 移除链表元素 - 力扣(LeetCode)
对于链表的题目,主要是分为两种处理方式,一种是创建虚拟头结点的方式,一种是不创建的方式,创建虚拟头结点,其余节点的处理逻辑就可以统一化,不需要单独处理头结点,如果不创建虚拟头结点,那么就需要单独处理虚拟头结点。
带虚拟头结点的写法:
public ListNode removeElements(ListNode head, int val) {
// 带头结点的解法
ListNode nHead = new ListNode(-1, head);
ListNode p = nHead;
while(p.next != null){
if(p.next.val != val){
p = p.next;
}
else{
p.next = p.next.next;
}
}
return nHead.next;
}
不带虚拟头结点的写法:
public ListNode removeElements(ListNode head, int val) {
//不带头结点的解法
ListNode p = head;
while(p != null && p.val == val){
p = p.next;
}
if(p == null) return null;
else{
//头结点为p
ListNode q = p; // 这里又创建一个结点q的原因是需要将p作为头结点返回,因为最初的head可能已经被移除了
while(q.next != null){
if(q.next.val != val){
q = q.next;
}
else{
q.next = q.next.next;
}
}
}
return p;
}
707.设计链表
题目链接:Loading Question... - 力扣(LeetCode)
该题目就是实现以下链表中的函数
单链表的实现方法如下:
单链表实现
class ListNode{
int val;
ListNode next;
ListNode(){}
ListNode(int val){
this.val = val;
}
}
class MyLinkedList {
// 链表的长度,方便addAtTail
int size;
// 虚拟头节点
ListNode head;
ListNode p;
public MyLinkedList() {
head = new ListNode(-1);
size = 0;
}
public int get(int index) {
if(index < 0 || index >= size) return -1;
p = head;
while(index > -1){
p = p.next;
index--;
}
return p.val;
}
public void addAtHead(int val) {
ListNode hnode = new ListNode(val);
hnode.next = head.next;
head.next = hnode;
size++;
}
public void addAtTail(int val) {
p = head;
while(p.next != null){
p = p.next;
}
ListNode tnode = new ListNode(val);
p.next = tnode;
size++;
}
public void addAtIndex(int index, int val) {
if(index <= 0){
addAtHead(val);
return;
}
if(index > size) return;
if(index == size){
addAtTail(val);
return;
}
p = head;
while(index > 0){
p = p.next;
index--;
}
ListNode iNode = new ListNode(val);
iNode.next = p.next;
p.next = iNode;
size++;
}
public void deleteAtIndex(int index) {
if(index < 0 || index >= size) return;
p = head;
while(index > 0){
p = p.next;
index--;
}
p.next = p.next.next;
size--;
}
}
双链表的实现方式如下:
// 双链表实现
class ListNode{
int val;
ListNode next,pre;
ListNode(){}
ListNode(int val){
this.val = val;
}
}
class MyLinkedList {
// 链表的长度,方便addAtTail
int size;
// 虚拟头节点
ListNode head;
// 虚拟尾节点
ListNode tail;
ListNode p;
public MyLinkedList() {
head = new ListNode(-1);
tail = new ListNode(-1);
head.next = tail;
tail.pre = head;
size = 0;
}
public int get(int index) {
if(index < 0 || index >= size) return -1;
p = head;
while(index > -1){
p = p.next;
index--;
}
return p.val;
}
public void addAtHead(int val) {
ListNode hnode = new ListNode(val);
hnode.next = head.next;
hnode.next.pre = hnode;
head.next = hnode;
hnode.pre = head;
size++;
}
public void addAtTail(int val) {
ListNode tnode = new ListNode(val);
tnode.next = tail;
tnode.pre = tail.pre;
tnode.pre.next = tnode;
tail.pre = tnode;
size++;
}
public void addAtIndex(int index, int val) {
if(index <= 0){
addAtHead(val);
return;
}
if(index > size) return;
if(index == size){
addAtTail(val);
return;
}
p = head;
while(index > 0){
p = p.next;
index--;
}
ListNode iNode = new ListNode(val);
iNode.next = p.next;
iNode.next.pre = iNode;
p.next = iNode;
iNode.pre = p;
size++;
}
public void deleteAtIndex(int index) {
if(index < 0 || index >= size) return;
p = head;
while(index > 0){
p = p.next;
index--;
}
p.next = p.next.next;
p.next.pre = p;
size--;
}
}
该题目需要留意的一点是代码复用的问题,前面实现的功能在后续的代码功能实现中是否可以复用,这个是值得思考的一个问题。
206.反转链表
带头结点的版本:
public ListNode reverseList(ListNode head) {
// 带头结点的版本
if(head == null || head.next == null) return head;
ListNode nHead = new ListNode(-1);
ListNode p = head;
while(p != null){
ListNode q = p.next;
p.next = nHead.next;
nHead.next = p;
p = q;
}
return nHead.next;
}
不带头结点的版本:
public ListNode reverseList(ListNode head) {
// 不带头结点的版本
if(head == null || head.next == null) return head;
ListNode p = head; // p永远是断链前面那段的头结点,q是锻炼后那段的头结点
ListNode q = p.next;
p.next = null;
while(q != null){
ListNode r = q.next;
q.next = p;
p = q;
q = r;
}
return p;
}
\