203.移除链表元素
思路
- 直接使用原来的链表来进行删除操作:
本方法需要注意的是移除头结点和移除其它结点的操作是不同的,因为链表的其他节点都是通过前一个结点来移除当前节点,而头结点没有前一个结点。这就需要对头结点额外处理:将头结点向后移动一位就可以,这样就从链表中移除了一个头结点。 - 设置一个虚拟头结点在进行删除操作:
本方法需要设置一个虚拟头结点dummyHead,让dummyHead指向头结点,这样一来,删除头结点的操作就和删除其它结点的操作统一了。
代码
直接使用原来的链表来进行删除操作:
/*class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}*/
class Solution {
public ListNode removeElements(ListNode head, int val) {
if(head == null){//链表为空,直接返回头结点
return head;
}
while(head != null && head.val == val){要删除的元素是头结点
head = head.next;
}
ListNode current = new ListNode();//新建current节点
current = head;//指向头节点
while(current != null && current.next != null){
if(current.next.val == val){//
current.next = current.next.next;
} else {
current = current.next;
}
}
return head;
}
}
设置一个虚拟头结点在进行删除操作:
class Solution{
public ListNode removeElements(ListNode head, int val) {
if(head == null){//链表为空,直接返回头结点
return head;
}
ListNode dummy = new ListNode();//定义虚拟头结点
dummy.next = head;// 将虚拟头结点指向head,这样方面后面做删除操作
ListNode current = dummy;
while(current.next != null){
if(current.next.val == val){
current.next = current.next.next;
} else {
current = current.next;
}
}
return dummy.next;
}
}
707.设计链表
思路
本题意在实现链表的5个功能:
- 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 的节点
代码
class LinkNode{
int val;//存储结点值
LinkNode next;//存储下一结点的地址
public LinkNode() {
}
public LinkNode(int val) {
this.val = val;
}
}
public class MyLinkedList {
int size; //size存储链表元素个数
LinkNode dummyHead;//虚拟头结点
LinkNode current;//当前结点
//初始化链表
public MyLinkedList() {
dummyHead = new LinkNode(0);
size = 0;
}
//获取链表中下标为 index 的节点的值。如果下标无效,则返回 -1 。
public int get(int index) {
//index非法
if(index < 0 || index >= size){
return -1;
}
current = dummyHead.next;
while (index > 0){
current = current.next;
index--;
}
return current.val;
}
//将一个值为 val 的节点插入到链表中第一个元素之前。
// 在插入完成后,新节点会成为链表的第一个节点
public void addAtHead(int val) {
LinkNode newNode = new LinkNode(val);
newNode.next = dummyHead.next;
dummyHead.next = newNode;
size++;
}
// 将一个值为 val 的节点追加到链表中作为链表的最后一个元素。
public void addAtTail(int val) {
LinkNode newNode = new LinkNode(val);
current = dummyHead;
while(current.next != null){
current = current.next;
}
current.next =newNode;
size++;
}
// 将一个值为 val 的节点插入到链表中下标为 index 的节点之前。
// 如果 index 等于链表的长度,那么该节点会被追加到链表的末尾。
// 如果 index 比长度更大,该节点将 不会插入 到链表中
public void addAtIndex(int index, int val) {
if(index > size || index < 0){
return;
}
LinkNode newNode = new LinkNode(val);
current = dummyHead;
while (index > 0){
current = current.next;
index--;
}
newNode.next = current.next;
current.next = newNode;
size++;
}
// 如果下标有效,则删除链表中下标为 index 的节点。
public void deleteAtIndex(int index) {
if(index < 0 || index >= size){
return;
}
current = dummyHead;
while (index > 0){
current = current.next;
index--;
}
current.next = current.next.next;
size--;
}
}
206.反转链表
思路
- 双指针法:cur指针指向头节点,pre指针指向cur指针前一个节点,方便改变方向
- 递归法
代码
双指针法
//双指针法
class Solution {
public ListNode reverseList(ListNode head) {
ListNode current = head; //当前指针
ListNode pre = null; //pre是新链表的尾结点
while(current != null){
//临时指针,趁没赋值之前保存current下一结点地址
ListNode temp = current.next;
//将current指向pre
current.next = pre;
//将pre后移到current位置
pre = current;
//将current指针移到temp保存的位置
current = temp;
}
//返回新链表的头结点
return pre;
}
}
递归法:
//递归法
class Solution2{
public ListNode reverse(ListNode current, ListNode pre){
//终止递归,返回头结点
if (current == null){
return pre;
}
//临时指针,趁没赋值之前保存current下一结点地址
ListNode temp = current.next;
//将current指向pre
current.next = pre;
//移动pre,current指针,整体后移一位
return reverse(temp, current);
}
public ListNode reverseList(ListNode head) {
// 递归调用reverse函数
return reverse(head, null);
}
}