【算法】分治法

分治(分而治之)

将 大 问 题 分 解 为 若 干 个 子 问 题 , 子 问 题 解 决 后 再 将 解 合 并 \color{#FF3030}{将大问题分解为若干个子问题,子问题解决后再将解合并}

归并排序

(本题图源自网络)
在这里插入图片描述

int* merge(int *a, int a_len, int *b, int b_len) {
	vector<int> res;
	int *t1 = a, *t2 = b;
	while (a_len > 0 && b_len > 0) {
		if (*t1 < *t2) {
			res.push_back(*t1);
			t1++;
			a_len--;
		}
		else {
			res.push_back(*t2);
			t2++;
			b_len--;
		}
	}
	while (a_len)
	{
		res.push_back(*t1);
		t1++;
		a_len--;
	}
	while (b_len) {
		res.push_back(*t2);
		t2++;
		b_len--;
	}
	int *re = new int[res.size()];
	if (!res.empty()) {
		memcpy(re, &res[0], res.size() * sizeof(int));
	}
	return re;
}
int* merge_sort(int *a, int n) {
	if (n < 2) return a;
	int mid = n / 2;
	int *t = a;
	return merge(merge_sort(a, mid), mid, merge_sort(t + mid, n - mid), n - mid);
}

即T(n)表示输入n个数据时的时间复杂度,那么 T ( n ) = 2 ∗ T ( n / 2 ) + n T(n)=2*T(n/2)+n Tn=2Tn/2+n 接下来用主定理方法来求递归算法的时间复杂度
在这里插入图片描述
符合case2,k=0,很容易得出答案
在这里插入图片描述

Pow(x, n)

Implement pow(x, n), which calculates x raised to the power n (xn).

Example 1:

Input: 2.00000, 10 Output: 1024.00000
Example 2:
Input: 2.10000, 3 Output: 9.26100

暴力法O(n)、分治法:
分解为n/2个数相乘,每个子问题又分解为n/2个数相乘。

    double myPow(double x,int n){
        if(n == 0) return 1;
        if(n < 0) return 1/myPow(x,-n);
        if(n == 1) return x;
        int half = n / 2;
        return myPow(x,half)*myPow(x,n-half);
    }

找出数组中重复的数字

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
剑指offer P42

求众数

Given an array of size n, find the majority element. The majority
element is the element that appears more than ⌊ n/2 ⌋ times.

You may assume that the array is non-empty and the majority element
always exist in the array.

Example 1:

Input: [3,2,3] Output: 3

参见此题的6种解法(需翻墙)

  • 暴力法遍历数组,对每个元素统计个数 O(n2)
  • set,将数组元素插入set,用count方法返回的最大值O(n),或map
    int majorityElement1(vector<int>& nums) {//哈希 O(n) 32ms 空间O(n)
        unordered_map<int,int> hash;
        for(int i=0;i<nums.size();i++){
            if (++hash[nums[i]]>nums.size()/2)
                return nums[i];
        }
    }  
  • 对数组排序,中间的那个数就是众数O(NlogN)
 int majorityElement2(vector<int>& nums) {
        nth_element(nums.begin(), nums.begin() + nums.size() / 2, nums.end());
        return nums[nums.size() / 2];         
   }   
  • 随机法:randomly pick an element and see if it is the majority one.
    int majorityElement3(vector<int>& nums) {
        int n = nums.size();
        srand(unsigned(time(NULL)));
        while (true) {
            int idx = rand() % n;
            int candidate = nums[idx];
            int counts = 0; 
            for (int i = 0; i < n; i++)
                if (nums[i] == candidate)
                    counts++; 
            if (counts > n / 2) return candidate;
        }
    }
  • 分治法,将数组分成两半,对左边和右边都调用函数找众数。O(NlogN)
	int majorityElement(vector<int>& nums) {  //3 分治:left<right 返回right =则随便返回
         return majority(nums, 0, nums.size() - 1);    
    }   
    int majority(vector<int>& nums, int left, int right) {
        if (left == right) return nums[left];//二分到头了 返回该值
        int mid = left + ((right - left) >> 1);
        int lm = majority(nums, left, mid);//二分查找左半部分  lm是左半部分的结果/数值
        int rm = majority(nums, mid + 1, right);
        if (lm == rm) return lm;//左半部分数值等于右半部分数值 那么这个就是我们需要的
        return count(nums.begin() + left, nums.begin() + right + 1, lm) > count(nums.begin() + left, nums.begin() + right + 1, rm) ? lm : rm;
        // 左半部分某个数出现的多,那么就返回这个数
    }
  • 摩尔投票法:以1 2 3 3 4 1 1 1 1为例。指针开始指向1,遇到不一样的2,他们抵消了。指针又指向3,遇到3,计数器加1,遇到4和1,又被抵消了。指针指向1,遇到1,没被抵消。遍历完毕,剩下的1就是众数。原理就是,若众数为1,其他数为-1,和一定大于0。
class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int target = nums[0];
        int count = 1;
        for(int i = 1;i<nums.size();i++)
            if(nums[i]!=target)  
            {  
                count--;
                if(count==0)//count为0 则选择下一个元素为target
                {
                    target = nums[i];
                    count = 1;
                }
            }else count++;
      return target;
    }
};

作者:heroine-yun
链接:https://leetcode-cn.com/problems/majority-element/solution/tong-gui-yu-jin-by-vailing/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值