将Python代码转换为Go时性能差劲。

huangapple go评论91阅读模式
英文:

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的追加操作,改用计数器来提高速度。

参考1 <br> 参考2

英文:

Working directly with the []byte will improve your performance drastically.

Results

func Solution(S string) int {

	b := []byte(S)
	stack := make([]byte, 0)

	for i, s := range b {

		ln := len(stack)
		if ln &gt; 0 &amp;&amp; stack[ln-1] == &#39;(&#39; &amp;&amp; s == &#39;)&#39; {
			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.

Ref 1 <br> Ref 2

答案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 == &#39;(&#39; {  // i got a &#39;(&#39;
            stack[top] = r
            top++
        } else { // i got a &#39;)&#39;
            top--
            if top &lt; 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.

huangapple
  • 本文由 发表于 2017年1月5日 14:31:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/41478597.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定