004前后缀分解——算法备赛

前后缀分解

除自身以外的的数组乘积

问题描述

给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。

约束:不能使用除法,且在 O(n) 时间复杂度内完成此题。

原题链接

思路分析

首先不考虑约束,为了能快速算出nums数组中除nums[i]以外的所有元素的乘积,可以先计算出数组中所有元素的乘积,然后利用乘法的逆运算除法,在O(1)的时间复杂度内算出除自身以外的其它所有数的乘积。

代码

vector<int> productExceptSelf(vector<int>& nums) {
    int n=nums.size(),product=1;
    vector<int>ans(n);
    
    for(int i:nums)  product*=i;
    for(int i:nums) ans.push_back(product/i);
    return ans;
}

现在考虑不能用除法,也就是不能利用运算的逆运算来还原某个状态。对于这类问题可以使用前后缀分解的方法,首先从左往后顺序遍历,计算出前i个数(从0计数)的乘积记为L[i],再从右往左逆序遍历,计算出后n-1-i个数(从0计数)的乘积记为R[i],除nums[i]以外的所有数的乘积就是L[i-1]*R[i+1],L和R都是提前算好的,总时间复杂度为O(n)。

具体实现时,R现算现用,可以用一个变量代替。

代码

vector<int> productExceptSelf(vector<int>& nums) {
        int n=nums.size();
        vector<int>L(n),ans(n);
        L[0]=1;
        for(int i=0;i<n-1;i++){
            L[i+1]=L[i]*nums[i];
        }
        int r=1;
        for(int i=n-1;i>=0;i--){
            ans[i]=L[i]*r;
            r*=nums[i];
        }
        return ans;
}

最大或值

问题描述

给你一个下标从 0 开始长度为 n 的整数数组 nums 和一个整数 k 。每一次操作中,你可以选择一个数并将它乘 2

你最多可以进行 k 次操作,请你返回 nums[0] | nums[1] | ... | nums[n - 1] 的最大值。

a | b 表示两个整数 ab按位或 运算。

原题链接

思路分析

题目k次操作后求所有元素的或值ans最大值,一个正数要大,其二进制表示的位数越高越好。题目要求每次选一个数乘二(左移1位),一共操作k次。这k次操作全放在一个数上,最后或值ans才更大,明确这一点,我们只需求某个数左移k位后再与其它数求或值的最大值即可。求所有的除自身外所有数或运算值可以用前后缀分解在O(n)内求得(参见上题)。

代码

 long long maximumOr(vector<int>& nums, int k) {
        int n=nums.size();
        vector<int>L(n);
        for(int i=1;i<n;i++){
            L[i]=L[i-1]|nums[i-1];
        }
        long long ans=0;
        int r=0;
        for(int i=n-1;i>=0;i--){
            int s=L[i]|r;
            r|=nums[i];
            long long sum=nums[i];  //先用long long 类型接住,防止越界
            sum<<=k;
            sum|=s;
            ans=max(sum,ans);
        }
        return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值