203.移除链表元素
203题目链接
对于单链表来说,想要删除某个节点,需要通过指向它的上一个节点,这是单链表的特性。 为啥有了虚拟头结点,还需要再定义一个 current 节点指向虚拟头结点,是因为虚拟头结点是不能改变的,对于本题来说,返回的是它的下一个节点。current 临时指针 是用来遍历整个链表的,如果使用头结点进行遍历的话,头结点是在不断发生改变的,最后就无法返回原先列表的头结点,所以说头结点的指针是不能改的。 此外,对比了是否设置虚拟头结点两种方法。可以发现,设置虚拟头结点,只需要考虑一种情况,更易分析理解。一般建议设置虚拟头节点。
第一种方法不设置虚拟头结点
class Solution {
public :
ListNode* removeElements ( ListNode* head, int val) {
while ( head != NULL && head-> val == val) {
ListNode* tmp = head;
head = head-> next;
delete tmp;
}
ListNode* current = head;
while ( current != NULL && current-> next != NULL ) {
if ( current-> next-> val == val) {
ListNode* tmp = current-> next;
current-> next = current-> next-> next;
delete tmp;
} else {
current = current-> next;
}
}
return head;
}
} ;
第二种方法设置虚拟头结点
class Solution {
public :
ListNode* removeElements ( ListNode* head, int val) {
ListNode* virtualHead = new ListNode ( 0 ) ;
virtualHead-> next = head;
ListNode* current = virtualHead;
while ( current-> next != NULL ) {
if ( current-> next-> val == val) {
ListNode* tmp = current-> next;
current-> next = current-> next-> next;
delete tmp;
} else {
current = current-> next;
}
}
head = virtualHead-> next;
delete virtualHead;
return head;
}
} ;
206.反转链表
206题目链接
对于单链表,想要访问里面的元素,只能通过上一个节点。所以要想实现链表内元素之间的交换,则需要在靠后的一个节点交换之前,把该节点的next 值提前保存下来,思路类似与交换两个数的值。 对于递归写法的话,尽量先把双指针法理解清楚,然后在写。递归方法可以理解为双指针法循环的另一种写法。首先需要把current 的下一个存下来,然后再去交换。
第一种方法双指针法
class Solution {
public :
ListNode* reverseList ( ListNode* head) {
ListNode* before = NULL ;
ListNode* current = head;
ListNode* tmp;
while ( current != NULL ) {
tmp = current-> next;
current-> next = before;
before = current;
current = tmp;
}
return before;
}
} ;
第二种方法递归法
class Solution {
public :
ListNode* reverseList ( ListNode* head) {
ListNode* before = NULL ;
ListNode* current = head;
return reverse ( before, current) ;
}
ListNode* reverse ( ListNode* before, ListNode* current) {
if ( current == NULL ) return before;
ListNode* tmp = current-> next;
current-> next = before;
return reverse ( current, tmp) ;
}
} ;
707.设计链表
707题目链接
在处理链表时,如果比较容易乱,可以通过画草图的方式来梳理思路。
class MyLinkedList {
public :
struct ListNode {
int val;
ListNode * next;
ListNode ( int x) : val ( x) , next ( nullptr ) { }
} ;
MyLinkedList ( ) {
_virtualHead = new ListNode ( 0 ) ;
_size = 0 ;
}
int get ( int index) {
if ( index > ( _size - 1 ) || index < 0 ) {
return - 1 ;
}
ListNode* current = _virtualHead-> next;
while ( index-- != 0 ) {
current = current-> next;
}
return current-> val;
}
void addAtHead ( int val) {
ListNode* addHead = new ListNode ( val) ;
addHead-> next = _virtualHead-> next;
_virtualHead-> next = addHead;
_size++ ;
}
void addAtTail ( int val) {
ListNode* addTail = new ListNode ( val) ;
ListNode* current = _virtualHead;
while ( current-> next != NULL ) {
current = current-> next;
}
current-> next = addTail;
_size++ ;
}
void addAtIndex ( int index, int val) {
if ( index > _size) return ;
if ( index < 0 ) index = 0 ;
ListNode* current = _virtualHead;
ListNode* addIndex = new ListNode ( val) ;
while ( index-- != 0 ) {
current = current-> next;
}
addIndex-> next = current-> next;
current-> next = addIndex;
_size++ ;
}
void deleteAtIndex ( int index) {
if ( index >= _size || index < 0 ) return ;
ListNode* current = _virtualHead;
while ( index-- != 0 ) {
current = current-> next;
}
ListNode* tmp = current-> next;
current-> next = current-> next-> next;
delete tmp;
tmp= nullptr ;
_size-- ;
}
private :
int _size;
ListNode* _virtualHead;
} ;