数组中出现次数超过一半的数字

本文介绍了三种查找数组中次数超过一半的数的算法设计思路,包括使用哈希表、排序与查找以及利用数组特点的方法,并提供了对应的代码实现。

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

package CGSwordToOffer;
import java.util.Date;
import java.util.Scanner;
/* 问题:查找数组中次数超过一半的数
 * 算法设计思路:
 * 1)哈希表,以数组值为下标,存储的值为出现的次数(空间换时间);
 * 2)排序+查找(这个算法时间复杂度要优化);
 * 3)依据数组的特点查找,即是该数出现的次数比其它所有数字出现的次数
 * 之和还要多(参考《剑指offer》)。
 */
public class CGNumTimesOverHalfInArray {


public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
try {
int len = sc.nextInt();// 数组长度
int[] nums = new int[len];// 一组数
for (int i = 0; i < len; i++) {
nums[i] = sc.nextInt();
}

// 查找次数超过一半的数
// 采用思路一,哈希表
// NumTimesOverHalfInArray_Hash(len, nums);
// 采用思路二,排序和查找
// NumTimesOverHalfInArray_Partition(len, nums);
// 采用思路三,数组特点
   NumTimesOverHalfInArray_Features(len, nums);

} catch (Exception e) {
System.out.println("error:"+e.getMessage());
}
sc.close();
}

//1-1 查找次数超过一半的数
public static void NumTimesOverHalfInArray_Hash(int len, int[] nums){
System.out.println("NumTimesOverHalfInArray_Hash");

// 首先找出最大值
int max = FindMaxValue(len, nums);
if(max < len){
max = len;
}
max++;// 多分配一个空间,因为最大值等于某个数值,而下标是从零开始的

// 定义一个哈希表,并初始化
int[] hash = new int[max];
for (int i = 0; i < len; i++) {
hash[i] = 0;
}

// 开始查找次数超过一半的数
for (int i = 0; i < len; i++) {
hash[nums[i]] += 1;
if (hash[nums[i]] > len / 2) {
System.out.println("出现次数超过一半的数: "+nums[i]);
break;
}
}
}

//2-1 出现次数超过一半的数字必然是中位数
public static void NumTimesOverHalfInArray_Partition(int len, int[] nums){
// 次数超过一般的数必然是出现在最中间的
System.out.println("NumTimesOverHalfInArray_Partition");
// 快速排序查找中位数
int middle = len >> 1;
int start = 0;
int end = len - 1;
int index = Partition(len, nums, start, end);
System.out.println("index:"+index);
while (index != middle) {
System.out.println("index:"+index);
if(index > middle){
end = index - 1;
index = Partition(len, nums, start, end);
}
else{
start = index + 1;
index = Partition(len, nums, start, end);
}
}

// 判断中位数出现的次数是否超过一半
int result = nums[middle];
CountOverHalf(len, nums, result);

}
//2-2 快速排序
public static int Partition(int len, int[] nums,int start,int end){
int tmp = nums[start];    //数组的第一个作为中轴  
        while (start < end) { 
            while (start < end && nums[end] > tmp) {  
                end--;  
            }  
            nums[start] = nums[end];   //比中轴小的记录移到低端  
            while (start < end && nums[start] <= tmp) {  
                start++;  
            }  
            nums[end] = nums[start];   //比中轴大的记录移到高端  
        }  
        nums[start] = tmp;              //中轴记录到尾  
        PrintArray(len, nums);
        return start; 
}

//2-3 开始计算出现的次数
public static void CountOverHalf(int len, int[] nums, int midNum){
System.out.println("CountOverHalf");
int times = 0;
for (int i = 0; i < len; i++) {
if(midNum == nums[i]){
times++;
}
}

if (times * 2 >= len) {
System.out.println("出现次数超过一半的数: "+midNum);
}
}

//3-1 利用数组特点
public static void NumTimesOverHalfInArray_Features(int len, int[] nums){
int result = nums[0];// 保存最后次数可能超过一半的数字
int times = 1;
for (int i = 1; i < len; i++) {
if (times == 0) {
result = nums[i]; 

else if(nums[i] == result){
times++;
}
else{
times--;
}
}

// 判断result出现的次数是否超过一半
CountOverHalf(len, nums, result);
}

// 查找最大值
public static int FindMaxValue(int len, int[] nums){
int max = 0;
for (int i = 0; i < len; i++) {
if (max < nums[i]) {
max = nums[i];
}
}
return max;
}

// 打印数组
public static void PrintArray(int len, int[] nums){
for (int i = 0; i < len; i++) {
System.out.print(nums[i]+" ");
}
System.out.println("\n");
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值