https://www.nowcoder.com/practice/70610bf967994b22bb1c26f9ae901fa2?tpId=13&tqId=11190&tPage=2&rp=2&ru=%2Fta%2Fcoding-interviews&qru=%2Fta%2Fcoding-interviews%2Fquestion-ranking
三种方法实现:
//方法一 O(n)遍历 没想到O(n)的解法也可以通过测试
int GetNumberOfK(vector data ,int k)
{
int num = 0;
for(int i = 0;i < data.size();i++)
{
if(data[i] == k)
{
num++;
}
}
return num;
}
//方法二:有序数组 当然二分查找 找第一个k位置 第二个k位置 相减得出结果
int findk1(vector &data ,int k,int first,int last)
{
int mid;
while(first <= last)
{
mid = (first + last) >> 1;
if(data[mid] < k)
{
first = mid + 1;//这一句 如果不+1... 末位可能永远
}
else if(data[mid] > k)
{
last = mid - 1;//忘了-1 导致没找到的时候 无限循环 退不出去
}
else if(mid -1 >= first && data[mid -1] == k)
{
last = mid -1;
}
else
{
return mid;
}
}
return -1;
}
int findk2(vector &data ,int k,int first,int last)
{
int mid;
while(first <= last)
{
mid = (first + last) >> 1;
if(data[mid] < k)
{
first = mid + 1;//这一句 如果不+1... 末位可能永远
}
else if(data[mid] > k)
{
last = mid-1;
}
else if(mid +1 <= last && data[mid+1] == k)
{
first = mid +1;
}
else
{
return mid;
}
}
return -1;
}
int GetNumberOfK(vector data ,int k)
{
if(data.empty()) return 0;
int dsize = data.size();
int firstk = findk1(data,k,0,dsize-1);
int lastk = findk2(data,k,0,dsize-1);
if(firstk != -1 && lastk != -1)
{
return (lastk - firstk +1);
}
return 0;
}
方法二的二分查找,是找一个最左边一个最右边;
方法三就是常规的二分查找;
//方法三:二分查找到一个k的位置 左右分别++ -- 计数 but超出时间限制 想不通为啥O(n)遍历都可以,这个就超出时间
int GetNumberOfK(vector data ,int k)
{
int dsize = data.size();
if(dsize <= 0) return 0;
int first = 0; //first下标
int last = dsize-1; //last下标
int mid = HalfSearch(data,first,last,k); //mid下标
if(mid == -1) return 0;
int num = 1;
for(int i = mid+1; i < dsize;i++)//向右遍历 i++
{
if(data[i] == k) num++;
else break;
}
for(int i = mid -1;i >= 0;i--) //向左遍历 i--
{
if(data[i] == k) num++;
else break;
}
return num;
}
int HalfSearch(vector &data ,int first,int last,int k)
{
int mid;
while(first <= last)
{
mid = (first + last) >> 1;
if(data[mid] == k) return mid;
if(data[mid] < k)
{
first = mid + 1;//这一句 如果不+1... 末位可能永远
}
if(data[mid] > k)
{
last = mid -1 ;//这一句 如果不-1...
}
}
return -1;
}
总结:这道题,就是一个二分查找,当然讨论区还是看到了大神的神级别思路,让我钦佩不已。
二分查找,+1 和-1的问题让我真的搞了好久......惭愧惭愧,一直报错超出时间限制,我还很奇怪在我本地测试实例就没有问题,后来一测试查找不存在的数据就无限循环了,额真的是........
方法一::map计数法: 将vector中的每个数据当做map的key值,挨个插入,key第一次插入对应的value=1,key值第二次插入对应的value为2;统计个数完毕,最后找到value==1的,即为数组中只有一个
代码:
void FindNumsAppearOnce(vector data,int* num1,int *num2)
{
//先判断不合理条件
int datasize = data.size();
if(datasize < 2) return;
map count;
for(int i = 0;i < datasize;i++)
{
int key = data[i];
map::iterator it = count.begin();
it = count.find(key);
if(it == count.end())
{
count.insert(pair(key,1));
}
else //if(it != count.end())
{
it->second = 2;
}
}
map::iterator it = count.begin();
bool flag = true;
for(it;it != count.end();it++)
{
if(flag && it->second == 1)
{
*num1 = it->first;
flag = false;
continue;
}
else if(!flag && it->second == 1)
{
*num2 = it->first;
break;
}
}
}
方法1.5:方法一对染能做出来,但是确实太笨重了,挨个遍历计数,再挨个遍历找计数为1的。
讨论区看到一个用set的,也是统计个数,不过方法比我巧妙。set中插入vector中数据,如果插入过再次插入时就直接删除该数据,那么最后set中剩下的两个数字就是最后的结果,因为出现两次的数字直接被删掉了。
而且代码简练,就几行。感觉我写的map表技术法太.....Low了......
代码:
链接:https://www.nowcoder.com/questionTerminal/e02fdb54d7524710a7d664d082bb7811?f=discussion
来源:牛客网
void FindNumsAppearOnce(vector data,int* num1,int *num2)
{
set save;
set::iterator iter;
for (int i = 0; i < data.size(); i++){
if (save.find(data[i]) == save.end())
save.insert(data[i]);
else{
iter = save.find(data[i]);
save.erase(iter);
}
}
iter = save.begin();
*num1 = *iter;
*num2 = *(++iter);
}
方法二:(看讨论区的做法)
1、异或思想,一个数与自己异或为0,一个数与0异或为自己
2、由于其它数字两两相同,所以所有数异或则得到这两个不同数的异或结果。取这个结果的第一个1作为标志位
3、这个标志的1,必须是:这两个数在该位一个为0,一个为1
4、这样可以将数组分为两组,一组在该标志位为1,一组在该标志位为0,这两个不同数字分别在这两组内
5、将两组内的数分别异或,得到两个结果则为这两个不同的数
代码:
void FindNumsAppearOnce(vector data,int* num1,int *num2)
{
int datasize = data.size();
if(datasize < 2) return;
int num=0;
for(int i=0;i < datasize;i++)
{
num^=data[i];//所有数异或,结果为不同的两个数字的异或
}
int count=0;//标志位,记录num中的第一个1出现的位置
for(;count < datasize;count++)
{
if((num&(1<
输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
vector printMatrix(vector > matrix)
{
vector vec;
int rownum = matrix.size();
if(rownum == 0) return vec;
int colnum = matrix[0].size();
if(colnum == 0) return vec;
int rfirst = 0;//行的最小值下标
int rlast = rownum - 1; //行的最大值下标
int cfirst = 0; //列的最小值下标
int clast = colnum -1 ; //列的最大值下标
while(clast >= cfirst && rfirst <= rlast)
{
//向右:
//行:最小行
//列:从从cfirst -> clast
//走完以后 最小行要+1
for(int i = cfirst;i <= clast && clast >= cfirst && rfirst <= rlast;i++)
{
vec.push_back(matrix[rfirst][i]);
}
rfirst++;
//向下:
//行:rfirst -> rlast
//列:最大列
//走完以后,最大列 -1
for(int i = rfirst;i <= rlast&& clast >= cfirst && rfirst <= rlast;i++)
{
vec.push_back(matrix[i][clast]);
}
clast--;
//向左:
//行:最大行
//列:最大 -> 最小
//走完以后,最大行 -1
for(int i = clast;i >= cfirst&& clast >= cfirst && rfirst <= rlast;i--)
{
vec.push_back( matrix[rlast][i] );
}
rlast--;
//向上
//行:最大 -> 最小
//列:最小
//走完以后,最小列+1
for(int i = rlast; i >= rfirst&& clast >= cfirst && rfirst <= rlast;i--)
{
vec.push_back(matrix[i][cfirst]);
}
cfirst++;
}
return vec;
}
代码:
//方法一:sort排序后 找前k个 时间复杂度O(n*lgn)
/*
vector GetLeastNumbers_Solution(vector input, int k)
{
vector vec;
int size = input.size();
if(k > size || k < 0 || size == 0)
return vec;
sort(input.begin(),input.end());
for(int i = 0;i < k;i++)
{
vec.push_back(input[i]);
}
return vec;
}
*/
//方法二:
//冒泡k次 把最小的放到最后,在从vec中删除末位 时间复杂度O(k*n)
/*
vector GetLeastNumbers_Solution(vector input, int k)
{
vector vec;
int size = input.size();
if(k > size || k < 0 || size == 0) return vec;
for(int i = 0;i < k;i++)
{
for(int j = 0;j < input.size()-1;j++)
{
if(input[j] < input[j+1])
{
int tmp = input[j];
input[j] = input[j+1];
input[j+1] = tmp;
}
}//冒泡出一个最小的
vec.push_back(input[input.size()-1]);
input.pop_back();
}
return vec;
}
*/
//方法三:放入set集合,空间复杂度O(n),时间复杂度O(n*logn)
vector GetLeastNumbers_Solution(vector input, int k)
{
vector vec;
int size = input.size();
if(k > size || k < 0 || size == 0) return vec;
set s;
for(int i = 0;i < size;i++)
{
s.insert(input[i]);
}
set::iterator it = s.begin();
for(int i = 0;i < k;i++)
{
vec.push_back(*it);
it++;
}
return vec;
}
目前我认为的最优解是:堆排序,建立小根堆,时间复杂度:O(nlgk)
代码参考牛客网,这里贴出链接:
链接:https://www.nowcoder.com/questionTerminal/6a296eb82cf844ca8539b57c23e6e9bf?f=discussion
来源:牛客网
class Solution {
private:
void heapSort(vector &input, int root, int end){
for(int j = end -1; j >= root; j --){
int parent = (j + root -1)/2;
if(input[parent] > input[j]){
int temp = input[j];
input[j] = input[parent];
input[parent] = temp;
}
}
}
public:
vector GetLeastNumbers_Solution(vector input, int k) {
vector result ;
if(k > input.size()) return result;
for(int i = 0; i < k ; i ++){
heapSort(input,i,input.size());
result.push_back(input[i]);
}
return result;
}
};