链表理论基础
定义:链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。
表示
下一个链表是:head.next
链表的值:head.value
数组和链表的区别:
数组是在内存中是连续分布的,但是链表在内存中不是连续分布的。
链表的创建:dummy = ListNode(0)---python
class ListNode(object):
def __init__(self, val=0, next=None):
self.val = val
self.next = next
链表的删除:
直接 只要将C节点的next指针 指向E节点就可以了
head.next = head.next.next
时间复杂度:O(1)
链表的增加:
时间复杂度:O(1)
数组和链表之间的对比:
203.移除链表元素
我的解法:
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
if head is None:
return
dummy = ListNode(0)
dummy.next = head
pre = dummy
while head is not None:
if head.val == val:
pre.next = head.next
else:
pre = pre.next
head = head.next
return dummy.next
疑问:head随着移动不懂断掉嘛?而且到底dummy指向的是head,但是移到了最后,head移到了最后,链表不是断掉了嘛?所以我的解法有很多问题,我自己都无法理解,然后就写出来了
题目题解:
(使用虚拟头节点)
class Solution(object):
def removeElements(self, head, val):
"""
:type head: ListNode
:type val: int
:rtype: ListNode
"""
if head is None:
return
dummy = ListNode(0) #dummy的作用:方便处理头节点
dummy.next = head
cur = dummy #单向链表,删除的时候,需要找到前面(a),指向(c)
#终止条件需要注意
while cur.next is not None:
if cur.next.val == val:
#指针的指向要设置正确
cur.next = cur.next.next
#if语句的逻辑有问题,很有可能出错
else:
cur = cur.next
return dummy.next #不直接return head 是因为head有可能被删除了
(原来链表的进行删除)
总结:
链表操作的两种方式:
- 直接使用原来的链表来进行删除操作。
- 设置一个虚拟头结点在进行删除操作。
二刷:
虽然是AC了,但是用一点时间
class Solution:
def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
dummy = ListNode(0)
dummy.next = head
pre = dummy
while pre is not None and pre.next is not None:
while pre.next is not None and pre.next.val == val:
pre.next = pre.next.next
pre = pre.next
return dummy.next
这个while就很灵魂,需要时刻注意,因为可能像[7,7,7,7]这种,就需要用到循环一直下去
var removeElements = function(head, val) {
const dummy = new ListNode(0,head)
let cur = dummy
while(cur.next){
if(cur.next.val === val){
cur.next = cur.next.next
}else{
cur = cur.next}
}
return dummy.next
};
206.反转链表
我自己解法,我都绕不过来,设置了三个指针,非常复杂。
题目解法:
(双指针法)
class Solution(object):
def reverseList(self, head):
"""
:type head: ListNode
:rtype: ListNode
"""
pre = None
cur = head
while cur is not None: #遍历到null时跳出循环,因为不需要反转null的指针
#保存节点,防止丢失。反转后会断掉
temp = cur.next
#反转节点
cur.next = pre
#pre 向前移动
pre = cur
#cur向前移动
cur = temp
#上面两步的顺序不能搞错,不然就是pre = temp了
#终止条件是pre,不是cur,因为他还会移动一次
return pre
(递归法)
class Solution(object):
def reverseList(self, head):
"""
根据双指针的题解来解的
"""
def reverse(pre,cur):
#终止条件,遍历到最后cur为空,不用反转了
if cur is None:
return pre
#记录一下拉下的节点
temp = cur.next
#反转指针
cur.next = pre
#这句话相当于pre = cur,cur = temp
return reverse(cur,temp)
return reverse(None,head)
递归要素:
接受的参数:reverse(pre,cur):
返回值:return reverse(cur,temp)
终止条件:if cur is None:
return pre
千万不要忘记
二刷
没有ac这道题
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
pre = None
cur = head
while cur is not None:
temp = cur.next
cur.next = pre
pre = cur
cur = temp
return pre
具体的问题在,设置pre 的时候,我直接等于dummy节点了。应该设置他为None。然后反转指针的时候,不知道往下面移动。
递归法,直接就反转了,没有那么多事情
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
#递归法
def reverse(pre,cur):
if cur is None:
return pre
temp = cur.next
cur.next = pre
return reverse(cur,temp)
return reverse(None,head)
三刷
var reverseList = function(head) {
let pre = null
let cur = head
while(cur){
let temp = cur.next
cur.next = pre
pre = cur
cur = temp
}
return pre
};
707.设计链表
class ListNode(object):
#创建不要忘记写初始化的函数名
def __init__(self,val):
self.val = val
self.next = None
class MyLinkedList(object):
def __init__(self):
#链表长度
self.size = 0
#创建虚拟头节点
self.head = ListNode(0)
def get(self, index):
#这个临界条件不要忘记写了
#不可以等于size,因为index从0 开始
if index < 0 or index >= self.size:
return -1
cur = self.head
for i in range(index+1):
cur = cur.next
return cur.val
def addAtHead(self, val):
self.addAtIndex(0,val)
def addAtTail(self, val):
self.addAtIndex(self.size,val)
def addAtIndex(self, index, val):
#临界条件要记得写,不等于size是因为可能插在最后
if index > self.size:
return
cur = self.head
newNode = ListNode(val)
for i in range(index):
cur = cur.next
newNode.next = cur.next
cur.next = newNode
self.size += 1
def deleteAtIndex(self, index):
#可能链表中没有节点
if index <0 or index >= self.size:
return
cur = self.head
for i in range(index):
cur = cur.next
cur.next = cur.next.next
self.size -= 1
总结:
临界条件不要忘记写,可能超出范围了呢!!!!!!!!
二刷:
这个临界条件没有写!
if index < 0 or index >= self.size:
return -1
这个循环遍历的写错了
for i in range(index+1):
self没加
self.size += 1
self.dummy = 0
class ListNode {
constructor(val, next) {
this.val = val == undefined ? 0 : val;
this.next = next == undefined ? null : next;
}
}
/**
* Initialize your data structure here.
*/
var MyLinkedList = function() {
this.head = null;
this.size = 0
};
/**
* Get the value of the index-th node in the linked list. If the index is invalid, return -1.
* @param {number} index
* @return {number}
*/
MyLinkedList.prototype.get = function(index) {
if (index < 0 || index >=this.size) return -1;
let cur = this.head;
for (let i = 0; i < index; i++) {
cur = cur.next;
}
if(cur !== null){
return cur.val;
}else{
return -1
}
};
/**
* Add a node of value val before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtHead = function(val) {
let node = new ListNode(val);
node.next = this.head;
this.head = node;
this.size ++
};
/**
* Append a node of value val to the last element of the linked list.
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtTail = function(val) {
if (this.head == null) {
this.addAtHead(val);
return;
}
let node = new ListNode(val);
let cur = this.head;
while (cur.next !== null) {
cur = cur.next;
}
cur.next = node;
this.size ++
};
/**
* Add a node of value val before the index-th node in the linked list. If index equals to the length of linked list, the node will be appended to the end of linked list. If index is greater than the length, the node will not be inserted.
* @param {number} index
* @param {number} val
* @return {void}
*/
MyLinkedList.prototype.addAtIndex = function(index, val) {
if (index === 0) {
this.addAtHead(val);
return;
}
if (index === this.size) {
this.addAtTail(val);
return;
}
if (index > this.size) return;
let cur = this.head;
let node = new ListNode(val);
for (let i = 0; i < index-1; i++) {
cur = cur.next;
}
let next = cur.next;
cur.next = node;
node.next = next;
this.size ++
};
/**
* Delete the index-th node in the linked list, if the index is valid.
* @param {number} index
* @return {void}
*/
MyLinkedList.prototype.deleteAtIndex = function(index) {
if (index < 0 || index >= this.size) return;
if (index == 0) {
this.head = this.head.next;
return;
}
let cur = this.head;
for (let i = 0; i < index-1; i++) {
cur = cur.next;
}
cur.next = cur.next.next;
this.size --
};