全排列||
来源:力扣(LeetCode) 链接:leetcode.cn/problems/pe…
给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。
示例 1:
输入:nums = [1,1,2]
输出:[[1,1,2],[1,2,1],[2,1,1]]
示例 2:
输入:nums = [1,2,3]
输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
提示:
- 1 <= nums.length <= 8
- -10 <= nums[i] <= 10
代码
class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums); // 先对数组进行排序,以便后续剪枝
boolean[] visited = new boolean[nums.length]; // 记录元素是否被访问过
backtrack(nums, visited, new ArrayList<>(), result);
return result;
}
private void backtrack(int[] nums, boolean[] visited, List<Integer> tempList, List<List<Integer>> result) {
if (tempList.size() == nums.length) {
result.add(new ArrayList<>(tempList));
} else {
for (int i = 0; i < nums.length; i++) {
if (visited[i] || (i > 0 && nums[i] == nums[i - 1] && !visited[i - 1])) {
continue; // 剪枝条件:元素已经访问过,或者与前一个元素相同且前一个元素未访问过
}
visited[i] = true;
tempList.add(nums[i]);
backtrack(nums, visited, tempList, result);
visited[i] = false;
tempList.remove(tempList.size() - 1);
}
}
}
}
思路分析
- 创建一个结果列表
result来存储所有的全排列。 - 对给定的数组
nums进行排序,以便后续的剪枝操作。 - 创建一个布尔数组
visited,用于记录数组中的元素是否被访问过。 - 调用回溯函数
backtrack,传入排序后的数组nums、visited数组、空的临时列表tempList以及结果列表result。 - 在回溯函数
backtrack中,当临时列表tempList的大小等于数组nums的长度时,说明已经生成了一个完整的全排列,将其加入结果列表result中。 - 否则,遍历数组
nums,对于每个元素,如果当前元素已经被访问过或者当前元素与前一个元素相同且前一个元素未被访问过,则跳过继续下一个元素。 - 否则,将当前元素标记为已访问,将其加入临时列表
tempList中,然后递归调用回溯函数backtrack,生成下一个位置的全排列。 - 递归调用结束后,将当前元素的访问状态还原,即将其标记为未访问,并将临时列表
tempList的最后一个元素移除,以便进行下一轮的遍历。
旋转图像
来源:力扣(LeetCode) 链接:leetcode.cn/problems/ro…
给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。
你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[[7,4,1],[8,5,2],[9,6,3]]
示例 2:
输入:matrix = [[5,1,9,11],[2,4,8,10],[13,3,6,7],[15,14,12,16]]
输出:[[15,13,2,5],[14,3,4,1],[12,6,8,9],[16,7,10,11]]
提示:
- n == matrix.length == matrix[i].length
- 1 <= n <= 20
- -1000 <= matrix[i][j] <= 1000
代码
class Solution {
public void rotate(int[][] matrix) {
int n = matrix.length;
// 先进行转置操作
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
// 再进行每行反转操作
for (int i = 0; i < n; i++) {
for (int j = 0; j < n / 2; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[i][n - 1 - j];
matrix[i][n - 1 - j] = temp;
}
}
}
}
思路分析
- 定义矩阵的边长n,并遍历矩阵。
- 首先进行转置操作。遍历矩阵的上半部分,交换matrix[i][j]和matrix[j][i],即矩阵的转置操作。
- 然后进行每行的反转操作。遍历矩阵的每一行,将第j列的元素与第n-1-j列的元素交换,即实现了每行的反转操作。
- 完成上述两个操作后,矩阵就完成了顺时针旋转90度的操作。