-
203移除链表元素
- 代码随想录 (programmercarl.com)
-
第一印象
- 链表章节的第一道题,主要是帮助理解链表结构的一道题,链表内移除节点的方法是,只要将指向此结点的指针直接指向下一个就可以。如果用的是C等需要手动删除结点的语言,则还需要临时存储一下被“删除”的结点。
-
讲解观后感
- 需要注意头结点的处理方式需要单独构建逻辑,如果需要用一种逻辑完成,则需要借助构造虚拟头结点。
-
遇到问题
- 自己写的时候,构造虚拟头结点出错。
- 原因是golang中声明结构体变量的写法正确应为
dummyNode := *ListNode{} -
代码结果及说明
- 单独讨论头结点
-
//C++ class Solution { public: ListNode* removeElements(ListNode* head, int val) { // 删除头结点 while (head != NULL && head->val == val) { // 注意这里不是if ListNode* tmp = head; head = head->next; delete tmp; }
// 删除非头结点
ListNode* cur = head;
while (cur != NULL && cur->next!= NULL) {
if (cur->next->val == val) {
ListNode* tmp = cur->next;
cur->next = cur->next->next;
delete tmp;
} else {
cur = cur->next;
}
}
return head;
}
};
- 设置虚拟头结点
-
/**
* Definition for singly-linked list.
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func removeElements(head *ListNode, val int) *ListNode {
dummyHead := &ListNode{}
dummyHead.Next = head
cur := dummyHead
for cur != nil && cur.Next != nil {
if cur.Next.Val == val {
cur.Next = cur.Next.Next
} else {
cur = cur.Next
}
}
return dummyHead.Next
}
- ## 707.设计链表
- [代码随想录 (programmercarl.com)](https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E4%BB%A3%E7%A0%81)
- ### 第一印象
- 主要考验对于链表实现的基本逻辑的掌握。
- ### 讲解观后感
- 主要还是针对于虚拟头结点的作用的理解。不过在golang这类语言当中,结构体本身可以直接担任虚拟头结点的作用。这在官方给出的答案中体现的很好。在文后会给出。
- ### 遇到问题
-
type SingleNode struct {
Val int
Next *SingleNode
}
type MyLinkedList struct {
Size int
dummyHead *SingleNode
}
func Constructor() MyLinkedList {
Dummy := &SingleNode{
Val:-1,
Next:nil,
}
return MyLinkedList{
Size:0,
dummyHead:Dummy,
}
}
func (this *MyLinkedList) Get(index int) int {
if index<0||this.Size-1 < index {
return -1
}
cur := this.dummyHead.Next
for i:=0;i<index;i++ {
cur = cur.Next
}
return cur.Val
}
func (this *MyLinkedList) AddAtHead(val int) {
// var head = this.dummyHead.Next
newNode := &SingleNode{
Val:val,
Next:this.dummyHead.Next,
}
this.dummyHead.Next = newNode
this.Size++
}
func (this *MyLinkedList) AddAtTail(val int) {
newNode := &SingleNode{
Val:val,
Next:nil,
}
cur := this.dummyHead
for cur.Next != nil {
cur = cur.Next
}
cur.Next = newNode
this.Size++
}
func (this *MyLinkedList) AddAtIndex(index int, val int) {
if index>this.Size{
return
}
if index<=0 {
this.AddAtHead(val)
return
// index = 0
}
if index==this.Size {
this.AddAtTail(val)
return
}
newNode := &SingleNode{Val:val}
cur := this.dummyHead
for i:=0;i<index;i++ {
cur = cur.Next
}
newNode.Next = cur.Next
cur.Next = newNode
this.Size++
}
func (this *MyLinkedList) DeleteAtIndex(index int) {
if this==nil||index < 0||index > this.Size-1 {
return
}
cur := this.dummyHead
for i:=0;i<index;i++ {
cur = cur.Next
}
// if cur.Next!=nil && cur.Next.Next != nil {
// cur.Next = cur.Next.Next
// this.Size--
// } else if cur.Next!=nil && cur.Next.Next==nil{
// cur.Next = nil
// this.Size--
// }
cur.Next = cur.Next.Next
this.Size--
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* obj := Constructor();
* param_1 := obj.Get(index);
* obj.AddAtHead(val);
* obj.AddAtTail(val);
* obj.AddAtIndex(index,val);
* obj.DeleteAtIndex(index);
*/
- 遇到的第一个问题是在`AddAtIndex`部分调用两外两种函数的时候,在一开始忘记在条件内`return`,造成了重复操作
- 另一个问题的在`DeleteAtIndex`部分最开始用判定语句写法时,内外进行了两次`this.Size--`
- 都是属于代码细节疏忽导致的问题,之后要注意
- ### 官方答案
-
type MyLinkedList struct {
Val int
Next *MyLinkedList
}
func Constructor() MyLinkedList {
return MyLinkedList{
Val: 0,
Next: nil,
}
}
func (this *MyLinkedList) Get(index int) int {
p := this.Next
for i:=0;i<index;i++ {
if p==nil {
return -1
}
p = p.Next
}
if p==nil {
return -1
}
return p.Val
}
func (this *MyLinkedList) AddAtHead(val int) {
head0 := this.Next
this.Next = &MyLinkedList{Val:val,Next:head0}
return
}
func (this *MyLinkedList) AddAtTail(val int) {
p := this
for p!=nil && p.Next !=nil {
p = p.Next
}
if p==nil {
// panic
}
p.Next = &MyLinkedList{Val: val}
}
func (this *MyLinkedList) AddAtIndex(index int, val int) {
p := this
for i:=0;i<index;i++ {
p = p.Next
if p==nil {
return
}
}
p.Next = &MyLinkedList{Val:val, Next:p.Next}
}
func (this *MyLinkedList) DeleteAtIndex(index int) {
p := this
for i:=0;i<index;i++ {
p = p.Next
if p==nil {
return
}
}
if p.Next == nil {
return
}
p.Next = p.Next.Next
}
/**
* Your MyLinkedList object will be instantiated and called as such:
* obj := Constructor();
* param_1 := obj.Get(index);
* obj.AddAtHead(val);
* obj.AddAtTail(val);
* obj.AddAtIndex(index,val);
* obj.DeleteAtIndex(index);
*/
- 官方答案直接利用了`list`本身作为结点使用,起到了虚拟头的作用,因此也省去了额外添加`size`的操作。
- ## 206 反转链表
- [代码随想录 (programmercarl.com)](https://programmercarl.com/0206.%E7%BF%BB%E8%BD%AC%E9%93%BE%E8%A1%A8.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC)
- ### 第一印象
- 这道题主要需要注意的就是两两结点改变指向的操作顺序。以及下一个结点的保存。
- ### 讲解观后感
- 了解到了递归的逻辑,构建方法就是递归函数要带有`pre`的参数,来达成类似于双指针每步的操作。
- ### 代码
-
//双指针
func reverseList(head *ListNode) *ListNode {
var pre *ListNode
cur := head
for cur != nil {
next := cur.Next
cur.Next = pre
pre = cur
cur = next
}
return pre
}
//递归
func reverseList(head *ListNode) *ListNode {
return help(nil, head)
}
func help(pre, head *ListNode)*ListNode{
if head == nil {
return pre
}
next := head.Next
head.Next = pre
return help(head, next)
}
-