数字相关算法

本文介绍了如何寻找数组中最小的K个元素,包括利用最大堆和快速排序的方法。同时,文章详细讲解了如何找出数组中3个只出现1次的数,其他数都出现2次的解题思路、算法流程及代码实现,涉及到异或操作和位运算的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

查找最小的K的元素

方法一:利用最大堆

  •     堆的大小为K,一次遍历整个数组,向最大堆插入元素。若当前元素小于最大堆的栈顶,则替换该栈顶,重新调整堆,否则继续遍历。

#include <iostream>
#include <vector>
#include <set>
using namespace std;

//注意:在申明MaxIntHeap类型时,greater<int>与>之间必须要有一个空格,否则编译器会报错!
typedef multiset<int, greater<int> > MaxIntHeap;
 
void findMinKElement(vector<int> &data, MaxIntHeap& leastNumbers, 
    unsigned int k)
{
    if (data.size() <= 0 || k <= 0) {
        cout << "Error input" << endl;
        return;
    }   
    leastNumbers.clear();
 
    for (vector<int>::iterator iter = data.begin(); iter != data.end(); iter++) {
        if (leastNumbers.size() < k) {
            leastNumbers.insert(*iter);
        } else {
            MaxIntHeap::iterator iterFirst = leastNumbers.begin();
 
            if (*iter < *iterFirst) {
                leastNumbers.erase(iterFirst);
                leastNumbers.insert(*iter);
            }   
        }   
    }   
}

方法二:利用快速排序法

  •     分割出最小的K的元素,找出第K大的元素,以此来分类

最大子序列的和

bool findMaxSeqSum(int *array, int length, int &maxSum) 
{
    int maxNegtive = 0;
    int negtiveCnt = 0;
    int currentSum = 0;
    int i = 0;
 
    if (array == NULL || length <= 0) {
        return false;
    }   
    
    for (i = 0; i < length; i++) {
        if (array[i] < 0) {
            negtiveCnt++;
            if (maxNegtive == 0) {
                maxNegtive = array[i];
            } else if (maxNegtive < array[i]) {
                maxNegtive = array[i];
            }   
        }   
 
        currentSum += array[i];
        if (currentSum < 0) {
            currentSum = 0;
        }   
        if (currentSum > maxSum) {
            maxSum = currentSum;
        }   
    }   
 
    if (negtiveCnt == length) {
        maxSum = maxNegtive;
    }   
    return true;
}

找出数组中3个只出现1次的数,其他的数都出现了2次

思路

  • 将所有的数字进行异或操作,得到只出现1次的三个数字的异或结果:x = a ^ b ^ c。
    • 【注】这3个数字的异或结果不可能等于3个数字的任何一个,否则,有其中两个数字必然相等。
  • 定义函数:F(n), 其中该函数保留n的二进制中表示的最后一位1,其他位都变成0。则有:f(x^a), f(x^b), f(x^c)均不为0
    • 若为0,则x的等于a、b、c
  • 考虑 f(x^a)^f(x^b)^f(x^c)。由于结果非0,则该等式的结果非0,并且其可能有1个1,或者3个1,即至少有一位1。
  • 假设最有一位1在第m位,则: x^a, x^b, x^c中,有一个或者三个数字的第m位为1。但是三个数字的第m位为1是不可能的,证明如下:
    • 若 x^a, x^b, x^c三个数的m位为1,则a、b、c三个数与x的第m位相反。假设m为0,则a、b、c的第m为均为1,此时m应为1,这自相矛盾;若m为1,则a、b、c的第m位均为0,此时m应为0,这自相矛盾。故而不可能三个数的第m位为1。
    • 若不可能三位数的第m位均为1,则只有一个数的异或结果的第m位为1。并且x在第m位为0。
  • 如此可以找到第m位为1的数,在找另外两个数。

算法流程

  1. 找出第一个只出现一次的数
    • 求三个只出现一次的数的异或结果:x
    • 求f(f(x^a)^f(x^b)^f(x^c))的结果:y
    • 通过y求出第一个只出现一次的数
  2. 找出剩下的两个只出现一个的数
    • 将第一个只出现一次的数挪到向量末尾,在0~end-1的区间进行求另外两个数。
    • 求出两个只出现一次的数的异或结果:x
    • 求出f(x):y
    • 根据y & 每一个数,分别求出两个只出现一次的数。

代码实现

#include <iostream>
#include <vector>
using namespace std;
 
int lastBitOf1(int num)
{
    //return num & ~(num - 1);
    return num ^ (num & (num-1));   
}
 
void getTwoUnique(vector<int>::iterator begin, 
    vector<int>::iterator end, vector<int>& unique)
{
    int xorResult = 0;
 
    for (vector<int>::iterator iter = begin; iter != end; iter++) {
        xorResult ^= *iter;
    }   
    int diff = lastBitOf1(xorResult);
    int first = 0;
    int second = 0;
 
    for (vector<int>::iterator iter = begin; iter != end; iter++) {
        if (diff & *iter) {
            first ^= *iter;
        } else {
            second ^= *iter;
        }   
    }   
 
    unique.push_back(first);
    unique.push_back(second);
}
 
void findUniqueThree(vector<int>& numbers, vector<int>& unique)
{
    if(numbers.size() < 3)
        return;
 
    //get XOR result
    int xorResult = 0;
    vector<int>::iterator iter = numbers.begin();
    for (; iter != numbers.end(); iter++) {
        xorResult ^= *iter;
    }
 
    //get last bif of 1 from three unique numbers
    int flags = 0;
    for (iter = numbers.begin(); iter != numbers.end(); iter++) {
        flags ^= lastBitOf1(xorResult ^ *iter);
    }
    flags = lastBitOf1(flags);
 
    //get first unique number
    int first = 0;
    for (iter = numbers.begin(); iter != numbers.end(); iter++) {
        if (lastBitOf1(flags ^ *iter) == flags) {
            first ^= *iter;
        }
    }
    unique.push_back(first);
 
    //move the first number to the last position of vector
    for (iter = numbers.begin(); iter != numbers.end(); iter++) {
        if (*iter == first ) {
            swap(*iter, *(numbers.end() - 1));
            break;
        }
    }
     //get last two unique numbers
    getTwoUnique(numbers.begin(), numbers.end()-1, unique);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值