初级算法(一)
1、引言
2、数组中是否有重复元素
最先想到是一个暴力解决,就是两层for循环,虽然能解出来,但是力扣上可能会超出时间限制。所以这个解决办法并不是最优解。
//方法一:暴力解决,执行用时750ms,内存消耗:55.3MB,力扣上有可能会显示超出时间限制
public boolean containsDuplicate(int[] nums){
if(nums.length<=1)
return false;
for (int i = 0; i <nums.length ; i++) {
for (int j = i+1; j <nums.length ; j++) {
if(nums[i]==nums[j])
return true;
}
}
return false;
}
其次,可以对数组进行排序。用一个指针加循环的方式。排序后的数组,如果里面有元素重复那肯定都是相邻的。
//方法二:先排序,再进行对比。执行用时:22ms 内存消耗:55.1MB
public boolean containsDuplicate2(int[] nums){
if(nums.length<=1)
return false;
int a=0;
Arrays.sort(nums);
for (int i = 1; i <nums.length ; i++) {
if(nums[a]==nums[i]){
return true;
}else{
a++;
}
}
return false;
}
第三种方法是采用Java带的数据结构,set集合。因为set集合存储的都是不允许有重复的元素,set中的add方法,如果添加的是集合里已有的元素,则返回值就是false。
//方法三:使用数据结构中的set集合,set集合中不允许有重复的元素,进行重复元素添加的时候,
// set会覆盖其中的值,并返回一个false
//力扣执行时间:4ms,内存消耗:49.2MB
public boolean containsDuplicate3(int[] nums){
if(nums.length<=1)
return false;
Set<Integer> set=new HashSet<Integer>();
for (int num:nums){
if(!set.add(num)){
return true;
}
}
return false;
}
3、数组中只出现一次的数字
这里可以先对数组进行排序,因为重复的元素一定是相隔一起的。
//方法一:先对数组进行排序,然后挑出只出现一次的元素
//执行用时:5ms 内存消耗:41.5MB
public int singleNumber(int[] nums) {
if(nums.length<=1)
return nums[0];
Arrays.sort(nums);
int a=0;
for (int i = 1; i <nums.length ; i+=2) {
if(nums[a]==nums[i]){
a+=2;
}else{
return nums[a];
}
}
return nums[nums.length-1] ;
}
方法二就是利用Java语言中的set集合的特性。利用set集合存储只出现一次的数字。
//方法二:还是使用的set集合的特性,就是不可重复和无序
//执行用时:10ms ,内存消耗:41.8M
public int singleNumber2(int[] nums) {
if(nums.length<=1){
return nums[0];
}
Set<Integer> set=new HashSet<Integer>();
for(int num : nums){
if(!set.add(num)){
set.remove(num);
}
}
return (int)set.toArray()[0];
}
方法三则是这个问题的最优解,因为力扣的题目要求上,明确说明了数组的元素就算重复,也只会重复两次。所以可以采用异或运算的方法。
//方法三:异或运算做优解,因为数组里的数最多重复一次
//执行时间:1ms,内存消耗:41.4MB
//异或运算的规律:自己和自己异或等于0,不同的异或结果为1并且异或运算具有交换律
public int singleNumber3(int[] nums) {
if(nums.length<=1){
return nums[0];
}
int tool=0;
for (int num : nums){
tool=tool ^ num;
}
return tool;
}
4、返回两个数组的交集II
这里不仅需要返回两个数组的重复元素,并且要求重复元素的次数在数组中都是一样的。最主要的难点都是这个。
方法一,就是采用的先将数组排序,然后使用两个指针。当指针所指的元素相同的时候,可以将这个数添加到list集合中,如果指针指的元素不同,就让指的较小元素的指针+1。
//方法一:使用list集合,并使用两个指针,重点是:指针指的元素不相同的时候,小的向后移动一位,大的不动
//执行时间用时:2ms,内存消耗:41.7MB
public int[] intersect(int[] nums1, int[] nums2) {
Arrays.sort(nums1);
Arrays.sort(nums2);
int i=0;
int j=0;
List<Integer> tool=new ArrayList<Integer>();
while(i<nums1.length && j<nums2.length){
if(nums1[i]==nums2[j]){
tool.add(nums1[i]);
i++;
j++;
}else if(nums1[i]<nums2[j]){
i++;
} else{
j++;
}
}
//list集合转换为数组
int index = 0;
int[] res=new int[tool.size()];
for (int k = 0; k <tool.size() ; k++) {
res[index++]=tool.get(k);
}
return res;
}
方法二:利用的是Java的数据结构,map集合。
//方法二:使用map集合
//执行用时:3ms,消耗内存:41.8MB
public int[] intersect2(int[] nums1, int[] nums2) {
HashMap<Integer,Integer> map=new HashMap<>();
ArrayList<Integer> list=new ArrayList<>();
for (int i = 0; i <nums1.length ; i++) {
//将值传入map集合中,key为数组的元素值,value为次数,一开始全都是1次
map.put(nums1[i],map.getOrDefault(nums1[i],0)+1);
}
for (int i = 0; i <nums2.length; i++) {
//循环遍历nums2数组中的元素,获取map中的value值,获取值成功后,list中添加值
if(map.getOrDefault(nums2[i],0)>0){
list.add(nums2[i]);
//并将这个值减1
map.put(nums2[i],map.get(nums2[i])-1);
}
}
int[] res=new int[list.size()];
for (int i = 0; i < list.size() ; i++) {
res[i] = list.get(i);
}
return res;
}