常见数组(Array)面试题(算法篇)汇总

1、将数组排成最小的数:输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323

public static String PrintMinNumber(int[] numbers) {
		if (numbers == null && numbers.length == 0) {
			return "";
		}
		List<Integer> list = new ArrayList<>();
		for (int i = 0; i < numbers.length; i++) {
			list.add(numbers[i]);
		}
		list.sort((a, b) -> (a + "" + b).compareTo(b + "" + a));
		return list.toString();
	}

	public static void main(String[] args) {
		int[] numbers = { 35, 34, 33 };
		System.out.println(PrintMinNumber(numbers)); // [33, 34, 35]
	}

2、连续正数序列:输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1-5,4-6和7-8

/**
	 * 以求和为9的所有连续序列为例,
	 * pSmall--指向正数序列的首
	 * pBig--指向正数序列的首尾
	 * pSum表示序列之和
	 * 开始pSmall=1,pBig=2,pSum=3<9
	 * 于是pBig向后移1,此时pSmall=1……pBig=3	pSum=6<9
	 * 于是pBig再向后移1,此时pSmall=1……pBig=4	pSum=10>9,序列需要删除一些数
	 * 于是pSmall-1,pSum=9,找到第一个满足条件的序列;
	 * 接着pBig+1,按照前面的方法继续查找满足条件的序列,直到pSmall等于(9+1)/2.
	 * (最小值都是9的一半,那么最大值肯定超过9的一半,所以二者加起来肯定是大于9, 
	 * 所以只需要最小值小于(9+1)/2)
	 */
	/**
	 * 求连续子区间的数字和
	 * 
	 * @param small
	 * @param big
	 * @return
	 */
	private static ArrayList<Integer> addFromSmallToBig(int small, int big) {
		ArrayList<Integer> list = new ArrayList<>();
		for (int i = small; i <= big; i++) {
			list.add(i);
		}
		return list;
	}

	/**
	 * 两个指针相互协作
	 * 
	 * @param sum
	 * @return
	 */
	public static ArrayList<ArrayList<Integer>> FindContinuousSequence(int sum) {
		ArrayList<ArrayList<Integer>> list = new ArrayList<>();
		if (sum <= 2) {
			return list;
		}
		int small = 1;// 下标
		int big = 2;// 下标
		int curSum = small + big;
		int mid = (sum + 1) / 2;
		while (small < mid) {
			// 每次判断一下是都大于了sum值了,大的话,那就只能减了,
			// 减的话,那就直接放到small的下一位,然后进行判断
			while (curSum > sum && small < mid) {
				curSum -= small;
				small++;
			}
			// 第一步判断是否相等,不不相等就持续变大big值,并加入到curSum中
			if (curSum == sum) {
				list.add(addFromSmallToBig(small, big));
			}
			// 以上都不符合,那就是sum的值很小了,继续加!
			big++;
			curSum += big;
		}

		return list;

	}

	public static void main(String[] args) {
		ArrayList<ArrayList<Integer>> list_3 = new ArrayList<>();
		list_3 = FindContinuousSequence(9);
		for (int i = 0; i < list_3.size(); i++) {
			System.out.println(list_3.get(i));
		}
		/**
		 * [2, 3, 4]
		 * [4, 5]
		 */
	}

3、在一个数组中除了一个数字只出现一次之外,其他数字都出现了2次,请找出那个只出现了一次的数字。
    要求:线性时间复杂度O(N),空间复杂度为O(1)(提示:位运算)

//相同数字异或结果是0,数组中的所有数字进行异或操作,结果就是唯一出现的那个数字
	public static int singleNumberTwo(int[] nums) {
		int temp = 0;
		for (int i = 0; i < nums.length; i++) {
			temp ^= nums[i];
		}
		return temp;
	}
	
	public static void main(String[] args) {
		int[] two = { 1, 1, 2, 2, 3, 3, 4, 4, 7 };
		System.out.println(singleNumberTwo(two)); //7
	}

4、在一个数组中除了一个数字只出现一次之外,其他数字都出现了3次,请找出那个只出现了一次的数字。
要求:线性时间复杂度O(N),空间复杂度为O(1)

/**
	 * 思路:三个相同的数字异或之后还是本身
	 * 转换思路:如果一个数字出现三次,那么他的二进制表示的每一位(0或者1)也出现3次。
	 * 把所有出现3次的数字的二进制的每一位都分别相加,那么每一位的和都能被3整除!!!
	 * 
	 * 该算法的时间复杂度为O(N),因为内层循环和后边的循环都是常数级别的时间复杂度。
	 * 空间复杂度O(1),因为数组长度为32的是常数级别的
	 */
	public static int singgleNumberThree(int[] nums) {
		int[] ints = new int[32];
		for (int i = 0; i < nums.length; i++) {
			int falg = 1;
			for (int j = 31; j >= 0; j--) {
				int anInt = nums[i] & falg;
				if (anInt != 0)
					ints[j] += 1;
				falg = falg << 1;
			}
		}
		int num = 0;
		for (int i = 0; i < 32; i++) {
			ints[i] = ints[i] % 3;
			num += ints[i] * Math.pow(2, 31 - i);
		}

		return num;
	}

	public static void main(String[] args) {
		int[] three = { 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 7 };
		System.out.println(singgleNumberThree(three)); // 7
	}
发布了185 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39309402/article/details/102695562