day3-linked list-part01-7.5

tasks for today

1. 链表理论基础

2. 203.移除链表元素

3. 707.设计链表

4. 206.反转链表

------------------------------------------------

1. 链表理论基础

单链表:(singly-linked list)

链表是一种通过指针串联在一起的线性结构,每一个节点由两部分组成,一个是数据域一个是指针域(存放指向下一个节点的指针),最后一个节点的指针域指向null(空指针的意思)。

链表的入口节点称为链表的头结点也就是head。

单链表中的指针域只能指向节点的下一个节点。

双链表:

双链表:每一个节点有两个指针域,一个指向下一个节点,一个指向上一个节点。

双链表 既可以向前查询也可以向后查询。

循环链表:

顾名思义,就是链表首尾相连。

注意:数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。

链表是通过指针域的指针链接在内存中各个节点。

It is important to learn how to define linked list by yourself, even if it is usually defined in advance when doing coding practice on leetcode. Below are linked list's definition in python, go, rust

# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

 // Definition for singly-linked list.
  type ListNode struct {
      Val int
      Next *ListNode
  }
//Definition for singly-linked list.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
  pub val: i32,
  pub next: Option<Box<ListNode>>
}

impl ListNode {
  #[inline]
  fn new(val: i32) -> Self {
    ListNode {
      next: None,
      val
    }
  }
}

the next usually store the next listnode, or none for the last node

related operation on linked list:

delete a listnode

add a listnode

2. 203.移除链表元素

here, if the head node should be deleted, to simlify the operation, a dummy node is used ahead of the head node. Or there should be a separate specific code snippet used for dealing with the condition where the head node should be deleted.

with dummy node VS without dummy node

class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        dummy_node = ListNode(next=head)

        temp = dummy_node
        while temp.next:
            if temp.next.val == val:
                temp.next = temp.next.next
            else:
                temp = temp.next

        return dummy_node.next
class Solution:
    def removeElements(self, head: Optional[ListNode], val: int) -> Optional[ListNode]:
        # here we don't use dummy head and introduce one only temp to record current listNode
        while head and head.val == val:
            head = head.next

        temp = head
        while temp and temp.next:
            if temp.next.val == val:
                temp.next = temp.next.next
            else:
                temp = temp.next
        
        return head

pay attention to how to initial a type instance in Go;

besides, it is not valid directly use "for temp.Next {}" in Go, the condition should be "temp.Next != nil"

func removeElements(head *ListNode, val int) *ListNode {
    dummy_node := &ListNode{}
    dummy_node.Next = head

    temp := dummy_node
    for temp.Next != nil {
        if temp.Next.Val == val {
            temp.Next = temp.Next.Next
        } else {
            temp = temp.Next
        }
    }
    return dummy_node.Next
}

Rust is disgusting!!!!!

impl Solution {
    pub fn remove_elements(head: Option<Box<ListNode>>, val: i32) -> Option<Box<ListNode>> {
        let mut dummy_node = Box::new(ListNode::new(0));
        dummy_node.next = head;

        let mut temp = dummy_node.as_mut();
        while let Some(nxt) = temp.next.take() {
            if nxt.val == val {
                temp.next = nxt.next;
            } else {
                temp.next = Some(nxt);
                temp = temp.next.as_mut().unwrap();
            }
        }
        return dummy_node.next
    }
}

3. 707.设计链表

here, a dummy node shows its advantage again. Besides, because it is as easy as array to get the length, so a variable recording the size is necessary.

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class MyLinkedList:

    def __init__(self):
        self.dummy_node = ListNode()
        self.size = 0

    def get(self, index: int) -> int:
        if index < 0 or index >= self.size:
            return -1
        temp = self.dummy_node
        cur_ind = 0
        while cur_ind <= index:
            temp = temp.next
            cur_ind += 1
        return temp.val

    def addAtHead(self, val: int) -> None:
        self.dummy_node.next = ListNode(val=val, next=self.dummy_node.next)
        self.size += 1

    def addAtTail(self, val: int) -> None:
        temp = self.dummy_node
        while temp.next:
            temp = temp.next
        temp.next = ListNode(val=val, next=None)
        self.size += 1

    def addAtIndex(self, index: int, val: int) -> None:
        if index > self.size:
            return
        cur_ind = 0
        temp = self.dummy_node
        while cur_ind < index:
            temp = temp.next
            cur_ind += 1
        temp.next = ListNode(val=val, next=temp.next)
        self.size += 1

    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >= self.size:
            return
        cur_ind = 0
        temp = self.dummy_node
        while cur_ind < index:
            temp = temp.next
            cur_ind += 1
        temp.next = temp.next.next
        self.size -= 1

4. 206.反转链表

- 双指针法

here, the initial definition of pre should be paid attention, pre=None is ok, do not define it as pre=ListNode(), or the last node will be a node with val=0

Note: The loop end when cur is None.

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        pre = None
        cur = head
        if not cur:
            return head
        while cur:
            temp = cur.next
            cur.next = pre
            pre = cur
            cur = temp
        return pre

- 递归backtracking

in backtracking, the function's repetitive usage acturally realize "cur = temp" and "pre = cur" in the loop.

class Solution:
    def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        return self.reserve_step(None, head)

    def reserve_step(self, pre, cur):
        if cur == None:
            return pre
        temp = cur.next
        cur.next = pre

        return self.reserve_step(cur, temp)

  • 13
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值