代码随想录算法训练营Day25
递增子序列
给你一个整数数组
nums,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。
数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
- 这里仍然是树层去重,不能排序后再去重,因为不能改变元素的相对位置
- 在哪一层取结果?(总结)
- 为什么不需要递归出口?
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> findSubsequences(int[] nums) {
backTracking(nums,0);
return result;
}
public void backTracking(int[] nums,int startIndex){
if(path.size()>1){
result.add(new ArrayList<>(path));
}
HashSet<Integer> set = new HashSet<>();//set有去重的功能
for(int i = startIndex;i<nums.length;i++){
//根据树形图去重
// 非递减判断
if (!path.isEmpty() && nums[i] < path.get(path.size() - 1)) {
continue;
}
// 当前层去重判断
if (set.contains(nums[i])) {
continue;
}
set.add(nums[i]);
path.add(nums[i]);
backTracking(nums,i+1);
path.remove(path.size()-1);
}
}
}
全排列
组合用startIndex标记,排列用used数组标记
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
boolean[] used = new boolean[nums.length];
backTracking(nums,used);
return result;
}
public void backTracking(int[] nums,boolean[] used){
if(path.size()==nums.length){
result.add(new ArrayList<>(path));
return;
}
for(int i = 0;i<nums.length;i++){
//if(used[i] == true) continue;
if(used[i]!=true){
used[i] = true;
path.add(nums[i]);
backTracking(nums,used);
path.removeLast();
used[i] = false;
}
}
}
}
全排列2
给定一个可包含重复数字的序列
nums,按任意顺序 返回所有不重复的全排列。在上题中去重,和前面组合问题中去重一样的逻辑
class Solution {
List<List<Integer>> result = new ArrayList<>();
List<Integer> path = new ArrayList<>();
public List<List<Integer>> permuteUnique(int[] nums) {
boolean[] used = new boolean[nums.length];
Arrays.sort(nums);
backTracking(nums, used);
return result;
}
public void backTracking(int[] nums, boolean[] used) {
if (path.size() == nums.length) {
result.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < nums.length; i++) {
if (used[i] == true)
continue;
if (i > 0 && nums[i] == nums[i - 1] && used[i - 1] == false)
continue;//这里和组合中的去重一样,used[i - 1] == false表示取的是第二个1
used[i] = true;
path.add(nums[i]);
backTracking(nums, used);
path.removeLast();
used[i] = false;
}
}
}
N皇后问题
按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
n 皇后问题 研究的是如何将n个皇后放置在n×n的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数n,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中'Q'和'.'分别代表了皇后和空位。
这里的难点在于如何处理二维数组的回溯
class Solution {
List<List<String>> result = new ArrayList<>();
public List<List<String>> solveNQueens(int n) {
char[][] chessboard = new char[n][n];
for (char[] c : chessboard) {//将chessboard填满.也可以用嵌套for来完成
Arrays.fill(c, '.');
}
backTracking(chessboard,n,0);
return result;
}
public void backTracking(char[][] chessboard,int n,int row){
if (row == n) {
result.add(Array2List(chessboard));
return;
}
for (int col = 0;col < n; ++col) {
if (isValid (row, col, n, chessboard)) {
chessboard[row][col] = 'Q';
backTracking(chessboard,n,row+1);
chessboard[row][col] = '.';
}
}
}
public List Array2List(char[][] chessboard) {
List<String> list = new ArrayList<>();
for (char[] c : chessboard) {
list.add(String.copyValueOf(c));
}
return list;
}
public boolean isValid(int row, int col, int n, char[][] chessboard) {
// 检查列
for (int i=0; i<row; ++i) { // 相当于剪枝
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 检查45度对角线
for (int i=row-1, j=col-1; i>=0 && j>=0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
// 检查135度对角线
for (int i=row-1, j=col+1; i>=0 && j<=n-1; i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}
}

浙公网安备 33010602011771号