英文:
Poor performance converting python code to Go
问题
我正在尝试学习Go的基础知识,并开始将以前用Python编写的Codility练习转换过来。下面的代码在处理大字符串时,最坏情况下的执行速度约为0.25秒。然而,当我将其转换为Go时,它未能通过Codility对大字符串的性能测试,并且执行时间超过了6秒。
def solution(S):
stack = []
for i in S:
if len(stack) and stack[-1] == "(" and i == ")":
stack.pop()
continue
stack.append(i)
return 1 if len(stack) == 0 else 0
Go实现:
package solution
func Solution(S string) int {
stack := make([]string, 0)
for i := range S {
s := string([]rune(S)[i])
ln := len(stack)
if ln > 0 && stack[ln-1] == "(" && s == ")" {
stack = stack[:ln-1]
continue
}
stack = append(stack, s)
}
if len(stack) == 0 {
return 1
} else {
return 0
}
}
有人可以分享一些关于如何正确实现这个Go版本的见解吗?
这是我试图回答的问题:
https://codility.com/programmers/lessons/7-stacks_and_queues/nesting/
英文:
I'm trying to learn the basics of Go and started off by converting old exercises written for Codility in Python over. The code below had a worst-case execution speed of about a quarter second for large strings. When I converted it to Go however, it failed the Codility performance tests for large strings and executed in over 6 seconds.
def solution(S):
stack = []
for i in S:
if len(stack) and stack[-1] == "(" and i == ")":
stack.pop()
continue
stack.append(i)
return 1 if len(stack) == 0 else 0
Go implementation
package solution
func Solution(S string) int {
stack := make([]string, 0)
for i := range S {
s := string([]rune(S)[i])
ln := len(stack)
if ln > 0 && stack[ln-1] == "(" && s == ")" {
stack = stack[:ln-1]
continue
}
stack = append(stack, s)
}
if len(stack) == 0 {
return 1
} else {
return 0
}
}
Can anyone share some insight on how I can properly implement this in Go?
This is the question I'm trying to answer
https://codility.com/programmers/lessons/7-stacks_and_queues/nesting/
答案1
得分: 1
直接使用[]byte
可以大大提高性能。
func Solution(S string) int {
b := []byte(S)
stack := make([]byte, 0)
for i, s := range b {
ln := len(stack)
if ln > 0 && stack[ln-1] == '(' && s == ')' {
stack = stack[:ln-1]
continue
}
stack = append(stack, s)
}
if len(stack) == 0 {
return 1
} else {
return 0
}
}
如Yandry Pozo
的答案中所提到的。
你可以通过放弃对stack的追加操作,改用计数器来提高速度。
英文:
Working directly with the []byte
will improve your performance drastically.
func Solution(S string) int {
b := []byte(S)
stack := make([]byte, 0)
for i, s := range b {
ln := len(stack)
if ln > 0 && stack[ln-1] == '(' && s == ')' {
stack = stack[:ln-1]
continue
}
stack = append(stack, s)
}
if len(stack) == 0 {
return 1
} else {
return 0
}
}
As mentioned in Yandry Pozo
's answer.
You can make it faster by dropping the append to stack and use a counter instead.
答案2
得分: 1
你可以使用range来迭代字符串,记住你会得到一个rune。你可以通过使用一个简单的计数器来避免使用append()
来节省时间。另一个考虑是,如果在找到一个')'并且栈为空时提前返回,你的算法可能会更快:
func Solution(S string) int {
stack := make([]rune, len(S)+1)
top := 0 // 跟踪栈顶
for _, r := range S {
if r == '(' { // 我得到了一个'('
stack[top] = r
top++
} else { // 我得到了一个')'
top--
if top < 0 { // 栈为空,提前返回
return 0
}
}
}
if top == 0 {
return 1
}
return 0
}
英文:
You can iterate over a string using range, keep in mind that you'll get a rune. You can save time avoiding append()
using just a simple counter. Other consideration your algorithm can be even faster if you return early when you find a ')' and the stack is empty:
func Solution(S string) int {
stack := make([]rune, len(S)+1)
top := 0 // keep track of the stack top
for _, r := range S {
if r == '(' { // i got a '('
stack[top] = r
top++
} else { // i got a ')'
top--
if top < 0 { // the stack is emtpy, early return
return 0
}
}
}
if top == 0 {
return 1
}
return 0
}
答案3
得分: 0
代码中的慢部分是这一行:
s := string([]rune(S)[i])
要遍历字符串的字节:
for i, b := range []byte(s) {}
要遍历字符串的码点:
for i, c := range s {}
所以只需使用这种两变量的循环。
英文:
The slow part of the code is this line:
s := string([]rune(S)[i])
To iterate over the bytes of a string:
for i, b := range []byte(s) {}
To iterate over the code points of a string:
for i, c := range s {}
So just use the two-variable for loop.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论