目录
一.基本概念:
🐻在计算机科学中,分治法是一种很重要的算法。字面上的解释就是“分而治之”,就是把一个复杂的问题分成两个或则更多个相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)……
任何一个可以用计算机求解的问题所需的计算时间都与其规模有关。问题的规模越小,越容易直接求解,解题所需的计算时间也越少。例如,对于n个元素的排序问题,当n=1时,不需任何计算。n=2时,只要作一次比较即可排好序。n=3时只要作3次比较即可,…。而当n较大时,问题就不那么容易处理了。要想直接解决一个规模较大的问题,有时是相当困难的。🧐分治策略是:对于一个规模为n的问题,若该问题可以容易地解决(比如说规模n较小)则直接解决,否则将其分解为k个规模较小的子问题,这些子问题互相独立且与原问题形式相同,递归地解这些子问题,然后将各子问题的解合并得到原问题的解。这种算法设计策略叫做分治法。
当我们对分治算法有了以上的一定了解后,来练习几道题目加深理解~~
二.归并排序:
归并排序的流程充分的体现了「分⽽治之」的思想,⼤体过程分为两步:
- 分:将数组⼀分为⼆为两部分,⼀直分解到数组的⻓度为1 ,使整个数组的排序过程被分为 「左半部分排序」+「右半部分排序」;
- 治:将两个较短的「有序数组合并成⼀个⻓的有序数组」,⼀直合并到最初的⻓度。
大致图解过程(图中例子为主):
咱们以leetcode排序数组题目为例:912. 排序数组 - 力扣(LeetCode)
代码详解:
class Solution {
int[] tmp;
public int[] sortArray(int[] nums) {
int n = nums.length;
tmp = new int[n];
mergeSort(nums,0,n - 1);
return nums;
}
public void mergeSort(int[] nums,int left,int right){
if(left >= right) return ;
//取中点划分区域
//[left,mid] [mid + 1,right];
int mid = left + (right - left) / 2;
//排序划分的左数组和右数组
mergeSort(nums,left,mid);
mergeSort(nums,mid + 1,right);
//合并两个有序数组
int cur1 = left,cur2 = mid + 1,i = 0;
while(cur1 <= mid && cur2 <= right){
if(nums[cur1] <= nums[cur2]){
tmp[i++] = nums[cur1++];
}else{
tmp[i++] = nums[cur2++];
}
}
//处理没有完全合并的数组
while(cur1 <= mid) tmp[i++] = nums[cur1++];
while(cur2 <= right) tmp[i++] = nums[cur2++];
//还原数组
for(int j = left;j <= right;j++){
nums[j] = tmp[j - left];
}
}
}
我们提取一下主要框架,大致就是:
看这个框架,也就明白那句经典的总结:归并排序就是先把左半边数组排好序,再把右半边数组排好序,然后把两半数组合并。
运行结果:
三.交易逆序对总数:
题目链接:LCR 170. 交易逆序对的总数 - 力扣(LeetCode)
题目描述:<