leetcode--backtracking[0]

word search、subsets I / II、N-Queens I / II、Permutations I / II

回溯算法,backtracking,就是穷举所有可能的结果,记录已经走过的路(如用vector等写入1),当此路走不通时,就擦除这一步的影响(写入0),回溯到上一步,重新选择。可以将所有的结果,写成树的形式。

for循环中的递归很难理解,看到网友说:递归是将大问题不断变成小问题,for循环是先把大问题变成很多子问题。

1.Word Search

flag数组用来标记,找到了要找的字符,标记为1;当后面的结果说明这一点不可取时再写成0.

bool findNext(char** board, int boardRowSize, int boardColSize, int i, int j, char* word, int n, int** flag){
	if (word[n] == '\0')
	{
		return true;
	}
	flag[i][j] = 1;
	//上下左右的顺序
	if (i > 0 && flag[i-1][j]!=1 && board[i - 1][j] == word[n])
	{
		if (findNext(board, boardRowSize, boardColSize, i - 1, j, word, n + 1, flag))
			return true;
	}
	if (i + 1 < boardRowSize && flag[i + 1][j] != 1 && board[i + 1][j] == word[n])
	{
		if (findNext(board, boardRowSize, boardColSize, i + 1, j, word, n + 1, flag))
			return true;
	}
	if (j>0 && flag[i][j - 1] != 1 && board[i][j - 1] == word[n])
	{
		if (findNext(board, boardRowSize, boardColSize, i, j - 1, word, n + 1, flag))
			return true;
	}
	if (j + 1<boardColSize && flag[i][j + 1] != 1 && board[i][j + 1] == word[n])
	{
		if (findNext(board, boardRowSize, boardColSize, i, j + 1, word, n + 1, flag))
			return true;
	}
	flag[i][j] = 0;
	return false;
}
bool exist(char** board, int boardRowSize, int boardColSize, char* word) {
	if (*word == '\0')
		return false;
	int i, j;
	int **flag = (int**)malloc(boardRowSize*sizeof(int*));
	for (i = 0; i < boardRowSize; i++){
		flag[i] = (int*)calloc(boardColSize, sizeof(int));
	}
	for (i = 0; i < boardRowSize; i++){
		for (j = 0; j < boardColSize ; j++){
			if (board[i][j] == word[0]){
				if (findNext(board, boardRowSize, boardColSize, i, j, word, 1, flag))
				{
					free(flag);
					return true;
				}					
			}
		}
	}
	free(flag);
	return false;
}

2.Subsets

  求子序列问题,看了答案难过

此题的数据是不重复的,可以不用排序的...当输入数长度为n时,每一位都只有两种情况,存在或不存在

当n=3时,如右图所示,还有一个类似地第一位不取的时候,树的叶子是我们要的结果,遍历flag得到答案

void sort(int *nums, int numsSize)
{
	int j;
	for (int increment = numsSize / 2; increment > 0; increment /= 2){
		for (int i = increment; i<numsSize; i++){
			int tmp = nums[i];
			for (j = i; j >= increment; j -= increment){
				if (tmp < nums[j - increment])
					nums[j] = nums[j - increment];
				else
					break;
			}
			nums[j] = tmp;
		}
	}
}
void getNsubsets(int *nums, int numsSize, int *flag, int i, int** ret, int* returnSize, int **columnSizes){
	if (i == numsSize)
	{
		int *col = (int*)malloc(numsSize * (sizeof(int)));
		int j, k, count = 0;
		for (j = 0, k = 0; j < numsSize; j++){
			if (flag[j] == 1)
			{
				col[k++] = nums[j];
				count++;
			}
		}
		ret[*returnSize] = col;
		(*columnSizes)[*returnSize] = count;
		(*returnSize)++;
	}
	else
	{
		flag[i] = 1; getNsubsets(nums, numsSize, flag, i + 1, ret, returnSize, columnSizes);
		flag[i] = 0; getNsubsets(nums, numsSize, flag, i + 1, ret, returnSize, columnSizes);
	}
}
int** subsets(int* nums, int numsSize, int** columnSizes, int* returnSize) {
	int i, j;
	*returnSize = 1;
	
	for (i = 0; i < numsSize; i++){
		(*returnSize) *= 2;
	}
	int **ret = (int**)malloc((*returnSize)*sizeof(int*));
	int *columnS = (int*)malloc((*returnSize)*sizeof(int));
	*columnSizes = columnS;
	int *flag = (int *)calloc(numsSize,sizeof(int));//
	*returnSize = 0;
	sort(nums, numsSize);
	getNsubsets(nums, numsSize, flag, 0, ret, returnSize, columnSizes);
	return ret;
}

