leetcode第47题

简介: 基本上都是在上道题的基础上改出来了,一些技巧也是经常遇到,比如先排序,然后判断和前一个是否重复。利用 Hash 去重的功能。利用原来的存储空间隐藏掉数据,然后再想办法还原。

image.png

上一道题类似,不同之处就是给定的数字中会有重复的,这样的话用之前的算法会产出重复的序列。例如,[ 1 1 ],用之前的算法,产生的结果肯定是 [ [ 1 1 ], [ 1 1 ] ],也就是产生了重复的序列。但我们可以在上一题的解法中进行修改从而解决这道题。

解法一 插入

这个没想到怎么在原基础上改,可以直接了当些,在它产生的结果里,对结果去重再返回。对于去重的话,一般的方法肯定就是写两个 for 循环,然后一个一个互相比较,然后找到重复的去掉。这里,我们用 39题 解法二中提到的一种去重的方法。

publicList<List<Integer>>permuteUnique(int[] nums) {
List<List<Integer>>all=newArrayList<>(); 
List<Integer>temp=newArrayList<>();
temp.add(nums[0]);
all.add(temp); 
for (inti=1; i<nums.length; i++) {
intcurrent_size=all.size();
for (intj=0; j<current_size; j++) {
List<Integer>last=all.get(j);
for (intk=0; k<=i; k++) {
if (k<i&&nums[i] ==last.get(k)) {
continue;
                }
temp=newArrayList<>(last);
temp.add(k, nums[i]);
all.add(temp);
            }
        }
for (intj=0; j<current_size; j++) {
all.remove(0);
        }
    }
returnremoveDuplicate(all);
}
privateList<List<Integer>>removeDuplicate(List<List<Integer>>list) {
Map<String, String>ans=newHashMap<String, String>();
for (inti=0; i<list.size(); i++) {
List<Integer>l=list.get(i);
Stringkey="";
// [ 2 3 4 ] 转为 "2,3,4"for (intj=0; j<l.size() -1; j++) {
key=key+l.get(j) +",";
        }
key=key+l.get(l.size() -1);
ans.put(key, "");
    }
// 根据逗号还原 ListList<List<Integer>>ans_list=newArrayList<List<Integer>>();
for (Stringk : ans.keySet()) {
String[] l=k.split(",");
List<Integer>temp=newArrayList<Integer>();
for (inti=0; i<l.length; i++) {
intc=Integer.parseInt(l[i]);
temp.add(c);
        }
ans_list.add(temp);
    }
returnans_list;
}

解法二 交换

这个改起来相对容易些,之前的想法就是在每一个位置,让每个数字轮流交换过去一下。这里的话,我们其实只要把当前位置已经有哪些数字来过保存起来,如果有重复的话,我们不让他交换,直接换下一个数字就可以了。

publicList<List<Integer>>permuteUnique(int[] nums) {
List<List<Integer>>all=newArrayList<>();
Arrays.sort(nums);
upset(nums, 0, all);
returnall;
}
privatevoidupset(int[] nums, intbegin, List<List<Integer>>all) {
if (begin==nums.length) {
ArrayList<Integer>temp=newArrayList<Integer>();
for (inti=0; i<nums.length; i++) {
temp.add(nums[i]);
        }
all.add(newArrayList<Integer>(temp));
return;
    }
HashSet<Integer>set=newHashSet<>(); //保存当前要交换的位置已经有过哪些数字了for (inti=begin; i<nums.length; i++) {
if (set.contains(nums[i])) { //如果存在了就跳过,不去交换continue;
        }
set.add(nums[i]);
swap(nums, i, begin);
upset(nums, begin+1, all);
swap(nums, i, begin);
    }
}
privatevoidswap(int[] nums, inti, intbegin) {
inttemp=nums[i];
nums[i] =nums[begin];
nums[begin] =temp;
}

基本上都是在上道题的基础上改出来了,一些技巧也是经常遇到,比如先排序,然后判断和前一个是否重复。利用 Hash 去重的功能。利用原来的存储空间隐藏掉数据,然后再想办法还原。

相关文章
|
4月前
|
算法
LeetCode第66题加一
LeetCode第66题"加一"的解题方法,通过遍历数组从后向前处理每一位的加法,并考虑进位情况,最终实现给定数字加一的功能。
LeetCode第66题加一
LeetCode 283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
89 0
|
存储
leetcode第56题
常规的思想,将大问题化解成小问题去解决。 假设给了一个大小为 n 的列表,然后我们假设 n - 1 个元素的列表已经完成了全部合并,我们现在要解决的就是剩下的 1 个,怎么加到已经合并完的 n -1 个元素中。 这样的话分下边几种情况, 我们把每个范围叫做一个节点,节点包括左端点和右端点。 1. 如下图,新加入的节点左端点和右端点,分别在两个节点之间。这样,我们只要删除
107 0
leetcode第56题
|
人工智能 算法
leetcode第41题
对于这种要求空间复杂度的,我们可以先考虑如果有一个等大的空间,我们可以怎么做。然后再考虑如果直接用原数组怎么做,主要是要保证数组的信息不要丢失。目前遇到的,主要有两种方法就是交换和取相反数。
leetcode第41题
leetcode第53题
解法一和解法二的动态规划,只是在定义的时候一个表示以 i 开头的子数组,一个表示以 i 结尾的子数组,却造成了时间复杂度的差异。问题就是解法一中求出了太多的没必要的和,不如解法二直接,只保存最大的和。
leetcode第53题
|
算法
leetcode第42题
也就是红色区域中的水, 数组是 height = [ 0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1 ] 。 原则是高度小于 2,temp ++,高度大于等于 2,ans = ans + temp,temp = 0。 temp 初始化为 0 ,ans 此时等于 2。 height [ 0 ] 等于 0 < 2,不更新。 height [ 1 ] 等于 1 < 2,不更新。 height [ 2 ] 等于 0 < 2, 不更新。 height [ 3 ] 等于 2 >= 2, 开始更新 height [ 4 ] 等于 1 < 2,temp = temp + 1 = 1。 h
105 0
leetcode第42题
leetcode第51题
较经典的回溯问题了,我们需要做的就是先在第一行放一个皇后,然后进入回溯,放下一行皇后的位置,一直走下去,如果已经放的皇后的数目等于 n 了,就加到最后的结果中。然后再回到上一行,变化皇后的位置,然后去找其他的解。 期间如果遇到当前行所有的位置都不能放皇后了,就再回到上一行,然后变化皇后的位置。再返回到下一行。 说起来可能还费力些,直接看代码吧。
leetcode第51题
|
算法
leetcode第32题
这几种算法,暴力破解和动态规划我觉得想的话,还是能分析出来的话,最后两种算法感觉是去挖掘题的本质得到的算法,普适性不是很强。但最后一种算法,从左到右,从右到左,是真的强。
102 0
leetcode第32题
|
存储 算法 Java
leetcode第29题
这道题看起来简单,却藏了不少坑。首先,我们用一次一次减造成了超时,然后我们用递归实现了加倍加倍的减,接着由于 int 表示的数的范围不是对称的,最小的负数并不能转换为对应的相反数,所以我们将之前的算法思路完全逆过来,正数边负数,大于变小于,还是蛮有意思的。
leetcode第29题