【剑指offer】面试题39:数组中出现次数超过一半的数字
来源:互联网 发布:怎么在淘宝举报店铺 编辑:程序博客网 时间:2024/06/05 07:00
题目
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。
思路
解法1
最直观的解法,用哈希表来做,数字映射出现的次数
时间复杂度O(n),空间复杂度O(n),数组不会乱序
解法2
也是很直观的解法,将数组排序后,遍历查看是否有符合条件的数字
时间复杂度O(n),空间复杂度O(1),数组会乱序
解法3
题目中透露了一个信息:如果把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组长度一半的数字
使用快排中的partition算法,时间复杂度为O(n),可以得到数组中任意第k大的数字。
得到第k大的数字后,这里要反过来检查这个第k大的数字是否真的出现次数超过数组长度一半
时间复杂度O(n),空间复杂度O(1),数组会乱序
解法4
根据数组特点找出时间复杂度为O(n)的算法
数组中有一个数字出现的次数超过数组长度的一半,说明它出现的次数比其他所有数字出现的次数和还要多。
因此我们可以使用以下解法:
1.保存两个值:一个是数组中的一个数字val,一个是次数count。
2.当我们遍历到下一个数字时,
if count=0,则val设置为当前数字,count设置为1;
else if 这个数字和val相同,则count+1;
else count-1;
由于我们要找的数字出现的次数比其他所有数字出现的次数和多,
那么要找的数字肯定是最后一次把数组设置为1时对应的数字,即val可能就是我们要的值
之所以说是可能,是因为还要验证val出现的次数是否真正超过了数组长度的一半
解法1
/** * 题目: * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 * * 解法1:使用哈希表 * 时间复杂度O(n) * 空间复杂度O(n) * 数组不会乱序 * * @author peige */public class _39_MoreThanHalfNumber_01 { public static int MoreThanHalfNum_Solution(int [] array) { if(array == null || array.length == 0) return 0; if(array.length == 1) return array[0]; int num = array.length / 2 + 1; Map<Integer, Integer> map = new HashMap<>(); for(int i : array) { if(map.containsKey(i)) { int n = map.get(i) + 1; if(n >= num) return i; map.put(i, n); } else map.put(i, 1); } return 0; }}
解法2
/** * 题目: * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 * * 解法2:排序后统计 * 时间复杂度O(nlogn) * 空间复杂度O(1) * 数组会乱序 * * 可以直接调用Array.sort,但是复习一下快排,这里就直接自己写了 * * @author peige */public class _39_MoreThanHalfNumber_02 { public int MoreThanHalfNum_Solution(int [] array) { if(array == null || array.length == 0) return 0; if(array.length == 1) return array[0]; quickSort(array); int num = array.length / 2 + 1; int number = array[0]; int count = 0; for(int i : array) { if(i == number) { ++count; if(count >= num) return i; } else { number = array[i]; count = 1; } } return 0; } private void quickSort(int[] array) { quickSort(array, 0, array.length - 1); } private void quickSort(int[] array, int low, int high) { if(low >= high) return; int p = partition(array, low, high); quickSort(array, low, p - 1); quickSort(array, p + 1, high); } private int partition(int[] array, int low, int high) { int val = array[low]; int i = low + 1; int j = high; while(true) { while(i <= high && array[i] < val) ++i; while(j >= low && array[j] > val) --j; if(i > j) break; swap(array, i++, j--); } swap(array, low, j); return j; } private void swap(int[] array, int indexA, int indexB) { int t = array[indexA]; array[indexA] = array[indexB]; array[indexB] = t; }}
解法3
/** * 题目: * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 * * 解法3:基于Partition函数的时间复杂度为O(n)的算法 * 时间复杂度O(n) * 空间复杂度O(1) * 数组会乱序 * * 思路: * 如果把这个数组排序,那么排序之后位于数组中间的数字 * 一定就是那个出现次数超过数组长度一般的数字 * * @author peige */public class _39_MoreThanHalfNumber_03 { public int MoreThanHalfNum_Solution(int [] array) { if(array == null || array.length == 0) return 0; int midIndex = array.length / 2; int start = 0; int end = array.length - 1; int p = partition(array, start, end); while(p != midIndex) { if(p > midIndex) end = p - 1; else if(p < midIndex) start = p + 1; p = partition(array, start, end); } if(checkMoreThanHalf(array, array[p])) return array[p]; return 0; } private boolean checkMoreThanHalf(int[] array, int val) { int count = 0; for(int i : array) { if(i == val) ++count; } return count > array.length / 2; } private int partition(int[] array, int low, int high) { int val = array[low]; int i = low + 1; int j = high; while(true) { while(i <= high && array[i] < val) ++i; while(j >= low && array[j] > val) --j; if(i > j) break; swap(array, i++, j--); } swap(array, low, j); return j; } private void swap(int[] array, int indexA, int indexB) { int t = array[indexA]; array[indexA] = array[indexB]; array[indexB] = t; }}
解法4
/** * 题目: * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。 * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。 * 由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 * * 解法4:根据数组特点找出时间复杂度为O(n)的算法 * 数组中有一个数字出现的次数超过数组长度的一半,说明它出现的次数比其他所有数字出现的次数和还要多。 * * 因此我们可以使用以下解法: * 1.保存两个值:一个是数组中的一个数字val,一个是次数count。 * 2.当我们遍历到下一个数字时, * if count=0,则val设置为当前数字,count设置为1; * else if 这个数字和val相同,则count+1; * else count-1; * * 由于我们要找的数字出现的次数比其他所有数字出现的次数和多, * 那么要找的数字肯定是最后一次把数组设置为1时对应的数字,即val可能就是我们要的值 * 之所以说是可能,是因为还要验证val出现的次数是否真正超过了数组长度的一半 * * @author peige */public class _39_MoreThanHalfNumber_04 { public int MoreThanHalfNum_Solution(int [] array) { if(array == null || array.length == 0) return 0; int val = 0; int count = 0; for(int i : array) { if(count == 0) { val = i; count = 1; } else if(val == i) ++count; else --count; } if(checkMoreThanHalf(array, val)) return val; return 0; } private boolean checkMoreThanHalf(int[] array, int val) { int count = 0; for(int i : array) { if(i == val) ++count; } return count > array.length / 2; }}
测试(这里只放解法3的,用例都一样)
public class _39_03_Test { public static void main(String[] args) { test1(); test2(); test3(); } /** * 功能测试 * 1.存在 * 2.不存在 */ private static void test1() { _39_MoreThanHalfNumber_03 m = new _39_MoreThanHalfNumber_03(); int res = m.MoreThanHalfNum_Solution(new int[] {2,4,1,3,4,4,1,4,4,6,4}); MyTest.equal(res, 4); res = m.MoreThanHalfNum_Solution(new int[] {2,4,1,3,4,4,1,4,4,6}); MyTest.equal(res, 0); } /** * 边界测试 * 1.只有一个元素 */ private static void test2() { _39_MoreThanHalfNumber_03 m = new _39_MoreThanHalfNumber_03(); int res = m.MoreThanHalfNum_Solution(new int[] {2}); MyTest.equal(res, 2); } /** * 极端测试 * 1.输入null * 2.输入数组长度为0 */ private static void test3() { _39_MoreThanHalfNumber_03 m = new _39_MoreThanHalfNumber_03(); int res = m.MoreThanHalfNum_Solution(null); MyTest.equal(res, 0); res = m.MoreThanHalfNum_Solution(new int[0]); MyTest.equal(res, 0); }}
- 数组中出现的次数超过一半的数字(剑指offer面试题39)
- 【剑指offer】面试题39:数组中出现次数超过一半的数字
- 【剑指offer】面试题 39:数组中出现次数超过一半的数字
- 【剑指offer】面试题39 数组中出现次数超过一半的数字
- [剑指offer][面试题29]数组中出现次数超过一半的数字
- 剑指Offer:面试题29 数组中出现次数超过一半的数字
- 剑指offer 面试题29—数组中出现次数超过一半的数字
- 《剑指Offer》学习笔记--面试题29:数组中出现次数超过一半的数字
- 【剑指Offer学习】【面试题29 :数组中出现次数超过一半的数字】
- 【剑指Offer面试题】 九度OJ1370:数组中出现次数超过一半的数字
- 剑指Offer面试题29(java版):数组中出现次数超过一半的数字
- 剑指offer面试题29-数组中出现次数超过一半的数字
- 剑指offer-面试题29:数组中出现次数超过一半的数字
- 剑指offer-面试题29.数组中出现次数超过一半的数字
- 剑指offer面试题 求数组中出现次数超过一半的数字
- 剑指offer之面试题29:数组中出现次数超过一半的数字
- 剑指offer之面试题29数组中出现次数超过一半的数字
- 剑指Offer----面试题29:数组中出现次数超过一半的数字
- 关于c语言中删除单向链表节点的问题
- 快速开发android应用6-实现scrollview和recyclerview同方向滑动
- 预备知识(2)——Objective-C的程序结构
- React-Native进阶_5.导航 Naviagtion
- Java 设计模式_观察者模式
- 【剑指offer】面试题39:数组中出现次数超过一半的数字
- [kuangbin带你飞]专题二 搜索进阶 C
- 通过控制台输出文件和启动程序
- Java 设计模式_模板模式
- Unity Shader入门精要总结--渲染路径
- 欢迎使用CSDN-markdown编辑器
- GUI
- 【Leetcode】【python】Unique Binary Search Trees
- html+css小游戏