数组类编程汇总

数组是最基本的数据结构,它将元素储存在连续的内存空间中。数组也是面试官最喜欢问的主题之一,在任何编程面试中都能听到非常多关于数组的问题,例如反转数组、排序数组或搜索数组元素等。
解决数组问题的关键是对数组数据结构有比较深的理解,同时还需要了解循环、递归和基本运算子等常见的编程结构。

1、在一个元素为 1 到 100 的整数数组中,如何搜索缺失元素?
思路一:求和
用n*(n+1)/2求连续数的和,然后减去现有数组和,即为缺失元素。
只能解决缺失一个数字情况

	public static int getMissingNumber(int[] numbers, int totalCount) {
		System.out.println(totalCount);
		int expectedSum = totalCount * (totalCount + 1) / 2;
		System.out.println(expectedSum);
		int actualSum = 0;
		for (int i : numbers) {
			actualSum += i;
		}
		System.out.println(actualSum);
		return expectedSum - actualSum;
	}

思路二:排序
先排序,再遍历每个数组下标是否与值相差1.

	public static int getMissingNumber(int[] numbers,int totalCount) {
		Arrays.sort(numbers);
		int count=1;
		for(int i=0;i<numbers.length;i++) {
			if(numbers[i]!=count) {
				return count;			
			}		
			count++;
		}
		return numbers.length+1;		
	}

思路三:用BitSet
BitSet是位操作的对象,值只有0或1(即true 和 false)。
set方法为置1.
例如 bitSet.set(1);bitSet.set(3);bitSet.set(5);
这时候bitSet的长度是 最大数+1 为5+1=6
打印结果为
false-true-false-true-false-true
0 1 2 3 4 5
主要用于海量数据的去重等操作。
在此题中,将存在的所有数置1,打印为0的即可。

	public static void getMissingNumber(int[] numbers,int totalCount) {
		int missCount=totalCount-numbers.length;
		BitSet bs=new BitSet(totalCount);
		for(int number:numbers) {
			bs.set(number-1);
		}
		int last=0;
		for(int i=0;i<missCount;i++) {
			last=bs.nextClearBit(last);
			System.out.println(++last);
		}			
	}

2.给定一个数组,搜索重复元素

思路一:遍历,不借助API

	public static int findRepeat(int [] arr) {
		int res=0;
		for(int i=0;i<arr.length;i++) {
			for(int j=0;j<arr.length;j++) {
				if(arr[i]==arr[j]&&i!=j)
					return arr[i];
			}
		}
		return res;
	}

思路二:list
创建一个List,遍历数组,对每个元素先判断是否在list中,如果不在则加入,如果在则说明是重复元素。

	public static int findRepeat(int[] arr) {
		int res = 0;
		List list = new ArrayList();
		for (int i = 0; i < arr.length; i++) {
			if (!list.contains(arr[i]))
				list.add(arr[i]);
			else if (list.contains(arr[i]))
				return arr[i];
		}
		return res;
	}

思路三:set去重
思路四:LinkedHashSet
思路X:借助BitSet
遍历一遍数组,将所有元素置1,如果为位置数为1表示为重复元素。

	public static int findRepeat(int [] arr) {
		int res = 0;
		BitSet bs=new BitSet();
		for(int i=0;i<arr.length;i++) {
			if(bs.get(arr[i])==true)
				return arr[i];
			bs.set(arr[i]);
		}
		return res;
	}

3.给定一个乱序数组,如何搜索最大和最小元素?
思路一:利用快排的分组思想,可以找第K大元素。

public static int part(int [] arr,int left,int right) {
		int pivot=arr[left];
		while(left<right) {
			while(left<right&&arr[right]>=pivot)
				right--;
			arr[left]=arr[right];
			while(left<right&&arr[left]<=pivot)
				left++;
			arr[right]=arr[left];
			
		}
		arr[left]=pivot;
		return left;
	}
public static int findMax(int [] arr,int k) {
		int left=0;
		int right=arr.length-1;
		int index=part(arr,left,right);
		while(index!=arr.length-k) {
			if(index>arr.length-k)
				index=part(arr,left,index-1);
			else
				index=part(arr,index+1,right);
		}
		return arr[index];
	}
	

