Golang每日一练(leetDay0048) 链表专题

简介: Golang每日一练(leetDay0048) 链表专题

141. 环形链表 Linked List Cycle


给你一个链表的头节点 head ,判断链表中是否有环。


如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。


如果链表中存在环 ,则返回 true 。 否则,返回 false 。

示例 1:

6d786cd8fe95e5cacc4b34d55154be73.png


输入:head = [3,2,0,-4], pos = 1

输出:true

解释:链表中有一个环,其尾部连接到第二个节点。


示例 2:

8361a6618220d76a7db8498f9ae1f206.png

输入:head = [1,2], pos = 0

输出:true

解释:链表中有一个环,其尾部连接到第一个节点。


示例 3:

4d1c31dc7273e9b66030f0caf8073955.png


输入:head = [1], pos = -1

输出:false

解释:链表中没有环。


提示:

  • 链表中节点的数目范围是 [0, 10^4]
  • -10^5 <= Node.val <= 10^5
  • pos-1 或者链表中的一个 有效索引

进阶:你能用 O(1)(即,常量)内存解决此问题吗?

代码1: 快慢指针


package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func hasCycle(head *ListNode) bool {
  if head == nil || head.Next == nil {
    return false
  }
  slow, fast := head, head.Next
  for slow != fast {
    if fast == nil || fast.Next == nil {
      return false
    }
    slow, fast = slow.Next, fast.Next.Next
  }
  return true
}
func createRingNodeList(nums []int, pos int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  if pos >= 0 {
    p := head
    for pos > 0 {
      p = p.Next
      pos--
    }
    tail.Next = p
  }
  return head
}
func main() {
  nums, pos := []int{3, 2, 0, -4}, 1
  head := createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
  nums, pos = []int{1, 2}, 0
  head = createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
  nums, pos = []int{1}, -1
  head = createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
}


代码2: 哈希表

package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func hasCycle(head *ListNode) bool {
  visited := make(map[*ListNode]bool)
  for head != nil {
    if visited[head] {
      return true
    }
    visited[head] = true
    head = head.Next
  }
  return false
}
func createRingNodeList(nums []int, pos int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  if pos >= 0 {
    p := head
    for pos > 0 {
      p = p.Next
      pos--
    }
    tail.Next = p
  }
  return head
}
func main() {
  nums, pos := []int{3, 2, 0, -4}, 1
  head := createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
  nums, pos = []int{1, 2}, 0
  head = createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
  nums, pos = []int{1}, -1
  head = createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
}


代码3: 递归

package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func hasCycle(head *ListNode) bool {
  visited := make(map[*ListNode]bool)
  return checkCycle(head, visited)
}
func checkCycle(head *ListNode, visited map[*ListNode]bool) bool {
  if head == nil {
    return false
  }
  if visited[head] {
    return true
  }
  visited[head] = true
  return checkCycle(head.Next, visited)
}
func createRingNodeList(nums []int, pos int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  if pos >= 0 {
    p := head
    for pos > 0 {
      p = p.Next
      pos--
    }
    tail.Next = p
  }
  return head
}
func main() {
  nums, pos := []int{3, 2, 0, -4}, 1
  head := createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
  nums, pos = []int{1, 2}, 0
  head = createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
  nums, pos = []int{1}, -1
  head = createRingNodeList(nums, pos)
  fmt.Println(hasCycle(head))
}



输出:

true

true

false


142. 环形链表 II Linked List Cycle II


给定一个链表的头节点  head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。


如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

不允许修改 链表。

示例 1:


daa0f9f22759cde66580ae43261f3125.png

daa0f9f22759cde66580ae43261f3125.png


输入:head = [3,2,0,-4], pos = 1

输出:返回索引为 1 的链表节点

解释:链表中有一个环,其尾部连接到第二个节点。


示例 2:

a97a3631c63d22703ffda6a8a92f6efb.png

输入:head = [1,2], pos = 0

输出:返回索引为 0 的链表节点

