struct的片段使用了太多的内存

时间:2018-02-08 08:42:30

标签: algorithm go memory-management breadth-first-search

我尝试用BFS解决this问题,但是对于输入" 99 100"我的程序使用超过260 Mb并且在线判断系统抛出MEMORY_LIMIT_EXCEEDED。我想问题是我使用QUEUE的方式。那么您认为这是什么问题?我该如何解决呢?

这是我的代码。并提前感谢!:

package main

import (
    "fmt"
)

type pair struct {
    nn int
    dd int
}

func main() {
    var n, m int
    fmt.Scanf("%d%d", &n, &m)

    if n >= m {
        fmt.Println(n - m)
    } else {
        device := make([]pair, 1)
        device[0] = pair{n, 0}

        ans := 0
        for {
            // pop front element
            tmp := device[0]
            device = device[1:]

            if tmp.nn == m { // reached destination
                ans = tmp.dd
                break
            }

            // add neighbors to the queue
            device = append(device, pair{tmp.nn - 1, tmp.dd + 1})
            device = append(device, pair{tmp.nn * 2, tmp.dd + 1})
        }

        fmt.Println(ans)
    }
}

编辑:更具可读性和工作性(已接受)代码:

package main

import (
    "fmt"
)

type pair struct {
    location int
    dist     int
}

func main() {
    var n, m int
    fmt.Scanf("%d%d", &n, &m)

    if n >= m {
        fmt.Println(n - m)
    } else {
        visited := make([]bool, m+2)

        queue := make([]pair, 1)
        queue[0] = pair{n, 0}

        ans := 0
        visited[n] = true
        for {
            // pop front element
            tmp := queue[0]
            queue = queue[1:]

            // reached destination
            if tmp.location == m {
                ans = tmp.dist
                break
            }

            // add neighbors to the queue
            if tmp.location*2 <= m+1 && visited[tmp.location*2] == false {
                queue = append(queue, pair{tmp.location * 2, tmp.dist + 1})
                visited[tmp.location*2] = true
            }
            if tmp.location-1 >= 0 && visited[tmp.location-1] == false {
                queue = append(queue, pair{tmp.location - 1, tmp.dist + 1})
                visited[tmp.location-1] = true
            }
        }

        fmt.Println(ans)
    }
}

2 个答案:

答案 0 :(得分:1)

您的算法不是BFS,因为您可以访问多个相同的状态。

例如,4 - &gt; 3 - &gt; 6和4 - &gt; 8 - &gt; 7 - &gt; 6,其中6将最终被处理两次。

其次,对于大于x的数字target,最小步数始终为

x - target + step to reach x

所以你不应该把它添加到队列中。

通过进行这两项修改,空间复杂度将限制为O(m),这可以帮助您解决问题。

示例代码

ans := -1
dist := make([]int, m + 1)
q := make([]int,1)
q[0] = n

for i := 0; i < len(q); i++ {
    node := q[i]
    if node == m {
       if ans == -1 || ans > dist[m]{
          ans = dist[m]
       }
       break;
    }
    a := node*2
    b := node - 1
    if a >= m {
       if ans == -1 || ans > (1 + dist[node] + a - m) {
          ans = 1 + dist[node] + a - m
       }
    }else if dist[a] == 0 && a != n {
       q = append(q, a)
       dist[a] = 1 + dist[node]
    }
    if dist[b] == 0 && b != n {
       q = append(q, b)
       dist[b] = 1 + dist[node]
    } 
}
return ans

答案 1 :(得分:0)

乍一看告诉我,对于你拥有的每个dd,队列中将有2^dd个元素。并且答案预计会大于50,这是一个保证的内存限制超过。

一个非常简单和常见的优化是跟踪被访问的节点(在您的情况下为nn)。创建map[int]bool(因为dd只是增加,因此没有理由记录上次访问的值)并且不会添加到队列中。

评论中提到的另一个优化是,不要将nn大于targets添加到队列中。这有点复杂,因为您需要记录值res = min(res, dd+nn-target),其中nn是大于目标的值,dd是获取值的步骤。如果当前dd大于res,你也想要中断。

接受答案的代码有错误。它从不试图确定b是否小于零。考虑到设计的测试用例,可能会发生范围索引的运行时恐慌。