我使用ChatGPT和LeetCode获取了Golang的专业知识。

Source: Golang and why it matters on Medium

我现在已经用Python编程了6年。虽然我在Python方面很擅长,但我一直想学习一种编译速度更快的编程语言。今年,我终于在boot.dev上学习了Golang课程。

Photo by Caspar Camille Rubin on Unsplash

进入Golang比我想象的要容易。我轻松通过了课程。我喜欢Golang的语法和酷炫的特性。尽管我知道它很快,但它的编译时间和可移植性还是让我感到惊讶。通过初步了解了Golang,我想要继续练习。我已经在Go中构建了基本的REST API和简单的ETL工具,但我想和我在Python中编写代码一样高效。

只需解决两个DSA问题

我想出了一招对我非常有效的技巧。每天喝完早晨咖啡后,我就坐下来解决两个简单或中等难度的Leetcode问题。

第一个问题:使用Python解决问题,然后尝试用Golang编写相同的代码。如果我在编写Go中的代码时卡住超过15分钟,我会向ChatGPT请求带有简单提示的代码。

ChatGPT prompt for basic Trie implementation

以下是ChatGPT生成的代码:

package main

import (
"fmt"
)

// Trie represents the trie data structure
type Trie struct {
root *Node
endSymbol rune
}

// Node represents a node in the trie
type Node struct {
children map[rune]*Node
isEnd bool
}

// NewTrie initializes and returns a new Trie
func NewTrie() *Trie {
return &Trie{
root: &Node{children: make(map[rune]*Node)},
endSymbol: '*', // Not strictly necessary for Go version
}
}

// Add adds a word to the trie
func (t *Trie) Add(word string) {
current := t.root
for _, letter := range word {
if _, found := current.children[letter]; !found {
current.children[letter] = &Node{children: make(map[rune]*Node)}
}
current = current.children[letter]
}
current.isEnd = true
}

// LongestCommonPrefix finds the longest common prefix in the trie
func (t *Trie) LongestCommonPrefix() string {
current := t.root
prefix := ""

for {
if current.isEnd {
break
}

// Get all children keys
var children []rune
for key := range current.children {
children = append(children, key)
}

// Check for end symbol or multiple children
if len(children) != 1 {
break
}

// Append to prefix and move to next node
prefix += string(children[0])
current = current.children[children[0]]
}

return prefix
}

// Solution represents a solution to find the longest common prefix
type Solution struct{}

// LongestCommonPrefix finds the longest common prefix among a list of strings
func (s *Solution) LongestCommonPrefix(strs []string) string {
trie := NewTrie()
for _, word := range strs {
trie.Add(word)
}
return trie.LongestCommonPrefix()
}

func main() {
solution := Solution{}
words := []string{"flower", "flow", "flight"}
fmt.Println(solution.LongestCommonPrefix(words)) // Output: "fl"
}

生成的代码是正确的,我可以通过向ChatGPT提供等效的Python实现来轻松学习数据结构如Tries是如何在Go中实现的。Go与Python不同之处在于它使用指针、接收器函数和结构体代替类。通过这种方法,我已经习惯了这两种风格。

第二个问题:这个问题应该和第一个问题类似,最好需要使用相似的数据结构或算法。这应该只使用 Go 来解决。可以利用 ChatGPT 来解决与语法相关的疑问。在过去了15分钟或者至少通过了一些测试用例之前,我不会使用 ChatGPT 来获得提示或解决方案。

干扰试验:秘密武器

Photo by Firmbee.com on Unsplash

除了学习Go语言外,能够更快地解决DSA问题和理解每个测试案例的代码运行方式也很重要。我进行干跑来更好地理解问题及其解决方案。

干预测试是逐步模拟执行代码,以评估代码的正确性、行为和影响,然后再实际执行代码。

举例来说,我使用ChatGPT做了一次干跑,以便更好地理解Leetcode问题#24:两两交换链表中的节点的代码运行方式。以下是ChatGPT生成的Go代码,当提供正确的Python代码时:

package main

import "fmt"