解释:链表中有一个环,其尾部连接到第一个节点。



示例 3:

b3ca99b5f87236603635ebe1f2833826.png

输入:head = [1], pos = -1

输出:返回 null

解释:链表中没有环。


提示:

   链表中节点的数目范围在范围 [0, 10^4] 内

   -10^5 <= Node.val <= 10^5

   pos 的值为 -1 或者链表中的一个有效索引

进阶:你是否可以使用 O(1) 空间解决此题?

代码1: 快慢指针

package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func detectCycle(head *ListNode) *ListNode {
  if head == nil || head.Next == nil {
    return nil
  }
  slow, fast := head, head
  for fast != nil && fast.Next != nil {
    slow = slow.Next
    fast = fast.Next.Next
    if slow == fast {
      slow = head
      for slow != fast {
        slow = slow.Next
        fast = fast.Next
      }
      return slow
    }
  }
  return nil
}
func createRingNodeList(nums []int, pos int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  if pos >= 0 {
    p := head
    for pos > 0 {
      p = p.Next
      pos--
    }
    tail.Next = p
  }
  return head
}
func showResult(head *ListNode) {
  if detectCycle(head) == nil {
    fmt.Println("null")
  } else {
    fmt.Println(detectCycle(head).Val)
  }
}
func main() {
  nums, pos := []int{3, 2, 0, -4}, 1
  head := createRingNodeList(nums, pos)
  showResult(detectCycle(head))
  nums, pos = []int{1, 2}, 0
  head = createRingNodeList(nums, pos)
  showResult(detectCycle(head))
  nums, pos = []int{1}, -1
  head = createRingNodeList(nums, pos)
  showResult(detectCycle(head))
}



代码2: 哈希表

package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func detectCycle(head *ListNode) *ListNode {
  visited := make(map[*ListNode]bool)
  for head != nil {
    if visited[head] {
      return head
    }
    visited[head] = true
    head = head.Next
  }
  return nil
}
func createRingNodeList(nums []int, pos int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  if pos >= 0 {
    p := head
    for pos > 0 {
      p = p.Next
      pos--
    }
    tail.Next = p
  }
  return head
}
func showResult(head *ListNode) {
  if detectCycle(head) == nil {
    fmt.Println("null")
  } else {
    fmt.Println(detectCycle(head).Val)
  }
}
func main() {
  nums, pos := []int{3, 2, 0, -4}, 1
  head := createRingNodeList(nums, pos)
  showResult(detectCycle(head))
  nums, pos = []int{1, 2}, 0
  head = createRingNodeList(nums, pos)
  showResult(detectCycle(head))
  nums, pos = []int{1}, -1
  head = createRingNodeList(nums, pos)
  showResult(detectCycle(head))
}


代码3: 数组

package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func detectCycle(head *ListNode) *ListNode {
  visited := make([]*ListNode, 0)
  for head != nil {
    for _, node := range visited {
      if node == head {
        return node
      }
    }
    visited = append(visited, head)
    head = head.Next
  }
  return nil
}
func createRingNodeList(nums []int, pos int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  if pos >= 0 {
    p := head
    for pos > 0 {
      p = p.Next
      pos--
    }
    tail.Next = p
  }
  return head
}
func showResult(head *ListNode) {
  if detectCycle(head) == nil {
    fmt.Println("null")
  } else {
    fmt.Println(detectCycle(head).Val)
  }
}
func main() {
  nums, pos := []int{3, 2, 0, -4}, 1
  head := createRingNodeList(nums, pos)
  showResult(detectCycle(head))
  nums, pos = []int{1, 2}, 0
  head = createRingNodeList(nums, pos)
  showResult(detectCycle(head))
  nums, pos = []int{1}, -1
  head = createRingNodeList(nums, pos)
  showResult(detectCycle(head))
}



输出:

2

1

null


143. 重排链表 Reorder List


给定一个单链表 L 的头节点 head ,单链表 L 表示为:


L0 → L1 → … → Ln - 1 → Ln


请将其重新排列后变为:

L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

示例 1:

9d4d0a2323328808f1db13fcdff671f3.png

输入:head = [1,2,3,4]

输出:[1,4,2,3]



示例 2:

efb626371c5c923b405ea8f2f417fb02.png

输入:head = [1,2,3,4,5]

输出:[1,5,2,4,3]

提示:

   链表的长度范围为 [1, 5 * 10^4]

   1 <= node.val <= 1000

代码: 快慢指针 + 反转链表

package main
import "fmt"
type ListNode struct {
  Val  int
  Next *ListNode
}
func reorderList(head *ListNode) {
  if head == nil || head.Next == nil {
    return
  }
  // 快慢指针找到中间节点
  slow, fast := head, head
  for fast.Next != nil && fast.Next.Next != nil {
    slow = slow.Next
    fast = fast.Next.Next
  }
  // 反转后半部分链表
  mid := slow.Next
  slow.Next = nil
  var prev *ListNode
  for mid != nil {
    next := mid.Next
    mid.Next = prev
    prev = mid
    mid = next
  }
  // 合并两个链表
  p1, p2 := head, prev
  for p2 != nil {
    next1 := p1.Next
    next2 := p2.Next
    p1.Next = p2
    p2.Next = next1
    p1 = next1
    p2 = next2
  }
}
func createNodeList(nums []int) *ListNode {
  if len(nums) == 0 {
    return nil
  }
  head := &ListNode{Val: nums[0]}
  tail := head
  for i := 1; i < len(nums); i++ {
    tail.Next = &ListNode{Val: nums[i]}
    tail = tail.Next
  }
  return head
}
func (head *ListNode) travel() {
  for p := head; p != nil; p = p.Next {
    fmt.Print(p.Val)
    if p.Next != nil {
      fmt.Print("->")
    }
  }
  fmt.Println("<nil>")
}
func main() {
  nums := []int{1, 2, 3, 4}
  head := createNodeList(nums)
  head.travel()
  reorderList(head)
  head.travel()
  nums = []int{1, 2, 3, 4, 5}
  head = createNodeList(nums)
  head.travel()
  reorderList(head)
  head.travel()
}

输出:

1->2->3->4<nil>

1->4->2->3<nil>

1->2->3->4->5<nil>

1->5->2->4->3<nil>



目录
相关文章
Go语言每日一练链表篇(一)
Go语言每日一练链表篇(一)
|
Rust 索引
Rust 编程小技巧摘选(6)
Rust 编程小技巧摘选(6)
190 1
Rust 编程小技巧摘选(6)
|
Shell Linux 算法
Shell编程——弱数据类型的脚本语言快速入门指南
Shell编程——弱数据类型的脚本语言快速入门指南
153 0
Shell编程——弱数据类型的脚本语言快速入门指南
|
Go Linux Shell
Linux 终端命令之文件浏览(2) more
Linux 终端命令之文件浏览(2) more
106 0
Linux 终端命令之文件浏览(2) more
|
Shell 机器学习/深度学习 Linux
Linux 终端操作命令(2)内部命令
Linux 终端操作命令(2)内部命令
204 0
Linux 终端操作命令(2)内部命令
|
Go Python Rust
Rust 编程小技巧摘选(7)
Rust 编程小技巧摘选(7)
197 0
Rust 编程小技巧摘选(7)
|
存储 SQL 算法
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
LeetCode力扣第114题:多种算法实现 将二叉树展开为链表
|
存储 SQL 算法
LeetCode 题目 86:分隔链表
LeetCode 题目 86:分隔链表
|
存储 算法 Java
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
【经典算法】Leetcode 141. 环形链表(Java/C/Python3实现含注释说明,Easy)
106 2
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点.
<数据结构>五道LeetCode链表题分析.环形链表,反转链表,合并链表,找中间节点
141 1

推荐镜像

更多