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");
}
}
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");
}
}