首页 > 编程语言 >算法练习-第三天【链表】

算法练习-第三天【链表】

时间:2022-09-24 01:33:42浏览次数:82  
标签:index head ListNode cur int 第三天 Next 链表 算法

链表

203. 移除链表元素

参考:代码随想录203.移除链表元素

看完题目的第一想法

一道基本的链表题目,遍历链表如果当前节点的下一个节点值等于 val,那么就将当前节点的 Next指针指向下下一个节点。
如果要删除的值刚好位于头部,由于单链表没有指向头结点的指针,那么就需要单独处理头结点。

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeElements(head *ListNode, val int) *ListNode {
	// 处理头节点
	for head != nil && head.Val == val {
		head = head.Next
	}

	cur := head
	// 处理后面的
	for cur != nil && cur.Next != nil {
		if cur.Next.Val == val {
			cur.Next = cur.Next.Next
		} else {
			cur = cur.Next
		}
	}

	return head
}

进阶

处理链表另一种方法就是设置一个虚拟头结点,只需要让虚拟的头结点的 Next 指针指向 head,那么就可以保证逻辑处理的一致性。
注意的是:返回值需要返回的是dummyHead.Next

/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func removeElements(head *ListNode, val int) *ListNode {
	dummyHead := &ListNode{Next: head}
	cur := dummyHead
	for cur.Next != nil {
		if cur.Next.Val == val {
			cur.Next = cur.Next.Next
		} else {
			cur = cur.Next
		}
	}

	return dummyHead.Next
}

今日收获

移除链表元素

  1. 首先想到的就是无头结点的方式遍历链表,然后单独处理头结点。
  2. 引入头结点可以是代码风格统一而且不需要单独处理头结点。
  3. 写代码时需要注意cur := dummyHead,遍历时移动的是cur;

707. 设计链表

参考:代码随想录707.设计链表

看完题目的第一想法

手写链表的一道题目,使用循环双向链表完成

  1. 在处理指定位置插入时,新插入的值应该在head 之前;
  2. 在处理指定位置删除时,head 为删除的元素,因此需要改变 head 的前后指针的指向。
type MyLinkedList struct {
	dummy *Node
}

type Node struct {
	Val  int
	Pre  *Node
	Next *Node
}

func Constructor() MyLinkedList {
	node := &Node{
		Val:  -1,
		Pre:  nil,
		Next: nil,
	}

	node.Next = node
	node.Pre = node

	return MyLinkedList{node}
}

func (m *MyLinkedList) Get(index int) int {
	head := m.dummy.Next
	for head != m.dummy && index > 0 {
		head = head.Next
		index--
	}

	if index != 0 {
		return -1
	}

	return head.Val
}

func (m *MyLinkedList) AddAtHead(val int) {
	dummy := m.dummy
	node := &Node{
		Val:  val,
		Pre:  dummy,
		Next: dummy.Next,
	}

	dummy.Next.Pre = node
	dummy.Next = node
}

func (m *MyLinkedList) AddAtTail(val int) {
	dummy := m.dummy
	node := &Node{
		Val:  val,
		Pre:  dummy.Pre,
		Next: dummy,
	}

	dummy.Pre.Next = node
	dummy.Pre = node
}

func (m *MyLinkedList) AddAtIndex(index int, val int) {
	head := m.dummy.Next
	for head != m.dummy && index > 0 {
		head = head.Next
		index--
	}
	if index > 0 {
		return
	}

	node := &Node{
		Val:  val,
		Pre:  head.Pre,
		Next: head,
	}

	head.Pre.Next = node
	head.Pre = node
}

func (m *MyLinkedList) DeleteAtIndex(index int) {
	if m.dummy.Next == m.dummy {
		return
	}
	head := m.dummy.Next
	for head.Next != m.dummy && index > 0 {
		head = head.Next
		index--
	}
	// 当前的head为删除的节点
	if index == 0 {
		head.Next.Pre = head.Pre
		head.Pre.Next = head.Next
	}
}

附上单链表的代码:

type Node struct{
    Val int
    Next *Node
 
}

type MyLinkedList struct {
    dummyhead *Node
    size int
}


func Constructor() MyLinkedList {
    return MyLinkedList{
        dummyhead: &Node{
            Val:-1,
            Next: nil,
        },
        size:0,
    }
}


func (c *MyLinkedList) Get(index int) int {
    if index < 0 || index > c.size-1{
        return -1
    }
    cur := c.dummyhead.Next
    for index > 0{
        cur = cur.Next
        index--
    }

    return cur.Val
}


func (c *MyLinkedList) AddAtHead(val int)  {
    cur := c.dummyhead
    node := &Node{
        Val:val,
        Next: cur.Next,
    }
    cur.Next = node
    c.size++
}


func (c *MyLinkedList) AddAtTail(val int)  {
    cur := c.dummyhead
    for cur.Next != nil{
        cur = cur.Next
    }

    node := &Node{
        Val:val,
        Next: nil,
    }

    cur.Next = node
    c.size++
}


