回溯法 backTrack 力扣题

回溯法

回溯法又称为试探法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”

回溯是一种算法思想,可以用递归实现. 通俗点讲回溯就是一种试探.

在回溯法中,每次扩大当前部分解时,都面临一个可选的状态集合,新的部分解就通过在该集合中选择构造而成。这样的状态集合,其结构是一棵多叉树,每个树结点代表一个可能的部分解,它的儿子是在它的基础上生成的其他部分解。树根为初始状态,这样的状态集合称为状态空间树。
回溯算法的思想:
不断尝试, 直到不能尝试为止, 回退到上一步, 继续尝试.其实是一个深度优先遍历的过程

回溯法的效率

回溯算法本质上还是穷举.穷举所有可能,然后选出想要的答案.
可以通过剪枝操作,提高效率
效率低,为什么还选择使用回溯?因为一些问题只能用暴力搜索,没有更高效的解法

回溯解决的问题

  1. 组合问题
  2. 切割问题
  3. 子集问题
  4. 排列问题
  5. 棋盘问题
  6. 其他问题

Leetcode

组合

var path []int
var res [][]int

func main() {
    
    
	n, k := 1, 1
	res := combine(n, k)
	fmt.Println(res)
}

func combine(n int, k int) [][]int {
    
    
	res = make([][]int, 0)
	backTracking(n, k, 0)
	return res
}

func backTracking(n, k, startIndex int) {
    
    
	if len(path) == k {
    
    
		comb := make([]int, k)
		copy(comb, path)
		res = append(res, comb)
		return
	}
	for i := startIndex; i < n; i++ {
    
    
		path = append(path, i + 1)
		backTracking(n, k, i + 1)
		path = path[:len(path) - 1]
	}
}

Java


class Solution {
    
    
    List<List<Integer>> result;
    List<Integer> path;

    public List<List<Integer>> combine(int n, int k) {
    
    
        path = new LinkedList<>();
        result = new LinkedList<>();
        backTracking(n, k, 0);
        return result;
    }

    private void backTracking(int n, int k, int startIndex) {
    
    
        if (path.size() == k) {
    
    
            result.add(new LinkedList<>(path));
            return;
        }
        for (int i = startIndex; i < n; i ++){
    
    
            path.add(i + 1);
            backTracking(n, k, i + 1);
            path.remove(path.size() - 1);
        }

    }
}

电话号码的字母组合

var result []string
var mp map[byte]string

func main() {
    
    
	s := letterCombinations("23")
	fmt.Println(s)
}

func letterCombinations(digits string) []string {
    
    
	result = make([]string, 0)
	if len(digits) == 0 {
    
    
		return result
	}
	path := ""
	mp = map[byte]string{
    
    
		'2': "abc",
		'3': "def",
		'4': "ghi",
		'5': "jkl",
		'6': "mno",
		'7': "pqrs",
		'8': "tuv",
		'9': "wxyz",
	}
	backTrack(digits, 0, path)
	return result
}

func backTrack(digits string, depth int, path string) {
    
    
	if len(digits) == len(path) {
    
    
		result = append(result, path)
		return
	}
	letter := mp[digits[depth]]
	for i := 0; i < len(letter); i++ {
    
    
		backTrack(digits, depth+1, path+string(letter[i]))
	}
}
class Solution {
    
    
    private Map<Character, String> mp;
    private final List<String> result = new LinkedList<>();
    private String digits;

    private void initMap() {
    
    
        this.mp = new HashMap<>();
        mp.put('2', "abc");
        mp.put('3', "def");
        mp.put('4', "ghi");
        mp.put('5', "jkl");
        mp.put('6', "mno");
        mp.put('7', "pqrs");
        mp.put('8', "tuv");
        mp.put('9', "wxyz");
    }

    public List<String> letterCombinations(String digits) {
    
    
        String combination = "";
        this.digits = digits;
        if (digits.length() == 0) {
    
    
            return result;
        }
        initMap();
        backTracking(0, combination);
        return result;
    }

