力扣1287. 有序数组中出现次数超过25%的元素
这一题要我们找有序数组中次数超过25%的元素,很明显可以用哈希表在O(n)的时间复杂度下完成查找,代码如下:
class Solution {
public:int findSpecialInteger(vector<int>& arr) {int n=arr.size();int k=n/4;unordered_map<int,int> mp;for(int i=0;i<n;i++) {mp[arr[i]]++;if(mp[arr[i]]>k){return arr[i];}} return 0; }
};
那有没有更好的做法呢?sure
首先题目上说了有序数组,那么我们是不是可以用二分?
次数超过25%的元素?是不是说明这个元素一定会在n1/4,n2/4,n*3/4处。
vector<int> candi;
candi={arr[n/4],arr[n/2],arr[n/4*3]}
结果一定在这些元素里面
那么我们是不是可以对这些元素进行一些二分,
找到每一个元素第一个大于等于该元素出现在数组中位置,和第一个小于等于该元素出现在数组中的位置,二者相减,如果长度大于n/4,就说明这个元素是符合的。
这样做的时间复杂度为O(3+log(n)+log(n)) ==O(logn)
完整代码如下:
class Solution {
public:int findSpecialInteger(vector<int>& arr) {int n=arr.size();int k=n/4;vector<int> candidates={arr[n/4],arr[n/2],arr[n*3/4]};for(int i=0;i<candidates.size();i++){int l=0;int r=n-1;int x=candidates[i];int lx=INT_MAX;int rx=-1;while(l<=r){int mid=(l+r)/2;if(x>=arr[mid]){rx=max(rx,mid);l=mid+1;}else{r=mid-1;}}l=0;r=n-1;while(l<=r){int mid=(l+r)/2;if(x<=arr[mid]){lx=min(lx,mid);r=mid-1;}else{l=mid+1;}}if(rx-lx+1>k){return x;}}return 0;}
};
注意一点在写找3/4位置时,一定要先n3/4,而不是n/43
这是因为由于整数除法会先让 n / 4 变小(向下取整),
导致结果比正确位置偏左(小了一些)。
因此我们在进行乘除运算时一定要先乘后除。