LeetCode 回溯法合集

78. Subsets

public List<List<Integer>> subsets(int[] nums) {
		//把空集加进去
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		result.add(new ArrayList<Integer>());
		
		List<Integer> item = new ArrayList<Integer>();
		generate(result, item, nums, 0);
		
		return result;
	}
	
	public void generate(List<List<Integer>> result,List<Integer> item, int[] nums, int i) {
		//递归结束条件
		if(i >= nums.length) {
			return;
		}
		
		List<Integer> tempItem = new ArrayList<Integer>(item);
		tempItem.add(nums[i]);
		result.add(tempItem);
		generate(result, tempItem, nums, i + 1);
        
		generate(result, item, nums, i + 1);
	}

90. Subsets II

public List<List<Integer>> subsetsWithDup(int[] nums) {
		Arrays.sort(nums);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		result.add(new ArrayList<Integer>());
		
		generate(result, new ArrayList<Integer>(), new HashSet<List<Integer>>(), nums, 0);
		
		return result;
	}
	
	public void generate(List<List<Integer>> result, List<Integer> item,
			HashSet<List<Integer>> set, int[] nums, int i) {
		if(i >= nums.length) {
			return;
		}
		
		List<Integer> tempItem = new ArrayList<Integer>(item);
		tempItem.add(nums[i]);
		if(set.add(tempItem)) {
			result.add(tempItem);
		}
		generate(result, tempItem, set, nums, i + 1);
		
		generate(result, item, set, nums, i + 1);
	}

40. Combination Sum II

public List<List<Integer>> combinationSum2(int[] nums, int target) {
		Arrays.sort(nums);
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		
		generate(result, new ArrayList<Integer>(), new HashSet<List<Integer>>(), nums, target, 0, 0);
		return result;
	}
	
	public void generate(List<List<Integer>> result, List<Integer> item,
			HashSet<List<Integer>> set, int[] nums,
			int target, int sum, int i) {
		
		if(i >= nums.length || sum > target) {					//剪枝操作
			return;
		}
		
		List<Integer> tempItem = new ArrayList<Integer>(item);
		tempItem.add(nums[i]);
		sum += nums[i];
		if(sum == target && set.add(tempItem)) {
			result.add(tempItem);
		}
		generate(result, tempItem, set, nums, target, sum, i + 1);
		
		//回溯
		sum -= nums[i];
		generate(result, item, set, nums, target, sum, i + 1);
	}

46. Permutations

public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
		generate(0, result, new ArrayList<Integer>(), nums);
		return result;
	}
	
	public void generate(int i, List<List<Integer>> result, List<Integer> item,
			int[] nums) {
		if(i == nums.length) {
			result.add(new ArrayList<Integer>(item));
			return;
		}
		
		//i代表第i个位置,j代表第j个元素
		for(int j = 0; j < nums.length; j++) {
			if(item.contains(nums[j])) {
				continue;
			}
			List<Integer> tempItem = new ArrayList<Integer>(item);
			tempItem.add(i, nums[j]);
			generate(i + 1, result, tempItem, nums);
		}
	}

51. N-Queens

public List<List<String>> solveNQueens(int n) {
        List<List<String>> result = new ArrayList<List<String>>();
		int[][] mark = new int[n][n];
		List<String> item = new ArrayList<String>();
		
		for(int i = 0; i < n; i++) {						//初始化item
			StringBuffer sb = new StringBuffer();
			for(int j = 0; j < n; j++) {
				sb.append(".");
			}
			item.add(sb.toString());
		}
		
		generate(0, item, result, mark);
		return result;
	}
	
	public void putDownTheQueen(int x, int y, int[][] mark) {
		int[] dx = {-1, -1, -1, 0, 1, 1, 1, 0};				//行
		int[] dy = {-1, 0, 1, 1, 1, 0, -1, -1};				//列
		
		for(int i = 1; i < mark.length; i++) {				//最多走n - 1步
			for(int j = 0; j < 8; j++) {					//8个方向
				int newX = x + i * dx[j];
				int newY = y + i * dy[j];
				
				if(newX >= 0 && newX < mark.length			//新坐标没有越界,标记为1
						&& newY >= 0 && newY < mark.length) {
					mark[newX][newY] = 1;
				}
			}
		}
	}
	
	public void generate(int k, List<String> item, List<List<String>> result, int[][] mark) {
		if(k == mark.length) {
			result.add(new ArrayList<String>(item));
			return;
		}
		
		for(int i = 0; i < mark.length; i++) {
			if(mark[k][i] == 0) {
				//放下皇后,并更新item和mark
                                String tempString = item.get(k);
				StringBuffer sb = new StringBuffer(tempString);
				sb.setCharAt(i, 'Q');
				item.set(k, sb.toString());
				//备份mark
				int[][] tempMark = new int[mark.length][mark.length];
				
				for(int x = 0; x < mark.length; x++) {
					for(int y = 0; y < mark.length; y++) {
						tempMark[x][y] = mark[x][y];
					}
				}
				putDownTheQueen(k, i, tempMark);
				//进行下一行的放置
				generate(k + 1, item, result, tempMark);
                item.set(k, tempString);
			}
		}
	}


这几题有很多相似的地方:

1.这几题都有选择与不选择的情况


2.当要把子结果push到result时,如果item是会发生变化的,注意要push(new ArrayList(item)),因为我们要的子结果是这个状态下的item。java是传址的,如果直接push(item) 会导致如果item改变后,result里的子结果跟着改变,最终结果不正确;


3.选择时:我们要对数据进行操作,这时候要把原数据备份,即类似于tempItem。

然后原数据不变,备份数据变,再把备份数据进行递归调用。不选择时:直接把原数据进行递归调用。


4.有时候还可能出现剪枝等优化操作。


5.当进行递归时,如果要避免重复,可以用mark数组。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值