思路二:借助堆

public static void adjust(int [] arr,int i,int length) {
		int tmp=arr[i];
		for(int k=i*2+1;k<length;k=k*2+1) {
			if(k+1<length&&arr[k+1]>arr[k])
				k=k+1;
			if(arr[k]>tmp) {
				arr[i]=arr[k];
				i=k;
			}else
				break;
		}
		arr[i]=tmp;
	}
	
	public static void sort(int [] arr) {
		for(int i=arr.length/2-1;i>=0;i--)
			adjust(arr,i,arr.length);
		
		for(int j=arr.length-1;j>0;j--) {
			swap(arr,0,j);
			adjust(arr,0,j);
		}
	}
	
	public static void swap(int [] arr,int left,int right) {
		int tmp=arr[left];
		arr[left]=arr[right];
		arr[right]=tmp;
	}

思路三:遍历

	public static void find(int [] arr) {
		int min=Integer.MAX_VALUE;
		int max=Integer.MIN_VALUE;
		for(int num:arr) {
			if(num>max)
				max=num;
			else if(min>num)
				min=num;
		}
		System.out.println(min);
		System.out.println(max);
	}

4.给定一个数值,如何搜索整数数组中加和为该数值的成对元素?
思路:遍历

class Solution {
    public int[] twoSum(int[] nums, int target) {
        int res[]=new int[2];
        for(int i=0;i<nums.length;i++){
            for(int j=0;j<nums.length;j++){
                if(nums[i]+nums[j]==target&&i!=j){
                    res[0]=i;
                    res[1]=j;
                }
            }   
        }
        Arrays.sort(res);
        return res;     
    }
}

5.如何使用 Java 反转一个数组?

思路一:遍历反转

	public static void rever(int[] arr) {
		for (int i = 0; i < arr.length / 2; i++) {
			int tmp = arr[i];
			arr[i] = arr[arr.length - 1 - i];
			arr[arr.length - 1 - i] = tmp;
		}
	}

思路二:建新数组,反序插入

	public static void reverse(String[] st) {
		String[] res = new String[st.length];
		for(int i=0;i<st.length;i++) {
			res[i]=st[st.length-1-i];
		}
		for(String i:res) {
			System.out.println(i);
		}
	}

三数之和
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。

注意:答案中不可以包含重复的三元组。

例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],

满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
思路:先排序,排序后,三个数和为0,即第一个数一定是负数,因此固定第一个负数,对另两个数以首尾指针思想查找。
剪枝策略:
1.第一个数只需遍历到len-3;
2.遍历到非负数,跳出循环;
3.跳过重复的数。
注意:头尾指针找数时,对重复的数要利用while跳过。

public static List<List<Integer>> threeSum(int[] nums) {
	List<List<Integer>> res = new ArrayList<List<Integer>>();
	if(nums==null || nums.length==0)
		return res;
	Arrays.sort(nums);
	int len = nums.length;
	for(int i=0;i<len-2;i++) {
		if(nums[i]>0)
			break;
		if(i!=0&&nums[i]==nums[i-1])
			continue;
		int target = 0-nums[i];
		int left=i+1;
		int right=len-1;
		while(left<right) {
			int sum = nums[left]+nums[right];
			if(sum==target) {
				List<Integer> tmp = new ArrayList<Integer>();
				tmp.add(nums[i]);
				tmp.add(nums[left]);
				tmp.add(nums[right]);
				res.add(tmp);
				while(left<right&&nums[left]==nums[left+1]) {
					left++;
				}
				while(left<right&&nums[right]==nums[right-1]) {
					right--;
				}
				left++;
				right--;
			}else if(sum<target) {
				left++;
			}else {
				right--;
			}
		}
	}
	return res;
    }

最接近的三数之和
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。

例如,给定数组 nums = [-1,2,1,-4], 和 target = 1.

与 target 最接近的三个数的和为 2. (-1 + 2 + 1 = 2).
思路:与三个数之和思路类似,找最接近的也就是和与目标值的绝对值最小;
先定一个全局的diff,在每次迭代中计算newdiff,取小的即可。

