一年没写博客了,感觉自己已经化身一条彻底的咸鱼了。
大三是能决定咸鱼是否翻身的宝贵的一年,希望自己不要再浪了,踏实地学好技术吧。
这周的算法课学到了分治法,刚好可以应用于这道题
所谓分治法,就是一种分治策略:
将一个问题分为若干个同等类型的子问题,然后递归地解决这些子问题,再适当地合并这些子问题的结果,也就解决了最初的问题。
比如这道题目,要求一个int容器里面的主元素,题目给定的主元素定义是出现次数超过⌊ n/2 ⌋次,其中n即为容器的元素数目。我们的分治思想就是将容器不断拆成无数个小容器,再去这些小容器中比较查找主元素,然后不断回溯上来。
分:把容器均分成容器A和容器B
治:寻找容器A和容器B的主元素(在这个过程中,又能对容器A和容器B进行分治)
这样分治下去肯定有尽头,所以递归的边界条件也就是容器只有一个元素时,直接返回该元素。
回溯的时候的判断:
如果A和B的主元素me相等,那么主元素就是me
如果A的主元素是me1,B的主元素是me2,那么重新遍历A和B还没分之前的那个容器,比较me1和me2出现的次数,谁次数大,谁来当主元素。
时间复杂度T(n)=2T(n/2)+2O(n)=O(nlogn)。
class Solution {
public:
int majorityElement(vector<int>& nums) {
if (nums.size() == 1) {
return nums[0];
}
vector<int> vec1(nums.begin(), nums.begin()+nums.size()/2);
int me1 = majorityElement(vec1);
vector<int> vec2(nums.begin()+nums.size()/2, nums.end());
int me2 = majorityElement(vec2);
if (me1 == me2) {
return me1;
} else {
int countme1 = 0;
int countme2 = 0;
for (int i=0; i<nums.size(); ++i) {
if (nums[i] == me1) {
countme1++;
} else {
countme2++;
}
}
return countme1 >= countme2 ? me1 : me2;//注意这里必须要有等号
}
}
};
在网上还有一种不用分治的更简单的算法,主元素的定义是出现次数超过⌊ n/2 ⌋次,并且题目已经给定条件说主元素一定存在,那么对容器的元素进行排序,中位数肯定是主元素,这时候代码如下:
class Solution {
public:
int majorityElement(vector<int>& nums) {
sort(nums.begin(),nums.end());
return nums[nums.size()/2];
}
};