// ListNode represents a node in the linked list.
type ListNode struct {
Val int
Next *ListNode
}

// swapPairs swaps adjacent pairs of nodes in the linked list.
func swapPairs(head *ListNode) *ListNode {
if head == nil || head.Next == nil {
return head
}

flag := true
p := head
var pr *ListNode // previous node for linking the swapped pairs

for p.Next != nil {
q := p
r := p.Next
p = p.Next
q.Next = r.Next
r.Next = q

if flag {
head = p
flag = false
} else {
pr.Next = r
}

p = p.Next
if p != nil && p.Next != nil {
p = p.Next
}
pr = q
}

return head
}

// Helper function to print the list
func printList(head *ListNode) {
for head != nil {
fmt.Printf("%d -> ", head.Val)
head = head.Next
}
fmt.Println("nil")
}

func main() {
// Example usage
head := &ListNode{Val: 1}
head.Next = &ListNode{Val: 2}
head.Next.Next = &ListNode{Val: 3}
head.Next.Next.Next = &ListNode{Val: 4}

fmt.Println("Original list:")
printList(head)

newHead := swapPairs(head)
fmt.Println("List after swapping pairs:")
printList(newHead)
}

然后,我要求ChatGPT为一个简单的测试案例做一次试运行,以下是提示:

给我一个链表[1,2,3,4]的试运行。

以下是由ChatGPT立即执行的干跑。

让我们来试运行一下swapPairs函数,使用链表[1, 2, 3, 4]。以下是函数如何处理链表的逐步细分:

初始设置

  • 输入列表: [1 -> 2 -> 3 -> 4 -> 空]
  • 指针:
  • 从头部(1)开始。

  • 标志位为真。
  • pr(前置节点指针)最初为nil。

步骤1:首先对调一对(1和2)

  • q = p(q指向1)
  • r = p.Next(r指向2)
  • 将p移动到p.Next(p指向2)
  • 更新 q.Next 到 r.Next (1.Next 指向 3)
  • 更新r.Next为q(2.Next 指向 1)

现在列表看起来像:[2 -> 1 -> 3 -> 4 -> nil]

  • 既然标志为真,则将头部更新为p(2),并将标志设为假。
  • 设置 pr = q(pr 指向1)。
  • 将p移动到p.Next(p指向3)。

第2步:第二对替换(3和4)

  • q = p (q 指向 3)
  • r = p.Next (r指向4)
  • 将p移动到p.Next(p指向4)
  • 更新 q.Next 到 r.Next(3.Next指向空)
  • 更新 r.Next 到 q(4. 下一个指向 3).

现在列表看起来像:[2 -> 1 -> 4 -> 3 -> 空]

  • 由于标志是假的,将 pr.Next 更新为 r(1.Next 指向 4),将之前交换的节点与新节点链接起来。
  • 设置pr = q(pr指向3)。
  • 将 p 移动到 p.Next(p 现在为 nil),结束循环。

最终列表

所有交换完成后的列表是: [2 -> 1 -> 4 -> 3 -> nil]。

变更摘要:

  1. 初始列表:[1 -> 2 -> 3 -> 4 -> 空]
  2. 在第一次交换后:[2 -> 1 -> 3 -> 4 -> 空]
  3. 在第二次交换之后:[2 -> 1 -> 4 -> 3 -> 空]

swapPairs函数正确地交换相邻节点对。如果您有关于此的更多问题,请告诉我!

上述信息极大地增强了我的直觉并节省了时间。在纸上进行相同的试运行会花费我几分钟的时间,但结果仍然不像上述结果那样有条理或详细。

当我第一次遇到任何新的Leetcode问题时,我会在纸上进行干运行,但对于那些解决方案复杂的困难问题,使用ChatGPT进行干运行会提高问题解决效率,我可以避免不必要的挫折。

如果您并不完全同意这种方法,您总是可以根据您的要求对其进行调整。我的目标是展示人工智能的进步如何通过一个简单但明确定义的流程来提高学习和技能发展的速度。

2024-09-14 04:32:15 AI中文站翻译自原文