diff --git a/problems/0046.全排列.md b/problems/0046.全排列.md index c5369ddd..836c3646 100644 --- a/problems/0046.全排列.md +++ b/problems/0046.全排列.md @@ -331,6 +331,34 @@ var permute = function(nums) { ``` +## TypeScript + +```typescript +function permute(nums: number[]): number[][] { + const resArr: number[][] = []; + const helperSet: Set = new Set(); + backTracking(nums, []); + return resArr; + function backTracking(nums: number[], route: number[]): void { + if (route.length === nums.length) { + resArr.push(route.slice()); + return; + } + let tempVal: number; + for (let i = 0, length = nums.length; i < length; i++) { + tempVal = nums[i]; + if (!helperSet.has(tempVal)) { + route.push(tempVal); + helperSet.add(tempVal); + backTracking(nums, route); + route.pop(); + helperSet.delete(tempVal); + } + } + } +}; +``` + ### C ```c diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md index 0cecac50..cce25cd9 100644 --- a/problems/0047.全排列II.md +++ b/problems/0047.全排列II.md @@ -292,6 +292,34 @@ var permuteUnique = function (nums) { ``` +### TypeScript + +```typescript +function permuteUnique(nums: number[]): number[][] { + nums.sort((a, b) => a - b); + const resArr: number[][] = []; + const usedArr: boolean[] = new Array(nums.length).fill(false); + backTracking(nums, []); + return resArr; + function backTracking(nums: number[], route: number[]): void { + if (route.length === nums.length) { + resArr.push(route.slice()); + return; + } + for (let i = 0, length = nums.length; i < length; i++) { + if (i > 0 && nums[i] === nums[i - 1] && usedArr[i - 1] === false) continue; + if (usedArr[i] === false) { + route.push(nums[i]); + usedArr[i] = true; + backTracking(nums, route); + usedArr[i] = false; + route.pop(); + } + } + } +}; +``` + ### Swift ```swift diff --git a/problems/0078.子集.md b/problems/0078.子集.md index cdb5f548..e1c52b5b 100644 --- a/problems/0078.子集.md +++ b/problems/0078.子集.md @@ -272,7 +272,28 @@ var subsets = function(nums) { }; ``` +## TypeScript + +```typescript +function subsets(nums: number[]): number[][] { + const resArr: number[][] = []; + backTracking(nums, 0, []); + return resArr; + function backTracking(nums: number[], startIndex: number, route: number[]): void { + resArr.push(route.slice()); + let length = nums.length; + if (startIndex === length) return; + for (let i = startIndex; i < length; i++) { + route.push(nums[i]); + backTracking(nums, i + 1, route); + route.pop(); + } + } +}; +``` + ## C + ```c int* path; int pathTop; diff --git a/problems/0090.子集II.md b/problems/0090.子集II.md index d08707b4..74ce000b 100644 --- a/problems/0090.子集II.md +++ b/problems/0090.子集II.md @@ -318,6 +318,28 @@ var subsetsWithDup = function(nums) { ``` +### TypeScript + +```typescript +function subsetsWithDup(nums: number[]): number[][] { + nums.sort((a, b) => a - b); + const resArr: number[][] = []; + backTraking(nums, 0, []); + return resArr; + function backTraking(nums: number[], startIndex: number, route: number[]): void { + resArr.push(route.slice()); + let length: number = nums.length; + if (startIndex === length) return; + for (let i = startIndex; i < length; i++) { + if (i > startIndex && nums[i] === nums[i - 1]) continue; + route.push(nums[i]); + backTraking(nums, i + 1, route); + route.pop(); + } + } +}; +``` + ### C ```c @@ -387,7 +409,7 @@ int** subsetsWithDup(int* nums, int numsSize, int* returnSize, int** returnColum } ``` -## Swift +### Swift ```swift func subsetsWithDup(_ nums: [Int]) -> [[Int]] { diff --git a/problems/0093.复原IP地址.md b/problems/0093.复原IP地址.md index 714dcb4f..7910fc50 100644 --- a/problems/0093.复原IP地址.md +++ b/problems/0093.复原IP地址.md @@ -455,6 +455,45 @@ var restoreIpAddresses = function(s) { }; ``` +## TypeScript + +```typescript +function isValidIpSegment(str: string): boolean { + let resBool: boolean = true; + let tempVal: number = Number(str); + if ( + str.length === 0 || isNaN(tempVal) || + tempVal > 255 || tempVal < 0 || + (str.length > 1 && str[0] === '0') + ) { + resBool = false; + } + return resBool; +} +function restoreIpAddresses(s: string): string[] { + const resArr: string[] = []; + backTracking(s, 0, []); + return resArr; + function backTracking(s: string, startIndex: number, route: string[]): void { + let length: number = s.length; + if (route.length === 4 && startIndex >= length) { + resArr.push(route.join('.')); + return; + } + if (route.length === 4 || startIndex >= length) return; + let tempStr: string = ''; + for (let i = startIndex + 1; i <= Math.min(length, startIndex + 3); i++) { + tempStr = s.slice(startIndex, i); + if (isValidIpSegment(tempStr)) { + route.push(s.slice(startIndex, i)); + backTracking(s, i, route); + route.pop(); + } + } + } +}; +``` + ## Go 回溯(对于前导 0的IP(特别注意s[startIndex]=='0'的判断,不应该写成s[startIndex]==0,因为s截取出来不是数字)) diff --git a/problems/0098.验证二叉搜索树.md b/problems/0098.验证二叉搜索树.md index c0f3e039..a8f3c324 100644 --- a/problems/0098.验证二叉搜索树.md +++ b/problems/0098.验证二叉搜索树.md @@ -408,7 +408,28 @@ class Solution: return True ``` -## Go +```python +# 遵循Carl的写法,只添加了节点判断的部分 +class Solution: + def isValidBST(self, root: TreeNode) -> bool: + # method 2 + que, pre = [], None + while root or que: + while root: + que.append(root) + root = root.left + root = que.pop() + # 对第一个节点只做记录,对后面的节点进行比较 + if pre is None: + pre = root.val + else: + if pre >= root.val: return False + pre = root.val + root = root.right + return True +``` + +## Go ```Go import "math" diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index 0007b4d4..e4e232c8 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -437,41 +437,6 @@ class Solution: return True ``` -层序遍历 - -```python -class Solution: - def isSymmetric(self, root: TreeNode) -> bool: - if not root: return True - que, cnt = [[root.left, root.right]], 1 - while que: - nodes, tmp, sign = que.pop(), [], False - for node in nodes: - if not node: - tmp.append(None) - tmp.append(None) - else: - if node.left: - tmp.append(node.left) - sign = True - else: - tmp.append(None) - if node.right: - tmp.append(node.right) - sign = True - else: - tmp.append(None) - p1, p2 = 0, len(nodes) - 1 - while p1 < p2: - if (not nodes[p1] and nodes[p2]) or (nodes[p1] and not nodes[p2]): return False - elif nodes[p1] and nodes[p2] and nodes[p1].val != nodes[p2].val: return False - p1 += 1 - p2 -= 1 - if sign: que.append(tmp) - cnt += 1 - return True -``` - ## Go ```go diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 496de431..7ecca773 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -790,7 +790,7 @@ func findRootIndex(target int,inorder []int) int{ ```javascript var buildTree = function(inorder, postorder) { - if (!preorder.length) return null; + if (!inorder.length) return null; const rootVal = postorder.pop(); // 从后序遍历的数组中获取中间节点的值, 即数组最后一个值 let rootIndex = inorder.indexOf(rootVal); // 获取中间节点在中序遍历中的下标 const root = new TreeNode(rootVal); // 创建中间节点 diff --git a/problems/0108.将有序数组转换为二叉搜索树.md b/problems/0108.将有序数组转换为二叉搜索树.md index bd5915fd..6ee3947b 100644 --- a/problems/0108.将有序数组转换为二叉搜索树.md +++ b/problems/0108.将有序数组转换为二叉搜索树.md @@ -355,6 +355,7 @@ func sortedArrayToBST(nums []int) *TreeNode { ``` ## JavaScript +递归 ```javascript var sortedArrayToBST = function (nums) { @@ -372,7 +373,44 @@ var sortedArrayToBST = function (nums) { return buildTree(nums, 0, nums.length - 1); }; ``` - +迭代 +```JavaScript +var sortedArrayToBST = function(nums) { + if(nums.length===0){ + return null; + } + let root=new TreeNode(0); //初始根节点 + let nodeQue=[root]; //放遍历的节点,并初始化 + let leftQue=[0]; //放左区间的下标,初始化 + let rightQue=[nums.length-1]; // 放右区间的下标 + + while(nodeQue.length){ + let curNode=nodeQue.pop(); + let left=leftQue.pop(); + let right=rightQue.pop(); + let mid=left+Math.floor((right-left)/2); + + curNode.val=nums[mid]; //将下标为mid的元素给中间节点 + +// 处理左区间 + if(left<=mid-1){ + curNode.left=new TreeNode(0); + nodeQue.push(curNode.left); + leftQue.push(left); + rightQue.push(mid-1); + } + +// 处理右区间 + if(right>=mid+1){ + curNode.right=new TreeNode(0); + nodeQue.push(curNode.right); + leftQue.push(mid+1); + rightQue.push(right); + } + } + return root; +}; +``` ## TypeScript ```typescript diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index f50f1c1d..10b747cb 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -450,6 +450,38 @@ var partition = function(s) { }; ``` +## TypeScript + +```typescript +function partition(s: string): string[][] { + function isPalindromeStr(s: string, left: number, right: number): boolean { + while (left < right) { + if (s[left++] !== s[right--]) { + return false; + } + } + return true; + } + function backTracking(s: string, startIndex: number, route: string[]): void { + let length: number = s.length; + if (length === startIndex) { + resArr.push(route.slice()); + return; + } + for (let i = startIndex; i < length; i++) { + if (isPalindromeStr(s, startIndex, i)) { + route.push(s.slice(startIndex, i + 1)); + backTracking(s, i + 1, route); + route.pop(); + } + } + } + const resArr: string[][] = []; + backTracking(s, 0, []); + return resArr; +}; +``` + ## C ```c diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index f0a46a40..741a735a 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -315,5 +315,75 @@ class Solution { } ``` +C: +```C +typedef struct HashNodeTag { + int key; /* num */ + struct HashNodeTag *next; +}HashNode; + +/* Calcualte the hash key */ +static inline int hash(int key, int size) { + int index = key % size; + return (index > 0) ? (index) : (-index); +} + +/* Calculate the sum of the squares of its digits*/ +static inline int calcSquareSum(int num) { + unsigned int sum = 0; + while(num > 0) { + sum += (num % 10) * (num % 10); + num = num/10; + } + return sum; +} + +#define HASH_TABLE_SIZE (32) + +bool isHappy(int n){ + int sum = n; + int index = 0; + bool bHappy = false; + bool bExit = false; + /* allocate the memory for hash table with chaining method*/ + HashNode ** hashTable = (HashNode **)calloc(HASH_TABLE_SIZE, sizeof(HashNode)); + + while(bExit == false) { + /* check if n has been calculated */ + index = hash(n, HASH_TABLE_SIZE); + + HashNode ** p = hashTable + index; + + while((*p) && (bExit == false)) { + /* Check if this num was calculated, if yes, this will be endless loop */ + if((*p)->key == n) { + bHappy = false; + bExit = true; + } + /* move to next node of the same index */ + p = &((*p)->next); + } + + /* put n intot hash table */ + HashNode * newNode = (HashNode *)malloc(sizeof(HashNode)); + newNode->key = n; + newNode->next = NULL; + + *p = newNode; + + sum = calcSquareSum(n); + if(sum == 1) { + bHappy = true; + bExit = true; + } + else { + n = sum; + + } + } + + return bHappy; +} +``` -----------------------
diff --git a/problems/0332.重新安排行程.md b/problems/0332.重新安排行程.md index e65786c6..d087d97b 100644 --- a/problems/0332.重新安排行程.md +++ b/problems/0332.重新安排行程.md @@ -448,6 +448,50 @@ var findItinerary = function(tickets) { ``` +### TypeScript + +```typescript +function findItinerary(tickets: string[][]): string[] { + /** + TicketsMap 实例: + { NRT: Map(1) { 'JFK' => 1 }, JFK: Map(2) { 'KUL' => 1, 'NRT' => 1 } } + 这里选择Map数据结构的原因是:与Object类型的一个主要差异是,Map实例会维护键值对的插入顺序。 + */ + type TicketsMap = { + [index: string]: Map + }; + tickets.sort((a, b) => { + return a[1] < b[1] ? -1 : 1; + }); + const ticketMap: TicketsMap = {}; + for (const [from, to] of tickets) { + if (ticketMap[from] === undefined) { + ticketMap[from] = new Map(); + } + ticketMap[from].set(to, (ticketMap[from].get(to) || 0) + 1); + } + const resRoute = ['JFK']; + backTracking(tickets.length, ticketMap, resRoute); + return resRoute; + function backTracking(ticketNum: number, ticketMap: TicketsMap, route: string[]): boolean { + if (route.length === ticketNum + 1) return true; + const targetMap = ticketMap[route[route.length - 1]]; + if (targetMap !== undefined) { + for (const [to, count] of targetMap.entries()) { + if (count > 0) { + route.push(to); + targetMap.set(to, count - 1); + if (backTracking(ticketNum, ticketMap, route) === true) return true; + targetMap.set(to, count); + route.pop(); + } + } + } + return false; + } +}; +``` + ### Swift 直接迭代tickets数组: diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 82be1829..45f19b6e 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -281,6 +281,38 @@ impl Solution { } } ``` + +C: +```C +int* intersection1(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ + + int nums1Cnt[1000] = {0}; + int lessSize = nums1Size < nums2Size ? nums1Size : nums2Size; + int * result = (int *) calloc(lessSize, sizeof(int)); + int resultIndex = 0; + int* tempNums; + + int i; + + /* Calculate the number's counts for nums1 array */ + for(i = 0; i < nums1Size; i ++) { + nums1Cnt[nums1[i]]++; + } + + /* Check if the value in nums2 is existing in nums1 count array */ + for(i = 0; i < nums2Size; i ++) { + if(nums1Cnt[nums2[i]] > 0) { + result[resultIndex] = nums2[i]; + resultIndex ++; + /* Clear this count to avoid duplicated value */ + nums1Cnt[nums2[i]] = 0; + } + } + * returnSize = resultIndex; + return result; +} +``` + ## 相关题目 * 350.两个数组的交集 II diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index c8d9bc04..b24fb365 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -208,6 +208,75 @@ class Solution { } ``` +```java +public class Solution { + public static void main(String[] args) { + int num[] = {1,5,11,5}; + canPartition(num); + + } + public static boolean canPartition(int[] nums) { + int len = nums.length; + // 题目已经说非空数组,可以不做非空判断 + int sum = 0; + for (int num : nums) { + sum += num; + } + // 特判:如果是奇数,就不符合要求 + if ((sum %2 ) != 0) { + return false; + } + + int target = sum / 2; //目标背包容量 + // 创建二维状态数组,行:物品索引,列:容量(包括 0) + /* + dp[i][j]表示从数组的 [0, i] 这个子区间内挑选一些正整数 + 每个数只能用一次,使得这些数的和恰好等于 j。 + */ + boolean[][] dp = new boolean[len][target + 1]; + + // 先填表格第 0 行,第 1 个数只能让容积为它自己的背包恰好装满 (这里的dp[][]数组的含义就是“恰好”,所以就算容积比它大的也不要) + if (nums[0] <= target) { + dp[0][nums[0]] = true; + } + // 再填表格后面几行 + //外层遍历物品 + for (int i = 1; i < len; i++) { + //内层遍历背包 + for (int j = 0; j <= target; j++) { + // 直接从上一行先把结果抄下来,然后再修正 + dp[i][j] = dp[i - 1][j]; + + //如果某个物品单独的重量恰好就等于背包的重量,那么也是满足dp数组的定义的 + if (nums[i] == j) { + dp[i][j] = true; + continue; + } + //如果某个物品的重量小于j,那就可以看该物品是否放入背包 + //dp[i - 1][j]表示该物品不放入背包,如果在 [0, i - 1] 这个子区间内已经有一部分元素,使得它们的和为 j ,那么 dp[i][j] = true; + //dp[i - 1][j - nums[i]]表示该物品放入背包。如果在 [0, i - 1] 这个子区间内就得找到一部分元素,使得它们的和为 j - nums[i]。 + if (nums[i] < j) { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i]]; + } + } + } + for (int i = 0; i < len; i++) { + for (int j = 0; j <= target; j++) { + System.out.print(dp[i][j]+" "); + } + System.out.println(); + } + return dp[len - 1][target]; + } +} +//dp数组的打印结果 +false true false false false false false false false false false false +false true false false false true true false false false false false +false true false false false true true false false false false true +false true false false false true true false false false true true +``` + + 二维数组版本(易于理解): ```Java class Solution { diff --git a/problems/0491.递增子序列.md b/problems/0491.递增子序列.md index 6103c3d0..3ea2382b 100644 --- a/problems/0491.递增子序列.md +++ b/problems/0491.递增子序列.md @@ -396,7 +396,35 @@ var findSubsequences = function(nums) { ``` +## TypeScript + +```typescript +function findSubsequences(nums: number[]): number[][] { + const resArr: number[][] = []; + backTracking(nums, 0, []); + return resArr; + function backTracking(nums: number[], startIndex: number, route: number[]): void { + let length: number = nums.length; + if (route.length >= 2) { + resArr.push(route.slice()); + } + const usedSet: Set = new Set(); + for (let i = startIndex; i < length; i++) { + if ( + nums[i] < route[route.length - 1] || + usedSet.has(nums[i]) + ) continue; + usedSet.add(nums[i]); + route.push(nums[i]); + backTracking(nums, i + 1, route); + route.pop(); + } + } +}; +``` + ### C + ```c int* path; int pathTop; diff --git a/problems/0509.斐波那契数.md b/problems/0509.斐波那契数.md index 638bfdfe..d339940c 100644 --- a/problems/0509.斐波那契数.md +++ b/problems/0509.斐波那契数.md @@ -277,7 +277,30 @@ int fib(int n){ return fib(n-1) + fib(n-2); } ``` +### Rust +动态规划: +```Rust +pub fn fib(n: i32) -> i32 { + let n = n as usize; + let mut dp = vec![0; 31]; + dp[1] = 1; + for i in 2..=n { + dp[i] = dp[i - 1] + dp[i - 2]; + } + dp[n] +} +``` - +递归实现: +```Rust +pub fn fib(n: i32) -> i32 { + //若n小于等于1,返回n + f n <= 1 { + return n; + } + //否则返回fib(n-1) + fib(n-2) + return fib(n - 1) + fib(n - 2); +} +``` -----------------------
diff --git a/problems/0704.二分查找.md b/problems/0704.二分查找.md index 15e096a0..55625130 100644 --- a/problems/0704.二分查找.md +++ b/problems/0704.二分查找.md @@ -276,7 +276,7 @@ func search(nums []int, target int) int { ``` **JavaScript:** -(版本一)左闭右闭区间 +(版本一)左闭右闭区间 [left, right] ```js /** @@ -285,10 +285,12 @@ func search(nums []int, target int) int { * @return {number} */ var search = function(nums, target) { + // right是数组最后一个数的下标,num[right]在查找范围内,是左闭右闭区间 let left = 0, right = nums.length - 1; - // 使用左闭右闭区间 + // 当left=right时,由于nums[right]在查找范围内,所以要包括此情况 while (left <= right) { let mid = left + Math.floor((right - left)/2); + // 如果中间数大于目标值,要把中间数排除查找范围,所以右边界更新为mid-1;如果右边界更新为mid,那中间数还在下次查找范围内 if (nums[mid] > target) { right = mid - 1; // 去左面闭区间寻找 } else if (nums[mid] < target) { @@ -300,7 +302,7 @@ var search = function(nums, target) { return -1; }; ``` -(版本二)左闭右开区间 +(版本二)左闭右开区间 [left, right) ```js /** @@ -309,10 +311,13 @@ var search = function(nums, target) { * @return {number} */ var search = function(nums, target) { - let left = 0, right = nums.length; - // 使用左闭右开区间 [left, right) + // right是数组最后一个数的下标+1,nums[right]不在查找范围内,是左闭右开区间 + let left = 0, right = nums.length; + // 当left=right时,由于nums[right]不在查找范围,所以不必包括此情况 while (left < right) { let mid = left + Math.floor((right - left)/2); + // 如果中间值大于目标值,中间值不应在下次查找的范围内,但中间值的前一个值应在; + // 由于right本来就不在查找范围内,所以将右边界更新为中间值,如果更新右边界为mid-1则将中间值的前一个值也踢出了下次寻找范围 if (nums[mid] > target) { right = mid; // 去左区间寻找 } else if (nums[mid] < target) { diff --git a/problems/0844.比较含退格的字符串.md b/problems/0844.比较含退格的字符串.md index 41791114..dccc5404 100644 --- a/problems/0844.比较含退格的字符串.md +++ b/problems/0844.比较含退格的字符串.md @@ -185,6 +185,36 @@ class Solution { } ``` +双指针: + +```java +class Solution { +public static boolean backspaceCompare(String s, String t) { + char[] sarray = s.toCharArray(); + char[] tarray = t.toCharArray(); + return generate(sarray).equals(generate(tarray)); + } + public static String generate(char[] a){ + int slow = -1; + int fast = 0; + if(a.length == 1){ + return new String(a); + } else{ + for(fast = 0; fast < a.length; fast++){ + if(a[fast] != '#') + a[++slow] = a[fast]; + else{ + if(slow >= 0) + slow--; + } + } + return new String(a,0,slow + 1); + } + } +} +``` + + ### python diff --git a/problems/周总结/20201112回溯周末总结.md b/problems/周总结/20201112回溯周末总结.md index c61de4bb..af08097b 100644 --- a/problems/周总结/20201112回溯周末总结.md +++ b/problems/周总结/20201112回溯周末总结.md @@ -76,7 +76,7 @@ * 空间复杂度:$O(n)$,递归深度为n,所以系统栈所用空间为$O(n)$,每一层递归所用的空间都是常数级别,注意代码里的result和path都是全局变量,就算是放在参数里,传的也是引用,并不会新申请内存空间,最终空间复杂度为$O(n)$。 排列问题分析: -* 时间复杂度:$O(n!)$,这个可以从排列的树形图中很明显发现,每一层节点为n,第二层每一个分支都延伸了n-1个分支,再往下又是n-2个分支,所以一直到叶子节点一共就是 n * n-1 * n-2 * ..... 1 = n!。 +* 时间复杂度:$O(n!)$,这个可以从排列的树形图中很明显发现,每一层节点为n,第二层每一个分支都延伸了n-1个分支,再往下又是n-2个分支,所以一直到叶子节点一共就是 n * n-1 * n-2 * ..... 1 = n!。每个叶子节点都会有一个构造全排列填进数组的操作(对应的代码:`result.push_back(path)`),该操作的复杂度为$O(n)$。所以,最终时间复杂度为:n * n!,简化为$O(n!)$。 * 空间复杂度:$O(n)$,和子集问题同理。 组合问题分析: diff --git a/problems/回溯算法去重问题的另一种写法.md b/problems/回溯算法去重问题的另一种写法.md index b4bdda00..f48097e1 100644 --- a/problems/回溯算法去重问题的另一种写法.md +++ b/problems/回溯算法去重问题的另一种写法.md @@ -365,6 +365,87 @@ class Solution: return res ``` +TypeScript: + +**90.子集II** + +```typescript +function subsetsWithDup(nums: number[]): number[][] { + nums.sort((a, b) => a - b); + const resArr: number[][] = []; + backTraking(nums, 0, []); + return resArr; + function backTraking(nums: number[], startIndex: number, route: number[]): void { + resArr.push(route.slice()); + const helperSet: Set = new Set(); + for (let i = startIndex, length = nums.length; i < length; i++) { + if (helperSet.has(nums[i])) continue; + helperSet.add(nums[i]); + route.push(nums[i]); + backTraking(nums, i + 1, route); + route.pop(); + } + } +}; +``` + +**40. 组合总和 II** + +```typescript +function combinationSum2(candidates: number[], target: number): number[][] { + candidates.sort((a, b) => a - b); + const resArr: number[][] = []; + backTracking(candidates, target, 0, 0, []); + return resArr; + function backTracking( + candidates: number[], target: number, + curSum: number, startIndex: number, route: number[] + ) { + if (curSum > target) return; + if (curSum === target) { + resArr.push(route.slice()); + return; + } + const helperSet: Set = new Set(); + for (let i = startIndex, length = candidates.length; i < length; i++) { + let tempVal: number = candidates[i]; + if (helperSet.has(tempVal)) continue; + helperSet.add(tempVal); + route.push(tempVal); + backTracking(candidates, target, curSum + tempVal, i + 1, route); + route.pop(); + + } + } +}; +``` + +**47. 全排列 II** + +```typescript +function permuteUnique(nums: number[]): number[][] { + const resArr: number[][] = []; + const usedArr: boolean[] = []; + backTracking(nums, []); + return resArr; + function backTracking(nums: number[], route: number[]): void { + if (nums.length === route.length) { + resArr.push(route.slice()); + return; + } + const usedSet: Set = new Set(); + for (let i = 0, length = nums.length; i < length; i++) { + if (usedArr[i] === true || usedSet.has(nums[i])) continue; + usedSet.add(nums[i]); + route.push(nums[i]); + usedArr[i] = true; + backTracking(nums, route); + usedArr[i] = false; + route.pop(); + } + } +}; +``` Go: