无序数组找中位数

1.无序数组找中位数

  1. 思路一
    把无序数组排好序,取出中间的元素
    时间复杂度 采用普通的比较排序法 O(N*logN)
    如果采用非比较的计数排序等方法, 时间复杂度 O(N), 空间复杂度也是O(N).

  2. 思路二
    (1)将前(n+1)/2个元素调整为一个小顶堆
    (2)对后续的每一个元素,和堆顶比较,如果小于等于堆顶,丢弃之,取下一个元素。 如果大于堆顶,用该元素取代堆顶,调整堆,取下一元素。重复2.2步
    (3)当遍历完所有元素之后,堆顶即是中位数。
    注:如果数组元素的个数是奇数,取数组前(size+1)/2个元素建堆,如果是偶数则取前 size/2 个元素建堆。但如果是数据流,数据个数是动态变动的,则应采用小根堆+大根堆的办法,具体见本文第5点介绍。

  3. 思路三
    找中位数也可以用快排分治的思想。具体如下:
    (1)任意挑一个元素,以改元素为支点,划分集合为两部分,如果左侧集合长度恰为 (n-1)/2,那么支点恰为中位数。如果左侧长度<(n-1)/2, 那么中位点在右侧,反之,中位数在左侧。
    (2)进入相应的一侧继续寻找中位点。
    注:可参考快排思想实现Top K

拓展:查找N个元素中的第K个小的元素,假设内存受限,仅能容下K/4个元素
分趟查找:

  1. 第一趟,用堆方法查找最小的K/4个小的元素,同时记录剩下的N-K/4个元素到外部文件。
  2. 第二趟,用堆方法从第一趟筛选出的N-K/4个元素中查找K/4个小的元素,同时记录剩下的N-K/2个元素到外部文件。
  3. 第四趟,用堆方法从第一趟筛选出的N-K/3个元素中查找K/4个小的元素,这是的第K/4小的元素即使所求。

https://blog.csdn.net/zdl1016/article/details/4676882


2.将十进制数字转化为X 进制的字符串

//将十进制数转化为X进制字符串 
string trans(int num, int base){
	string str;
	while(num > 0){
		if(num % base < 10)
			str += num % base + '0';
		else
			str += num % base - 10 + 'A';
		num = num / base;
	}
	reverse(str.begin(),str.end());
	
	return str;
}

3.找出字符串中第k次出现的字符

  1. 思路一
    遍历这个字符串(缺点是要对这个字符串查找好多次)
  2. 思路二
    (1) 先创建一个数组然后这个数组你就放成256个元素。
    (2) 把这个字符串转化成ASCLL码进行查找。(因为ASCLL码的范围比较小)
    (3) 当我们发现字符串中出现a(a的ASCLL为97)的时候,我们可以把刚才256个元素中下边为97的元素的值加一。
char find_first_K(string str, int K)
{
	int count[256] = { 0 };
	for (char ch : str) ++count[ch];

	for (char ch : str) {
		if (count[ch] == K)
			return ch;
	}

	return '0';
}

5.找出数据流中的中位数

在这里插入图片描述

注意:始终保证小根堆A中元素个数不少于大根堆B中的元素个数,即A、B元素相等时,将B中最大元素加入A,否则将A中最小元素加入B,来维持元素个数平衡。

class MedianFinder {
private:
    priority_queue<int,vector<int>, greater<int>> A;    //小根堆
    priority_queue<int,vector<int>, less<int>> B;       //大根堆

public:
    //插入新元素
    void addNum(int num) {
        if(A.size()==B.size()){ //把B中最大元素加入到A
            B.push(num);
            A.push(B.top());
            B.pop();
        }else{                  //把A中最小元素加入到B
            A.push(num);
            B.push(A.top());
            A.pop();
        }
    }
    
    //查找当前中位数
    int findMedian() {
        return A.size()==B.size()?(A.top()+B.top())/2.0:A.top();
    }
};

6.英文字符串流和中文字符串流如何分词

一种对英文字符串进行分词的方法:https://d.wanfangdata.com.cn/periodical/jsjyyyj200707016

字典与统计相结合的中文分词方法:https://d.wanfangdata.com.cn/periodical/xxwxjsjxt200609039

暴力方法:

  1. 英文分词:根据字符串中的空格、标点符号进行分词。
  2. 中文分词:固定两个字为一词进行拆分。

7.10亿QQ号去重

1. 内存够的情况

分段、map、多线程。

  1. 分段:哈希分桶,根据哈希值对桶数目取模得到对应桶号。
  2. map:需要计数采用unordered_map去重;不需要计数采用set去重。
  3. 多线程:将数据进行哈希分桶之后,各桶内map的去重可以采用多线程执行。

2. 内存不够的情况

思路一:bitmap

位图bitmap:每个int数字只用一个比特位来做标记

位图的操作(算法)基本依赖于下面3个元操作:

set_bit(char x, int n); //将x的第n位置1,可以通过x |= (1 << n)来实现

clr_bit(char x, int n); //将x的第n位清0,可以通过x &= ~(1 << n)来实现

get_bit(char x, int n); //取出x的第n位的值,可以通过(x >> n) & 1来实现

比如,要对数字int x = 1848105做标记,就可以调用set_bit(bit_map[x/8], x%8);

除法看做求“组编号”,x/8即是 以8个位为一个小组,分组到编号为idx = x/8的bit_map元素中,然后在组内偏移lft = x%8个比特位。

10亿数字(int 32位):10^8 * 32 / 8 = 40亿字节 / 1024 ≈ 400万 KB / 1024 ≈ 4000 MB / 1024 ≈ 4 GB
int 32位所需bitmap大小:2^32 / 8 = 2^29 字节 / 1024 = 2^19 KB / 1024 = 2^9 MB = 512 MB

10亿数字(long long 64位):4 GB * 2 = 8GB
long long 64位所需bitmap大小:2^64 / 2^23 = 2^41 MB / 1024 = 2^31 GB / 1024 = 2^21 TB / 1024 = 2048 PB = 2 EB

https://www.cnblogs.com/zhanghaiba/p/3594559.html

思路二:多路归并排序

问题:如何给100亿个数字排序?

注:100亿个 int 型数字放在文件里面大概有 37.2GB

  1. 把这个37GB的大文件,用哈希分成1000个小文件,每个小文件平均38MB左右(理想情况),把100亿个数字对1000取模,模出来的结果在0到999之间,每个结果对应一个文件,所以我这里取的哈希函数是 h = x % 1000,哈希函数取得”好”,能使冲突减小,结果分布均匀。
  2. 按各输入文件中下一个读到的元素的大小构造一个输入流最小堆.
  3. 从堆顶文件里读一个元素并写入输出文件.
  4. 同时按读的那个文件的下一个元素的值调整堆.
  5. 若第3步已到达文件结尾.则从堆中删除该输入流.
  6. 如果堆中还有元素. 回到第2步.

3. 外存不够的情况

考虑是不是可以进行分布式处理

待查~


  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,可以使用PriorityQueue来实现无序数组中位数。PriorityQueue是一个基于优先级堆的无界优先级队列,默认是一个最小堆。具体实现可以参考以下代码: ``` import java.util.PriorityQueue; public class Median { public static double median(int[] array) { int heapSize = array.length / 2 + 1; PriorityQueue<Integer> heap = new PriorityQueue<>(heapSize); for (int i = 0; i < heapSize; i++) { heap.add(array[i]); } for (int i = heapSize; i < array.length; i++) { if (heap.peek() < array[i]) { heap.poll(); heap.add(array[i]); } } if (array.length % 2 == 1) { return (double) heap.peek(); } else { return (double) (heap在Java中,可以使用PriorityQueue来实现无序数组中位数。PriorityQueue是一个基于优先级堆的无界优先级队列,默认是一个最小堆。具体实现可以参考以下代码: ``` import java.util.PriorityQueue; public class Median { public static double median(int[] array) { int heapSize = array.length / 2 + 1; PriorityQueue<Integer> heap = new PriorityQueue<>(heapSize); for (int i = 0; i < heapSize; i++) { heap.add(array[i]); } for (int i = heapSize; i < array.length; i++) { if (heap.peek() < array[i]) { heap.poll(); heap.add(array[i]); } } if (array.length % 2 == 1) { return (double) heap.peek(); } else { return (double) (heap.poll() + heap.peek()) / 2.0; } } public static void main(String[] args) { int[] array = new int[]{12, 34, 1, 209, 17, 900, -10}; System.out.println(median(array)); } } ``` 其中,首先定义了一个大小为数组长度一半加一的最小堆,然后将数组的前一半元素加入堆中。接着,遍历数组的后一半元素,如果当前元素比堆顶元素大,则将堆顶元素弹出,将当前元素加入堆中。最后,如果数组长度为奇数,则中位数就是堆顶元素;如果数组长度为偶数,则中位数就是堆顶元素和次顶元素的平均值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值