代码随想录第三天| 203.移除链表元素 707.设计链表 206.反转链表 |01笔记

87 阅读3分钟
  • 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;
                }
        
    

image.png // 删除非头结点 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)
  }
-