算法:数组处理
数组中出现次数超过一半的数字
题目描述
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如,输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}由于数字2在数组中出现了五次,超过了数组长度的一半,因此输入2.
解题思路
数组中有一个数字出现的次数超过了数组长度的一半。如果把这个数组排序,那么排序之后位于数组中间的数字一定就是那个出现次数超过数组长度一半的数字。也就是说,这个数字就是统计学上的中位数,即长度为n的数组中第n/2大的数字。
还有一种实现思路:数组中有一个数字出现的次数超过数组长度的一半,也就是说他出现的次数比其他所有数字出现的次数和还要多。我们用两个变量统计数字特征,一个统计数组中的数字一个统计该数字出现的次数,当我们遍历到下一个数字的时候,如果下一个数字和我们之前保存的数字相同,则次数加1;如果下一个数字和我们之前保存的数字不同,则次数减1;如果次数为0,我们需要保存下一个数字。 举例数组,1,2,3,2,2,2,5,4,2 因为2出现的次数超过一半,所以我们要找的数字最后一定次数是大于等于1的。
Java实现代码
public static int MoreThanHalfNum(int[] nums,int length)
{
int result = nums[0];
int times = 1;
for(int i=1;i<length;i++)
{
if(times==0)
{
result=nums[i];
times=1;
}
else if(nums[i]==result)
{
times++;
}
else
times--;
}
return result;
}
最小的K个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4、5、1、6、2、7、3、8这8个数,则最小的4个数字是1、2、3、4.
解题思路
这道题最简单的思路就是把输入的n个数进行排序,排序之后位于最前面的K个数就是最小的K个数。这种思想的时间复杂度是O(nlogn)。
我们可以基于快速排序算法的Partition函数来解决这个问题。如果基于数组的第k个数字来调整,则使得比第K个数字小的所有数字都位于数组的左边,比第K个大的所有数字都位于数组的右边。这样调整以后,位于数组中左边的的K个数字就是最小的K个数。
Java实现代码
public class toOffer_40 {
public static void main(String[] args)
{
int[] arr ={4,5,1,6,2,7,3,8};
int index = partition(arr,0,arr.length-1);
int start=0;
int end =arr.length-1;
while (index!=3)
{
if(index>3)
{
end=index-1;
index =partition(arr,start,end);
}
else{
start=index+1;
index=partition(arr,start,end);
}
}
for(int i=0;i<4;i++)
{
System.out.println(arr[i]);
}
}
public static void exch(int[] arr,int i,int j)
{
int tmp = arr[i];
arr[i]=arr[j];
arr[j]=tmp;
}
public static int partition(int[] aux,int lo,int hi)
{
int i=lo,j=hi+1; //左右两个指针,分别从两端开始
int val = aux[lo]; //取最左边的第一个元素为枢纽元素
while (true)
{
while (aux[++i]<val)if(i==hi)break; //左指针向右找到一个大于枢纽的
while (aux[--j]>val)if(j==lo)break; //右指针向左找到一个大于枢纽的
if(i>=j) break; //这个i>=j是很关键的,这表明现在已经划分成功,即两边元素有序!
exch(aux,i,j); //i!=j,表示还有能找的!
}
exch(aux,lo,j); //把枢纽元素交换至它应该的位置!
return j; //把划分点返回区,目的是说,从这里开始,两边分别已成为为左右子序列,返回的是j这是很关键的,因为i可能大于j。
}
}
连续子数组的最大和
题目描述
输入一个整形数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个数组。求所拥有子数组的和的最大值。要求时间复杂度为O(n)
解题思路
我们可以用动态规划的思想来解决这个问题。以函数f(i)表示以第i个数字结尾的子数组的最大和,那么我们需要求出max[f(i)],其中0<=i<=n。我们可用如下递归公式求f(i):
简单说明一下动态规划的思想:以第i-1个数结尾的最大和是多少,如果f(i-1)为负数,则与pData[i]相加,结果一定小于pData[i],所以直接取pData[i],否则加起来得到以第i个数字结尾的子数组的最大和。
Java实现代码
public class toOffer_41 {
public static void main(String[] args)
{
int[] arr={1,-2,3,10,-4,7,2,-5};
int[] sum=new int[arr.length];
sum[0]=arr[0];
for(int i=1;i<arr.length;i++)
{
if(sum[i-1]>0)
sum[i]=sum[i-1]+arr[i];
else
sum[i]=arr[i];
}
int max = sum[0];
for(int i=0;i<sum.length;i++)
if(max<sum[i])
max=sum[i];
System.out.println(max);
}
}