3.Subsets II

 

数据重复时的情况,感觉有点难委屈

比如122,画出左边的树,每一个节点都是我们要的结果;先排序,当前层cur和开始的下标index的关系饶了很久

void sort(int *nums, int numsSize)
{
	int j;
	for (int increment = numsSize / 2; increment > 0; increment /= 2){
		for (int i = increment; i<numsSize; i++){
			int tmp = nums[i];
			for (j = i; j >= increment; j -= increment){
				if (tmp < nums[j - increment])
					nums[j] = nums[j - increment];
				else
					break;
			}
			nums[j] = tmp;
		}
	}
}
void getNsubsetsWithDup(int *nums, int numsSize, int *flag, int cur,int index, int** ret, int* returnSize, int **columnSizes){
	if (cur <=numsSize)
	{
		int *col = (int*)malloc((cur+1) * (sizeof(int)));
		int j, k;
		for (j = 0, k = 0; j < cur; j++, k++){
			col[k] = flag[j];		
		}
		ret[*returnSize] = col;
		(*columnSizes)[*returnSize] = cur;
		(*returnSize)++;
		
	}
    for (int i = index ; i < numsSize; i++){
		if (i == index  || nums[i] != nums[i - 1])
		{
			
			flag[cur] = nums[i];
		
			getNsubsetsWithDup(nums, numsSize, flag, cur + 1,i+1, ret, returnSize, columnSizes);		
		}
	}
}
int** subsetsWithDup(int* nums, int numsSize, int** columnSizes, int* returnSize) {
	int i, j;
	*returnSize = 1;

	for (i = 0; i < numsSize; i++){
		(*returnSize) *= 2;
	}
	int **ret = (int**)malloc((*returnSize)*sizeof(int*));
	int *columnS = (int*)malloc((*returnSize)*sizeof(int));
	*columnSizes = columnS;
	int *flag = (int *)calloc(numsSize, sizeof(int));
	*returnSize = 0;
	sort(nums, numsSize);
	getNsubsetsWithDup(nums, numsSize, flag, 0,0, ret, returnSize, columnSizes);
	return ret;


}
4.Permutations   排序问题,看了答案


交换的数据之后要交换回来,相当于是擦除动作,swap写复杂了,传入两个地址就行

void swap_ij(int *nums, int numsSize, int i, int j){
	int tmp = nums[i];
	nums[i] = nums[j];
	nums[j] = tmp;
}
void permute_dfs(int*nums,int numsSize,int *returnSize,int **ret,int i){
	if (i == numsSize - 1)
	{
		int *col = (int*)malloc(numsSize * sizeof(int));
		memcpy(col, nums, numsSize*sizeof(int));
		ret[*returnSize] = col;
		(*returnSize)++;
	}

	for (int j = i; j < numsSize; j++)
	{
		swap_ij(nums, numsSize, i, j);		
		permute_dfs(nums, numsSize, returnSize, ret, i + 1);
		swap_ij(nums, numsSize, i, j);
	}
}
int** permute(int* nums, int numsSize, int* returnSize) {
	*returnSize = 0;
//	sort(nums, numsSize);
	int length = 1;
	for (int i = 1; i <= numsSize; i++){
		length *= i;
	}
	int **ret = (int **)malloc(length * sizeof(int *));
	int *col;
	permute_dfs(nums, numsSize, returnSize, ret, 0);
	return ret;
}

