题目:
一个整形数组里除了一个数字出现3次以外,其他数字都出现2次.请写程序找出这个出现3次的数字.
要求使用辅助空间O1,时间复杂度Onlogn.
1.使用堆排序.(堆排序的时间复杂度为Onlogn)
因为堆排序每次取到的都是最大(或是最小)的数字,三个相同的数字肯定是紧挨着被取出的.
所以在原先的堆排序算法上,加2个标记记录即可.
代码:
// 使用堆排序,每次取最大的,连续取到3个相同的,那说明就是 public static int find2(int[] array) { // 堆排序的:形成堆结构, // 从最后一个有叶子节点的节点开始, // 也就是最后一个节点的父节点 for (int i = (array.length >> 1) - 1; i >= 0; i--) { refactor(array, i, array.length); } // 2个分别用来记录前以及前前 Integer pre = null; Integer prePre = null; for (int i = 1; i <= array.length; i++) { // 如果相同,返回 if (pre != null && pre == prePre && array[0] == pre) { return array[0]; } if (pre == null) { pre = array[0]; swap(array, 0, array.length - i); refactor(array, 0, array.length - i); continue; } prePre = pre; pre = array[0]; swap(array, 0, array.length - i); refactor(array, 0, array.length - i); } // 如果没找到,说明输入数组有问题,抛异常 throw new RuntimeException(); } static void refactor(int[] array, int root, int length) { int left = (root << 1) + 1; int right = (root + 1) << 1; if (left == length - 1 && array[left] > array[root]) { swap(array, root, left); return; } if (right < length) { if (array[left] >= array[right] && array[left] > array[root]) { swap(array, root, left); refactor(array, left, length); return; } if (array[right] > array[left] && array[right] > array[root]) { swap(array, root, right); refactor(array, right, length); return; } } } private static void swap(int[] array, int a, int b) { int tmp = array[a]; array[a] = array[b]; array[b] = tmp; }
2.这里有个非常简单的方法:
那就是异或:
一个数异或他本身得到0,那么把所有的数异或得到的最后的结果肯定就是出现3次的那个数了.
public static int find1(int[] array) { int target = array[0]; // 遍历,异或所有 for (int i = 1; i < array.length; i++) { target ^= array[i]; } // 最后的值就是本身 return target; }
升级版:
剑指offer面试题40-数组中只出现一次的数字