找出数组中出现次数大于n/2、n/3,n/k的数

1.找出数组中次数大于n/2的元素
说明:算法空间复杂度o(n),时间复杂度o(1)
数组中次数超过n/2的数最多1个,设置一个频率数,前一个数和后一个数相同,频率+1,
否则-1,只要有数频率超过数组长度一半,最终这个频率肯定大于0.

public static int solve2(int [] array) {
    	if(array == null || array.length == 0) return -1;
    	int temp = array[0],time = 0;
    	for(int i= 0;i<array.length;i++) {
    		if(array[i] == temp) time++;
    		else if(time <=0) {
    			temp = array[i];
    			time = 0;
    		}else {
    			time --;
    		}
    	}
    	 time = 0;
    	for(int i = 0;i<array.length;i++) {
    		if(temp == array[i]) time++;
    	}
    	if(time>array.length/2) return temp;
    	return -1;
    }

2.找出数组中出现次数超过n/3的数
超过n/2的数,最多2个,可以设置两个临时变量保存数组元素,两个频率变量

public static ArrayList solve(int [] array) {
    ArrayList<Integer> list = new ArrayList<Integer>();
    if(array == null ||array.length == 0) return null;
    int maj1 = array[0],maj2 = array[0];
    int count1 = 0,count2 = 0;
    int len = array.length;
    for(int i = 0;i<len;i++) {
    	if(array[i] == maj1) count1++;
    	else if(array[i] == maj2) count2++;
    	else if(count1<=0) {
    		count1 = 1;
    		maj1 = array[i];
    	}else if(count2<=0) {
    		count2 = 1;
    		maj2 = array[i];
    	}else {
    		--count1;
    		--count2;
    	}
    }
    count1 = count2 =0;
    for(int i =0;i<len;i++) {
    	if(array[i] == maj1) count1++;
    	if(array[i] == maj2) count2++;
    }
    if(count1>len/3) list.add(maj1);
    if(count2>len/3) list.add(maj2);
    return list;
    }

3.找出数组个数大于n/k的
大于n/k的最多也就是k-1个,所以map集合每当满k-1个的时候,如果,前后不相等,集合内所有的元素个数都要-1,为0的清除掉。

public static void solve3(int [] arr,int k) {
    	Map<Integer,Integer> map = new HashMap<>();
    	//首先找到k-1个不同的数,并记录他们出现的次数,继续向后遍历
    	//若下一个数map里有则将该数个数即value+1,否则map里数的个数都减1
    	//否则加入该数,次数记为1
    	for(int anArr:arr) {
    	 Integer value;
    	 if((value = map.get(anArr))!=null) {
    		 map.replace(anArr, value+1);
    	 }else {
    		 if(map.size() == k-1) {
    			 subtrackAll(map,k);
    		 }else {
    			 map.put(anArr,1);
    		 }
    	 }
      }
     //将map里所有数的个数即value都清0,因为map中的数并非都符合要求
    	map.keySet().forEach(integer->map.replace(integer, 0));
     //再次循环统计map里数字的真正个数
    	for(int num:arr) {
    		Integer val;
    		if((val = map.get(num))!= null) {
    			map.replace(num, val+1);
    		}
    	}
    	map.forEach((key,value)->{
    		if(value>arr.length/k) {
    			System.out.println(key+" ");
    		}
    	});
    }
	private static void subtrackAll(Map<Integer, Integer> map, int k) {
		List<Integer> list = new ArrayList();
	// 将map里全部数字的value值减1,减1后若value==0,则删除该键
		map.forEach((integer,integer2)->{
			if(integer2 == 1) {
				list.add(integer);
			}else map.replace(integer, integer2-1);
		});
		if(list.size()!=0) {
			for(Integer key:list) {
				map.remove(key);
			}
		}	
	}  

为什么最后还要验证一下,例如找大于n/2的数,数组为 2 2 2 3 3 3 最终temp为3但是显然3个数并没有大于n/2

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是用C语言实现该算法的代码: ```c #include <stdio.h> #include <stdlib.h> #define MAX_N 1000 int cmp(const void *a, const void *b) { return *(int *)a - *(int *)b; } int main() { int n, k; int nums[MAX_N], count[MAX_N] = {0}, res[MAX_N], len = 0; printf("请输入n和k:\n"); scanf("%d%d", &n, &k); printf("请输入%d个正整:\n", n); for (int i = 0; i < n; i++) { scanf("%d", &nums[i]); } qsort(nums, n, sizeof(int), cmp); // 排序 for (int i = 0; i < n; i++) { int j = i; while (j < n && nums[j] == nums[i]) { j++; } count[nums[i]] = j - i; // 记录每个出现次数 i = j - 1; } for (int i = 0; i < n; i++) { if (count[nums[i]] > k) { // 找出出现次数大于k的字 int j; for (j = 0; j < len; j++) { if (res[j] == nums[i]) { break; } } if (j == len) { // 避免重复添加 res[len++] = nums[i]; } } } printf("出现次数大于%d的字为:\n", k); for (int i = 0; i < len; i++) { printf("%d ", res[i]); } printf("\n"); return 0; } ``` 首先,我们定义了一个`cmp`函用于排序,然后读入`n`和`k`,以及`n`个正整到`nums`数组中。接着,使用`qsort`函对`nums`数组进行排序。 然后,我们遍历`nums`数组,记录每个出现次数到`count`数组中。接着,再遍历`nums`数组找出出现次数大于`k`的字,并将其加入到结果数组`res`中,避免重复添加。 最后,输出结果数组`res`中的字即可。 需要注意的是,由于本题中字大小不超过1000,因此我们可以使用一个长度为1000的数组`count`来记录每个出现次数。如果字范围很大,需要使用哈希表等据结构来记录。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值