491.递增子序列
给定一个整型数组, 你的任务是找到所有该数组的递增子序列,递增子序列的长度至少是2。
示例:
- 输入: [4, 6, 7, 7]
- 输出: [[4, 6], [4, 7], [4, 6, 7], [4, 6, 7, 7], [6, 7], [6, 7, 7], [7,7], [4,7,7]]
说明:
- 给定数组的长度不会超过15。
- 数组中的整数范围是 [-100,100]。
- 给定数组中可能包含重复数字,相等的数字应该被视为递增的一种情况。
分析:
使序列合法的办法非常简单,即给「选择」做一个限定条件,只有当前的元素大于等于上一个选择的元素的时候才能选择这个元素,这样枚举出来的所有元素都是合法的
那如何保证没有重复呢?我们需要给「不选择」做一个限定条件,只有当当前的元素不等于上一个选择的元素的时候,才考虑不选择当前元素,直接递归后面的元素。因为如果有两个相同的元素,我们会考虑这样四种情况:——考虑怎么样会重复?需要避免的情况是什么样的?
x前者被选择,后者被选择
前者被选择,后者不被选择
前者不被选择,后者被选择
前者不被选择,后者不被选择
其中第二种情况和第三种情况其实是等价的,我们这样限制之后,舍弃了第二种,保留了第三种,于是达到了去重的目的。——也就是前者被选择的时候,后者一定会被选择
作者:力扣官方题解
终止情况不仅要考虑合法的、输出的情况,更需要考虑遍历完了 但是非法的情况
void bp(int *nums,int numsSize,int *returnSize,int *path,int p,int **returnColumnSizes,int start,int **ans){
if(start>=numsSize && p>1){//至少有两个元素
ans[*returnSize]=malloc(sizeof(int)*p);
memcpy(ans[*returnSize], path, sizeof(int)*p);
(*returnColumnSizes)[(*returnSize)++]=p;
return;
}
else if(start>=numsSize) return;
int j=start;
if(p>=1 && nums[j]==path[p-1]){//和前一个数字相同必须放入
path[p]=nums[j];
bp(nums, numsSize, returnSize,path, p+1, returnColumnSizes, j+1,ans);
}
else if(p==0 || ( p>=1 && nums[j]>=path[p-1] ))
{//放入第一个数,或者和前一个放入的数字不同 且是递增关系的时候,可以任选放入和不放入
//不放
bp(nums, numsSize, returnSize,path, p, returnColumnSizes, j+1,ans);
//放
path[p]=nums[j];
bp(nums, numsSize, returnSize,path, p+1, returnColumnSizes, j+1,ans);
}
else bp(nums, numsSize, returnSize,path, p, returnColumnSizes, j+1,ans);//不放
}
int** findSubsequences(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int **ans=(int **)malloc(sizeof(int *)*(pow(2,numsSize)-numsSize-1));
*returnSize=0;
int *path=(int *)malloc(sizeof(int)*numsSize);
*returnColumnSizes=(int *)malloc(sizeof(int)*(pow(2,numsSize)-numsSize-1));
bp(nums, numsSize, returnSize, path, 0, returnColumnSizes, 0,ans);
return ans;
}
46.全排列
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
- 输入: [1,2,3]
- 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
分析:
已经很像dfs搜索了,需要用used数组来判断这个数据是否被轮到过了,然后再bp之后 回溯的部分 再把used修改回来
代码:
void bp (int *nums,int numsSize,int *returnSize,int **returnColumnSizes,int *path,int p,int **ans,int *used){
if(p==numsSize){
ans[*returnSize]=malloc(sizeof(int)*p);
memcpy(ans[*returnSize], path, sizeof(int)*p);
(*returnColumnSizes)[(*returnSize)++]=p;
return;
}
for (int i=0;i<numsSize;i++){
//不放
if(used[i]==1) continue;
//放入
path[p]=nums[i];
used[i]=1;
bp(nums, numsSize, returnSize, returnColumnSizes, path,p+1, ans, used);
used[i]=0;
}
}
int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int **ans =malloc(sizeof(int *)*6*5*4*3*2);
*returnSize=0;
int *path=(int *)malloc(sizeof(int)*numsSize);
int *used=(int *)malloc(sizeof(int)*numsSize);
*returnColumnSizes=(int *)malloc(sizeof(int)*6*5*4*3*2);
for (int i=0;i<numsSize;i++){
used[i]=0;
}
bp(nums, numsSize, returnSize, returnColumnSizes, path, 0, ans, used);
return ans;
}
47.全排列 II
给定一个可包含重复数字的序列 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
分析:
这是为什么呢,就是上面我刚说的,如果要对树层中前一位去重,就用used[i - 1] == false
,如果要对树枝前一位去重用used[i - 1] == true
。
对于排列问题,树层上去重和树枝上去重,都是可以的,但是树层上去重效率更高!
这么说是不是有点抽象?
来来来,我就用输入: [1,1,1] 来举一个例子。
树层上去重(used[i - 1] == false),的树形结构如下:
树枝上去重(used[i - 1] == true)的树型结构如下:
大家应该很清晰的看到,树层上对前一位去重非常彻底,效率很高,树枝上对前一位去重虽然最后可以得到答案,但是做了很多无用搜索。
代码:
int cmp(const void *a,const void *b) {
return *(int*)a-*(int*)b;
}
void bp (int *nums,int numsSize,int *returnSize,int **returnColumnSizes,int *path,int p,int **ans,int *used){
if(p==numsSize){
ans[*returnSize]=malloc(sizeof(int)*p);
memcpy(ans[*returnSize], path, sizeof(int)*p);
(*returnColumnSizes)[(*returnSize)++]=p;
return;
}
int prior;
for (int i=0;i<numsSize;i++){
//不放
if(used[i]==1) continue;
if(i<numsSize-1 && nums[i]==nums[i+1] && used[i+1]==0) continue;
//放入
path[p]=nums[i];
used[i]=1;
bp(nums, numsSize, returnSize, returnColumnSizes, path,p+1, ans, used);
used[i]=0;
}
}
int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
int len=1;
for (int x=1;x<=numsSize;x++){
len=len*x;
}
int **ans =malloc(sizeof(int *)*len);
*returnSize=0;
qsort(nums, numsSize, sizeof(int), cmp);
int *path=(int *)malloc(sizeof(int)*numsSize);
int *used=(int *)malloc(sizeof(int)*numsSize);
*returnColumnSizes=(int *)malloc(sizeof(int)*len);
for (int i=0;i<numsSize;i++){
used[i]=0;
}
bp(nums, numsSize, returnSize, returnColumnSizes, path, 0, ans, used);
return ans;
}