JZ27 字符串的排列

字符串的排列

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

输入描述: 输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。

思路:

对于一个长度为 nn 的字符串(假设字符互不重复),其排列方案数共有:n×(n−1)×(n−2)…×2×1

通过递归实现字符串的排列。在每一层递归中,根据当前未使用的字符,选择一个字符加入到当前排列中,并标记该字符为已使用。然后继续递归下一层,当排列的长度等于字符串长度时,将当前排列加入到结果中。最后,清除标记并回溯到上一层,继续尝试其他未使用的字符。

当字符串存在重复字符时,排列方案中也存在重复的排列方案。为排除重复方案,需在固定某位字符时,保证 “每种字符只在此位固定一次” ,即遇到重复字符时不交换,直接跳过。从 DFS 角度看,此操作称为 “剪枝” 。

 

func Permutation(str string) []string {
	result := []string{}
	visited := make([]bool, len(str))
    strBytes := []byte(str)
    sort.Slice(strBytes, func(i, j int) bool {// 排序去除重复元素影响
        return strBytes[i] < strBytes[j]
    })
	backtrack(string(strBytes), []byte{}, visited, &result)
	return result
}

func backtrack(str string, path []byte, visited []bool, result *[]string) {// byte,bool是基础类型,会拷贝,所以不需要指针类型
	if len(path) == len(str) {
		*result = append(*result, string(path))
		return
	}

	for i := 0; i < len(str); i++ {// 这里要考虑重复元素的影响
		if (visited)[i] || (i > 0 && str[i] == str[i - 1] && !(visited)[i-1]){
			continue
		}

		visited[i] = true
		path = append(path, str[i])

		backtrack(str, path, visited, result)

		visited[i] = false
		path = path[:len(path)-1]
	}
}

  

posted @ 2021-04-09 23:42  zqlucky  阅读(44)  评论(0编辑  收藏  举报