Day23 回溯算法 part02

58 阅读3分钟

概念

刷题

  1. 组合总和

leetcode.cn/problems/co…

image.png

剪枝操作: 对 candidates 进行排序,如果 candidates[i] > target, i后面的元素无需继续遍历

  1. 组合总和II

leetcode.cn/problems/co…

image.png

  1. 分割回文串

leetcode.cn/problems/pa…

image.png

优化:

使用动态规划

上面的代码还存在一定的优化空间, 在于如何更高效的计算一个子字符串是否是回文字串。上述代码isPalindrome函数运用双指针的方法来判定对于一个字符串s, 给定起始下标和终止下标, 截取出的子字符串是否是回文字串。但是其中有一定的重复计算存在:

例如给定字符串"abcde", 在已知"bcd"不是回文字串时, 不再需要去双指针操作"abcde"而可以直接判定它一定不是回文字串。

具体来说, 给定一个字符串s, 长度为n, 它成为回文字串的充分必要条件是s[0] == s[n-1]s[1:n-1]是回文字串。

大家如果熟悉动态规划这种算法的话, 我们可以高效地事先一次性计算出, 针对一个字符串s, 它的任何子串是否是回文字串, 然后在我们的回溯函数中直接查询即可, 省去了双指针移动判定这一步骤.

具体参考代码如下:

var isPalindRome [][]bool

  


func partition(s string) (result [][]string) {

computePalindRome(s)

path := make([]string, 0)

var backTracking func(int)

backTracking = func(startIndex int) {

if startIndex >= len(s) {

tmpPath := make([]string, len(path))

copy(tmpPath, path)

result = append(result, tmpPath)

}

for i := startIndex; i < len(s); i++ {

if isPalindRome[startIndex][i] {

path = append(path, s[startIndex:i+1])

backTracking(i + 1)

path = path[:len(path)-1]

}

}

}

backTracking(0)

return

}

  


func computePalindRome(s string) {

isPalindRome = make([][]bool, len(s))

for i := 0; i < len(isPalindRome); i++ {

isPalindRome[i] = make([]bool, len(s))

}

for i := len(s) - 1; i >= 0; i-- {

for j := i; j < len(s); j++ {

if i == j {

isPalindRome[i][j] = true

}

if j-i == 1 {

isPalindRome[i][j] = s[i] == s[j]

}

if j-i > 1 {

isPalindRome[i][j] = s[i] == s[j] && isPalindRome[i+1][j-1]

}

}

}

}

总结

在Go语言中,排序可以通过多种方式实现,包括使用标准库中的sort包提供的函数,或者自定义比较函数来实现更复杂的排序逻辑。下面是一些常用的排序方法:

  1. 使用sort包进行排序 Go语言的sort包提供了对切片(slice)进行排序的函数。你可以使用sort.Ints, sort.Float64s, sort.Strings等函数对基本类型的切片进行排序,或者使用sort.Slice和sort.SliceStable来自定义排序逻辑。 示例1: 对整数切片排序
package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    numbers := []int{5, 3, 8, 4, 2}
    sort.Ints(numbers)
    fmt.Println(numbers) // 输出: [2 3 4 5 8]
}

示例2: 对字符串切片排序

package main
 
import (
    "fmt"
    "sort"
)
 
func main() {
    words := []string{"pear", "apple", "lime", "banana"}
    sort.Strings(words)
    fmt.Println(words) // 输出: [apple banana lime pear]
}

  1. 使用sort.Slice自定义排序逻辑 如果你需要对切片进行更复杂的排序(例如,根据结构体或多个字段排序),可以使用sort.Slice。这个函数允许你提供一个比较函数来自定义排序逻辑。 示例3: 对结构体切片按字段排序
package main
 
import (
    "fmt"
    "sort"
)
 
type Person struct {
    Name string
    Age  int
}
 
func main() {
    people := []Person{
        {"Bob", 31},
        {"John", 42},
        {"Michael", 17},
        {"Jenny", 26},
    }
    // 按年龄排序
    sort.Slice(people, func(i, j int) bool { return people[i].Age < people[j].Age })
    fmt.Println("Sorted by age:", people) // 按年龄排序输出结果可能因运行环境而异,但大致如此。
}