203.移除链表元素
题目链接
最基础的链表题,主要是为了教会你用虚拟头节点,我是认为只要是删除类型的题,最好都用虚拟头节点来做。
已经刷了太多遍了,惯性了。。。
需要注意的问题
1.如果不使用头节点可能会造成 7 - 7 - 7 - 7
这种链表少删一个的情况
2.注意空指针异常的问题,链表最容易出现空指针异常,主要出现在循环条件里是head != null
还是 head.next != null
还是head != null && head.next != null
,最好是画图来解决
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode pre = dummy;
while (head != null) {
if (head.val == val) {
pre.next = head.next;
head = head.next;
} else {
head = head.next;
pre = pre.next;
}
}
return dummy.next;
}
}
707.设计链表
题目链接
通过自己实现一个链表,实现一些方法来对链表进行插入,删除,查询等操作
需要注意的是链表的下标类似于数组是从0开始
1.初始化链表: 创建链表的头节点 以及 对链表的size赋值0
2.链表下标查询:
- 对传入的index进行合法性校验
- 遍历下标
3.链表的插入:
- 对传入的index进行合法性校验
- 通过pre指针来遍历到插入位置的前一个元素
4.链表的删除:
- 对传入的index进行合法性校验
- 通过pre指针来遍历到删除位置的前一个元素
class ListNode {
int val;
ListNode next;
ListNode() {};
ListNode(int val) {
this.val = val;
}
}
class MyLinkedList {
int size;
ListNode head;
public MyLinkedList() {
// 初始化
size = 0;
head = new ListNode(0);
}
public int get(int index) {
// 如果index非法,则返回-1
if (index < 0 || index >= size) {
return -1;
}
ListNode cur = head;
for (int i = 0; i <= index; i++) {
cur = cur.next;
}
return cur.val;
}
public void addAtHead(int val) {
addAtIndex(0, val);
}
public void addAtTail(int val) {
addAtIndex(size, val);
}
public void addAtIndex(int index, int val) {
if (index > size) {
return;
}
if (index < 0) {
index = 0;
}
size++;
ListNode pre = head;
ListNode temp = new ListNode(val);
for (int i = 0; i < index; i++) {
pre = pre.next;
}
temp.next = pre.next;
pre.next = temp;
}
public void deleteAtIndex(int index) {
if (index < 0 || index >= size) {
return;
}
size--;
if (index == 0) {
head = head.next;
return;
}
ListNode pre = head;
for (int i = 0; i < index; i++) {
pre = pre.next;
}
pre.next = pre.next.next;
}
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* MyLinkedList obj = new MyLinkedList();
* int param_1 = obj.get(index);
* obj.addAtHead(val);
* obj.addAtTail(val);
* obj.addAtIndex(index,val);
* obj.deleteAtIndex(index);
*/
206.反转链表
方法一:递归(很难真正理解清楚)
…
方法二:遍历交换
1.使用temp变量保存cur的下一个元素,便于反转一对节点之后指针后移
2.将当前节点指向它的前一个节点pre
3.此时反转完成,后移pre节点到cur,cur到cur的后一个节点也就是刚才保存的temp
4.继续往后遍历,反转.
class Solution {
public ListNode reverseList(ListNode head) {
ListNode cur = head;
ListNode pre = null;
ListNode temp = null;
while (cur != null) {
temp = cur.next;
cur.next = pre;
pre = cur;
cur = temp;
}
return pre;
}
}
拓展
92.反转链表II
题目链接
相比于反转链表I,提升了难度,本题为给定区间内的反转
1 - 2 - 3 - 4 - 5
2, 4
1 - 4 - 3 - 2 - 5
所以不能在向反转链表I一样按正常逻辑依次反转,本题我们采用类似于头插法的方式进行反转
因为需要找到交换区间第一个元素的前一个元素,然后往这个元素后面插入,所以需要使用虚拟头节点
1.第一个for循环遍历找到进入区间的位置,start指向left(区间左边界),prestart指向start前一个元素
2.第二个for循环遍历区间,依次将元素插在prestart后面完成反转
class Solution {
public ListNode reverseBetween(ListNode head, int left, int right) {
ListNode dummy = new ListNode(-1);
dummy.next = head;
ListNode preStart = dummy;
ListNode start = head;
for (int i = 1; i < left; i++) {
preStart = start;
start = start.next;
}
for (int i = 0; i < right - left; i++) {
ListNode temp = start.next;
start.next = temp.next;
temp.next = preStart.next;
preStart.next = temp;
}
return dummy.next;
}
}