203.移除链表元素
思路:创建一个虚拟头结点,用来保证删除第一个元素和删除其他元素的操作相同。
时间复杂度:O(n)
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode headnode = new ListNode(-1, head); // 创建虚拟头结点
ListNode i = headnode;
while (i != null && i.next != null) {
while (i.next != null && i.next.val == val) { // 注意删除连续的节点
i.next = i.next.next;
}
i = i.next;
}
return headnode.next;
}
}
随想录的解法,思路上是一样的,但是代码逻辑更加清晰
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(-1, head); // 虚拟头结点
ListNode pre = dummy; // 当前节点的上一个节点
ListNode cur = head; // 当前节点
while (cur != null) {
if (cur.val == val) {
pre.next = cur.next;
} else {
pre = cur;
}
cur = cur.next;
}
return dummy.next;
}
}
707.设计链表
思路:题目要求可以设计所有类型的链表,这里选择设计带虚拟头结点的单链表。
时间复杂度:除了在第一个节点之前插入节点为O(1),其他都是O(n)
class MyLinkedList {
public class ListNode {
int val;
ListNode next;
ListNode(){}
ListNode(int val){this.val = val;}
ListNode(int val, ListNode next){this.val = val; this.next = next;}
}
private ListNode head; // 头结点
private int len; // 链表长度
public MyLinkedList() {
head = new ListNode(0);
len = 0;
}
public int get(int index) {
ListNode i = head.next;
while (i != null) {
if (index == 0) {
return i.val;
}
index--;
i = i.next;
}
return -1;
}
public void addAtHead(int val) {
ListNode newNode = new ListNode(val, head.next);
head.next = newNode;
len++;
}
public void addAtTail(int val) {
ListNode i = head;
while (i.next != null) {
i = i.next;
}
ListNode newNode = new ListNode(val);
i.next = newNode;
len++;
}
public void addAtIndex(int index, int val) {
if (index < 0) {
addAtHead(val);
}
ListNode newNode = new ListNode(val);
ListNode i = head;
while (i != null) {
if (index == 0) {
newNode.next = i.next;
i.next = newNode;
len++;
return;
}
index--;
i = i.next;
}
}
public void deleteAtIndex(int index) {
if (index >= 0 && index <= len -1) {
ListNode i = head;
while (i != null && i.next != null) {
if (index == 0) {
i.next = i.next.next;
len--;
return;
}
index--;
i = i.next;
}
}
}
}
这里不再粘贴随想录上的解法了,链表的基本操作思路比较固定,代码细节上和随想录有些许不同。
206.反转链表
思路:我的解法相当于创建一个新的链表,然后遍历给出的链表的每个节点,用头插法插入到新的链表中,就是一个反转的链表。
时间复杂度:O(n)
class Solution {
public ListNode reverseList(ListNode head) {
ListNode headNode = new ListNode();
// 遍历一次节点,每次插入到头结点后面
ListNode i = head;
ListNode temp;
while (i != null) {
temp = i.next;
i.next = headNode.next;
headNode.next = i;
i = temp;
}
return headNode.next;
}
}
这里看一下随想录上的解法,思路有所不同。将每个节点的next指针的指向改变,然后返回最后一个节点作为头结点。具体的代码实现可以用双指针法和递归法。
双指针法:
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode cur = head;
ListNode temp = null;
while (cur != null) {
temp = cur.next;// 保存下一个节点
cur.next = prev;
prev = cur;
cur = temp;
}
return prev;
}
}
递归法:
class Solution {
public ListNode reverseList(ListNode head) {
return reverse(null, head);
}
private ListNode reverse(ListNode prev, ListNode cur) {
if (cur == null) {
return prev;
}
ListNode temp = null;
temp = cur.next;// 先保存下一个节点
cur.next = prev;// 反转
// 继续反转下一个节点。
return reverse(cur, temp);
}
}