Day23_数组计算_剑指Offer
数组中出现次数超过一半的数字
Easy 原题连接:数组中出现次数超过一半的数字
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例:
输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2
限制:
1 <= 数组长度 <= 50000
解题思路
摩尔投票:记录一个值当作目标值,对比接下来的值是否和目标值一致,一致则计数加一,否则减一,当计数为零时更换目标值
使用前提:数组中一定存在超过一半的符合要求的数,否则算法不成立【1,1,4,4,4,7,7】会返回 7 而不是 4 ,当数组中一定存在超过一半的目标数,剩余的数全部对撞目标数,留下的也一定是目标数。
Java代码
class Solution {
    public int majorityElement(int[] nums) {
        //摩尔投票算法:对拼消耗
        int ans = 0, maxNum = 0;
        for(int num : nums) {
            if(maxNum == 0) {
                ans = num;
            }
            if(num == ans) {
                maxNum++;
            }else {
                maxNum--;
            }
        }
        return ans;
    }
}
构建乘积数组
medium 原题连接:构建乘积数组
给定一个数组 A[0,1,…,n-1],请构建一个数组 B[0,1,…,n-1],其中 B[i] 的值是数组 A 中除了下标 i 以外的元素的积, 即 B[i]=A[0]×A[1]×…×A[i-1]×A[i+1]×…×A[n-1]。不能使用除法。
示例:
输入: [1,2,3,4,5]
输出: [120,60,40,30,24]
提示:
- 所有元素乘积之和不会溢出 32 位整数
 a.length <= 100000
解题思路
题目提示长度可能达到10w,循环暴力破解肯定是超时下策,但是每个数乘积又需要遍历得到,这时应该考虑复用计算结果
将计算 i 位的目标乘积分为两部分来看的话:i 以前的累乘 * i 以后的累乘
计算 i 位的前 i-1 位目标乘积时,i+1 位只需要在此基础上多乘个 a[i]
计算 i 位的后 a.length - i 位乘积时,i-1 位只需要再次基础上多乘个 a[i]
实现:
- 创建对应长度的数组,附上1便于做乘积
 - 首次循环,计算 i 之前的累积,使用中间值mid存储累积结果
 - 第二次循环,计算 i 之后的累积,使用中间值mid存储累积结果
 - 返回结果
 
Java代码
class Solution {
    public int[] constructArr(int[] a) {
        int[] ans = new int[a.length];
        int mid = 1;
        for(int i=0; i<ans.length; i++) {
            ans[i] = 1;
            ans[i] *= mid;
            mid *= a[i];
        }
        mid = 1;
        for(int i=ans.length-1; i>=0; i--) {
            ans[i] *= mid;
            mid *= a[i];
        }
        return ans;
    }
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 IT蛋的个人博客!

