【贪心法】奇数数组 思路解析和代码

奇数数组

输入正整数n和长度为n(n ≤ 105)的数列an(1 ≤ ai ≤ 109)。在一次操作中你可以选择一个偶数c,并且把所有等于c的数除以2。例如a = [6,8,12,6,3,12],选择c = 6进行一次操作后a = [3,8,12,3,3,12]。请问最少进行多少次操作后, 𝑎𝑛 的所有数都变成奇数。请尝试设计算法进行计算。
样例输入
6
40 6 40 3 20 1
样例输出
4

个人思路

思路

本题应该采用贪心策略,每次选择数组中最大的偶数作为操作数,然后遍历整个数组并对与操作数相等的数进行除2操作,直到数组中全部为奇数为止

贪心策略证明:设当前有四个偶数并满足a > b > c > d。根据贪心策略,第一次取操作数为a,得到数组[a/2,b,c,d]:

  • if(a/2 > b),第二次操作数为a/2,得到的数组为[a/4,b,c,d]
  • else if(a/2 == b),第二次操作数为a/2,得到的数组为[a/4,b/2,c,d]
  • else(即a/2 < b),第二次操作数为b,得到的数组为[a/2,b/2,c,d]

显然取最大的数字作为操作数时,有可能同时对两个及以上个数的元素进行除2操作,因此是最优选择

注意

  • 使用双端队列deque,便于在初始化时对数组进行排序操作
  • deque中只保存偶数元素
  • 操作过程中,如果出现偶数直接删去
  • 每次对deque遍历后,要对序列进行排序,由于此时序列基本有序,因此采用插排更有效率

个人思路代码

/*
 * @Author: LLX 
 * @Date: 2020-10-31 19:19:03 
 * @Last Modified by: SEUer
 * @Last Modified time: 2020-10-31 21:03:58
 */
//记录偶数,记录最大的数字
#include<bits/stdc++.h>
using namespace std;
deque<int> arr;
int n, ans;
void insertSort(){//对于基本有序的数组,插排效率更高
    int index = 0;
    for(int i = 1; i < n; ++i){
        if(arr[index] < arr[i]){
            swap(arr[index], arr[i]);
            index = i;
        }else{
            break;
        }
    }
}
void display(){
    for(int i = 0; i < arr.size(); ++i){
        cout << arr[i] << " ";
    }
    cout << endl;
}
int main(){
    int firstnum;
    scanf("%d%d", &n, &firstnum);
    arr.push_back(firstnum);
    for(int i = 1; i < n; ++i){
        int num;
        scanf("%d", &num);
        if(num % 2 == 0){//arr中只存在偶数
            if(num > arr[0])
                arr.push_front(num);
            else
                arr.push_back(num);
        }
    }
    display();
    while(arr.size() > 0){
        int c = arr[0];//取整个数组当前最大偶数
        ans++;
        cout << "******第" << ans << "次*******" << endl;
        for(auto j = arr.begin(); j != arr.end(); ++j){
            if(arr.size() == 0){
                break;
            }
            if(*j == c)
                *j /= 2;
            if(*j % 2 == 1)//除2之后为奇数,则出队
            arr.erase(j);
            insertSort();
            display();
        }
    } 
    cout << ans << endl;
    system("pause");
    return 0;
}
/*
4
56 16 24 40
ans
13
*/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值