题目描述
给你一个有序整数数组,数组中的数可以是正数、负数、零,请实现一个函数,这个函数返回一个整数:返回这个数组所有数的平方值中有多少种不同的取值。举例:
nums = {-1,1,1,1},
那么你应该返回的是:1。因为这个数组所有数的平方取值都是1,只有一种取值。
nums = {-1,0,1,2,3}
你应该返回4,因为nums数组所有元素的平方值一共4种取值:1,0,4,9
思路
方法1 暴力破解
直接计算每个数字的平方,然后和其他数字的数字的平方进行对比,并进行统计。时间复杂度为 O ( n 2 ) O(n^2) O(n2)。
方法2 哈希表
使用哈希表,一遍遍历且计算每个树的平方存档到哈希表里面,最终统计哈希表中元素的个数。时间复杂度 O ( n ) O(n) O(n), 空间复杂度是 O ( n ) O(n) O(n)。
方法3 双指针夹逼
类似快速排序双指针夹逼,左右指针交替移动
时间复杂度为
O
(
n
)
O(n)
O(n),空间复杂度为
O
(
1
)
O(1)
O(1)。
由于数组是有序的,绝对值相等的情况主要有两种情况,临近元素相等,左右指针互为相反数。算法过程主要是分为三种情况:
- 当左指针所指元素的绝对值小于右指针元素的绝对值的时候,此时针对右指针所指的元素,左指针位置以及左边肯定没有满足的元素可以和右指针的平方相匹配。因此右指针往做移动,计数器加1。
- 当左指针所指元素的绝对值大于右指针元素的绝对值的时候,情况分析同上
- 当两者相等的时候,此时在移动左右指针之前,也要考虑左右指针各自临近元素是否有相等的情况,针对左右指针相等的临近元素,直接跳过,一直到两者相碰(left>=right为碰撞条件)。注意最后当循环跳出的时候,要是左右指针相等,说明整个数组的中间仍旧有一个元素的绝对值是唯一的,将计数器加1。如果最后循环跳出的时候,左指针大于右指针,说明中间不存在唯一的绝对值元素,即直到最终相碰左右指针两者的绝对值都是相等的,那么计算器就不再加1。
代码实现
#include <iostream>
#include <vector>
using namespace std;
int main(int argc, char *argv[]) {
vector<int> arr = {-3,-3,-2,-2,-1,-1,0,1,1,2,2,2,3,3,3,3,3,3,3,4};
int res = 0;
int left = 0;
int right = arr.size()-1;
while(left<right){
if(abs(arr[left])<abs(arr[right])){
right--;
res++;
}
if(abs(arr[left])>abs(arr[right])){
left++;
res++;
}
if(abs(arr[left])==abs(arr[right])){
while(left<right && abs(arr[left+1])==abs(arr[left])) left++;
while(left<right && abs(arr[right-1])==abs(arr[right])) right--;
left++;
right--;
res++;
}
}
if(left==right) res++;
cout<<res;
}