字节题目
有一个正整数数组A[N]每个元取值范围[1,N],统计每个元素出现次数。
要求:时间负责度O(n),空间复杂度O(1)
输入
1 3 2 5 3 1
输出
1=>2
2=>1
3=>2
5=>1
思路
常规思路是利用map进行统计,但不满足时间和空间复杂度的要求;
正确思路:
遍历数组,通过当前元素的值a
作为下标,找到下一个元素。最后得到的数组中,下标(因为数组的下标都是从0开始的,所以需要+1)为数组中出现的元素,每个下标对应的值取反输出即是该元素出现的次数。
- 若当前元素
a
小于0,则跳过; - 若当前元素
a
大于0,则判断其作为下标对应的元素b
是否大于0。- 若
b
大于0,则把b
的值赋值给a
,并把b
置为-1; - 若
b
小于0,则把a
置为0,并把b
自减1;
- 若
注意遍历时,若当前元素为正数依旧处理该当前元素;
// 举例
vector<int> arr = {2, 5, 5, 2, 3};
下标都+1;
/*
1、遍历数组,第一个arr[1]=2,然后看下标为2的元素是arr[2]=5。
2、把arr[2]对应的5赋值给arr[1],然后arr[2]就设置为-1
3、然后重复整个过程直到结束
它的整个变化过程就是这样
- {2, 5, 5, 2, 3}
- 5, [-1], 5, 2, 3
- 3, [-1], 5, 2, [-1]
- 5, [-1], [-1], 2, [-1]
- [0], [-1], [-1], 2, [-2]
- [0], [-2], [-1], [0], [-2]
这个结果表示:1有0个,2有2个,3有一个,4有0个,5有2个
*/
理解:第一个数是2,然后把arr2的值给arr1,然后arr2就为-1,表示2这个数出现了一次,以此类推。主要因为数组的范围就是1-n,所以这个方法可以遍历一次就统计出来
代码实现
#include <iostream>
#include <vector>
using namespace std;
void sort(vector<int> &num, int n) {
int i = 0;
while (i < n) {
int temp = num[i] - 1;
if (temp < 0) {
i++;
continue;
}
if (num[temp] > 0) {
num[i] = num[temp];
num[temp] = -1;
} else {
num[temp]--;
num[i] = 0;
}
}
}
int main() {
vector<int> a{2, 5, 5, 2, 3};
sort(a, a.size());
for (int i = 0; i < a.size(); i++) {
if (a[i] < 0)
cout << i + 1 << " " << (-a[i]) << endl;
}
return 0;
}
结果
参考:https://zhuanlan.zhihu.com/p/103778682