当前位置: 代码网 > 科技>电脑产品>内存 > 【From C To Go】2.1 链表刷题(持续更新)

【From C To Go】2.1 链表刷题(持续更新)

2024年08月01日 内存 我要评论
Val int。

记录一些链表相关的算法题的解法


更新记录:

日期内容
2024/05/22链表定义,反转链表,成对反转链表

0 准备

0.1 链表结构定义

type listnode struct {
	val  int
	next *listnode
}

0.2 工具函数

0.2.1 生成长度为n,值随机的单链表
func generatelist(n int) *listnode {
	var head *listnode
	for i := 0; i < n; i++ {
		node := &listnode{val: rand.intn(100)}
		if head == nil {
			head = node
		} else {
			node.next = head
			head = node
		}
	}
	return head
}
0.2.2 遍历输出链表
func printlist(head *listnode) {
	for head != nil {
		print(head.val, " ")
		head = head.next
	}
	println()
}

1 反转单链表

1.1 问题描述

给定一个单链表的头结点phead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。

数据范围:
0≤n≤1000
要求:空间复杂度 o(1) ,
时间复杂度 o(n) 。

如当输入链表{1,2,3}时,
经反转后,原链表变为{3,2,1},所以对应的输出为{3,2,1}。

1.2 迭代方式

1.2.1 思路描述
  1. 需要声明两个指针类型变量,cur指向当前链表节点(初始为head),prev存放该链表节点的前置节点
  2. 迭代方式求解问题就像剥洋葱,一层一层地解决问题,问题的规模会随着迭代的深入变得越来越小,当满足某种终止条件时,最后的问题得到解决,也就意味着解决了全部问题
  3. 针对此问题,由于cur初始时指向链表头结点,因此迭代解决该问题其实就是从头结点开始,将cur的前置节点变为后置节点,同时将后置节点变为前置节点,然后对cur进行迭代(执行下一个节点),直至cur为空值(意味着链表走到了尽头)
1.2.2 代码
// 迭代方式反转链表
func reverselistiter( head *listnode ) *listnode {
    cur := head // 需要迭代的主体
	var prev *listnode // 迭代过程中需要记录的上一个节点
	for cur!= nil { 
		// 迭代过程中,记录当前节点的下一个节点,避免丢失
		tmp := cur.next
		// 迭代过程中,将当前节点的下一个节点指向上一个节点
		cur.next = prev
		// 迭代过程中,将上一个节点指向当前节点
		prev = cur
		// 迭代过程中,将当前节点指向下一个节点
		cur = tmp
	}
	// 迭代完成后,将头节点指向最后一个节点
	head = prev
	return head
}

1.2.3 验证
func main() {
	head := generatelist(10)
	printlist(head)
	printlist(reverselistiter(head))
}

运行结果:
在这里插入图片描述

1.3 递归方式

1.3.1 思路描述
  1. 递归的基本情况是:长度为0或1的链表,反转的结果是其本身
  2. 否则,对于长度为n的链表,反转该链表相当于将该链表的头结点拼接到第2个节点到第n个节点组成的长度为n-1的链表反转后的链表尾结点之后
  3. 递归进行第2步直到达到基本情况
1.3.2 代码
func reverselistrecur(head *listnode) *listnode {
	// 递归终止条件
	if head == nil || head.next == nil {
		return head
	}
	// 递归反转剩余部分
	newhead := reverselistrecur(head.next)

	// 反转当前节点
	head.next.next = head
	head.next = nil

	return newhead
}
1.3.3 验证
func main() {
	head := generatelist(10)
	printlist(head)
	printlist(reverselistrecur(head))
}

运行结果:
在这里插入图片描述

2 成对反转链表

2.1 描述

一对一对的反转链表内的结点
for example,
given1->2->3->4, return 2->1->4->3.

2.2 迭代方式

2.2.1 思路
  1. 使用一个虚拟头节点 dummy,指向链表的头节点。这有助于处理边界情况。
  2. 使用三个指针:prev(指向每对节点的前一个节点,初始指向 dummy),first(指向每对节点中的第一个节点),second(指向每对节点中的第二个节点)。
  3. 逐步交换每对节点,并更新指针以处理下一对节点。
2.2.2 代码
func reverselistpairiter(head *listnode) *listnode {
	dummy := &listnode{next: head}
	prev := dummy

	for head != nil && head.next != nil {
		first := head
		second := head.next

		// 交换节点
		first.next = second.next
		second.next = first
		prev.next = second

		// 迭代
		prev = first
		head = first.next
	}
	return dummy.next
}
2.2.3 验证
func main() {
	head := generatelist(11)
	printlist(head)
	printlist(reverselistpairiter(head))
}

运行结果:
在这里插入图片描述

2.3 递归方式

2.3.1 思路
  1. 基本情况:如果链表为空或只有一个节点,不需要交换,直接返回头节点。
  2. 递归处理剩余链表的交换操作。
  3. 交换当前两节点,然后将递归处理的结果连接到交换后的节点后面。
2.3.2 代码
func reverselistpairrecur(head *listnode) *listnode {
	// 基本情况
	if head == nil || head.next == nil {
		return head
	}
	tmp := head.next
	head.next = reverselistpairrecur(tmp.next)
	tmp.next = head
	return tmp
}
2.3.3 验证
func main() {
	head := generatelist(11)
	printlist(head)
	printlist(reverselistpairrecur(head))
}

运行结果:
在这里插入图片描述

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com