leecode 90. 子集 II

这篇博客探讨了在给定整数数组中生成所有可能子集的问题,重点在于如何处理重复元素以确保结果子集不重复。通过使用回溯算法和used数组,实现了在排序后的数组中进行层序遍历来避免重复。博客详细解释了算法的实现过程,并提供了Java代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

90. 子集 II

        本题需要在子集1的基础上去重,集合中可以有重复,但是求得的所有子集不能有重复。

属于树层去重,可以用used数组来表示是否重复过。

 

class Solution {

    List<List<Integer>> res = new ArrayList<>();
    LinkedList<Integer> path = new LinkedList<>();
    boolean[] used;
    public List<List<Integer>> subsetsWithDup(int[] nums) {
        if (nums.length == 0) {
            res.add(path);
            return res;
        }
        used = new boolean[nums.length];
//这步很重要,所有的去重都需要先排序,不排序做不出来
        Arrays.sort(nums);
       backtrack(nums, 0);
       return res;
    }

    private void backtrack(int[] nums, int index) {
//这里先加入空集合
        res.add(new ArrayList<>(path));
//这步可有可无,是判断结束条件的,但是如果没有这一步,for循环也会自动不满足条件结束
        if (index >= nums.length) return;
        for (int i = index; i < nums.length; i ++) {
//判断i>0且与上一个值相等且上一个值现在没用到,说明不是树枝上的相同的值,跳过这层循环
            if (i > 0 && nums[i - 1] == nums[i] && !used[i - 1]) continue;
            path.add(nums[i]);
            used[i] = true;
            backtrack(nums, i + 1);
            used[i] = false;
            path.removeLast();
        }
    }
}

<think>好的,我现在需要帮用户准备LeetCode面试常见题型及解法。首先,用户已经提供了一些参考资料,包括引用[1]、[2]、[3],涉及计数问题、滑动窗口、哈希表等。我需要根据这些信息,结合常见的LeetCode题型,整理出一个结构清晰的回答。 首先,常见的LeetCode题型有哪些呢?通常包括数组和字符串、链表、树与图、动态规划、回溯算法、滑动窗口、哈希表、堆和栈、数学问题等。用户提到的引用中提到了计数类型、滑动窗口、哈希表,这些都需要重点覆盖。 接下来,我需要按照用户的要求,分点列出题型及解法,每个部分给出示例题号和解题思路。同时,要引用用户提供的参考资料中的例子,比如引用[1]中的387题,引用[2]中的3题,引用[3]中的快乐数问题。 然后,生成相关问题,可能需要根据每个题型提出相关问题,比如数组中的双指针应用,或者动态规划的优化方法。但根据用户示例中的相关问题,可能更偏向于针对每个题型的进一步提问,比如如何优化、应用场景等。 需要注意的是,用户要求回答结构清晰,逐步解决问题,保证真实可靠。所以每个题型需要简明扼要地说明解题思路,并附上例题和可能的代码示例,但代码示例需要符合用户给的格式,比如Python。 另外,用户提供的引用中有提到滑动窗口的时间复杂度优化到O(n),哈希表用于检测循环,这些都要在相应的部分提到,并正确标注引用。例如,在滑动窗口部分提到例题3,引用[2],在哈希表部分提到快乐数问题,引用[3]。 还需要确保数学表达式使用正确的格式,比如变量用$...$包裹,独立公式用$$...$$。不过当前内容可能数学公式不多,但如果有的话需要正确应用。 最后,生成相关问题部分,需要针对每个题型提出相关问题,可能包括解法优化、时间复杂度分析、应用场景等。例如,数组和字符串部分可能问如何优化空间复杂度,滑动窗口如何扩展到其他问题等。 现在,整理结构: 1. 数组与字符串:双指针、哈希表计数(例题387引用[1]) 2. 滑动窗口:无重复字符的最长子串(例题3引用[2]) 3. 哈希表应用:快乐数(引用[3]) 4. 链表:虚拟头节点、快慢指针 5. 树与二叉树:递归、DFS/BFS 6. 动态规划:状态转移方程 7. 回溯算法:排列组合问题 8. 堆与优先队列:Top K问题 每个部分给出解题思路、例题和代码示例(如有必要),并正确标注引用。然后生成相关问题,例如数组相关的优化方法,滑动窗口的复杂度分析等。 需要检查是否有遗漏的常见题型,比如栈、队列、位运算等,但考虑到用户提供的引用,可能重点放在提到的部分。不过为了全面性,还是应该覆盖更多常见题型。 现在开始组织内容,确保每个部分简洁,包含例题和引用,最后生成相关问题。</think>### LeetCode 面试常见题型及解法 #### 1. 数组与字符串 **核心方法**:双指针、哈希表计数、原地修改 - **双指针**:用于有序数组去重、两数之和等问题。例如用左右指针夹逼法在$O(n)$时间内找到两数之和。 - **哈希表计数**:统计元素频率,如$387$. 字符串中的第一个唯一字符[^1]。 ```python def firstUniqChar(s: str) -> int: freq = {} for c in s: freq[c] = freq.get(c, 0) + 1 for i, c in enumerate(s): if freq[c] == 1: return i return -1 ``` #### 2. 滑动窗口 **优势**:将暴力遍历优化到$O(n)$时间复杂度[^2]。 - **关键点**:窗口左右指针移动条件,如$3$. 无重复字符的最长子串。 ```python def lengthOfLongestSubstring(s: str) -> int: char_set = set() left = max_len = 0 for right in range(len(s)): while s[right] in char_set: char_set.remove(s[left]) left += 1 char_set.add(s[right]) max_len = max(max_len, right - left + 1) return max_len ``` #### 3. 哈希表与数学 **应用场景**:检测循环、快速查找。 - **快乐数问题**:通过哈希表记录平方和避免无限循环[^3]。 $$n = 19 \rightarrow 1^2 + 9^2 = 82 \rightarrow 8^2 + 2^2 = 68 \rightarrow \dots$$ #### 4. 链表 **核心技巧**:虚拟头节点、快慢指针。 - **虚拟头节点**:简化头节点删除操作。 - **快慢指针**:找中点或检测环,如$141$. 环形链表。 #### 5. 树与二叉树 **高频考点**:递归遍历、DFS/BFS。 - **递归三要素**:终止条件、本级任务、返回值。例如$104$. 二叉树的最大深度。 ```python def maxDepth(root: TreeNode) -> int: if not root: return 0 return 1 + max(maxDepth(root.left), maxDepth(root.right)) ``` #### 6. 动态规划 **核心思想**:定义状态转移方程,避免重复计算。 - **经典问题**:$70$. 爬楼梯($dp[n] = dp[n-1] + dp[n-2]$),背包问题。 #### 7. 回溯算法 **适用场景**:排列、组合、子集问题。 - **模板**:选择→递归→撤销选择,如$46$. 全排列。 #### 8. 堆与优先队列 **典型应用**:Top K 问题、合并K个有序链表。 - **Python实现**:使用`heapq`模块,如$215$. 数组中的第K个最大元素。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值