第一题:数组中出现次数超过一半的数字
仔细分析一下,这个数字必定是数组的中位数。可以利用快排的思想
int MoreThanHalfNum(vector<int> &nums)
{
int length = nums.size();
int middle = length >> 1;
int start = 0;
int end = length - 1;
int index = Partition(nums, start, end);
while (index != middle)
{
if (index > middle)
{
end = index - 1;
index = Partition(nums, start, end);
}
else
{
start = index + 1;
index = Partition(nums, start, end);
}
}
return nums[index];
}
或者还有一个更好的算法,如果数组中一个数字出现次数超过一半,那么就是说它出现的次数比所有数字出现次数和还要多。因此我们可以在遍历数组的时候保存两个值:值与次数,遇到相同次数加1,否则减1,如果次数为0,则放弃当前,保存下一个。
int MoreThanHalfNum(vector<int> &nums)
{
int value = nums[0];
int count = 1;
for (int i = 1; i < nums.size(); i++)
{
if (nums[i] == value)
++count;
else
--count;
if (count == 0)
{
value = nums[i];
count = 1;
}
}
return value;
}
第二题:最小的k个数
这一题同样可以用快排思想来解,如果基于数组的第k个数字来调整,使得比第k个数字小的都在数组的左边。和上面一题同样解法,只不过把middle 换成k-1
另一种解法是用容器保存最小的k个数,如果已有的数据小于k个,则执行插入操作。如果已经有k个数,则执行替换操作。
void GetLeastNumbers(vector<int> &nums, int k)
{
multiset<int, greater<int> > leastNums;
for (int i = 0; i < nums.size(); i++)
{
if (leastNums.size() < k)
leastNums.insert(nums[i]);
else
{
multiset<int, greater<int> >::iterator it = leastNums.begin();
if (nums[i] < *it)
{
leastNums.erase(it);
leastNums.insert(nums[i]);
}
}
}
multiset<int, greater<int> >::iterator begin = leastNums.begin();
multiset<int, greater<int> >::iterator end = leastNums.end();
while (begin != end)
{
cout << *begin;
begin++;
}
cout << endl;
}
第三题:连续子数组最大和
这一题leetcode上也有,记住当前sum与历史sum,如果当前sum小于0,那么重置当前sum为当前数,否则进行相加操作。如果当前sum大于历史sum,则赋值。
int FindGreatestSumOfSubArray(vector<int> &nums)
{
int cSum = 0;
int GreatestSum = INT_MIN;
for (int i = 0; i < nums.size(); i++)
{
if (cSum < 0)
cSum = nums[i];
else
cSum += nums[i];
if (cSum > GreatestSum)
GreatestSum = cSum;
}
return GreatestSum;
}
第四题:从1到n整数中1出现的次数
从1到n整数中1出现的次数 这个博客的解法比书上要好的多。
第五题:把数组排成最小的数
书上的解法是将数字转换为字符串,然后定义排序规则,即AB与BA的大小进行比较来排序A和B,关键在于字符串一些函数的运用,比如sprintf函数,strcpy、strcat、strcmp函数
第六题:丑数,我们把只包含因子2、3和5的数称为丑数,求按小到大的顺序第1500个丑数
如何判断一个数是否为丑数:如果一个数能被2整除,我们就把它连续除以2,如果能被3整除,就连续除以3,如果能被5整除,连续除以5,最后如果是1,则为丑数否则不是。
bool IsUgly(int number)
{
while (number % 2 == 0)
number /= 2;
while (number % 3 == 0)
number /= 3;
while (number % 5 == 0)
number /= 5;
return (number == 1) ? true : false;
}
基于这个判断,我们可以按照顺序判断每一个数是否为丑数,时间复杂度不够好。我们考虑一个数组,数组存储的是当前的丑数,以后的每个丑数,都是用之前的数组的元素相乘的来的。接下来就是如何得到后面的丑数并保证它是有序的。可以想到,数组的第一个元素是1,1与2 3 5分别相乘,可以得到三个值,这三个值里面最小的,肯定就是下一个丑数的最大值,接着max2的下标后移,继续比较。
void mkUglyNumber(){
gArr[top++] = 1;
int *max2 = gArr;
int *max3 = gArr;
int *max5 = gArr;
while(top < 1500){
int min = getMin(*max2*2,*max3*3,*max5*5);
gArr[top] = min;
while(*max2*2 <= gArr[top])
++max2;
while(*max3*3 <= gArr[top])
++max3;
while(*max5*5 <= gArr[top])
++max5;
++top;
}
}
第七题:第一个只出现一次的字符
由于字符可与整数进行互换,且字符最多为256个,所以可以用一个大小为256的数组来记录字符出现的次数。此题较为简单。
第八题:数组中的逆序对
在数组中的两个数字如果前面一个数字大于后面的数字,则成为逆序对。此题可以利用归并排序来解,此博客比较详细 点击打开链接
第九题:两个链表的第一个公共结点
第一种方法是用栈来解决,先将两个链表分别入栈,然后逐一出栈比较,最后一个相同的即为第一个公共结点
第二种方法是先遍历两个链表,得到长度为m和n,先在长的链表上走m-n(假设m>n),再一起走,第一个相同的即为所求点
第三种可以用带环链表求解,因为两个链表相交,必定为Y型,可以变成带环链表