1,46题,全排列
var res [][]int
func permute(nums []int) [][]int {
res=nil
helper(nums,[]int(nil))
return res
}
func helper(nums[]int,tmp []int){
if len(tmp)==len(nums){
//不能直接用tmp
// 这个 tmp 变量是一个地址引用,结束当前递归,将它加入 res,后续的递归分支还要继续进行搜
// 索,还要继续传递这个 tmp ,这个地址引用所指向的内存空间还要继续被操作,所以 res 中的
// tmp 所引用的内容会被改变,这就造成了 res 中的内容随 tmp 变化。
// 所以要复制 tmp 内容到一个新的数组里,然后放入 res,这样后续对 tmp 的操作,
// 就不会影响已经放入 res 的内容。
temp := make([]int, len(tmp))
copy(temp,tmp)
res=append(res,temp)
return
}
for i:=0;i<len(nums);i++{
if container(tmp,nums[i]){
continue
}
tmp=append(tmp,nums[i])
//next
helper(nums,tmp)
//recover
tmp=tmp[:len(tmp)-1]
}
}
func container(nums[]int,num int)bool{
for i:=0;i<len(nums);i++{
if nums[i]==num{
return true
}
}
return false
}
var res [][]int
var used[]bool
/*
同一轮中即使前后数字相同(即重复)也可以加,但是不同轮中不行。以[1,1,2]为例 在第一轮(初始轮)中,先取了第一个1之后,第二个1依然可以取,并不能被continue掉,说明单纯 if (vis[i] || (i > 0 && nums[i] == nums[i - 1])) { continue; }是不行的,因为这样的话就会执行continue了。 而什么时候需要continue呢?实际上是第一轮结束后,[1,1,2]已经被加入结果集中之后,最外层for循环(也就是取可行解第一个元素的for循环)往后运行,走到下标为1的第二个“1”的位置,我称之为第二轮,在第二轮中先确定可行解第一个元素为“1”之后再调用backtrack进入第二层for循环,for循环依然从i=0开始走,会发现此时0号位的1是false,那么这个“1”加不加呢?答案是不能加,因为假设加了之后,第二轮的可行解的[1,1,2]跟第一轮的可行解[1,1,2]是重复的(唯一的区别就是这里面的1和1对应原数组的下标是互换的)。 所以,!vis[i - 1]这个限制条件的作用主要是针对不同轮。
所以,如果两个相同的数字中(为了容易区分,命名为1a 和 1b),前一个(1a)的标记位为false,说明此时肯定不是在同一轮了(因为每时每刻处于同一轮的一定是标记位同时为true的(好好体会这句话),况且1a还在前面,如果在同一轮中,1a肯定是true,之所以为false,说明是回溯到1a的父层后, 先把1a置false,再for遍历到1b),既然不在同一层,那就要注意,不能在1b的轮中再加入1a了(因为1a的轮中肯定加入过1b了),所以判断1a和1b值相同,同时1a标记位为false,那就果断continue,那如果1b后面还有1c呢?同样的道理,只需要判断1b的状态是不是false,如果是false,说明他俩不在同一轮,1b的轮次中肯定加入过1c了,所以1c的轮次中就可以跳过1b
*/
func permuteUnique(nums []int) [][]int {
res=nil
used=make([]bool,len(nums))
sort.Ints(nums)
helper(nums,[]int(nil))
return res
}
func helper(nums[]int,tmp[]int){
if len(nums)==len(tmp){
temp:=make([]int,len(tmp))
copy(temp,tmp)
res=append(res,temp)
return
}
for i:=0;i<len(nums);i++{
if used[i]{
//我们已经选择过的不需要再放进去
continue
}
if i>0&&nums[i]==nums[i-1]&&used[i-1]==false{
//每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」
continue
}
tmp=append(tmp,nums[i])
used[i]=true
helper(nums,tmp)
//recove
tmp=tmp[:len(tmp)-1]
used[i]=false
}
}
3,39题,组合总和
var res [][]int
func combinationSum(candidates []int, target int) [][]int {
res=nil
if len(candidates)<1{
return res
}
sort.Ints(candidates)
if candidates[0]>target{
return res
}
helper(candidates,target,0,[]int(nil))
return res
}
func helper(candidates []int,target,start int,tmp []int){
if target==0{
temp:=make([]int,len(tmp))
copy(temp,tmp)
res=append(res,temp)
return
}
if target<0{
return
}
for i:=start;i<len(candidates);i++{
//无需保证唯一性,因为数字可以反复
tmp=append(tmp,candidates[i])
helper(candidates,target-candidates[i],i,tmp)
tmp=tmp[:len(tmp)-1]
}
}
var res [][]int
func combinationSum2(candidates []int, target int) [][]int {
res=nil
if len(candidates)<1{
return res
}
sort.Ints(candidates)
if candidates[0]>target{
return res
}
helper(candidates,target,0,[]int(nil))
return res
}
func helper(candidates[]int,target,start int,tmp[]int){
if target==0{
temp:=make([]int,len(tmp))
copy(temp,tmp)
res=append(res,temp)
return
}
if target<0{
return
}
for i:=start;i<len(candidates);i++{
// 大剪枝:减去 candidates[i] 小于 0,减去后面的 candidates[i + 1]、candidates[i + 2] 肯定也小于 0,因此用 break
if target-candidates[i]<0{
break
}
// 小剪枝:同一层相同数值的结点,从第 2 个开始,候选数更少,结果一定发生重复,因此跳过,用 continue
if i>start&&candidates[i]==candidates[i-1]{
continue
}
tmp=append(tmp,candidates[i])
helper(candidates,target-candidates[i],i+1,tmp)//不重复使用故i+1
tmp=tmp[:len(tmp)-1]
}
}
4,77题,组合
var res[][]int
func combine(n int, k int) [][]int {
res=nil
if n<1||k>n{
return res
}
helper(n,k,1,[]int(nil))
return res
}
func helper(n,k,start int,tmp[]int){
if len(tmp)==k{
temp:=make([]int,k)
copy(temp,tmp)
res=append(res,temp)
return
}
for i:=start;i<=n;i++{
tmp=append(tmp,i)
helper(n,k,i+1,tmp)
tmp=tmp[:len(tmp)-1]
}
}
var res [][]string
var colFollow[][]string
func solveNQueens(n int) [][]string {
res=nil
colFollow=make([][]string,n)
for i:=range colFollow{
colFollow[i]=make([]string,n)
}
for i:=range colFollow{
for j:=range colFollow[i]{
colFollow[i][j]="."
}
}
helper(n,0,colFollow)
return res
}
func helper(n,row int,colFollow[][]string){
if row==n{
tmp:=make([]string,n)
for i:=0;i<n;i++{
tmp[i]=strings.Join(colFollow[i],"")
}
res=append(res,tmp)
return
}
for col:=0;col<n;col++{
if isValid(row,col,colFollow,n){
colFollow[row][col]="Q"//放置
helper(n,row+1,colFollow)
colFollow[row][col]="."
}
}
}
func isValid(row,col int,colFollow[][]string,n int)bool{
//check col
for i:=0;i<col;i++{
if colFollow[row][i]=="Q"{
return false
}
}
//check row
for i:=0;i<row;i++{
if colFollow[i][col]=="Q"{
return false
}
}
//check positive
for i,j:=row-1,col-1;i>=0&&j>=0;i,j=i-1,j-1{
if colFollow[i][j]=="Q"{
return false
}
}
//check negetive
for i,j:=row-1,col+1;i>=0&&j<n;i,j=i-1,j+1{
if colFollow[i][j]=="Q"{
return false
}
}
return true
}