5.Permutations II

 

还是和I一样画树,不过用set记录是否出现过,用C++简单些...

class Solution {
public:
	void swap_ij(vector<int>& nums, int i, int j){
		int tmp = nums[i];
		nums[i] = nums[j];
		nums[j] = tmp;
	}
	void permute_dfs(vector<int>& nums, vector<vector<int>> &ret,int i){
		if (i == nums.size() - 1)
		{
			ret.push_back(nums);
			return;
		}
		unordered_set<int> set;
		for (int j = i; j < nums.size(); j++)
		{
			if (j == i || (nums[i] != nums[j] && set.find(nums[j])==set.end()))
			{
				set.insert(nums[j]);
				swap_ij(nums, i, j);
				
				permute_dfs(nums,  ret,i + 1);
				swap_ij(nums, i, j);
				
			}
		}
	}
	vector<vector<int>> permuteUnique(vector<int>& nums) {
		vector<vector<int>> ret;
		permute_dfs(nums, ret, 0);
		return ret;
	}
};

6.N-Queens

 

基本上这里每道题都有多种解法,八皇后问题也可以看做是序列问题,可以用一个N维数组标记,总的来说都是回溯,我用的最傻的方法。II更简答

char **chessBoard(int n)
{
	char ** ret = (char**)malloc(n*sizeof(char*));
	for (int i = 0; i < n; i++)
	{
		ret[i] = (char*)malloc((n+1)*sizeof(char));
		memset(ret[i], '.', n*sizeof(char));
		ret[i][n] = '\0';
	}
	return ret;
}
//确定char[i][j]是Q还是.
int isSafe(char** chess, int i, int j, int n){
	if (j >= n)
		return n;
	int ii, jj;//row,column
	for (jj = j; jj < n; jj++){
		for (ii = 0; ii < i;  ii++){
			if (chess[ii][jj] == 'Q')
			{
				break;
			}
		}
		if (ii == i)
		{
			break;
		}
	}
	if (jj == n)
	{
		return n;
	}
	//斜线
	for (int k = 0; jj-k >= 0; k++){
		if (ii >= k && chess[ii - k][jj - k] == 'Q')
		{
			jj=isSafe(chess, i, jj + 1, n);
			return jj;
		}
	}
	for (int k = 0; jj+k <n; k++){
		if (ii >= k && chess[ii - k][jj + k] == 'Q')
		{
			jj=isSafe(chess, i, jj + 1, n);
			return jj;
		}
	}
	if (jj == n)
		return n;
	return jj;
}
void backtrackingNQueens(int n, int i, int j, int *returnSize, char **map,char*** ret){
	if (i == n)
	{
		char ** chess = chessBoard(n);
//		memcpy(chess, map, n*sizeof(char*));
		for (int k = 0; k < n; k++){
	//		memcpy(chess[k], map[k], n*sizeof(char));
			for (int j = 0; j < n; j++){
				chess[k][j] = map[k][j];
			}
		}
		ret[*returnSize] = chess;
		(*returnSize)++;
		return;
	}
	while ((j = isSafe(map, i,j, n)) != n)
	{
		map[i][j] = 'Q';
		backtrackingNQueens(n, i + 1, 0, returnSize, map,ret);	
		map[i][j] = '.';
		j++;
	}
	/*if ((j = isSafe(map, i, j+1, n)) != n)
	{
		backtrackingNQueens(n, i + 1, 0, returnSize, map, ret);
	}*/
	
}
char*** solveNQueens(int n, int* returnSize) {
	*returnSize = 0;
	//建一个棋盘
	char ** map = chessBoard(n);
	char ***ret = (char ***)malloc(1000 * sizeof(char**));
	backtrackingNQueens(n, 0, 0, returnSize, map, ret);
	return ret;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值