    private void backTracking(int depth, String combination) {
    
    
        if (combination.length() == digits.length()) {
    
    
            result.add(combination.toString());
            return;
        }
        String letter = mp.get(digits.charAt(depth));
        for (int i = 0; i < letter.length(); i++) {
    
    
            backTracking(depth + 1, combination + letter.charAt(i));
        }
    }
}

N皇后

func solveNQueens(n int) (result [][]string) {
    
    
	tmpResult := [][]int{
    
    }
	//我这里用uesd 维护棋盘位置是否可选的状态
	used := make([][]bool, n)
	for i := 0; i < n; i++ {
    
    
		used[i] = make([]bool, n)
	}
	path := []int{
    
    }
	var backTracking func([][]bool, int)
	backTracking = func(used [][]bool, index int) {
    
    
		if index > n {
    
    
			return
		}
		if len(path) == n {
    
    
			tmp := make([]int, n)
			copy(tmp, path)
			tmpResult = append(tmpResult, tmp)
			return
		}
		for i := 0; i < n; i++ {
    
    
			if !used[index][i] {
    
    
				path = append(path, i)
				// 为回溯做准备
				tmp := make([][]bool, n)
				for i := 0; i < n; i++ {
    
    
					tmp[i] = make([]bool, n)
					copy(tmp[i], used[i])
				}
				changeState(used, index, i)
				backTracking(used, index+1)
				// 回溯
				used = tmp
				path = path[:len(path)-1]
			}
		}
	}
	backTracking(used, 0)
	result = make([][]string, len(tmpResult))
	for i := 0; i < len(tmpResult); i++ {
    
    
		result[i] = make([]string, n)
		for j := 0; j < len(tmpResult[i]); j++ {
    
    
			for k := 0; k < n; k++ {
    
    
				if k == tmpResult[i][j] {
    
    
					result[i][j] += "Q"
				} else {
    
    
					result[i][j] += "."
				}
			}
		}
	}
	return
}

func changeState(used [][]bool, x, y int) {
    
    
	b := y - x
	b1 := x + y
	for i := 0; i < len(used); i++ {
    
    
		for j := 0; j < len(used[i]); j++ {
    
    
			if j == y {
    
    
				used[i][j] = true
			} else if j-i == b || i+j == b1 {
    
    
				used[i][j] = true
			}
		}
	}
}

全排列

golang

func permute(nums []int) (result [][]int) {
    
    
	path := []int{
    
    }
	//用used切片维护可选情况
	used := make([]bool,len(nums))
	var backTracking func([]int)
	backTracking = func(c []int) {
    
    
		if len(path) == len(nums) {
    
    
			comb := make([]int, len(nums))
			copy(comb, path)
			result = append(result, comb)
			return
		}
		for i := 0; i < len(c); i++ {
    
    
			if !used[i] {
    
    
				path = append(path, c[i])
				used[i] = true
				backTracking(nums)
				path = path[:len(path)-1]
				used[i] = false
			}
		}
	}
	backTracking(nums)
	return
}

Java

class Solution {
    
    
    private List<List<Integer>> result;
    private List<Integer> path;

    public List<List<Integer>> permute(int[] nums) {
    
    
        result = new LinkedList<>();
        path = new LinkedList<>();
        boolean[] used = new boolean[nums.length];
        backTracking(nums,used);
        return result;
    }

    private void backTracking(int[] nums, boolean[] used) {
    
    
        if (path.size() == nums.length) {
    
    
            this.result.add(new LinkedList<>(path));
            return;
        }
        for (int i = 0; i < nums.length; i++) {
    
    
            if (!used[i]) {
    
    
                path.add(nums[i]);
                used[i] = true;
                backTracking(nums,used);
                path.remove(path.size() - 1);
                used[i] = false;
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45867397/article/details/119057696
今日推荐