代码随想录算法训练营第三天|203.移除链表元素、707.设计链表、206.反转链表
一. 链表理论基础
-
链表是通过指针链接成的一种链式结构,链表的每个节点都有两部分组成,一个是数据区一个是指针;最后一个节点指向空代表链表结束; -
链表有只指向下一节点的单链表和双向指向节点的双链表 -
如果链表最后一个节点指向头节点的话就是环形链表,循环链表可以用来解决约瑟夫环问题。 -
链表与数组的区别
- 数组在c++中是连续的存储空间(java中非连续),链表是不连续的;
- 数组创建后不能改变长度,删除节点只能覆盖,插入节点只能创建新数组,访问数据只需要下标就可以;链表插入删除比较方便但是查找的话需要从头查找
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; }
}
二. 链表相关算法题
这道题考察链表的删除操作,链表删除很简单就是找到将要删除的节点,把节点的前位节点指向后一位即可 另外java是不需要考虑删除后的内存清理交由JVM处理,C++最好做一下内存清理操作 最好是定义一个虚拟头节点接入链表头这样好操作,不用单独写一段头节点删除逻辑
class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode newHead = new ListNode(1,head);
ListNode current = newHead;
while(current.next != null){
if (current.next.val == val){
current.next = current.next.next;
}else {
current = current.next;
}
}
return newHead.next;
}
}
- 操作链表时要注意循环终止条件
- 定义一个虚拟头链表会少很多头处理工作
class MyLinkedList {
private int val;
private MyLinkedList next;
public MyLinkedList() {
}
public int get(int index) {
int current = 0;
MyLinkedList currentNode = this.next;
while (currentNode != null) {
if (current == index) {
return currentNode.val;
}
current++;
currentNode = currentNode.next;
}
return -1;
}
public void addAtHead(int val) {
MyLinkedList linkedList = new MyLinkedList();
linkedList.val = val;
linkedList.next = this.next;
this.next = linkedList;
}
public void addAtTail(int val) {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.val = val;
MyLinkedList linkedList = this;
while (linkedList.next != null) {
linkedList = linkedList.next;
}
linkedList.next = myLinkedList;
}
public void addAtIndex(int index, int val) {
if (index < 0) {
this.addAtHead(val);
return;
}
int current = 0;
MyLinkedList currentNode = this;
while (currentNode != null) {
if (current == index) {
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.val = val;
myLinkedList.next = currentNode.next;
currentNode.next = myLinkedList;
return;
}
current++;
currentNode = currentNode.next;
}
}
public void deleteAtIndex(int index) {
int current = 0;
MyLinkedList currentNode = this;
while (currentNode.next != null) {
if (current == index) {
currentNode.next = currentNode.next.next;
return;
}
current++;
currentNode = currentNode.next;
}
}
}
迭代
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null) {
return head;
}
ListNode current = head;
ListNode newHead = head;
while (current.next != null) {
head = newHead;
newHead = current.next;
current.next = current.next.next;
newHead.next = head;
}
return newHead;
}
}
双指针法–这个更好理解哎
- 看下面代码随想录总结的动图就好了
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null) {
return head;
}
ListNode current = head;
ListNode newHead = null;
ListNode temp = head;
while (current != null) {
temp = current.next;
current.next = newHead;
newHead = current;
current = temp;
}
return newHead;
}
}
递归
递归其实就是做了双指针交换的事情,如图
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null) {
return head;
}
return reverse(null,head);
}
ListNode reverse(ListNode newHead, ListNode current){
if (current == null){
return newHead;
}
ListNode temp = current.next;
current.next = newHead;
return reverse(current,temp);
}
}
|