func (c *MyLinkedList) AddAtIndex(index int, val int)  {
    if index > c.size{
        return
    }
    cur := c.dummyhead
    for index > 0 {
        cur = cur.Next
        index--
    }
    node := &Node{
        Val:val,
        Next: cur.Next,
    }

    cur.Next = node
    c.size++
}


func (c *MyLinkedList) DeleteAtIndex(index int)  {
    if index <0 || index > c.size-1{
        return
    }
    cur := c.dummyhead
    for index > 0{
        cur = cur.Next
        index--
    }
    cur.Next = cur.Next.Next
    c.size--
}

今日收获

练习了循环双向链表,还需要再多多练习
操作链表的指针时,需要注意前后的顺序,不要在已断开的指针上再进行操作

206.反转链表

参考:代码随想录206. 反转链表

看完题目的第一想法

反转单链表只需要改变指针 next 的指向即可
使用双指针的解法:

  1. 首先使用变量tmp指向cur.Next
  2. 改变cur.Next指针指向
  3. 让pre向前走,移动到cur的位置
  4. cur 向前走,走到下一个位置(注意不能使用cur.Next,因为cur.Next此时指向已经发生了改变)
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseList(head *ListNode) *ListNode {
    // pre 指向空结点, cur指向头结点
    var pre *ListNode
    cur := head
    for cur != nil{
        tmp := cur.Next
        cur.Next = pre
        pre = cur
        cur = tmp
    }

    return pre
}

使用递归的解法

  1. 递归的返回值就是链表的头结点
  2. 递归函数reverse(pre,cur) 可以理解成pre = cur; cur = tmp,与双指针的解法逻辑相同
/**
 * Definition for singly-linked list.
 * type ListNode struct {
 *     Val int
 *     Next *ListNode
 * }
 */
func reverseList(head *ListNode) *ListNode {
	var reverse func(*ListNode, *ListNode) *ListNode
	reverse = func(pre, cur *ListNode) *ListNode {
		if cur == nil {
			return pre
		}
		tmp := cur.Next
		cur.Next = pre

		return reverse(cur, tmp)
	}

	return reverse(nil, head)
}

今日收获

反转链表比较容易, 了解双指针的解法后递归的写法也比较容易理解了。

标签:index,head,ListNode,cur,int,第三天,Next,链表,算法
From: https://www.cnblogs.com/neilliu/p/16724549.html

相关文章

  • 代码随想录day3|203.移除链表元素 707.设计链表 206. 反转链表
    203.移除链表元素题目链接:[https://leetcode.cn/problems/remove-linked-list-elements/submissions/]文章链接:[https://www.programmercarl.com/0203.移除链表元素.ht......
  • 代码随想录第三天| 203.移除链表元素、707.设计链表、206.反转链表
    第一题其实这题我一直不理解为什么明明整个过程没有操作dummy,最后要返回dummy.next,dedug了一下发现是pre.next=cur.next;这一步的时候对dummy进行了更新,之后又看了......
  • 驱动开发:内核中的链表与结构体
    Windows内核中是无法使用vector容器等数据结构的,当我们需要保存一个结构体数组时,就需要使用内核中提供的专用链表结构LIST_ENTRY通过一些列链表操作函数对结构体进行装入弹......
  • 6th 2022/6/8 算法总结·LCA·倍增
    开头的话这个算法对于大部分图论无环图题都是必备的,应多多复习大概是对于两个点的公共祖先倍增众所周知,为了找到公共祖先,最暴力的算法就莫过于一个个往上跳,直至相遇而......
  • 4th 2022/5/25 算法总结 哈希篇
    开头的话这个算法,并不像大部分其它的算法那样,逻辑正确后,时间复杂度一般都是较稳定的,哪怕是最高和最低之间也没差多少但哈希不一样,它时间复杂度较不稳定,虽然可以通过特殊......
  • 计算机系统结构大题精讲4-页面替换算法-Cache 组相连映像
    1、在一个采用LRU算法和组相连映像的Cache系统中,主存由0-15共16块组成;Cache分为2组,每组两块,每块大小为16个存储字。在某个程序执行时,访存的主存块地址流为:6、2、4、1、4、6......
  • KMP 算法实现
    #coding=utf-8defget_next_list(findding_str):#求一个字符串序列每个位置的最长相等前、后缀j=0#最长相等前缀的末位next=[0]#next数组用......
  • C语言经典算法100例二
    【程序21】题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一......
  • 算法实现2D OBB碰撞
    boxusingSystem;usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;publicclassDrawLine:MonoBehaviour{publicVector3[]......
  • leetcode 144. Binary Tree Preorder Traversal 二叉树展开为链表(中等)
    一、题目大意给你二叉树的根节点root,返回它节点值的前序遍历。示例1:输入:root=[1,null,2,3]输出:[1,2,3]示例2:输入:root=[]输出:[]示例3:输入:root=......