1.LeetCode 491.递增子序列
题目链接:https://leetcode.cn/problems/non-decreasing-subsequences/description/
文章链接:https://programmercarl.com/0491.递增子序列.html
视频链接:https://www.bilibili.com/video/BV1EG4y1h78v/
思路:
本题的难点有如下:
1.终止条件;
2.如何去重;
3.如何判断递增。
1.终止条件:当获取到符合的列表后,需添加到结果集中,但不需要返回,因为还需要继续添加元素。
2.如何去重:
本题数组nums不能调整顺序,而且内部有重复元素,因此不能对其进行排序。故可以使用map对单层的元素使用情况进行标记,当出现重复元素时,只需要判断是否使用即可。
3.如何判断递增:将当前的节点与list中最后的元素进行比较(也就是上一层添入的元素),若大于则添入list中,否则,跳过当前节点继续判断。
解法:
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> list = new ArrayList<>();public List<List<Integer>> findSubsequences(int[] nums) {if (nums == null || nums.length == 0) {return res;}find(nums,0);return res;}public void find(int[] nums,int startIndex){if (list.size() >= 2) {res.add(new ArrayList(list));}// 检查单层中元素是否被使用Map<Integer,Boolean> used = new HashMap<>();for (int i = startIndex;i<nums.length;i++) {// 去重if (used.get(nums[i]) == null) {used.put(nums[i],true);} else if (used.get(nums[i]) == true) {continue;}// 处理当前节点// 递增if (list.size() == 0 || nums[i] >= list.get(list.size()-1)) {list.add(nums[i]);// 递归find(nums,i+1);// 撤销处理当前节点list.removeLast();} }}
}
2. LeetCode 46.全排列
题目链接:https://leetcode.cn/problems/permutations/description/
文章链接:https://programmercarl.com/0046.全排列.html
视频链接:https://www.bilibili.com/video/BV19v4y1S79W/
思路:
排列问题的不同:
1.每层都是从0开始搜索而不是startIndex
2.防止path列表中元素重复使用:需要used数组记录path里都放了哪些元素了,也可以使用list的contains方法。
解法:
class Solution {// List<List<Integer>> res = new ArrayList<>();// List<Integer> list = new ArrayList<>();// public List<List<Integer>> permute(int[] nums) {// if(nums==null || nums.length==0){// return res;// }// find(nums);// return res;// }// public void find(int[] nums) {// // 终止条件// if (list.size()==nums.length) {// res.add(new ArrayList(list));// return;// }// for(int i = 0; i<nums.length; i++) {// //处理当前节点// //判断当前节点是否在之前层添加过 去重// if(list.contains(nums[i])) {// continue;// }// list.add(nums[i]);// //递归// find(nums);// //撤销当前节点// list.removeLast();// }// }List<List<Integer>> res = new ArrayList<>();List<Integer> list = new ArrayList<>();boolean[] used = null;public List<List<Integer>> permute(int[] nums) {if(nums==null || nums.length==0){return res;}used = new boolean[nums.length];find(nums);return res;}public void find(int[] nums) {// 终止条件if (list.size()==nums.length) {res.add(new ArrayList(list));return;}for(int i = 0; i<nums.length; i++) {//处理当前节点//判断当前节点是否在之前层添加过 去重if(used[i] == true) continue;used[i] = true;list.add(nums[i]);//递归find(nums);//撤销当前节点used[i] = false;list.removeLast();}}
}
3. LeetCode 47.全排列 II
题目链接:https://leetcode.cn/problems/permutations-ii/description/
文章链接:https://programmercarl.com/0047.全排列II.html
视频链接:https://www.bilibili.com/video/BV1R84y1i7Tm/
思路:
题目值给定了一个包含重复数字的序列,因此需要去重。
1️⃣首先排序;
2️⃣单层出现重复元素,除了要判断i-1位置是否与i位置值相同外,还要判断第i-1位置是否被其他层使用过,若使用过,则当前层中i-1位置的值不参与去重判断,否则,参与去重判断。
注意:单层中只能给nums中一个位置的元素赋值ture,表示使用过;若出现第二个,说明是其他层使用过。
解法:
class Solution {List<List<Integer>> res = new ArrayList<>();List<Integer> path = new ArrayList<>();boolean[] used = null;public List<List<Integer>> permuteUnique(int[] nums) {if (nums == null || nums.length == 0) {return res;}Arrays.sort(nums);used = new boolean[nums.length];find(nums);return res;}public void find(int[] nums) {if (path.size() == nums.length) {res.add(new ArrayList(path));return;} for (int i=0;i<nums.length;i++) {if (used[i] == true) {continue;}// 去重
// 若used[i-1]=true,说明i-1位置的值已经被上面的层用过了,则当前层对i-1位置的判断就没有意义了,不应该将i-1位置参与当前层的分析,也就是说,即便nums[i] == nums[i-1],仍然不需要continue;若used[i-1]=false,则当前层对i-1位置的判断就有意义了,应该将i-1位置参与当前层的分析,也就是说,nums[i] == nums[i-1],需要continue。if (i>0 && nums[i] == nums[i-1] && used[i-1] == false) {continue;}// 处理当前节点used[i] = true;path.add(nums[i]);// 递归find(nums);// 撤销当前节点used[i] = false;path.removeLast();}}
}