《剑指offer》——数组中出现次数超过一半的数字

来源:互联网 发布:java学生宿舍管理系统 编辑:程序博客网 时间:2024/06/10 01:30

  • 我的解法
  • 更高效的解法

T:

题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

如果用暴力搜索,那就太没意思了,所有的问题都可以用枚举法解决。

我的解法:

把当前array数组的第0号元素,即array[0],与后面的作比较,如果相等,计数器count ++;否则,就把不同的元素放在一个新数组tempArray中,等这一轮遍历完之后:

  1. 比较count 与 array.length/2的大小,如果前者大于后者,直接返回array[0]元素;
  2. 即使前者不大于后者,说明这个array[0]不是要寻找的目标元素,此时,记下共有多少与array[0]不同的元素存在(这些元素都在新数组tempArray中),标记为newLength,把tempArray中的元素覆盖在array数组上,继续以上操作;
  3. 继续以上操作的情况分为两种,一种是array数组中根本就不存在目标元素,此时,有newLength = 0;如果存在,就会从while循环的判断条件跳出。

code:

    /**     * T: 数组中出现次数超过一半的数字     *      * 题目描述      * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。     * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,     * 超过数组长度的一半,因此输出2。如果不存在则输出0。     *      * date: 2015.11.27     * @author SSS     *     */    public class Solution {        public int MoreThanHalfNum_Solution(int [] array) {            if (array.length == 0 || array == null) {                return 0;            }            int targetNum = 0;            int newLength = array.length;            int []tempArray = new int[array.length];            // 统计每个数字在数组中的个数            int count = 0;            int curNum = array[0];            while (count <= array.length / 2) {                // 说明数组已到最后                if (newLength == 0) {                    break;                }                int k = 0;                count = 0;                //每次都用array数组的第0号元素与后面的相比,把不同的元素放在新数组tempArray中                for (int i = 0; i < newLength; i++) {                    if (array[0] != array[i]) {                        tempArray[k++] = array[i];                    } else {                        count ++;                    }                }                curNum = array[0];                newLength = k;                for (int i = 0; i < newLength; i++) {                    array[i] = tempArray[i];                }            }            // 这种情况下,不是经由while退出的,而是因为找不到此类元素而退出的,要返回0            if (count <= array.length / 2) {                targetNum = 0;            } else {                targetNum = curNum;            }            return targetNum;        }    }

更高效的解法

首先看一个规律:

给定一个数组:array=[a(1),...,a(j),a(j+1),...,a(n)]

将数组分为两部分: [a(1),...,a(j)][a(j+1),...,a(n)]
设想:如果在 [a(1),...,a(j)] 部分中,如果某个元素正好只占一半,单考虑这部分数组,该元素是不会成为目标元素的,那么可以继续寻找下一部分数组中能超过一半的元素。

而本代码的思想也是如此,设定初始元素,看其在一部分数组中占有的比例,当比例达到一半时,就抛弃,相当于前半部分不曾有过,把下一个元素设定为主对比元素,重复此步骤。

以上讲解也说不清楚,看代码,比较简单:

code:

    /**     * T: 数组中出现次数超过一半的数字     *      * 题目描述      * 数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。     * 例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,     * 超过数组长度的一半,因此输出2。如果不存在则输出0。     *      * date: 2015.11.27  18:49     * @author SSS     *     */    public class Solution {        /**         * 解题的另一种方式,时间复杂度O(n)         * @param array         * @return         */        public int MoreThanHalfNum_Solution(int [] array) {            int targetNum = 0;            if (array.length == 0 || array == null) {                return 0;            }            //当前num元素的计数            int count = 1;            int num = array[0];            for (int i = 1; i < array.length; i++) {                if (array[i] == num) {                    count ++;                } else {                    count --;                }                // 小于零,则说明array[i]之前的元素中,没有一个元素的个数超过了半数,                // 顶多是一半,或者更少,这个时候就要从后面的元素重新开始找                if (count < 0) {                    num = array[i];                    count = 1;                }            }            int numCount = 0;            for (int i = 0; i < array.length; i++) {                if (array[i] == num) {                    numCount ++;                }            }            if (numCount <= array.length / 2) {                return 0;            } else {                targetNum = num;            }            return targetNum;        }    }
0 0
原创粉丝点击