public int threeSumClosest(int[] nums, int target) {
    if(nums==null || nums.length==0)
		return 0;
	Arrays.sort(nums);
	int len = nums.length;
	int close=nums[0]+nums[1]+nums[2];
	int diff=Math.abs(close-target);
	for(int i=0;i<len-2;i++) {
		int left=i+1;
		int right=len-1;
		while(left<right) {
			int sum = nums[i]+nums[left]+nums[right];
			int newdiff=Math.abs(sum-target);
			if(newdiff<diff) {
				diff=newdiff;
				close=sum;
			}
			if(sum==target) {
				return sum;
			}else if(sum<target) {
				left++;
			}else {
				right--;
			}
		}
	}
	return close;
    }

删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

示例 1:

给定数组 nums = [1,1,2],

函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

你不需要考虑数组中超出新长度后面的元素。
思路:两个指针,快指针遍历,慢指针指向非重复元素的下标;
遍历快指针,与慢指针指向值不同则慢指针++;

public static int removeDuplicates(int[] nums) {
	if(nums==null||nums.length==0)
		return 0;
	int index = 0;
	int len = nums.length;
	for(int p=1;p<len;p++) {
		if(nums[index]!=nums[p]) {
			nums[++index]=nums[p];
		}
	}
	return index+1;
}

合并两个有序数组
给定两个有序整数数组 nums1 和 nums2,将 nums2 合并到 nums1 中,使得 num1 成为一个有序数组。

说明:

初始化 nums1 和 nums2 的元素数量分别为 m 和 n。
你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素。
示例:

输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

输出: [1,2,2,3,5,6]
思路一:借助新的数组,遍历两个数组,把小的值放入新数组中。
问题:由于A数组一定有足够的空间,这就导致一种情况,A数组没有有序元素,即m=0,而B数组n>0,也就是A中有n个0;
因此需要考虑两类情况,一类是常规,m,n同时小于0,则比较插数;
一类一个数组的排序数字为空,需要把另一个数组所有元素插入新数组,上述例外情况可以视为A数组为空;

public static void merge2(int[] nums1, int m, int[] nums2, int n) {
		if (m <= 0 && n <= 0) return;
		int a=0;
		int b=0;
		int [] res = new int[m+n];
		int index = 0;
		while(a<m&&b<n) {
			if(nums1[a]<=nums2[b])
				res[index++]=nums1[a++];
			else
				res[index++]=nums2[b++];
		}
		if(a>=m)
			while(b<n)
				res[index++]=nums2[b++];
		if(b>=n)
			while(a<m)
				res[index++]=nums1[a++];
		for(int i =0;i<m+n;i++)
			nums1[i]=res[i];
		
	}

思路二:从后往前排序;
同样遍历m+n次,把大的放后面,这样避免了在原数组上移动多个元素;
问题:也是分两类情况,先排AB数组都有有效数字的情况;
如果B数组还有元素,再插B数组元素;
如果A数组还有元素,不用考虑,因为,A数组本身有序;

public static void merge1(int[] nums1, int m, int[] nums2, int n) {
		if (m <= 0 && n <= 0) return;
		int len = m + n - 1;
		m--;
		n--;
		while (n >= 0 && m >= 0) {
			nums1[len--] = nums1[m] >= nums2[n] ? nums1[m--] : nums2[n--];
		}
		while (n >= 0)
			nums1[len--] = nums2[n--];
	}

存在重复元素
给定一个整数数组,判断是否存在重复元素。

如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

示例 1:

输入: [1,2,3,1]
输出: true
思路:HashMap
或者排序

class Solution {
    public boolean containsDuplicate(int[] nums) {
        	if(nums==null||nums.length==0)
		return false;
	Map<Integer,Integer> map = new HashMap<Integer,Integer>();
	for(int i=0;i<nums.length;i++) {
		if(!map.containsKey(nums[i])) {
			map.put(nums[i], 0);
		}else {
			int count = map.get(nums[i]);
			map.put(nums[i], count++);
			return true;
		}
	}
	return false;
    }
}

猜你喜欢

转载自blog.csdn.net/sky_noodle/article/details/82889037
今日推荐