将python代码转换为Go的性能不佳

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/

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 > 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.

Ref 1
Ref 2

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
}

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.